cancel
Showing results for 
Search instead for 
Did you mean: 

The UART4 peripheral only transmits once when using the DMA

Avan.11
Associate II

I have been exhaustively trying 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.

I am using the following code:

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

What is going on here?

4 REPLIES 4

>>What is going on here?

Any chance any of those functions are returning an error code, or you're getting some error call-back?

I'd perhaps want to initialize all the clocks first, but at the very least the initialize the USART before the DMA.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Avan.11
Associate II

Thanks for your fast response! I updated the code initialising the clocks first. After initialising the clocks, I initialise the GPIO, UART and lastly, the DMA. Unfortunately, the UART sends out 513 bytes before locking/shutting down. I can confirm that the UART is transmitting as I attached my oscilloscope to the corresponding pin.

The HAL_UART_Transmit_DMA function returns 0x02 -> Busy, which is expected as its busy transmitting the 513 bytes.

Make sure that the SysTick interrupt, or whatever HAL/mbed is using for timing, has a high priority (lower number) than anything else.

Instrument the Hard Fault Handler to see if it arrives there.

Stop execution in the debugger and understand where it is stuck, and what it is waiting for.

You should see 10 messages a second, perhaps try USART or SWV for debug output.

Instrument routines to understand success and failure, and implement functions to identify failure paths.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Avan.11
Associate II

The SysTick interrupt is indeed set as the highest priority. As I have no experience - so far - with the hard fault handler, I will try to find some info on that. Perhaps you can help me on a more theoretical side. On the one hand, I am using the DMA to read - with a byte alignment - 513 bytes from SRAM and to forward them to the UART peripheral. The CPU, on the other hand, is writing and reading data to/from variables in the SRAM. Could this cause the AHB/APB bus to lockup, causing the CPU to stop execution? Additionally, the UART peripheral I am using is on APB1. All the timers are connected to the same APB1. Does this mean that I am not able to read/write to the timers when the UART is busy reading/writing?