2018-11-24 10:59 AM
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.
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?
2018-11-24 11:16 AM
>>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.
2018-11-24 11:32 AM
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.
2018-11-24 11:52 AM
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.
2018-11-26 12:16 AM
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?