Rupesh kadam
Rupesh kadam

Reputation: 11

I am getting DMA Transfer error interrupt every time I try to send a byte through PC COM Port to STM32F446RE

I am trying register level programming for STM32F446RE Nucleo-64 board. I want to receive data through UART in circular mode using DMA. I am getting DMA Transfer error interrupt every time I try to send a byte through PC COM port to STM32F446RE. I am using Tera Term Terminal for sending the byte over COM Port at Baud rate of 115200.

I am using UART2 because its pins are connected to usb through ST-Link micro. which I can access through PC via virtual COM Port.

I am suspecting the sequence which I am using for enabling bits are faulty. Here is the sequence I am using: UART RX EN >> DMAR EN >> DMA Stream EN >> UART EN.

Is it the correct sequence to configure UART with DMA for reception?

So far I have implemented:

main.c

#include <stdint.h>
#include <string.h>
#include "stm32f446xx.h"

void HT_Complete_callback(void);
void FT_Complete_callback(void);
void TE_error_callback(void);
void FE_error_callback(void);
void DME_error_callback(void);
void IDLE_IRQ_callback(void);

void DMA_init(void);
void DMA_Config (uint32_t srcAdd, uint32_t destAdd, uint16_t datasize);
void UART2_init (void);
void UART2_config (void);


#define RXSIZE 20
#define pDest (SRAM2_BASE + 0x800)

int main(void)
{
    UART2_init ();
    DMA_init();
    DMA_Config (USART2->DR,(uint32_t) pDest, RXSIZE);
    UART2_config ();

    /* Loop forever */
    while (1)
    {

    }
}

void UART2_init (void)
{
    RCC_TypeDef* pRCC = RCC;
    GPIO_TypeDef* pGPIOA = GPIOA;

    // 1. Enable RCC Clock for UART and GPIOA pins PA2-TX and PA3-RX
    pRCC->AHB1ENR |= (1 << 0);
    pRCC->APB1ENR |= (1 << 17);

    // 2. Configure PA2 and PA3 pins as alternate function pins moder register
    pGPIOA->MODER |= (0x2 << 4);
    pGPIOA->MODER |= (0x2 << 6);

    pGPIOA->AFR[0]  |= (7<<8);
    pGPIOA->AFR[0]  |= (7<<12);

    // Enable internal pull-up for PA2
    pGPIOA->PUPDR |= (0x1 << 4);
    // Enable internal pull-up for PA3
    pGPIOA->PUPDR |= (0x1 << 6);
}

void UART2_config (void)
{
    USART_TypeDef* pUART2 = USART2;
    DMA_Stream_TypeDef* pRXStream = DMA1_Stream5; //RX

    pUART2->CR1 = 0x00;   // Clear ALL

    pUART2->CR1 |= (1 << 4); // Enable IDLE Interrupt
    NVIC_EnableIRQ(USART2_IRQn);

    //Configure baud rate
    pUART2->BRR = 0x8B;

    // 10. Enable RX engine
    pUART2->CR1 |= (1 << 2);

    pUART2->CR3 |= (1 << 6); //DMR bit enable

    // 4. Enable the DMA1 stream 5
    pRXStream->CR &= ~(1<<0);
    while((pRXStream->CR & (1<<0)));

    pRXStream->CR |= 1<<0; // 4. Enable the DMA1 stream 5

    // 11. Enable UART engine
    pUART2->CR1 |= (1 << 13);
}

void HT_Complete_callback(void)
{
    while (1); //TODO: Implement callback
}

void FT_Complete_callback(void)
{
    while (1); //TODO: Implement callback
}

