diff --git a/FreeRTOS/Demo/CORTEX_A9_Zynq_ZC702/RTOSDemo/.project b/FreeRTOS/Demo/CORTEX_A9_Zynq_ZC702/RTOSDemo/.project
index 15d9fcbe6c..1d9dcfbc6d 100644
--- a/FreeRTOS/Demo/CORTEX_A9_Zynq_ZC702/RTOSDemo/.project
+++ b/FreeRTOS/Demo/CORTEX_A9_Zynq_ZC702/RTOSDemo/.project
@@ -34,6 +34,11 @@
2FREERTOS_ROOT/FreeRTOS/Source
+
+ src/Sample-CLI-commands.c
+ 1
+ FREERTOS_ROOT/FreeRTOS-Plus/Demo/Common/FreeRTOS_Plus_CLI_Demos/Sample-CLI-commands.c
+
src/Standard_Demo_Tasks2
diff --git a/FreeRTOS/Demo/CORTEX_A9_Zynq_ZC702/RTOSDemo/src/FreeRTOSConfig.h b/FreeRTOS/Demo/CORTEX_A9_Zynq_ZC702/RTOSDemo/src/FreeRTOSConfig.h
index 14a58f5952..53d62550fe 100644
--- a/FreeRTOS/Demo/CORTEX_A9_Zynq_ZC702/RTOSDemo/src/FreeRTOSConfig.h
+++ b/FreeRTOS/Demo/CORTEX_A9_Zynq_ZC702/RTOSDemo/src/FreeRTOSConfig.h
@@ -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
diff --git a/FreeRTOS/Demo/CORTEX_A9_Zynq_ZC702/RTOSDemo/src/main_full.c b/FreeRTOS/Demo/CORTEX_A9_Zynq_ZC702/RTOSDemo/src/main_full.c
index 081e0f5a2c..4a37911f78 100644
--- a/FreeRTOS/Demo/CORTEX_A9_Zynq_ZC702/RTOSDemo/src/main_full.c
+++ b/FreeRTOS/Demo/CORTEX_A9_Zynq_ZC702/RTOSDemo/src/main_full.c
@@ -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
diff --git a/FreeRTOS/Demo/CORTEX_A9_Zynq_ZC702/RTOSDemo/src/serial.c b/FreeRTOS/Demo/CORTEX_A9_Zynq_ZC702/RTOSDemo/src/serial.c
index 53e7fcdb16..cf154578b1 100644
--- a/FreeRTOS/Demo/CORTEX_A9_Zynq_ZC702/RTOSDemo/src/serial.c
+++ b/FreeRTOS/Demo/CORTEX_A9_Zynq_ZC702/RTOSDemo/src/serial.c
@@ -64,23 +64,24 @@
*/
/*
- BASIC INTERRUPT DRIVEN SERIAL PORT DRIVER FOR UART2.
-
- ***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.
- */
+ BASIC INTERRUPT DRIVEN SERIAL PORT DRIVER.
+
+ 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;
-
- xTimeOnEntering = xTaskGetTickCount();
+BaseType_t xReturn;
- 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 );
+}
+
+
+
+
+