使用DMA控制器传输UART

时间:2018-11-23 20:46:13

标签: arm stm32 uart gpio dma

我一直在尝试对STM32F7xx微控制器进行编程,以使用DMA传输到UART。正在发生三件事,我无法解释或理解为什么会发生这种情况,希望有人可以帮助我解决这个问题。

  1. 在主while循环中,我正在打印三个中断状态标志。如果已调用相应的ISR,则设置这些标志。我添加了此代码,以检查是否在未在ISR中添加阻塞语句的情况下调用了ISR。但是,没有一个中断被调用。
  2. DMA仅发送1个513字节序列。当我将main中的while循环修改为仅包含HAL_UART_Transmit_DMA(&handleUart4, dmxBuffer, 513);时,没有任何变化,该函数仅被调用/执行一次。
  3. 在while循环中,我打印ISR标志的状态。打印后,CPU停止/锁定/关闭/退出while循环。起初,我以为我在终端上使用UART,在DMA控制器上使用UART,从而使AHB变得拥塞。我禁用了终端,并使用了LED,这并没有改变任何东西。

当前,我唯一的运行假设是我的CPU某种程度上禁用了中断。

#include "stm32f7xx.h"
#include "mbed.h"

uint8_t dmxBuffer[513];
volatile bool irqA = false;
volatile bool irqB = false;
volatile bool irqC = false;

Serial pc(USBTX, USBRX, 115200);

UART_HandleTypeDef handleUart4;
DMA_HandleTypeDef handleDma;

void initialiseGPIO()
{
  GPIO_InitTypeDef GPIO_InitStruct;

  __GPIOA_CLK_ENABLE();

  /**UART4 GPIO Configuration
  PA0     ------> USART4_TX
  */
  GPIO_InitStruct.Pin = GPIO_PIN_0;
  GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
  GPIO_InitStruct.Pull = GPIO_PULLUP;
  GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
  GPIO_InitStruct.Alternate = GPIO_AF8_UART4;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}

void initialiseDMAController()
{
  /* DMA controller clock enable */
  __DMA1_CLK_ENABLE();

  /* Peripheral DMA init*/
  handleDma.Instance = DMA1_Stream4;
  handleDma.Init.Channel = DMA_CHANNEL_4;
  handleDma.Init.Direction = DMA_MEMORY_TO_PERIPH;
  handleDma.Init.PeriphInc = DMA_PINC_DISABLE;
  handleDma.Init.MemInc = DMA_MINC_ENABLE;
  handleDma.Init.PeriphDataAlignment = DMA_MDATAALIGN_BYTE;
  handleDma.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
  handleDma.Init.Mode = DMA_NORMAL;
  handleDma.Init.Priority = DMA_PRIORITY_MEDIUM;
  handleDma.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
  HAL_DMA_Init(&handleDma);

  //Define 
  __HAL_LINKDMA(&handleUart4,hdmatx,handleDma);

  /* DMA interrupt init */
  HAL_NVIC_SetPriority(DMA1_Stream4_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(DMA1_Stream4_IRQn);
}

void initialiseUart()
{
  __UART4_CLK_ENABLE();

  handleUart4.Instance = UART4;
  handleUart4.Init.BaudRate = 250000;
  handleUart4.Init.WordLength = UART_WORDLENGTH_8B;
  handleUart4.Init.StopBits = UART_STOPBITS_2;
  handleUart4.Init.Parity = UART_PARITY_NONE;
  handleUart4.Init.Mode = UART_MODE_TX;
  handleUart4.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  handleUart4.Init.OverSampling = UART_OVERSAMPLING_16;
  HAL_UART_Init(&handleUart4);

  /* Peripheral interrupt init*/
  HAL_NVIC_SetPriority(UART4_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(UART4_IRQn);
}

/* This function handles DMA1 stream4 global interrupt. */
void DMA1_Stream4_IRQHandler(void)
{
  irqA = true;
  HAL_DMA_IRQHandler(&handleDma);
}

/* This function handles the UART4 interups */
void UART4_IRQHandler(void)
{
  irqB = true;
  HAL_UART_IRQHandler(&handleUart4);
}

//HAL_UART_TxCpltCallback
/* This callback function is called when the DMA successfully transmits all scheduled bytes. */
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
  irqC = true;
}


int main(void)
{
  /* Reset of all peripherals */
  HAL_Init();

  //Initialise peripherals
  initialiseGPIO();
  initialiseDMAController();
  initialiseUart();

  //Fill buffer with test data
  for (int x = 0; x < 100; x++)
  {
      dmxBuffer[x] = x;
  }

  //Now instruct the UART peripheral to transmit 513 bytes using the DMA controller.
  HAL_UART_Transmit_DMA(&handleUart4, dmxBuffer, 513);

  while(1)
  {
        pc.printf("irqA: %d - irqB: %d - irqC: %d\r\n", irqA, irqB, irqC);
        wait_ms(100); //Wait to see if any of the interupt handlers / callback functions are called

        //Check if all bytes are sent, if so, retransmit
        if (irqC)
        {
            irqC = false;
            HAL_UART_Transmit_DMA(&handleUart4, dmxBuffer, 513);
        }

  }
}

1 个答案:

答案 0 :(得分:0)

检查中断向量表

验证向量表确实包含指向您的处理函数的指针,而不是指向具有无限循环(使程序挂起)的某些通用占位符的指针。

entire 源代码中搜索中断处理程序函数的名称。还有其他任何对象或#define可能会干扰函数定义或向量表条目吗?

更改处理程序的名称,包括函数定义和向量表条目。它仍然可以编译吗?否则,将extern "C"添加到函数原型中是否有帮助?

.map文件中查找处理程序的地址,并在参考手册(嵌套矢量中断控制器(NVIC)/中断和异常)中的向量表中找到中断的偏移项向量)。以给定的偏移量检查编译的程序二进制文件的内容。它与.map文件+ 1中找到的地址匹配吗?

在运行程序时检查NVIC->VTOR处的值加上偏移量。它应该与二进制文件中的相同。如果没有,请查看VTOR寄存器是否设置在右向量表的开头。