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