2024-11-12 09:36 AM
I'm trying to program an STM32L011F4 to transmit data through USART2 by way of the DMA controller. My code compiles but the IRQ handler for DMA is never called. Either I have not correctly initialized the DMA controller or there is another problem I am overlooking. Can anyone provide suggestions?
//-----------------------------------------------------------------------------
#include <stdio.h>
#include "stm32l0xx.h"
//-----------------------------------------------------------------------------
#define USART_TX_PIN GPIO_PIN_2
#define DMA_BUFFER_SIZE 64
uint8_t dma_buffer[ DMA_BUFFER_SIZE ] = "String to send through USART2 by DMA!\r\n";
//-----------------------------------------------------------------------------
void SystemClock_Config(void);
void USART2_Init(void);
void DMA_Init(void);
void Start_DMA_Transmission(void);
//-----------------------------------------------------------------------------
int main( void ) {
SystemClock_Config(); // Configure system clock
USART2_Init(); // Initialize USART2
DMA_Init(); // Initialize DMA
Start_DMA_Transmission(); // Start data transmission over DMA
while (1) { __asm__( "NOP" ); };
}; // end main
//-----------------------------------------------------------------------------
void SystemClock_Config( void ) {
// Configure the system clock to use HSI at 16 MHz
RCC->CR |= RCC_CR_HSION; // Enable HSI
while ( !( RCC->CR & RCC_CR_HSIRDY ) ){ __asm__( "NOP" ); }; // Wait for HSI
RCC->CFGR = 0; // System clock source is HSI
SystemCoreClockUpdate(); // Update SystemCoreClock variable
}; // end SystemClock_Config
//-----------------------------------------------------------------------------
void USART2_Init( void ) {
// Enable GPIOA and USART2 clocks
RCC->IOPENR |= RCC_IOPENR_GPIOAEN;
RCC->APB1ENR |= RCC_APB1ENR_USART2EN;
// Configure PA2 as USART2 TX
GPIOA->MODER &= ~GPIO_MODER_MODE2; // Clear mode bits
GPIOA->MODER |= GPIO_MODER_MODE2_1; // Set PA2 to alternate function mode
GPIOA->AFR[0] |= ( 4 << GPIO_AFRL_AFSEL2_Pos ); // Set PA2 to AF4 (USART2)
// Configure USART2 baud rate, enable TX, enable USART
USART2->BRR = SystemCoreClock / 9600; // Set baud rate to 9600 (assuming 16 MHz clock)
USART2->CR1 = USART_CR1_TE | USART_CR1_UE; // Enable TX and USART
}; // end USART2_Init
//-----------------------------------------------------------------------------
void DMA_Init(void) {
RCC->AHBENR |= RCC_AHBENR_DMA1EN; // Enable DMA clock
DMA1_Channel2->CCR &= ~DMA_CCR_EN; // Disable channel before configuration
DMA1_Channel2->CCR &= ~( DMA_CCR_MSIZE_0 | DMA_CCR_MSIZE_1 ); // Set size to 8 bits
DMA1_Channel2->CCR &= ~( DMA_CCR_PSIZE_0 | DMA_CCR_PSIZE_1 ); // Set USART to 8 bits
DMA1_Channel2->CCR =
DMA_CCR_MINC | // Enable memory increment
DMA_CCR_DIR | // Read from memory
DMA_CCR_TEIE | // Transfer error flag
DMA_CCR_HTIE | // Half transfer flag
DMA_CCR_TCIE; // Enable transfer complete interrupt
// Configure DMA for USART2 TX (Channel 2)
DMA1_Channel2->CPAR = (uint32_t)(&(USART2->TDR)); // Set peripheral address to USART2 TDR
DMA1_Channel2->CMAR = (uint32_t)dma_buffer; // Set memory address to dma_buffer
DMA1_Channel2->CNDTR = sizeof(dma_buffer) - 1; // Set number of data items to transfer
DMA1_Channel2->CCR &= ~( DMA_CCR_PL_0 | DMA_CCR_PL_1 ); // Set priority to low
// Enable DMA interrupt in NVIC
NVIC_SetPriority( DMA1_Channel2_3_IRQn, 0x0 );
NVIC_EnableIRQ( DMA1_Channel2_3_IRQn );
}; // DMA_Init
//-----------------------------------------------------------------------------
void Start_DMA_Transmission( void ) {
USART2->CR3 |= USART_CR3_DMAT; // Enable DMA for USART2 TX
while ( ( USART2->ISR & USART_ISR_TC ) != USART_ISR_TC ) { __asm__( "NOP" ); };
USART2->ICR = USART_ICR_TCCF; // Clear TC Flag
DMA1_Channel2->CCR |= DMA_CCR_EN; // Enable DMA Channel 2
}; // end Start_DMA_Transmission
//-----------------------------------------------------------------------------
void DMA1_Channel2_3_IRQHandler( void ) {
if ( DMA1->ISR & DMA_ISR_TCIF2 ) { // Check for transfer complete interrupt flag
DMA1->IFCR = DMA_IFCR_CTCIF2; // Clear transfer complete interrupt flag
DMA1_Channel2->CCR &= ~DMA_CCR_EN; // Disable DMA Channel 4 after transfer
return;
}; // end TCIF2
}; // end DMA1_Channel2_3_IRQHandler
Solved! Go to Solution.
2024-11-12 10:41 AM
You have to set DMA_CSELR.C2S = 0b0100 to map the USART2_TX request to DMA1_Channel2 (your STM32 model is Cat.1, right?)
JW
2024-11-12 10:31 AM
> IRQ handler for DMA is never called.
How do you know?
Where does the PC end up, isn't it some default handler?
Read out and check/post content of the DMA registers.
Check the interrupt vector table in disasm.
Generic "interrupt does not fire" checklist here.
JW
2024-11-12 10:41 AM
You have to set DMA_CSELR.C2S = 0b0100 to map the USART2_TX request to DMA1_Channel2 (your STM32 model is Cat.1, right?)
JW
2024-11-12 11:59 AM
That was it, the code now works correctly. Thanks for pointing out what I had overlooked.
I had read that section of the manual several times but thought it wasn't required because I was transmitting and not receiving data on the usart.
-Archadious