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
353 lines
12 KiB
C
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);
|
|
}
|