cancel
Showing results for 
Search instead for 
Did you mean: 

DMA on STM32L011F4

Archadious
Associate II

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
View more

 

1 ACCEPTED SOLUTION

Accepted Solutions

You have to set DMA_CSELR.C2S = 0b0100 to map the USART2_TX request to DMA1_Channel2 (your STM32 model is Cat.1, right?)

waclawekjan_0-1731436880271.png

JW

View solution in original post

3 REPLIES 3

> 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

You have to set DMA_CSELR.C2S = 0b0100 to map the USART2_TX request to DMA1_Channel2 (your STM32 model is Cat.1, right?)

waclawekjan_0-1731436880271.png

JW

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