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 IO | Raw CC35 GPIO | Carrier net |
|---|---|---|
ALP_E1M_GPIO_IO8 | 30 | I2S_EN |
ALP_E1M_GPIO_IO9 | 12 | PCIE_IO_EXP.RST |
ALP_E1M_GPIO_IO10 | 35 | PCIE0_I2C.EN |
ALP_E1M_GPIO_IO11 | 2 | USB2_SELECT |
ALP_E1M_GPIO_IO13 | 13 | I2S_SELECT ← demo pad |
ALP_E1M_GPIO_IO15 | 14 | S_BMI323.INT1 |
ALP_E1M_GPIO_IO16 | 17 | EN_W_DIS2n (open-drain) |
ALP_E1M_GPIO_IO18 | 18 | M2E_SDIO_WAKEn |
ALP_E1M_GPIO_IO19 | 19 | M2E_UART.WAKEn_L |
ALP_E1M_GPIO_IO20 | 26 | MUX_EN |
The two camera-enable LDOs are which=0 → CAM_EN_LDO0 and which=1 → CAM_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_INTERRUPTframe 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
cc3501e_bridge_bringup()— open the bridge SPI + control lines, attach the proxy, power + reset the coprocessor.gpio_config_out— configure pad 13 asDIR_OUTPUT/PULL_NONE.gpio_write_high— drive pad 13 high.gpio_write_low— drive pad 13 low.gpio_config_in— reconfigure pad 13 asDIR_INPUT/PULL_UP.gpio_read— sample pad 13 and print the level.cam_enable/cam_disable— enable then disable camera LDO0.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
aen-cc3501e-bringup— the minimal power + PING soak, and the inter-chip wiring tableaen-cc3501e-companion-tour— the full-surface capstonealp-console— reaches the same proxy throughalp companion gpio<alp/peripheral.h>reference — GPIO- Chip catalogue
- Examples overview