summaryrefslogtreecommitdiff
path: root/FreeRTOS/Demo/Safer_Interrupts_M33F_NXP_LPC55S69_MCUXpresso/Application/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'FreeRTOS/Demo/Safer_Interrupts_M33F_NXP_LPC55S69_MCUXpresso/Application/main.c')
-rw-r--r--FreeRTOS/Demo/Safer_Interrupts_M33F_NXP_LPC55S69_MCUXpresso/Application/main.c393
1 files changed, 393 insertions, 0 deletions
diff --git a/FreeRTOS/Demo/Safer_Interrupts_M33F_NXP_LPC55S69_MCUXpresso/Application/main.c b/FreeRTOS/Demo/Safer_Interrupts_M33F_NXP_LPC55S69_MCUXpresso/Application/main.c
new file mode 100644
index 000000000..804fc4211
--- /dev/null
+++ b/FreeRTOS/Demo/Safer_Interrupts_M33F_NXP_LPC55S69_MCUXpresso/Application/main.c
@@ -0,0 +1,393 @@
+/*
+ * FreeRTOS V202107.00
+ * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * http://www.FreeRTOS.org
+ * http://aws.amazon.com/freertos
+ *
+ * 1 tab == 4 spaces!
+ */
+
+/*
+ * This demo demonstrates the best practice of deferring majority of the
+ * interrupt processing work from IRQ handlers to an unprivileged task. IRQ
+ * handlers execute in privileged mode and therefore, have access to all the
+ * memories. Keeping the IRQ handlers small and deferring most of the work to
+ * unprivileged task provides better security.
+ *
+ * This demo creates a queue, known as interrupt queue. IRQ handlers post
+ * requests to this queue which are later served by an unprivileged interrupt
+ * handler task.
+ *
+ * +-------------------------+
+ * +--------->+ Interrupt Queue +------------+
+ * | +-------------------------+ |
+ * | | Fetch and Serve
+ * Post | |
+ * | v
+ * | +------+--------+
+ * +------+--------+ | |
+ * | IRQ Handler | | |
+ * | (Privileged) | | Interrupt |
+ * +---------------+ | Handler |
+ * | Task |
+ * | (Unprivileged)|
+ * | |
+ * | |
+ * +---------------+
+ *
+ * This demo show-cases the following 2 demos:
+ * 1. LED Demo - The LED demo creates a task which periodically toggles the on
+ * board RGB LED. Whenever user presses the USER button, the
+ * user button pressed IRQ handler changes the color of the LED.
+ * The user button pressed IRQ handler posts a request to the
+ * interrupt queue and task of changing the LED color is deferred
+ * to the unprivileged handler.
+ * 2. UART Demo - The UART demo creates a task which prints a command menu on
+ * the serial console and then waits for the user input. Whenever
+ * user enters any input on the serial console to run a command,
+ * the UART received IRQ handler handles it and prints the
+ * appropriate response on the serial console. The UART received
+ * IRQ handler posts a request to the interrupt queue and task of
+ * handling the command and providing the response is deferred
+ * to the unprivileged handler.
+ */
+
+/* FreeRTOS kernel includes. */
+#include "FreeRTOS.h"
+#include "task.h"
+#include "queue.h"
+
+/* BSP includes. */
+#include "board.h"
+#include "clock_config.h"
+#include "fsl_debug_console.h"
+#include "fsl_device_registers.h"
+#include "fsl_inputmux.h"
+#include "fsl_power.h"
+#include "fsl_pint.h"
+#include "fsl_usart.h"
+#include "pin_mux.h"
+
+/* Demo includes. */
+#include "led_demo.h"
+#include "uart_demo.h"
+#include "interrupt_handler_task.h"
+
+/**
+ * @brief Length of the interrupt queue.
+ */
+#define USER_IRQ_QUEUE_LEN 8
+#define USER_IRQ_QUEUE_BUF_SIZE ( sizeof( UserIrqRequest_t ) * USER_IRQ_QUEUE_LEN )
+
+/**
+ * @brief UART_MEM_START to (UART_MEM_START + UART_MEM_LEN) cover the range
+ * used by USART_WriteBlocking().
+ */
+#define UART_MEM_START ( USART0 )
+#define UART_MEM_LEN ( 3648 )
+
+/**
+ * @brief GPIO_MEM_START to (GPIO_MEM_START + GPIO_MEM_LEN) covers the range
+ * used for setting and clearing GPIO pins.
+ */
+#define GPIO_MEM_START ( 0x4008E200u )
+#define GPIO_MEM_LEN ( 256 )
+
+/**
+ * @brief Handle and storage for the interrupt queue shared between IRQ handlers
+ * and the interrupt handler task.
+ */
+static QueueHandle_t xUserIrqQueueHandle;
+static StaticQueue_t xStaticQueue;
+static uint8_t ucQueueBuffer[ USER_IRQ_QUEUE_BUF_SIZE ];
+/*-----------------------------------------------------------*/
+
+/**
+ * @brief Initialize hardware.
+ */
+static void prvInitializeHardware( void );
+
+/**
+ * @brief Initialize user button pressed interrupt.
+ */
+static void prvInitializeUserButtonInterrupt( void );
+
+/**
+ * @brief Initialize UART received interrupt.
+ */
+static void prvInitializeUartReceivedInterrupt( void );
+
+/**
+ * @brief Handler for pin interrupt when USER button is pressed.
+ *
+ * The handler enqueues a user IRQ request for the IRQ to be further processed
+ * in the unprivileged interrupt handler.
+ */
+static void userButtonPressedHandler( pint_pin_int_t xInterruptType, uint32_t ulMatchStatus );
+
+/**
+ * @brief Handler for UART interrupt when UART data is received.
+ *
+ * The handler enqueues a user IRQ request for the IRQ to be further processed
+ * in the unprivileged interrupt handler.
+ */
+void FLEXCOMM0_IRQHandler( void );
+
+/**
+ * @brief Create the demo tasks.
+ */
+static void prvCreateDemoTasks( void );
+/*-----------------------------------------------------------*/
+
+static void prvInitializeHardware( void )
+{
+ /* Set BOD VBAT level to 1.65V. */
+ POWER_SetBodVbatLevel( kPOWER_BodVbatLevel1650mv, kPOWER_BodHystLevel50mv, false );
+
+ /* Attach main clock divide to FLEXCOMM0 (debug console). */
+ CLOCK_AttachClk( BOARD_DEBUG_UART_CLK_ATTACH );
+
+ /* Board initialization. */
+ BOARD_InitBootPins();
+ BOARD_InitBootClocks();
+ BOARD_InitDebugConsole();
+}
+/*-----------------------------------------------------------*/
+
+static void prvInitializeUserButtonInterrupt( void )
+{
+ /* Connect trigger sources to PINT. */
+ INPUTMUX_Init( INPUTMUX );
+ INPUTMUX_AttachSignal( INPUTMUX, kPINT_PinInt0, kINPUTMUX_GpioPort1Pin9ToPintsel );
+
+ /* Turnoff clock to inputmux to save power. Clock is only needed to make changes. */
+ INPUTMUX_Deinit( INPUTMUX );
+
+ /* Initialize PINT. */
+ PINT_Init( PINT );
+
+ /* Setup Pin Interrupt 0 for rising edge. */
+ PINT_PinInterruptConfig( PINT, kPINT_PinInt0, kPINT_PinIntEnableRiseEdge, userButtonPressedHandler );
+
+ /* Enable callback for PINT0 by Index. */
+ PINT_EnableCallbackByIndex( PINT, kPINT_PinInt0 );
+}
+/*-----------------------------------------------------------*/
+
+static void prvInitializeUartReceivedInterrupt( void )
+{
+ usart_config_t config;
+ USART_GetDefaultConfig( &( config ) );
+ config.enableTx = true;
+ config.enableRx = true;
+ USART_Init( USART0, &( config ), CLOCK_GetFlexCommClkFreq( 0U ) );
+
+ /* Enable RX interrupt. */
+ USART_EnableInterrupts( USART0, kUSART_RxLevelInterruptEnable | kUSART_RxErrorInterruptEnable );
+ EnableIRQ( FLEXCOMM0_IRQn );
+}
+/*-----------------------------------------------------------*/
+
+static void userButtonPressedHandler( pint_pin_int_t xInterruptType, uint32_t ulMatchStatus )
+{
+ UserIrqRequest_t xIrqRequest;
+
+ /* Silence warnings about unused variables. */
+ ( void ) xInterruptType;
+ ( void ) ulMatchStatus;
+
+ /* Enqueue a request to user IRQ queue to be processed in the unprivileged
+ * interrupt handler. */
+ xIrqRequest.xHandlerFunction = vButtonPressedIRQHandler;
+ xIrqRequest.ulData = 0; /* Not used. */
+ xQueueSendFromISR( xUserIrqQueueHandle, &( xIrqRequest ), NULL );
+}
+/*-----------------------------------------------------------*/
+
+/* Override weak definition of FLEXCOMM0_IRQHandler */
+void FLEXCOMM0_IRQHandler(void)
+{
+ UserIrqRequest_t xIrqRequest;
+
+ /* If new data arrived. */
+ if( ( kUSART_RxFifoNotEmptyFlag | kUSART_RxError ) & USART_GetStatusFlags( USART0 ) )
+ {
+ /* Enqueue a request to user IRQ queue to be processed in the unprivileged
+ * interrupt handler. */
+ xIrqRequest.xHandlerFunction = vUartDataReceivedIRQHandler;
+ xIrqRequest.ulData = ( uint32_t ) USART_ReadByte( USART0 );
+ xQueueSendFromISR( xUserIrqQueueHandle, &( xIrqRequest ), NULL );
+ }
+}
+/*-----------------------------------------------------------*/
+
+static void prvCreateDemoTasks( void )
+{
+ static StackType_t xInterruptHandlerTaskStack[ configMINIMAL_STACK_SIZE ] __attribute__( ( aligned( 32 ) ) );
+ static StackType_t xLedDemoTaskStack[ configMINIMAL_STACK_SIZE ] __attribute__( ( aligned( 32 ) ) );
+ static StackType_t xUartDemoTaskStack[ configMINIMAL_STACK_SIZE ] __attribute__( ( aligned( 32 ) ) );
+
+ extern TaskHandle_t xUartDemoTaskHandle;
+ extern uint32_t __user_irq_shared_memory_start__[];
+ extern uint32_t __user_irq_shared_memory_end__[];
+ uint32_t ulSharedMemoryLength = ( uint32_t )__user_irq_shared_memory_end__ - ( uint32_t )__user_irq_shared_memory_start__ + 1;
+
+ /* The interrupt handler task needs access to UART memory region too as we
+ * write the response to UART from the interrupt handler in the UART demo. */
+ TaskParameters_t xInterruptHandlerTaskParameters =
+ {
+ .pvTaskCode = vInterruptHandlerTask,
+ .pcName = "InterruptHandlerTask",
+ .usStackDepth = configMINIMAL_STACK_SIZE,
+ .pvParameters = xUserIrqQueueHandle,
+ .uxPriority = configMAX_PRIORITIES - 1, /* Run the interrupt handler task at the highest priority. */
+ .puxStackBuffer = xInterruptHandlerTaskStack,
+ .xRegions =
+ {
+ { __user_irq_shared_memory_start__, ulSharedMemoryLength, tskMPU_REGION_READ_WRITE | tskMPU_REGION_EXECUTE_NEVER },
+ { ( void * ) UART_MEM_START, UART_MEM_LEN, tskMPU_REGION_READ_WRITE | tskMPU_REGION_EXECUTE_NEVER },
+ { 0, 0, 0 },
+ }
+ };
+ TaskParameters_t xLedDemoTaskParameters =
+ {
+ .pvTaskCode = vLedDemoTask,
+ .pcName = "LedDemoTask",
+ .usStackDepth = configMINIMAL_STACK_SIZE,
+ .pvParameters = NULL,
+ .uxPriority = tskIDLE_PRIORITY,
+ .puxStackBuffer = xLedDemoTaskStack,
+ .xRegions =
+ {
+ { __user_irq_shared_memory_start__, ulSharedMemoryLength, tskMPU_REGION_READ_WRITE | tskMPU_REGION_EXECUTE_NEVER },
+ { ( void * ) GPIO_MEM_START, GPIO_MEM_LEN, tskMPU_REGION_READ_WRITE | tskMPU_REGION_EXECUTE_NEVER },
+ { 0, 0, 0 },
+ }
+ };
+ TaskParameters_t xUartDemoTaskParameters =
+ {
+ .pvTaskCode = vUartDemoTask,
+ .pcName = "UartDemoTask",
+ .usStackDepth = configMINIMAL_STACK_SIZE,
+ .pvParameters = NULL,
+ .uxPriority = tskIDLE_PRIORITY,
+ .puxStackBuffer = xUartDemoTaskStack,
+ .xRegions =
+ {
+ { __user_irq_shared_memory_start__, ulSharedMemoryLength, tskMPU_REGION_READ_WRITE | tskMPU_REGION_EXECUTE_NEVER },
+ { ( void * ) UART_MEM_START, UART_MEM_LEN, tskMPU_REGION_READ_WRITE | tskMPU_REGION_EXECUTE_NEVER },
+ { 0, 0, 0 },
+ }
+ };
+
+ xTaskCreateRestricted( &( xInterruptHandlerTaskParameters ), NULL );
+ xTaskCreateRestricted( &( xLedDemoTaskParameters ), NULL );
+ xTaskCreateRestricted( &( xUartDemoTaskParameters ), &( xUartDemoTaskHandle ) );
+}
+/*-----------------------------------------------------------*/
+
+/**
+ * @brief Entry point.
+ */
+int main( void )
+{
+ /* Initialize board hardware. */
+ prvInitializeHardware();
+
+ /* Create the interrupt queue for deferring work from ISRs to the
+ * unprivileged interrupt handler task. */
+ xUserIrqQueueHandle = xQueueCreateStatic( USER_IRQ_QUEUE_LEN,
+ sizeof( UserIrqRequest_t ),
+ ucQueueBuffer,
+ &( xStaticQueue ) );
+
+ prvCreateDemoTasks();
+ prvInitializeUserButtonInterrupt();
+ prvInitializeUartReceivedInterrupt();
+
+ vTaskStartScheduler();
+
+ /* Should never reach here. */
+ for( ; ; );
+}
+/*-----------------------------------------------------------*/
+
+/* Stack overflow hook. */
+void vApplicationStackOverflowHook( TaskHandle_t xTask, char *pcTaskName )
+{
+ /* Force an assert. */
+ configASSERT( pcTaskName == 0 );
+}
+/*-----------------------------------------------------------*/
+
+/* configUSE_STATIC_ALLOCATION is set to 1, so the application must provide an
+ * implementation of vApplicationGetIdleTaskMemory() to provide the memory that
+ * is used by the Idle task. */
+void vApplicationGetIdleTaskMemory( StaticTask_t ** ppxIdleTaskTCBBuffer,
+ StackType_t ** ppxIdleTaskStackBuffer,
+ uint32_t * pulIdleTaskStackSize )
+{
+ /* If the buffers to be provided to the Idle task are declared inside this
+ * function then they must be declared static - otherwise they will be
+ * allocated on the stack and so not exists after this function exits. */
+ static StaticTask_t xIdleTaskTCB;
+ static StackType_t uxIdleTaskStack[ configMINIMAL_STACK_SIZE ] __attribute__( ( aligned( 32 ) ) );
+
+ /* Pass out a pointer to the StaticTask_t structure in which the Idle
+ * task's state will be stored. */
+ *ppxIdleTaskTCBBuffer = &xIdleTaskTCB;
+
+ /* Pass out the array that will be used as the Idle task's stack. */
+ *ppxIdleTaskStackBuffer = uxIdleTaskStack;
+
+ /* Pass out the size of the array pointed to by *ppxIdleTaskStackBuffer.
+ * Note that, as the array is necessarily of type StackType_t,
+ * configMINIMAL_STACK_SIZE is specified in words, not bytes. */
+ *pulIdleTaskStackSize = configMINIMAL_STACK_SIZE;
+}
+/*-----------------------------------------------------------*/
+
+/* configUSE_STATIC_ALLOCATION and configUSE_TIMERS are both set to 1, so the
+ * application must provide an implementation of vApplicationGetTimerTaskMemory()
+ * to provide the memory that is used by the Timer service task. */
+void vApplicationGetTimerTaskMemory( StaticTask_t ** ppxTimerTaskTCBBuffer,
+ StackType_t ** ppxTimerTaskStackBuffer,
+ uint32_t * pulTimerTaskStackSize )
+{
+ /* If the buffers to be provided to the Timer task are declared inside this
+ * function then they must be declared static - otherwise they will be
+ * allocated on the stack and so not exists after this function exits. */
+ static StaticTask_t xTimerTaskTCB;
+ static StackType_t uxTimerTaskStack[ configTIMER_TASK_STACK_DEPTH ] __attribute__( ( aligned( 32 ) ) );
+
+ /* Pass out a pointer to the StaticTask_t structure in which the Timer
+ * task's state will be stored. */
+ *ppxTimerTaskTCBBuffer = &xTimerTaskTCB;
+
+ /* Pass out the array that will be used as the Timer task's stack. */
+ *ppxTimerTaskStackBuffer = uxTimerTaskStack;
+
+ /* Pass out the size of the array pointed to by *ppxTimerTaskStackBuffer.
+ * Note that, as the array is necessarily of type StackType_t,
+ * configTIMER_TASK_STACK_DEPTH is specified in words, not bytes. */
+ *pulTimerTaskStackSize = configTIMER_TASK_STACK_DEPTH;
+}
+/*-----------------------------------------------------------*/