STM32F4xx problem UART DMA
Jaroslav Buchta
jaroslav.buchta na hascomp.cz
Úterý Březen 22 22:38:31 CET 2016
Narazil jsem na zapeklity problem, pouzivam HAL knihovny (vim, to je ten
problem ;-) ) prijem HAL_UART_Receive_IT, Vysilani HAL_UART_Transmit_DMA
Problem je, ze obcas nastane UART_DMAError a sekne se to v IT od prijmu,
protoze se prichozi znaky uz ignoruji ale preruseni se nezakaze. Tusi
nekdo, jak muze chyba DMA prenosu vzniknout u takto pomale periferie?
Navic je procesor jinak v klidu, ostatni periferie necinne... Pricinou
je zda se priznak DMA TEIF
Uz mi dochazeji napady... Vypis podstatne casti kodu je prilozen, pokud
nekoho neco napadne (je to jednoducha terminalova konzole)
#include "stm32f4xx_hal.h"
#include "cmsis_os.h"
#include "uartdbg.h"
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
static xSemaphoreHandle semphDbg = NULL;
static UART_HandleTypeDef *hDbgUart = NULL;
static volatile uint8_t dbgRcvChar;
#pragma GCC optimize ("O0")
void DBGUSART_Config(UART_HandleTypeDef *huart)
{
hDbgUart = huart;
HAL_UART_Receive_IT(hDbgUart, (uint8_t *)&dbgRcvChar, 1);
}
#define RXBUFFERSIZE 64
#define TXBUFFERSIZE 2048
volatile static int32_t ubRxIndex = 0;
volatile static uint8_t aRxBuffer[RXBUFFERSIZE];
volatile static char dbgBuf[TXBUFFERSIZE];
volatile static int dbgBufR = 0;
volatile static int dbgBufW = 0;
volatile static int dbgTxCnt = 0;
// UART Tx complette callback function (DMA TC, USART have not callback
in handle)
static void TxRecovery();
static void SendEchoChar (uint8_t c);
// function is called from ISR!
void DbgTxCpltCallback()
{
uint32_t origPri = portSET_INTERRUPT_MASK_FROM_ISR();
dbgBufR += dbgTxCnt;
if (dbgBufR >= TXBUFFERSIZE) dbgBufR = 0;
dbgTxCnt = 0;
TxRecovery();
portCLEAR_INTERRUPT_MASK_FROM_ISR(origPri);
}
void DbgRxCpltCallback()
{
uint8_t bRelease = 0;
uint32_t origPri = portSET_INTERRUPT_MASK_FROM_ISR();
portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
if (dbgRcvChar == '\b')
{
if (ubRxIndex > 0)
{
ubRxIndex--;
SendEchoChar(dbgRcvChar);
}
}
else if(dbgRcvChar == '\n' || dbgRcvChar == '\r')
{
bRelease = ubRxIndex != 0 ? 1 : 0;
SendEchoChar(dbgRcvChar);
}
else if (ubRxIndex < RXBUFFERSIZE)
{
/* Receive Transaction data */
aRxBuffer[ubRxIndex++] = dbgRcvChar;
SendEchoChar(dbgRcvChar);
}
portCLEAR_INTERRUPT_MASK_FROM_ISR(origPri);
HAL_UART_Receive_IT(hDbgUart, (uint8_t *)&dbgRcvChar, 1);
if (bRelease && semphDbg != NULL)
{
xSemaphoreGiveFromISR(semphDbg, &xHigherPriorityTaskWoken);
}
if (xHigherPriorityTaskWoken != pdFALSE)
{
portEND_SWITCHING_ISR( xHigherPriorityTaskWoken );
}
}
// function may be called from ISR at interrupt disabled
static void TxRecovery()
{
if (dbgTxCnt != 0) return;
if (dbgBufR == dbgBufW) return;
int nCnt = (int)dbgBufW - (int)dbgBufR;
if (nCnt < 0) nCnt = TXBUFFERSIZE - dbgBufR;
if (nCnt > 32) nCnt = 32;
HAL_UART_Transmit_DMA(hDbgUart, (uint8_t *)dbgBuf+dbgBufR, nCnt);
dbgTxCnt = nCnt;
}
// function is called from ISR!
static void SendEchoChar (uint8_t c)
{
uint32_t origPri = portSET_INTERRUPT_MASK_FROM_ISR();
int w = dbgBufW+1;
if (w >= sizeof(dbgBuf)) w = 0;
if (w != dbgBufR)
{
dbgBuf[dbgBufW] = c;
dbgBufW = w;
TxRecovery();
}
portCLEAR_INTERRUPT_MASK_FROM_ISR(origPri);
}
uint8_t * DBGUSART_GetCmdStr(portTickType nWait)
{
if (semphDbg == NULL)
{
vSemaphoreCreateBinary(semphDbg);
xSemaphoreTake(semphDbg, 0);
}
if (xSemaphoreTake(semphDbg, nWait) == pdFALSE) return NULL;
uint8_t *cmd = NULL;
vPortEnterCritical();
if (ubRxIndex != 0)
{
cmd = malloc(ubRxIndex + 1);
if (cmd != NULL)
{
memcpy ((void *)cmd, (void *)aRxBuffer, ubRxIndex);
cmd[ubRxIndex] = 0;
}
ubRxIndex = 0;
}
vPortExitCritical();
return cmd;
}
void DBGUSART_dbgSendStr(char *s)
{
uint32_t origPri = portSET_INTERRUPT_MASK_FROM_ISR();
while (*s)
{
dbgBuf[dbgBufW] = *(s++);
int w = dbgBufW+1;
if (w >= sizeof(dbgBuf)) w = 0;
if (w == dbgBufR) break;
dbgBufW = w;
}
TxRecovery();
portCLEAR_INTERRUPT_MASK_FROM_ISR(origPri);
}
Další informace o konferenci Hw-list