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

 

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