mirror of
https://github.com/FreeRTOS/FreeRTOS-Kernel.git
synced 2025-04-20 05:21:59 -04:00
Update Zynq serial.c to be interrupt driven.
This commit is contained in:
parent
d310ac4552
commit
6c72f470ac
|
@ -34,6 +34,11 @@
|
|||
<type>2</type>
|
||||
<locationURI>FREERTOS_ROOT/FreeRTOS/Source</locationURI>
|
||||
</link>
|
||||
<link>
|
||||
<name>src/Sample-CLI-commands.c</name>
|
||||
<type>1</type>
|
||||
<locationURI>FREERTOS_ROOT/FreeRTOS-Plus/Demo/Common/FreeRTOS_Plus_CLI_Demos/Sample-CLI-commands.c</locationURI>
|
||||
</link>
|
||||
<link>
|
||||
<name>src/Standard_Demo_Tasks</name>
|
||||
<type>2</type>
|
||||
|
|
|
@ -169,9 +169,9 @@ Zynq MPU. */
|
|||
unsigned long ulGetRunTimeCounterValue( void );
|
||||
void vInitialiseRunTimeStats( void );
|
||||
|
||||
#define configGENERATE_RUN_TIME_STATS 0
|
||||
//#define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() vInitialiseRunTimeStats()
|
||||
//#define portGET_RUN_TIME_COUNTER_VALUE() ulGetRunTimeCounterValue()
|
||||
#define configGENERATE_RUN_TIME_STATS 1
|
||||
#define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() vInitialiseRunTimeStats()
|
||||
#define portGET_RUN_TIME_COUNTER_VALUE() ulGetRunTimeCounterValue()
|
||||
|
||||
/* The size of the global output buffer that is available for use when there
|
||||
are multiple command interpreters running at once (for example, one on a UART
|
||||
|
|
|
@ -226,7 +226,6 @@ extern void vRegTest2Implementation( void );
|
|||
* defined in CLI-Commands.c and File-Related-CLI-Command.c respectively.
|
||||
*/
|
||||
extern void vRegisterSampleCLICommands( void );
|
||||
extern void vRegisterFileSystemCLICommands( void );
|
||||
|
||||
/*
|
||||
* The task that manages the FreeRTOS+CLI input and output.
|
||||
|
@ -264,7 +263,7 @@ void main_full( void )
|
|||
vUARTCommandConsoleStart( mainUART_COMMAND_CONSOLE_STACK_SIZE, mainUART_COMMAND_CONSOLE_TASK_PRIORITY );
|
||||
|
||||
/* Register the standard CLI commands. */
|
||||
// vRegisterSampleCLICommands();
|
||||
vRegisterSampleCLICommands();
|
||||
|
||||
|
||||
/* Create the register check tasks, as described at the top of this
|
||||
|
|
|
@ -64,23 +64,24 @@
|
|||
*/
|
||||
|
||||
/*
|
||||
BASIC INTERRUPT DRIVEN SERIAL PORT DRIVER FOR UART2.
|
||||
BASIC INTERRUPT DRIVEN SERIAL PORT DRIVER.
|
||||
|
||||
***Note*** This example uses queues to send each character into an interrupt
|
||||
service routine and out of an interrupt service routine individually. This
|
||||
is done to demonstrate queues being used in an interrupt, and to deliberately
|
||||
load the system to test the FreeRTOS port. It is *NOT* meant to be an
|
||||
example of an efficient implementation. An efficient implementation should
|
||||
use the DMA, and only use FreeRTOS API functions when enough has been
|
||||
received to warrant a task being unblocked to process the data.
|
||||
*/
|
||||
Note1: This driver is used specifically to provide an interface to the
|
||||
FreeRTOS+CLI command interpreter. It is *not* intended to be a generic
|
||||
serial port driver. Nor is it intended to be used as an example of an
|
||||
efficient implementation. In particular, a queue is used to buffer
|
||||
received characters, which is fine in this case as key presses arrive
|
||||
slowly, but a DMA and/or RAM buffer should be used in place of the queue in
|
||||
applications that expect higher throughput.
|
||||
|
||||
Note2: This driver does not attempt to handle UART errors.
|
||||
*/
|
||||
|
||||
/* Scheduler includes. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "queue.h"
|
||||
#include "semphr.h"
|
||||
#include "comtest2.h"
|
||||
|
||||
/* Demo application includes. */
|
||||
#include "serial.h"
|
||||
|
@ -90,14 +91,37 @@
|
|||
#include "xscugic.h"
|
||||
#include "xil_exception.h"
|
||||
|
||||
/* The UART interrupts of interest when receiving. */
|
||||
#define serRECEIVE_INTERRUPT_MASK ( XUARTPS_IXR_RXOVR | XUARTPS_IXR_RXFULL | XUARTPS_IXR_TOUT )
|
||||
|
||||
/* The UART interrupts of interest when transmitting. */
|
||||
#define serTRANSMIT_IINTERRUPT_MASK ( XUARTPS_IXR_TXEMPTY )
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* The UART being used. */
|
||||
static XUartPs xUARTInstance;
|
||||
|
||||
/* The interrupt controller, which is configred by the hardware setup routines
|
||||
defined in main(). */
|
||||
extern XScuGic xInterruptController;
|
||||
|
||||
/* The queue into which received key presses are placed. NOTE THE COMMENTS AT
|
||||
THE TOP OF THIS FILE REGARDING THE USE OF QUEUES FOR THIS PURPOSE. */
|
||||
static QueueHandle_t xRxQueue = NULL;
|
||||
|
||||
/* The semaphore used to indicate the end of a transmission. */
|
||||
static SemaphoreHandle_t xTxCompleteSemaphore = NULL;
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvISRHandler( void *pvUnused, uint32_t ulEvent, uint32_t ulUnused2 );
|
||||
/*
|
||||
* The UART interrupt handler is defined in this file to provide more control,
|
||||
* but still uses parts of the Xilinx provided driver.
|
||||
*/
|
||||
void prvUART_Handler( void *pvNotUsed );
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* See the serial2.h header file.
|
||||
|
@ -107,84 +131,186 @@ xComPortHandle xSerialPortInitMinimal( uint32_t ulWantedBaud, UBaseType_t uxQueu
|
|||
BaseType_t xStatus;
|
||||
XUartPs_Config *pxConfig;
|
||||
|
||||
/* Create the queue used to hold received characters. NOTE THE COMMENTS AT
|
||||
THE TOP OF THIS FILE REGARDING THE QUEUE OF QUEUES FOR THIS PURPSOE. */
|
||||
xRxQueue = xQueueCreate( uxQueueLength, sizeof( char ) );
|
||||
configASSERT( xRxQueue );
|
||||
|
||||
/* Create the semaphore used to signal the end of a transmission, then take
|
||||
the semaphore so it is in the correct state the first time
|
||||
xSerialSendString() is called. A block time of zero is used when taking
|
||||
the semaphore as it is guaranteed to be available (it was just created). */
|
||||
xTxCompleteSemaphore = xSemaphoreCreateMutex();
|
||||
configASSERT( xTxCompleteSemaphore );
|
||||
xSemaphoreTake( xTxCompleteSemaphore, 0 );
|
||||
|
||||
/* Look up the UART configuration then initialise the dirver. */
|
||||
pxConfig = XUartPs_LookupConfig( XPAR_XUARTPS_0_DEVICE_ID );
|
||||
configASSERT( pxConfig );
|
||||
|
||||
xStatus = XUartPs_CfgInitialize( &xUARTInstance, pxConfig, pxConfig->BaseAddress );
|
||||
/* Initialise the driver. */
|
||||
xStatus = XUartPs_CfgInitialize( &xUARTInstance, pxConfig, XPAR_PS7_UART_1_BASEADDR );
|
||||
configASSERT( xStatus == XST_SUCCESS );
|
||||
|
||||
/* Misc. parameter configuration. */
|
||||
XUartPs_SetBaudRate( &xUARTInstance, ulWantedBaud );
|
||||
|
||||
XUartPs_SetOperMode( &xUARTInstance, XUARTPS_OPER_MODE_NORMAL );
|
||||
|
||||
return 0;
|
||||
/* Install the interrupt service routine that is defined within this
|
||||
file. */
|
||||
xStatus = XScuGic_Connect( &xInterruptController, XPAR_XUARTPS_1_INTR, (Xil_ExceptionHandler) prvUART_Handler, (void *) &xUARTInstance );
|
||||
configASSERT( xStatus == XST_SUCCESS );
|
||||
|
||||
/* Ensure interrupts start clear. */
|
||||
XUartPs_WriteReg( XPAR_PS7_UART_1_BASEADDR, XUARTPS_ISR_OFFSET, XUARTPS_IXR_MASK );
|
||||
|
||||
/* Enable the UART interrupt within the GIC. */
|
||||
XScuGic_Enable( &xInterruptController, XPAR_XUARTPS_1_INTR );
|
||||
|
||||
/* Enable the interrupts of interest in the UART. */
|
||||
XUartPs_SetInterruptMask( &xUARTInstance, XUARTPS_IXR_RXFULL | XUARTPS_IXR_RXOVR | XUARTPS_IXR_TOUT | XUARTPS_IXR_TXEMPTY );
|
||||
|
||||
/* Set the receive timeout. */
|
||||
XUartPs_SetRecvTimeout( &xUARTInstance, 8 );
|
||||
|
||||
return ( xComPortHandle ) 0;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
BaseType_t xSerialGetChar( xComPortHandle pxPort, signed char *pcRxedChar, portTickType xBlockTime )
|
||||
{
|
||||
TickType_t xTimeOnEntering;
|
||||
const TickType_t xDelay = 10UL / portTICK_PERIOD_MS;
|
||||
BaseType_t xReturn = 0;
|
||||
BaseType_t xReturn;
|
||||
|
||||
xTimeOnEntering = xTaskGetTickCount();
|
||||
|
||||
do
|
||||
{
|
||||
/* Only wanting to receive one key press at a time. */
|
||||
if( XUartPs_Recv( &xUARTInstance, pcRxedChar, sizeof( pcRxedChar ) ) != 0 )
|
||||
{
|
||||
xReturn = 1;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
vTaskDelay( xDelay );
|
||||
}
|
||||
} while( ( xTaskGetTickCount() - xTimeOnEntering ) <= xBlockTime );
|
||||
/* Only a single port is supported. */
|
||||
( void ) pxPort;
|
||||
|
||||
/* Obtain a received character from the queue - entering the Blocked state
|
||||
(so not consuming any processing time) to wait for a character if one is not
|
||||
already available. */
|
||||
xReturn = xQueueReceive( xRxQueue, pcRxedChar, xBlockTime );
|
||||
return xReturn;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vSerialPutString( xComPortHandle pxPort, const signed char * const pcString, unsigned short usStringLength )
|
||||
{
|
||||
static const xTxDelay = 10UL / portTICK_PERIOD_MS;
|
||||
uint32_t ulBytesSent = 0UL;
|
||||
const TickType_t xMaxWait = 200UL / portTICK_PERIOD_MS;
|
||||
|
||||
/* Only a single port is supported. */
|
||||
( void ) pxPort;
|
||||
|
||||
while( ulBytesSent < usStringLength )
|
||||
{
|
||||
ulBytesSent += XUartPs_Send( &xUARTInstance, pcString + ulBytesSent, usStringLength - ulBytesSent );
|
||||
/* Start the transmission. The interrupt service routine will complete the
|
||||
transmission if necessary. */
|
||||
XUartPs_Send( &xUARTInstance, ( void * ) pcString, usStringLength );
|
||||
|
||||
while( XUartPs_IsSending( &xUARTInstance ) )
|
||||
{
|
||||
vTaskDelay( xTxDelay );
|
||||
}
|
||||
}
|
||||
/* Wait until the string has been transmitted before exiting this function,
|
||||
otherwise there is a risk the calling function will overwrite the string
|
||||
pointed to by the pcString parameter while it is still being transmitted.
|
||||
The calling task will wait in the Blocked state (so not consuming any
|
||||
processing time) until the mutex is available. */
|
||||
xSemaphoreTake( xTxCompleteSemaphore, xMaxWait );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
signed portBASE_TYPE xSerialPutChar( xComPortHandle pxPort, signed char cOutChar, portTickType xBlockTime )
|
||||
{
|
||||
static const xTxDelay = 10UL / portTICK_PERIOD_MS;
|
||||
/* Only a single port is supported. */
|
||||
( void ) pxPort;
|
||||
|
||||
XUartPs_Send( &xUARTInstance, &cOutChar, sizeof( cOutChar ) );
|
||||
/* Send the character. */
|
||||
XUartPs_Send( &xUARTInstance, ( void * ) &cOutChar, sizeof( cOutChar ) );
|
||||
|
||||
while( XUartPs_IsSending( &xUARTInstance ) )
|
||||
{
|
||||
vTaskDelay( xTxDelay );
|
||||
}
|
||||
/* Wait for the transmission to be complete so the mutex is left in the
|
||||
correct state for the next time vSerialPutString() is called. */
|
||||
xSemaphoreTake( xTxCompleteSemaphore, xBlockTime );
|
||||
|
||||
return 0;
|
||||
return pdPASS;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vSerialClose(xComPortHandle xPort)
|
||||
{
|
||||
/* Not supported as not required by the demo application. */
|
||||
( void ) xPort;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void prvUART_Handler( void *pvNotUsed )
|
||||
{
|
||||
extern unsigned int XUartPs_SendBuffer( XUartPs *InstancePtr );
|
||||
uint32_t ulActiveInterrupts, ulChannelStatusRegister;
|
||||
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
||||
char cChar;
|
||||
|
||||
configASSERT( pvNotUsed == &xUARTInstance );
|
||||
|
||||
/* Read the interrupt ID register to see which interrupt is active. */
|
||||
ulActiveInterrupts = XUartPs_ReadReg(XPAR_PS7_UART_1_BASEADDR, XUARTPS_IMR_OFFSET);
|
||||
ulActiveInterrupts &= XUartPs_ReadReg(XPAR_PS7_UART_1_BASEADDR, XUARTPS_ISR_OFFSET);
|
||||
|
||||
/* Are any receive events of interest active? */
|
||||
if( ( ulActiveInterrupts & serRECEIVE_INTERRUPT_MASK ) != 0 )
|
||||
{
|
||||
/* Read the Channel Status Register to determine if there is any data in
|
||||
the RX FIFO. */
|
||||
ulChannelStatusRegister = XUartPs_ReadReg( XPAR_PS7_UART_1_BASEADDR, XUARTPS_SR_OFFSET );
|
||||
|
||||
/* Move data from the Rx FIFO to the Rx queue. NOTE THE COMMENTS AT THE
|
||||
TOP OF THIS FILE ABOUT USING QUEUES FOR THIS PURPSOE. */
|
||||
while( ( ulChannelStatusRegister & XUARTPS_SR_RXEMPTY ) == 0 )
|
||||
{
|
||||
cChar = XUartPs_ReadReg( XPAR_PS7_UART_1_BASEADDR, XUARTPS_FIFO_OFFSET );
|
||||
|
||||
/* If writing to the queue unblocks a task, and the unblocked task
|
||||
has a priority above the currently running task (the task that this
|
||||
interrupt interrupted), then xHigherPriorityTaskWoken will be set
|
||||
to pdTRUE inside the xQueueSendFromISR() function.
|
||||
xHigherPriorityTaskWoken is then passed to portYIELD_FROM_ISR() at
|
||||
the end of this interrupt handler to request a context switch so the
|
||||
interrupt returns directly to the (higher priority) unblocked
|
||||
task. */
|
||||
xQueueSendFromISR( xRxQueue, &cChar, &xHigherPriorityTaskWoken );
|
||||
ulChannelStatusRegister = XUartPs_ReadReg( XPAR_PS7_UART_1_BASEADDR, XUARTPS_SR_OFFSET );
|
||||
}
|
||||
}
|
||||
|
||||
/* Are any transmit events of interest active? */
|
||||
if( ( ulActiveInterrupts & serTRANSMIT_IINTERRUPT_MASK ) != 0 )
|
||||
{
|
||||
if( xUARTInstance.SendBuffer.RemainingBytes == 0 )
|
||||
{
|
||||
/* Give back the semaphore to indicate that the tranmission is
|
||||
complete. If giving the semaphore unblocks a task, and the
|
||||
unblocked task has a priority above the currently running task (the
|
||||
task that this interrupt interrupted), then xHigherPriorityTaskWoken
|
||||
will be set to pdTRUE inside the xSemaphoreGiveFromISR() function.
|
||||
xHigherPriorityTaskWoken is then passed to portYIELD_FROM_ISR() at
|
||||
the end of this interrupt handler to request a context switch so the
|
||||
interrupt returns directly to the (higher priority) unblocked
|
||||
task. */
|
||||
xSemaphoreGiveFromISR( xTxCompleteSemaphore, &xHigherPriorityTaskWoken );
|
||||
|
||||
/* No more data to transmit. */
|
||||
XUartPs_WriteReg( XPAR_PS7_UART_1_BASEADDR, XUARTPS_IDR_OFFSET, XUARTPS_IXR_TXEMPTY );
|
||||
}
|
||||
else
|
||||
{
|
||||
/* More data to send. */
|
||||
XUartPs_SendBuffer( &xUARTInstance );
|
||||
}
|
||||
}
|
||||
|
||||
/* portYIELD_FROM_ISR() will request a context switch if executing this
|
||||
interrupt handler caused a task to leave the blocked state, and the task
|
||||
that left the blocked state has a higher priority than the currently running
|
||||
task (the task this interrupt interrupted). See the comment above the calls
|
||||
to xSemaphoreGiveFromISR() and xQueueSendFromISR() within this function. */
|
||||
portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
|
||||
|
||||
/* Clear the interrupt status. */
|
||||
XUartPs_WriteReg( XPAR_PS7_UART_1_BASEADDR, XUARTPS_ISR_OFFSET, ulActiveInterrupts );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue