最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

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

programmeradmin5浏览0评论

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.

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.

Share Improve this question edited Feb 5 at 11:47 Lundin 214k45 gold badges274 silver badges430 bronze badges asked Feb 5 at 10:49 Rupesh kadamRupesh kadam 111 bronze badge 2
  • Are you getting any of the error codes you are checking for? – Lundin Commented Feb 5 at 11:46
  • Look at the examples in the STM32CubeF4 package. Review how the example configures the UART and DMA via the STM32F4xx HAL, and compare that with your code. Read the example project readme.txt https://github.com/STMicroelectronics/STM32CubeF4/tree/master/Projects/STM32446E_EVAL/Examples/UART/UART_HyperTerminal_DMA – kkrambo Commented Feb 5 at 13:28
Add a comment  | 

1 Answer 1

Reset to default 0

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);

与本文相关的文章

发布评论

评论列表(0)

  1. 暂无评论