diff --git a/IDE/STM32Cube/README.md b/IDE/STM32Cube/README.md index e9923e25..7c7b1201 100644 --- a/IDE/STM32Cube/README.md +++ b/IDE/STM32Cube/README.md @@ -125,6 +125,18 @@ void HAL_ETH_MspInit(ETH_HandleTypeDef* heth) } ``` +### BusFault in an atomic operation on STM32H7R/S + +Symptom: a precise BusFault (`CFSR.PRECISERR`, with `BFAR` pointing at the variable) in `__atomic_fetch_add` or another atomic, for example in wolfSSL built with `FREERTOS`. + +Cause: the MPU region covering the AXI SRAM is marked Shareable. Atomics compile to `LDREX`/`STREX`, and an exclusive access to Shareable memory faults on this family. Set `IsShareable = MPU_ACCESS_NOT_SHAREABLE` for that region. + +Shareable memory is also not held in the Cortex-M7 D-cache, so a Shareable AXI SRAM region runs uncached even with the D-cache enabled. + +### Task stacks in DTCM or CCM + +wolfIP builds outgoing frames on the stack of the task that sends them, and the Ethernet DMA cannot read core-coupled memory. With `STM32_HAL_ETH_TX_BOUNCE` defined, `stm32_hal_eth.c` copies each frame into a static buffer before transmitting, so the stack may be placed anywhere. It is on by default for STM32H7R/S, whose vendor linker scripts put the main stack in DTCM; define `STM32_HAL_ETH_NO_TX_BOUNCE` there to turn it off. Without it, every stack that wolfIP transmits from must be in memory the Ethernet DMA can reach. The driver's own RX and TX buffers are static data, so the section they are linked into (`.bss` by default) must be in DMA-reachable memory as well. + ## Using TLS with wolfIP To use TLS (HTTPS, secure sockets): diff --git a/src/port/stm32_hal/stm32_hal_eth.c b/src/port/stm32_hal/stm32_hal_eth.c index b7990b12..05c9ecd8 100644 --- a/src/port/stm32_hal/stm32_hal_eth.c +++ b/src/port/stm32_hal/stm32_hal_eth.c @@ -233,6 +233,19 @@ static int hal_eth_poll(struct wolfIP_ll_dev *dev, void *frame, uint32_t len) return (int)frame_len; } +/* wolfIP builds outgoing frames on the caller's stack. Sending from a static + * buffer keeps the DMA off that stack, which it cannot reach when the stack + * is in core-coupled memory (DTCM, CCM). On by default for STM32H7R/S, where + * the vendor linker scripts put the main stack in DTCM. Like rx_buffers, the + * buffer must be linked into memory the DMA can reach. */ +#if defined(STM32H7RS) && !defined(STM32_HAL_ETH_NO_TX_BOUNCE) && \ + !defined(STM32_HAL_ETH_TX_BOUNCE) + #define STM32_HAL_ETH_TX_BOUNCE +#endif +#ifdef STM32_HAL_ETH_TX_BOUNCE +static uint8_t tx_frame[ETH_RX_BUFFER_SIZE] __attribute__((aligned(32))); +#endif + /** * @brief Send an Ethernet frame */ @@ -247,6 +260,11 @@ static int hal_eth_send(struct wolfIP_ll_dev *dev, void *frame, uint32_t len) return -1; } +#ifdef STM32_HAL_ETH_TX_BOUNCE + memcpy(tx_frame, frame, len); + frame = tx_frame; +#endif + #ifdef ETH_DCACHE_ENABLED if (ETH_DCACHE_ENABLED()) { SCB_CleanDCache_by_Addr((uint32_t *)frame, (int32_t)len); diff --git a/src/port/stm32_hal/stm32_hal_eth.h b/src/port/stm32_hal/stm32_hal_eth.h index cec8429b..0997f48a 100644 --- a/src/port/stm32_hal/stm32_hal_eth.h +++ b/src/port/stm32_hal/stm32_hal_eth.h @@ -106,6 +106,10 @@ * several descriptors and is dropped * - On Cortex-M7 with the D-cache enabled, RX buffers are invalidated and * TX frames cleaned around each DMA transfer + * - With STM32_HAL_ETH_TX_BOUNCE, TX frames are copied into a static buffer + * before transmission, so the caller's stack may be in memory the DMA + * cannot reach (DTCM, CCM). Default on STM32H7R/S; turn it off there with + * STM32_HAL_ETH_NO_TX_BOUNCE * - Assumes CubeMX generates `heth` and `TxConfig` as extern globals */