Thanks to help from this site, my code can send and receive over the STM32F446RE Nucleo UART (using the Nucleo's built-in ST-Link / VCP). I'm now trying to move the receive to DMA, and seem to get a no-op: The uint8_t uart_recv_dma_buf0
remain all 00
(as shown in gdb), and the ISR is never called.
I've checked my code against the examples I can find online, and don't see anything missing or incorrect. (There's obviously a bit of a gap with each example, as each one I've found targets a somewhat different configuration).
What should be my next step in debugging?
#pragma once
#include <stdint.h>
#include <libopencm3/stm32/rcc.h>
#include <libopencm3/stm32/dma.h>
#include <libopencm3/stm32/usart.h>
#include <libopencm3/cm3/nvic.h>
#define UART_RECV_DMA_BUF_SIZE 8
volatile uint8_t uart_recv_dma_buf0[UART_RECV_DMA_BUF_SIZE];
volatile uint8_t uart_recv_dma_buf1[UART_RECV_DMA_BUF_SIZE];
// The values below are for USART2 on STM32F446xx
#define SER USART2
#define SER_RX_PERIPH_ADDR USART2_DR
// DMA Controller 1
#define SER_RX_DMA DMA1
#define SER_RX_DMA_RCC RCC_DMA1
// DMA Stream 5
#define SER_RX_DMA_STREAM DMA_STREAM5
#define SER_RX_DMA_IRQ NVIC_DMA1_STREAM5_IRQ
#define SER_RX_DMA_ISR dma1_stream5_isr
// DMA Channel 4
#define SER_RX_DMA_CHANNEL DMA_SxCR_CHSEL_4
void uart_recv_dma_init() {
// Config
rcc_periph_clock_enable(SER_RX_DMA_RCC);
dma_stream_reset(SER_RX_DMA, SER_RX_DMA_STREAM);
dma_set_priority(SER_RX_DMA, SER_RX_DMA_STREAM, DMA_SxCR_PL_LOW);
dma_channel_select(SER_RX_DMA, SER_RX_DMA_STREAM, SER_RX_DMA_CHANNEL);
dma_set_transfer_mode(SER_RX_DMA, SER_RX_DMA_STREAM, DMA_SxCR_DIR_PERIPHERAL_TO_MEM);
dma_set_memory_size(SER_RX_DMA, SER_RX_DMA_STREAM, DMA_SxCR_MSIZE_8BIT); // 1 byte at a time
dma_set_peripheral_size(SER_RX_DMA, SER_RX_DMA_STREAM, DMA_SxCR_MSIZE_8BIT);
dma_enable_memory_increment_mode(SER_RX_DMA, SER_RX_DMA_STREAM); // Increment mem ptr each time
dma_disable_peripheral_increment_mode(SER_RX_DMA, SER_RX_DMA_STREAM); // Periph addr is fixed
dma_enable_circular_mode(SER_RX_DMA, SER_RX_DMA_STREAM);
dma_enable_double_buffer_mode(SER_RX_DMA, SER_RX_DMA_STREAM);
// Addresses
dma_set_peripheral_address(SER_RX_DMA, SER_RX_DMA_STREAM, SER_RX_PERIPH_ADDR); // Read from USART DR
dma_set_memory_address(SER_RX_DMA, SER_RX_DMA_STREAM, (uint32_t) uart_recv_dma_buf0); // And write to these addresses
dma_set_memory_address_1(SER_RX_DMA, SER_RX_DMA_STREAM, (uint32_t) uart_recv_dma_buf1);
dma_set_initial_target(SER_RX_DMA, SER_RX_DMA_STREAM, 0);
dma_set_number_of_data(SER_RX_DMA, SER_RX_DMA_STREAM, UART_RECV_DMA_BUF_SIZE);
// Interrupts
nvic_enable_irq(SER_RX_DMA_IRQ);
// TODO set priority
dma_enable_transfer_complete_interrupt(SER_RX_DMA, SER_RX_DMA_STREAM);
// TODO: Enable intrpt for idle, to process partial transfers
// And launch!
dma_enable_stream(SER_RX_DMA, SER_RX_DMA_STREAM);
usart_enable_rx_dma(SER);
}
void SER_RX_DMA_ISR(void) {
asm("bkpt");
}
```