Использование контроллера DMA для передачи UART - PullRequest
0 голосов
/ 23 ноября 2018

Я пытался запрограммировать мой микроконтроллер STM32F7xx на использование DMA для передачи в UART.Происходят три вещи, и я не могу объяснить или понять, почему это происходит, и надеюсь, что кто-то может помочь мне с этой проблемой.

  1. В главном цикле while я печатаю три флага состояния прерывания.Эти флаги устанавливаются, если был вызван соответствующий ISR.Я добавил это, чтобы проверить, был ли вызван ISR без добавления блокирующих операторов в ISR.Однако ни одно из прерываний не вызывается.
  2. DMA передает только 1 последовательность из 513 байтов.Когда я изменяю цикл while в своем main, чтобы он содержал только HAL_UART_Transmit_DMA(&handleUart4, dmxBuffer, 513);, ничего не меняется, функция вызывается / выполняется только один раз.
  3. В цикле while я печатаю состояние флагов ISR.После печати процессор останавливается / блокирует / выключает / выходит из цикла while.Сначала я подумал, что перегружаю AHB, используя UART для моего терминала и UART для контроллера DMA.Я отключил свой терминал и использовал светодиоды, это ничего не изменило.

В настоящее время у меня есть единственная гипотеза о том, что мой процессор каким-то образом отключил прерывания.

#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 голосов
/ 25 ноября 2018

Проверьте таблицу векторов прерываний

Убедитесь, что таблица векторов действительно содержит указатель на вашу функцию-обработчик, а не на какой-то универсальный заполнитель с бесконечным циклом(это приводит к зависанию программы).

Поиск имени функции обработчика прерывания во полном исходном коде.Есть ли какой-либо другой объект или #define, который может помешать определению функции или записи таблицы векторов?

Изменить имя обработчика, определение функции и запись таблицы векторов.Это все еще компилируется?Если нет, поможет ли добавление extern "C" к прототипу функции?

Найдите адрес обработчика в файле .map и запись смещения для прерывания в таблице векторов, приведенной в Справочном руководстве.( Вложенный векторный контроллер прерываний (NVIC) / Векторы прерываний и исключений ).Проверьте содержимое двоичного файла скомпилированной программы по заданному смещению.Соответствует ли он адресу, найденному в файле .map + 1?

Проверьте значение в NVIC->VTOR плюс смещение при запуске программы.Он должен быть таким же, как тот, который находится в двоичном файле.Если нет, убедитесь, что регистр VTOR установлен в начало правой таблицы векторов.

...