void DMA_init(void)
{
    // 0. Pointers for the registers
    RCC_TypeDef* pRCC = RCC;        //pointer to RCC_Typedef
    DMA_Stream_TypeDef* pRXStream = DMA1_Stream5; //RX

    // 1. Enable DMA1 Clock
    pRCC->AHB1ENR |= (1 << 21);

    pRXStream->CR = 0x0; //clear reg before config

    pRXStream->CR |= (1 << 27); // channel 4 select

    // 2. Enable DMA Interrupts
    DMA1->HIFCR = 0x00; //clear flags first
    pRXStream->CR |= (1<<1);  // TCIE, HTIE, TEIE, DMEIE Enabled
    pRXStream->CR |= (1<<2);
    pRXStream->CR |= (1<<3);
    pRXStream->CR |= (1<<4);

    NVIC_EnableIRQ(DMA1_Stream5_IRQn);

    // 3. Set the Data Direction
    pRXStream->CR |= (1<<6);   // Peripheral to Memory

    // 4. Enable the circular mode (CIRC)
    pRXStream->CR |= 1<<8;

    // 5. Enable the Memory Increment (MINC)
    pRXStream->CR |= 1<<10;

    // 6. Set the Peripheral data size (PSIZE)
    pRXStream->CR &= ~(3<<11);  // 00 : 8 Bit Data

    // 7. Set the Memory data size (MSIZE)
    pRXStream->CR &= ~(3<<13);  // 00 : 8 Bit Data

    // 8. Set the Priority Level
    pRXStream->CR &= ~(3<<16);  // PL = 0
}

void DMA_Config (uint32_t srcAdd, uint32_t destAdd, uint16_t datasize)
{
    DMA_Stream_TypeDef* pRXStream = DMA1_Stream5; //RX

    // 1. Set the data size in CNDTR Register
    pRXStream->NDTR = datasize;

    // 2. Set the  peripheral address in PAR Register
    pRXStream->PAR = srcAdd;

    // 3. Set the  Memory address in M0AR Register
    pRXStream->M0AR = destAdd;

}


void TE_error_callback(void)
{
    while (1); //TODO: Implement callback
}
void FE_error_callback(void)
{
    while (1); //TODO: Implement callback
}
void DME_error_callback(void)
{
    while (1); //TODO: Implement callback
}

void IDLE_IRQ_callback(void)
{
    while (1); //TODO: Implement callback
}

stm32f446_it.c

#include "stm32f446xx.h"
#include <stdint.h>

#define is_it_HT()  DMA1->HISR & ( 1 << 10)
#define is_it_FT()  DMA1->HISR & ( 1 << 11)
#define is_it_TE()  DMA1->HISR & ( 1 << 9)
#define is_it_FE()  DMA1->HISR & ( 1 << 6)
#define is_it_DME()     DMA1->HISR & ( 1 << 8)

#define is_it_IDLE() USART2->SR & ( 1 << 4)

extern void HT_Complete_callback(void);
extern void FT_Complete_callback(void);
extern void TE_error_callback(void);
extern void FE_error_callback(void);
extern void DME_error_callback(void);
extern void IDLE_IRQ_callback(void);

void USART2_IRQHandler(void)
{
    if(is_it_IDLE())
    {
        USART2->SR &= ~( 1 << 4); // clear IDLE bit
    }
    else
    {
        ;
    }
}

void DMA1_Stream5_IRQHandler(void)
{

    if( is_it_HT() )
    {
        DMA1->HIFCR |= ( 1 << 10);
        HT_Complete_callback();
    }else if(is_it_FT() )
    {
        DMA1->HIFCR |= ( 1 << 11);
        FT_Complete_callback();
    }else if ( is_it_TE() )
    {
        DMA1->HIFCR |= ( 1 << 9);
        TE_error_callback();

    }else if (is_it_FE() )
    {
        DMA1->HIFCR |= ( 1 << 6);
        FE_error_callback();
    }else if( is_it_DME() )
    {
        DMA1->HIFCR |= ( 1 << 8);
        DME_error_callback();
    }else{
          ;
    }

}

I tried debugging the code while transmitting a byte through PC. Initialization of the code executes well it even goes to super while loop. as soon as send a byte through PC. It goes to DMA transfer interrupt handler.

Upvotes: 1

Views: 69

Answers (1)

Flexz
Flexz

Reputation: 706

Transfer error occurs when DMA tries to read/write an inaccessible location. Your function

void DMA_Config (uint32_t srcAdd, uint32_t destAdd, uint16_t datasize)

expects address as the first argument. Change this

DMA_Config (USART2->DR,(uint32_t) pDest, RXSIZE);

to

DMA_Config ((uint32_t)&(USART2->DR),(uint32_t) pDest, RXSIZE);

Upvotes: 0

Related Questions