Files
hsb/S - Software/0 - HSB MRTS Kathode-MCP/3 - Implementation/0 - Code/Platform/src/uart.c
mmi 5e6e8a8ff5 Stability Fix
Clearing flags instead of ITStatus seems to improve stability in EXTI interrupts

Added ASSERT functionality for STM std periphery library

Also busy updating the HW validation menu


git-svn-id: https://svn.vbchaos.nl/svn/hsb/trunk@411 05563f52-14a8-4384-a975-3d1654cca0fa
2017-12-22 14:09:08 +00:00

353 lines
12 KiB
C

// -----------------------------------------------------------------------------
/// @file uart.c
/// @brief Description
// -----------------------------------------------------------------------------
// Micro-Key bv
// Industrieweg 28, 9804 TG Noordhorn
// Postbus 92, 9800 AB Zuidhorn
// The Netherlands
// Tel: +31 594 503020
// Fax: +31 594 505825
// Email: support@microkey.nl
// Web: www.microkey.nl
// -----------------------------------------------------------------------------
/// $Revision$
/// $Author$
/// $Date$
// (c) 2017 Micro-Key bv
// -----------------------------------------------------------------------------
/// @file uart.c
/// @ingroup {group_name}
// -----------------------------------------------------------------------------
// Include files
// -----------------------------------------------------------------------------
#include "FreeRTOS.h"
#include "semphr.h"
#include "stm32f10x_usart.h"
#include "uart.h"
#include "misc.h"
// -----------------------------------------------------------------------------
// Constant and macro definitions
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
// Type definitions
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
// File-scope variables
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
// Function declarations
// -----------------------------------------------------------------------------
static ErrorStatus write(const struct IODevice* self, const char* buffer, size_t length);
static ErrorStatus read(const struct IODevice* self, char* buffer, size_t length, size_t* actualLength);
// -----------------------------------------------------------------------------
// Function definitions
// -----------------------------------------------------------------------------
ErrorStatus Uart_construct(struct Uart* self, struct UartParameters* parameters)
{
ErrorStatus returnValue = SUCCESS;
if(!self->initialized)
{
IODevice_construct(&self->device, read, write);
//! Create semaphore to synchronize with USART interrupt handler
vSemaphoreCreateBinary(self->txSemaphore);
USART_DeInit(self->USART_TypeDef);
// Initialise the UART
self->USART_InitStruct.USART_BaudRate = parameters->baudrate;
self->USART_InitStruct.USART_WordLength = parameters->wordlength;
self->USART_InitStruct.USART_StopBits = parameters->stopbits;
self->USART_InitStruct.USART_Parity = parameters->parity;
self->USART_InitStruct.USART_Mode = parameters->mode;
self->USART_InitStruct.USART_HardwareFlowControl = parameters->hwFlowControl;
USART_Init(self->USART_TypeDef, &self->USART_InitStruct);
//! Enable USART interface
USART_Cmd(self->USART_TypeDef, ENABLE);
//! Create a new FREERTOS queue to handle data from app to USART output
self->txQueue = xQueueCreate(parameters->txQueueSize, sizeof(struct usartQueueItem));
//! Create a new FREERTOS queue to handle data from USART input to app
self->rxQueue = xQueueCreate(parameters->rxQueueSize, sizeof(struct usartQueueItem));
//! Queue identifier must not be 0 (0 means that the queue is not available)
if (self->txQueue == 0)
{
//! Queue identifier is 0 -> error
returnValue = ERROR; //! Set error flag
}
if (self->rxQueue == 0)
{
//! Queue identifier is 0 -> error
returnValue = ERROR; //! Set error flag
}
//! Queue identifier is not 0 -> queue is available
//! take txSemaphore
if (xSemaphoreTake(self->txSemaphore, 0) == pdFALSE)
{
//! An error has occurred
returnValue = ERROR;
}
if (returnValue == SUCCESS)
{
//! Enable the UART RX not empty interrupt
USART_ITConfig(self->USART_TypeDef, USART_IT_RXNE, ENABLE);
self->initialized = true;
}
}
else
{
returnValue = ERROR;
}
return returnValue;
}
ErrorStatus Uart_getDefaultParameters(struct UartParameters* parameters)
{
ErrorStatus returnValue = SUCCESS;
parameters->baudrate = UART_DEF_BAUDRATE;
parameters->wordlength = UART_DEF_WORDLENGTH;
parameters->stopbits = UART_DEF_STOPBITS;
parameters->mode = UART_DEF_MODE;
parameters->parity = UART_DEF_PARITY;
parameters->hwFlowControl = UART_DEF_HW_FLOW_CONTROL;
parameters->txQueueSize = UART_DEF_TX_QUEUE;
parameters->rxQueueSize = UART_DEF_RX_QUEUE;
return returnValue;
}
static ErrorStatus write(const struct IODevice* self, const char* buffer, size_t length)
{
return Uart_write((struct Uart*)self, buffer, length);
}
static ErrorStatus read(const struct IODevice* self, char* buffer, size_t length, size_t* actualLength)
{
return Uart_read((struct Uart*)self, buffer, length, actualLength);
}
ErrorStatus Uart_write(struct Uart* self, const char* buffer, int length)
{
struct usartQueueItem usartTxItem;
ErrorStatus returnValue = SUCCESS; //! Define return variable
int txCounter; //! Define a loop counter var
if (self->initialized)
{
//! Copy the incoming data into UART data structure
for (txCounter = 0; txCounter < length; txCounter++)
{
usartTxItem.byte = buffer[txCounter]; //! Copy current data in struct
if (uxQueueSpacesAvailable(self->txQueue) == 2)
{
USART_ITConfig(self->USART_TypeDef, USART_IT_TXE, ENABLE);
}
//! Add the current set of data to UART transmission queue
if (pdTRUE != xQueueSend(self->txQueue, &usartTxItem, portMAX_DELAY))
{
//! Adding item was NOT successful - break out of loop
returnValue = ERROR; //! Set return value to FALSE
break;
}
}
if (returnValue == SUCCESS)
{
//! Semaphore has been taken
//! Enable the USARTx TXE (transmission empty) interrupt
USART_ITConfig(self->USART_TypeDef, USART_IT_TXE, ENABLE);
//! Try to take Semaphore - If the USART transmission is still busy, the
//! Semaphore cannot be taken - FREERTOS will suspend this task until the
//! Semaphore is released again
xSemaphoreTake(self->txSemaphore, portMAX_DELAY);
/** Enabling the TX interrupt will immediately cause an interrupt because
* the transmission register is still empty. The ISR will get the data
* from the uart transmission queue and transmit byte-wise until the
* queue is empty.
* An empty queue will cause the transmission complete flag (TC) to be set,
* which is polled
*/
while (USART_GetFlagStatus(self->USART_TypeDef, USART_FLAG_TC) == RESET)
{
//! The software must wait until TC=1. The TC flag remains cleared during
//! all data transfers and it is set by hardware at the last frame's
//! end of transmission
}
}
else
{
//! Do nothing
}
}
else
{
returnValue = ERROR;
}
return (returnValue); //! Return result to caller
}
ErrorStatus Uart_read (struct Uart* self, char* buffer, size_t length, size_t* actualLength)
{
ErrorStatus returnValue = SUCCESS;
int loopCounter = 0;
*actualLength = 0;
struct usartQueueItem usartRxItem;
if (self->initialized)
{
for (loopCounter = 0; loopCounter < length; loopCounter++)
{
if (xQueueReceive(self->rxQueue, &usartRxItem, 0) != pdFALSE)
{
// Item successfully fetched from Queue
buffer[loopCounter] = usartRxItem.byte;
*actualLength = *actualLength + 1;
}
else
{
break;
}
}
}
else
{
returnValue = ERROR;
}
return returnValue;
}
/** ----------------------------------------------------------------------------
* @brief Function: USART1_IRQHandler
*
* Dedicated Interrupt Service Routine for USART1
*
* @return void
*
* @todo
* -----------------------------------------------------------------------------
*/
void USART1_IRQHandler(void)
{
signed portBASE_TYPE higherPriorityTaskWoken = pdFALSE;
//! Transmission register empty interrupt
if(USART_GetITStatus(USART1, USART_IT_TXE) != RESET)
{
//! Receive element from usart transmission queue
struct usartQueueItem usartTxItem;
xQueueReceiveFromISR(uart1->txQueue, &usartTxItem, &higherPriorityTaskWoken);
//! Write one byte to the transmit data register
USART_SendData(USART1, usartTxItem.byte);
//! check if queue is empty -> all bytes transmit
if(pdTRUE == xQueueIsQueueEmptyFromISR(uart1->txQueue))
{
//! Disable the COMPORT Transmit interrupt and release semaphore
USART_ITConfig(USART1, USART_IT_TXE, DISABLE);
xSemaphoreGiveFromISR(uart1->txSemaphore, &higherPriorityTaskWoken);
}
}
//! Current interrupt is triggered by USART_RXNE (receive register not empty)
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)
{
//! Read one byte from the receive data register
struct usartQueueItem usartRxItem;
//! Reading from reception register automatically clears the RXNE interrupt
usartRxItem.byte = USART_ReceiveData(USART1);
//! Add the byte to the USART RX queue
//! In case of a full queue, the data is dumped
(void)xQueueSendFromISR(uart1->rxQueue, &usartRxItem, &higherPriorityTaskWoken);
}
portEND_SWITCHING_ISR(higherPriorityTaskWoken);
}
/** ----------------------------------------------------------------------------
* @brief Function: USART3_IRQHandler
*
* Dedicated Interrupt Service Routine for USART3
*
* @return void
*
* @todo
* -----------------------------------------------------------------------------
*/
void USART3_IRQHandler(void)
{
signed portBASE_TYPE higherPriorityTaskWoken = pdFALSE;
//! Transmission register empty interrupt
if(USART_GetITStatus(USART3, USART_IT_TXE) != RESET)
{
//! Receive element from usart transmission queue
struct usartQueueItem usartTxItem;
xQueueReceiveFromISR(uart3->txQueue, &usartTxItem, &higherPriorityTaskWoken);
//! Write one byte to the transmit data register
USART_SendData(USART3, usartTxItem.byte);
//! check if queue is empty -> all bytes transmit
if(pdTRUE == xQueueIsQueueEmptyFromISR(uart3->txQueue))
{
//! Disable the COMPORT Transmit interrupt and release semaphore
USART_ITConfig(USART3, USART_IT_TXE, DISABLE);
xSemaphoreGiveFromISR(uart3->txSemaphore, &higherPriorityTaskWoken);
}
}
//! Current interrupt is triggered by USART_RXNE (receive register not empty)
if(USART_GetITStatus(USART3, USART_IT_RXNE) != RESET)
{
//! Read one byte from the receive data register
struct usartQueueItem usartRxItem;
//! Reading from reception register automatically clears the RXNE interrupt
usartRxItem.byte = (char)USART_ReceiveData(USART3);
//! Add the byte to the USART RX queue
//! In case of a full queue, the data is dumped
(void)xQueueSendFromISR(uart3->rxQueue, &usartRxItem, &higherPriorityTaskWoken);
}
portEND_SWITCHING_ISR(higherPriorityTaskWoken);
}