2024-11-14 10:30 AM - last edited on 2024-11-14 11:06 AM by SofLit
Previous post: https://community.st.com/t5/stm32-mcus-embedded-software/dma-on-stm32l011f4/td-p/742092
I am working with code on the STM32L011 that uses DMA to read data from USART2. I received excellent help on this forum before and I'm hoping for the same now.
I'm using a custom PCB and several colored LEDs for debugging.
I expect the code to echo data it receives from the USART2 but it does not. And neither LED is turned on. It seems that the DMA IRQ handler is not being called. I believe I'm missing something simple again.
-A
2024-11-14 10:32 AM
//-----------------------------------------------------------------------------
#include <stdbool.h>
#include <stdio.h>
#include "stm32l0xx.h"
#include "gpio.h"
//-----------------------------------------------------------------------------
#define DMA_BUFFER_SIZE 8
uint8_t dma_buffer[ DMA_BUFFER_SIZE ];
volatile bool flag = false;
//-----------------------------------------------------------------------------
void systemclock_config( void );
void usart2_init( void );
void usart2_write( uint8_t );
void dma_init( void );
//-----------------------------------------------------------------------------
int __io_putchar( int chr ) {
usart2_write( chr );
return chr;
}; // end __io_putchar
//-----------------------------------------------------------------------------
int main( void ) {
systemclock_config( ); // Configure system clock
// Clear buffer - quick and dirty code
for ( int i = 0; i < DMA_BUFFER_SIZE; ++i ) { dma_buffer[ i ] = 0x0; };
usart2_init( );
dma_init( );
USART2->CR3 |= USART_CR3_DMAR; // turn on DMA
printf( "Start of Application\r\n" );
while ( 1 ) {
if ( flag == true ) {
WHITE_LED_ON;
flag = false;
printf( "\r\nReceived '%s'\r\n", dma_buffer );
}; // end if flag
}; // end while loop
}; // 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)); // Wait for HSI to be ready
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 PA0 as USART2 TR
GPIOA->MODER &= ~GPIO_MODER_MODE0; // Clear mode bits
GPIOA->MODER |= GPIO_MODER_MODE0_1; // Set PA0 to alternate function mode
GPIOA->AFR[0] |= ( 4 << GPIO_AFRL_AFSEL0_Pos ); // Set PA0 to AF0 (USART2)
// 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 with a 16 MHz clock)
USART2->CR1 =
USART_CR1_RE | // Enable RX
USART_CR1_TE | // Enable TX
USART_CR1_UE; // Enable USART
}; // end init_usart2
//-----------------------------------------------------------------------------
void usart2_write( uint8_t ch ) {
while ( !( USART2->ISR & USART_ISR_TXE ) ) { __asm__( "nop" ); };
USART2->TDR = ( ch & 0xff ); // ensure all 8-bits are transmitted
}; // end usart2_write
//-----------------------------------------------------------------------------
void dma_init( void ) {
// Enable DMA clock
RCC->AHBENR |= RCC_AHBENR_DMA1EN;
DMA1_Channel5->CCR &= ~DMA_CCR_EN; // turn off DMA1
DMA1_CSELR->CSELR &= ~DMA_CSELR_C5S;
DMA1_CSELR->CSELR |= ( 0b0100 << DMA_CSELR_C5S_Pos );
// Configure DMA for USART2 TX (Channel 5)
DMA1_Channel5->CPAR = (uint32_t)&USART2->RDR; // Set peripheral address to USART2 RDR
DMA1_Channel5->CMAR = (uint32_t)dma_buffer; // Set memory address to dma_buffer
DMA1_Channel5->CNDTR = DMA_BUFFER_SIZE - 1; // Set number of data items to transfer
DMA1_Channel5->CCR =
DMA_CCR_MINC | // enable memory increment
DMA_CCR_TCIE; // | // enable transfer complete interrupt
DMA1_Channel5->CCR &= ~DMA_CCR_DIR; // clear DIR field
DMA1_Channel5->CCR |= ( 0b11 << DMA_CCR_PL_Pos );
DMA1_Channel5->CCR &= ~DMA_CCR_MSIZE; // memory size 8-bits
DMA1_Channel5->CCR &= ~DMA_CCR_PSIZE; // usart size 8-bits
// Enable DMA interrupt in NVIC
NVIC_EnableIRQ(DMA1_Channel4_5_IRQn);
NVIC_SetPriority( DMA1_Channel4_5_IRQn, 0x0 );
DMA1_Channel5->CCR |= DMA_CCR_EN; // turn on DMA1
}; // end init_dma
//-----------------------------------------------------------------------------
void DMA1_Channel4_5_IRQHandler( void ) {
ORANGE_LED_ON;
if ( DMA1->ISR & DMA_ISR_TCIF5 ) { // Check for transfer complete interrupt flag
DMA1->IFCR = DMA_IFCR_CTCIF5; // Clear transfer complete interrupt flag
DMA1_Channel5->CCR &= ~DMA_CCR_EN; // Disable DMA Channel 5 after transfer
flag = true;
}; // end if
}; // end IRQ