【问题标题】:Using DMA controller to transmit UART使用 DMA 控制器传输 UART
【发布时间】:2019-04-26 10:12:05
【问题描述】:

我一直在竭尽全力地对我的 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 连接我的终端和使用 UART 连接 DMA 控制器使 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);
        }

  }
}

【问题讨论】:

    标签: arm stm32 uart gpio dma


    【解决方案1】:

    检查中断向量表

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

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

    更改处理程序的名称,包括函数定义和向量表条目。它仍然编译吗?如果没有,在函数原型中添加extern "C" 有帮助吗?

    .map文件中查找处理程序的地址,以及参考手册中提供的向量表中中断的偏移条目(嵌套向量中断控制器(NVIC)/中断和异常向量)。检查给定偏移量处已编译程序二进制文件的内容。与.map文件+1中的地址是否匹配?

    在运行程序时检查NVIC-&gt;VTOR 的值加上偏移量。它应该与在二进制文件中找到的相同。如果不是,请查看VTOR 寄存器设置为右向量表的开头。

    【讨论】:

    • 根据STM32F7的参考手册,DMA1Stream4全局中断位于内存位置:0x0000007C。该寄存器包含一个指向应该调用的函数的指针。我目前正在使用一个在线编译器 - mbed - 它只为我生成一个用于对微控制器进行编程的 bin 文件。如何验证我的中断处理函数是否确实在相应的地址?
    • @AlexvanRijs printf("function address 0x%08lx vector table entry 0x%08lx\n", (uint32_t)DMA1_Stream4_IRQHandler, *(uint32_t *)(NVIC-&gt;VTOR + 0x7c));
    • @AlexvanRijs 并找到一种在调试器中使用适当工具链的方法。在使用随机 printf 语句找出简单错误所需的时间里,可以设置一个 IDE,从 mbed 导入项目,然后在挂起时点击暂停按钮。两次。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-08-29
    • 1970-01-01
    • 2014-07-09
    • 1970-01-01
    • 1970-01-01
    • 2013-09-07
    • 1970-01-01
    相关资源
    最近更新 更多