mothercup/mcm-ddc-ble/inc/bsp_usart.h
evan.liu f729d16ff2 V1.00.25: UART OTA stream mode + RX DMA ring + SRAM cliff fix
Firmware:
- bsp_usart: RX moved from RXDNE byte-queue IRQ to DMA CH2 circular ring
  (2KB) + IDLE-irq wakeup; bytes keep landing during flash-erase
  interrupt-off windows (the reason lockstep was needed before)
- app_ota: stream mode (ble_protocol.md section 6.7) - 16B BEGIN with
  flags bit0=STREAM (UART channel only), DATA acked on 4KB sector
  crossings (original chunk length; two ack-gating bugs fixed during
  field test), throttled BAD_STATE for go-back-N
- FreeRTOS heap 20KB->18KB: the 2KB ring pushed the stack top past the
  0x2000C000 SRAM cliff (probed via SWD: accesses above fault on this
  silicon, usable app SRAM is 32KB) which locked the board at boot;
  merge_image.py now hard-fails the package when the image initial SP
  leaves (0x20004000, 0x2000C000]

Tools:
- ble_ota_update.py: UART stream sender (8KB window, stall watchdog
  rewind, auto-fallback to lockstep on pre-V1.00.24 firmware,
  --lockstep to force); case-insensitive option parsing
- flash_package.py/bat: stream NSpyocd output live (chunked reads keep
  the \r progress bar), vendor banner rebranded to CAIIC NSLINK UMP
- merge_image.py: initial-SP cliff guard

Verified: UART stream OTA both directions, 55.8KB in ~5.9s @9.5kB/s
0 rewinds (lockstep was 39s), PASS after reboot; board boot fixed and
verified via SWD.

Docs: ble_protocol.md section 6.7, dev log section 47 (+ SRAM cliff
post-mortem), AGENTS.md RAM rule rewritten (both cliffs) + V1.00.25
2026-09-05 09:48:28 +08:00

70 lines
2.4 KiB
C

/**
* @file bsp_usart.h
* @brief USART1 support: printf retarget (polling TX), DMA TX, RX DMA
* circular ring + IDLE interrupt. TX=PB6, RX=PB7, 115200 8N1.
*/
#ifndef __BSP_USART_H__
#define __BSP_USART_H__
#ifdef __cplusplus
extern "C" {
#endif
#include "n32wb03x.h"
#define BSP_USARTx USART1
#define BSP_USART_CLK RCC_APB2_PERIPH_USART1
#define BSP_USART_GPIO GPIOB
#define BSP_USART_GPIO_CLK RCC_APB2_PERIPH_GPIOB
#define BSP_USART_TX_PIN GPIO_PIN_6
#define BSP_USART_RX_PIN GPIO_PIN_7
#define BSP_USART_TX_GPIO_AF GPIO_AF4_USART1
#define BSP_USART_RX_GPIO_AF GPIO_AF4_USART1
#define BSP_USART_BAUDRATE 115200
/* USART1 TX DMA channel (remap required on this chip) */
#define BSP_USART_TX_DMA_CH DMA_CH1
#define BSP_USART_TX_DMA_TC DMA_FLAG_TC1
#define BSP_USART_TX_DMA_REMAP DMA_REMAP_USART1_TX
/* USART1 RX DMA channel: circular mode into a 2KB ring, drained by
* bsp_usart_read_byte(). DMA keeps sampling while interrupts are off
* (flash erase windows during UART OTA streaming). */
#define BSP_USART_RX_DMA_CH DMA_CH2
#define BSP_USART_RX_DMA_REMAP DMA_REMAP_USART1_RX
#define BSP_USART_DAT_ADDR (USART1_BASE + 0x04)
/* Pass to bsp_usart_read_byte() to block without timeout */
#define BSP_USART_WAIT_FOREVER 0xFFFFFFFFu
void bsp_usart_init(void);
/* Re-apply the baud rate at runtime (keeps RX interrupt/DMA setup).
* Used by the "uartrst" CLI command after a baud parameter change. */
void bsp_usart_set_baud(uint32_t baud);
/* TX: send a buffer through DMA (polled completion) */
void bsp_usart_write_dma(const uint8_t* data, uint16_t len);
/* RX: fetch one received byte. Source order: the inject queue (BLE
* downlink feeding the CLI) first, then the DMA RX ring. Returns 1 on
* success, 0 on timeout. */
int bsp_usart_read_byte(uint8_t* ch, uint32_t timeout_ms);
/* RX: inject bytes from task context (BLE downlink feeds the CLI through
* this). Bytes are dropped when the inject queue is full. */
void bsp_usart_rx_inject(const uint8_t* data, uint16_t len);
/* TX mutex so that DMA bursts and polling printf lines do not interleave.
* No-ops while the scheduler is not running. */
void bsp_usart_tx_lock(void);
void bsp_usart_tx_unlock(void);
/* Called from USART1_IRQHandler (see n32wb03x_it.c) */
void bsp_usart_rx_isr_handler(void);
#ifdef __cplusplus
}
#endif
#endif /* __BSP_USART_H__ */