Skip to main content

aen-cc3501e-gpio

Host (Alif) side of the on-module TI CC3501E GPIO proxy + camera-enable demo on the E1M-AEN801 (Alif Ensemble E8) SoM.

It runs on the Alif M55-HE core. It brings the inter-chip SPI bridge up exactly like aen-cc3501e-bringup — one call to cc3501e_bridge_bringup() — then exercises a different slice of the coprocessor firmware: it configures, drives, and reads a proxied CC3501E GPIO, and enables/disables the camera LDOs over the bridge, using only the portable cc3501e_* host API.

Source: examples/aen/aen-cc3501e-gpio/.

What is the GPIO proxy?

Some E1M edge IO pads on the AEN SoM are not wired to an Alif pin — they are wired to a CC3501E GPIO. So when an application asks for IO13, the SDK cannot toggle an Alif register; it asks the CC3501E firmware to toggle the pad on its behalf, over the SPI bridge. That indirection — host op → bridge frame → CC3501E drives the pad — is the proxy.

There are two ways to reach it.

Portable — what an application normally writes:

alp_gpio_t *io = alp_gpio_open(ALP_E1M_GPIO_IO13);
alp_gpio_configure(io, ALP_GPIO_OUTPUT, ALP_GPIO_PULL_NONE);
alp_gpio_write(io, true);

With CONFIG_ALP_SDK_GPIO_CC3501E_PROXY=y and the example's route table, the SDK silently routes ALP_E1M_GPIO_IO13 over the bridge to raw CC3501E GPIO_13. The app never names the coprocessor.

Direct — what this demo does, so each bridge op is visible in the teaching log:

cc3501e_gpio_configure(&fw, 13, ALP_CC3501E_GPIO_DIR_OUTPUT,
ALP_CC3501E_GPIO_PULL_NONE, 100);
cc3501e_gpio_write(&fw, 13, true, 100);

Here the pad number is the raw CC3501E GPIO index — the same wire op the portable path emits underneath.

The proxied pads

From the example's route table (E1M-AEN netlist):

E1M IORaw CC35 GPIOCarrier net
ALP_E1M_GPIO_IO830I2S_EN
ALP_E1M_GPIO_IO912PCIE_IO_EXP.RST
ALP_E1M_GPIO_IO1035PCIE0_I2C.EN
ALP_E1M_GPIO_IO112USB2_SELECT
ALP_E1M_GPIO_IO1313I2S_SELECTdemo pad
ALP_E1M_GPIO_IO1514S_BMI323.INT1
ALP_E1M_GPIO_IO1617EN_W_DIS2n (open-drain)
ALP_E1M_GPIO_IO1818M2E_SDIO_WAKEn
ALP_E1M_GPIO_IO1919M2E_UART.WAKEn_L
ALP_E1M_GPIO_IO2026MUX_EN

The two camera-enable LDOs are which=0CAM_EN_LDO0 and which=1CAM_EN_LDO1.

The host-IRQ caveat — read before using interrupts

This HW rev uses hardware SS0 for SPI framing and a READY input for per-phase gating, but it still does not expose GPIO edge events as portable application callbacks. The Alif is always master; the CC3501E is always slave. Without a dedicated async event-delivery path, the slave cannot spontaneously tell the master "an edge happened."

So cc3501e_gpio_set_interrupt():

  • arms the edge on the CC3501E's own GPIO controller — this is real; it latches edges in the coprocessor;
  • but the async ALP_CC3501E_EVT_GPIO_INTERRUPT frame is not a portable callback path in this example.

Poll cc3501e_gpio_read() when you need to observe a level. Do not build a design that depends on EVT_GPIO_INTERRUPT delivery on this rev.

EDGE_BOTH is unsupported on the CC35xx controller — arm RISING or FALLING, never both.

What it does

  1. cc3501e_bridge_bringup() — open the bridge SPI + control lines, attach the proxy, power + reset the coprocessor.
  2. gpio_config_out — configure pad 13 as DIR_OUTPUT / PULL_NONE.
  3. gpio_write_high — drive pad 13 high.
  4. gpio_write_low — drive pad 13 low.
  5. gpio_config_in — reconfigure pad 13 as DIR_INPUT / PULL_UP.
  6. gpio_read — sample pad 13 and print the level.
  7. cam_enable / cam_disable — enable then disable camera LDO0.
  8. gpio_irq_arm — arm a rising-edge interrupt on pad 13 (arms only — see the caveat above).

board.yaml

som:
sku: E1M-AEN801

preset: e1m-evk

cores:
a32_cluster:
os: "off"
m55_he:
app: ./src
peripherals:
- spi
- gpio

chips:
- cc3501e # on-module Wi-Fi 6 + BLE 5.4 coprocessor (host driver)

diagnostics:
log_level: info

The inter-chip wiring lives in the per-board overlay rather than board.yaml's pins: — those are SoM-internal control nets, not E1M edge pads.

Bench contract

Each step prints exactly one line a sibling bench script greps:

GPIO_TEST: <step> <PASS|FAIL>

with the step tokens, in order: gpio_config_out, gpio_write_high, gpio_write_low, gpio_config_in, gpio_read, cam_enable, cam_disable, gpio_irq_arm. Then:

GPIO_TEST: SUMMARY pass=<n> fail=<n>

On silicon with the CC3501E firmware up, expect pass=8 fail=0.

Status

build_only: true on native_sim/native/64. The host build there sees only an emulated SPI controller with no CC3501E attached, so every bridge op times out and the contract lines print FAIL — that is expected. native_sim proves the example builds; the PASS/FAIL contract is a silicon signal.

The CC3501E peer firmware is Alp-authored and lives in the SDK tree at firmware/cc3501e/ (embedded, like the GD32 bridge). Bench bring-up needs two J-Links — one on the Alif, one on the CC3501E — and the CC3501E reads VTref=0V until the Alif app powers it.

See also

Questions about this page? Discuss in Community Forum