Skip to main content
Visitor II
November 14, 2024
Question

STM32L011 USART2 and DMA (Continued)

  • November 14, 2024
  • 7 replies
  • 2926 views

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 

    This topic has been closed for replies.

    7 replies

    Visitor II
    November 14, 2024
    //-----------------------------------------------------------------------------
    #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
    Graduate II
    November 14, 2024

    Is there an reception? Does it work with POLLED, or IRQ?

    Or is it locked up with a RX ERROR of some sort? Check USART2 ISR for parity, framing or noise errors.

    Visitor II
    November 14, 2024

    Very good question.  I should have mentioned that I am able to use polling and interrupts without DMA to receive data from USART2.  This proved to me that the hardware is correct. 

    I believe my configuration of DMA maybe at fault and was hoping to have other eyes on my code to point out where my misunderstanding is.

     

    -A

    Super User
    November 15, 2024

    Read out and check/post DMA and UART registers content.

    JW

    Visitor II
    November 17, 2024

    That was a good suggestion.  However, I am still not seeing the reason why the code is not receiving incoming data.  I must still be a setting with DMA.

     

    DMA1.registers.jpg

    Super User
    November 17, 2024

    I don't see any problem here.

    Is this *after* data have been arrived at the UART's Rx pin?

    What are the UART registers content after that? (note, that you should not observe those registers permanently in the IDE, due to reading UARTx_RDR by debugger clearing the RXNE flag).

    JW

    Visitor II
    November 18, 2024

    Are there any specific register values that I should be looking for?  If my DMA settings look correct, then maybe I do need to take another look at my USART code.

     

    -A 

    Super User
    November 18, 2024
    > Are there any specific register values that I should be looking for?
     
    As I have no idea what's wrong (especially since you've said that polled implementation works, which would rule out hardware-related issues like incorrectly connected/setup Rx pin, incorrectly set baudrate, etc.), this is just  the generic recommendation. The mcu works out of the registers not out of source code, so looking at the registers (carefully, given debugger is intrusive, see above) should be the ultimate debugging method for the peripherals.
    JW
    Visitor II
    November 18, 2024

    usart.dma.jpg

    Super User
    November 19, 2024

    FE status bit is suspicious, and also the RDR content - have you transmitted 0x00 to Rx pin?

    Without writing any more code, try to

    - stop program execution

    - disable DMA by writing to its control register

    - transmit one byte to the UART_Rx pin

    - observe the UART registers - RXNE should be set (don't use "live registers view" or similar in IDE, which would repeatedly read the registers, as reading UART_RDR clears RXNE)

    - stop observing the UART registers

    - enable DMA

    - transmit one byte to the UART_Rx pin

    - look at the DMA registers, there should be a decrement in NDTR and the received byte should appear in the memory buffer

    JW

    Visitor II
    November 27, 2024

    A simple solution and an embarrassing oversight.

    I finally noticed that I was setting pin A0 (USART2 RX) to AF4 rather than AF0.  My code now works correctly.  

    Thank you for your suggests.

     

    -A