1
votes

I have been trying exhaustively to program my STM32F7xx microcontroller to use DMA to transmit to UART. Three things are going on and I cannot explain or understand why this is happening, and hope somebody can help me out with this issue.

  1. In the main while loop, I am printing three interrupt status flags. These flags are set if the corresponding ISR has been called. I added this to check if the ISR was called without adding blocking statements in the ISRs. None of the interrupts, however, are called.
  2. The DMA only transmits 1 sequence of 513 bytes. When I modify the while loop in my main to only contain HAL_UART_Transmit_DMA(&handleUart4, dmxBuffer, 513);, nothing changes, the function is only called/executed once.
  3. In the while loop, I print the status of the ISR flags. After printing, the CPU stops/locks/shutdown/exits the while loop. At first, I thought I was congesting the AHB by using the UART to my terminal and the UART for the DMA controller. I disabled my terminal, and used LEDs, this didn't change anything.

Currently, the only running hypothesis I have is that my CPU somehow has interrupts disabled.

#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

1 Answers

1
votes

Check the interrupt vector table

Verify that the vector table does indeed contain a pointer to your handler function, not to some generic placeholder with an infinite loop (that makes the program hang).

Search for the name of the interrupt handler function in the entire source code. Is there any other object or #define that could interfere with the function definition, or the vector table entry?

Change the name of the handler, both the function definition and the vector table entry. Does it still compile? When not, does adding extern "C" to the function prototype help?

Look up the address of the handler in the .map file, and the offset entry for the interrupt in the vector table provided in the Reference Manual (Nested vectored interrupt controller (NVIC) / Interrupt and exception vectors). Check the contents of the compiled program binary file at the given offset. Does it match the address found in the .map file + 1?

Check the value at NVIC->VTOR plus the offset while running the program. It should be the same as the one found in the binary. If not, see that the VTOR register is set to the beginning of the right vector table.