diff --git a/freertos_exercise_1.ino b/freertos_exercise_1.ino new file mode 100644 index 0000000000000000000000000000000000000000..1294d78268bcf413f981ab33aa9e6c5d586a2e80 --- /dev/null +++ b/freertos_exercise_1.ino @@ -0,0 +1,50 @@ +#include <FreeRTOS.h> +#include <task.h> + +#define SERIAL_PORT Serial +#define BLINK_ON_TIME 2000 +#define BLINK_OFF_TIME 2000 + +/* Dimensions of the buffer that the task being created will use as its stack. + NOTE: This is the number of words the stack will hold, not the number of + bytes. For example, if each stack item is 32-bits, and this is set to 100, + then 400 bytes (100 * 32-bits) will be allocated. */ +#define STACK_SIZE 200 + +/* Structure that will hold the Task Control Block of the task being created. */ +StaticTask_t xTaskBuffer; + +/* Buffer that the task being created will use as its stack. Note this is + an array of StackType_t variables. . */ +StackType_t xStack[ STACK_SIZE ]; + + +void setup() +{ + + SERIAL_PORT.begin(115200); + pinMode(LED_BUILTIN, OUTPUT); + xTaskCreateStatic(led, "led", STACK_SIZE, NULL, configMAX_PRIORITIES - 1, xStack, &xTaskBuffer); +} + +void led(void *pvParameters) +{ + (void) pvParameters; + while (1) + { + SERIAL_PORT.println("LED ON!"); + digitalWrite(LED_BUILTIN, HIGH); + vTaskDelay(BLINK_ON_TIME); + + + SERIAL_PORT.println("LED OFF!"); + digitalWrite(LED_BUILTIN, LOW); + vTaskDelay(BLINK_OFF_TIME); + } +} + + + +void loop() { + +} diff --git a/freertos_exercise_2_base.ino b/freertos_exercise_2_base.ino new file mode 100644 index 0000000000000000000000000000000000000000..aca119fae086215631edc0c03dec1e9fbfde9600 --- /dev/null +++ b/freertos_exercise_2_base.ino @@ -0,0 +1,53 @@ +#include <FreeRTOS.h> +#include <task.h> + +#define SERIAL_PORT Serial +#define BLINK_ON_TIME 2000 +#define BLINK_OFF_TIME 2000 + +/* Dimensions of the buffer that the task being created will use as its stack.*/ +#define STACK_SIZE 200 + +/* Structure that will hold the Task control block of the tasks being created. */ +StaticTask_t xTaskBuffer_A; +StaticTask_t xTaskBuffer_B; + +/* Buffer that the task being created will use as its stack. */ +StackType_t xStack_A[ STACK_SIZE ]; +StackType_t xStack_B[ STACK_SIZE ]; + + +void setup() +{ + + SERIAL_PORT.begin(115200); + pinMode(LED_BUILTIN, OUTPUT); + + xTaskCreateStatic(led_ON, "led_ON", STACK_SIZE, NULL, 1, xStack_A, &xTaskBuffer_A); + xTaskCreateStatic(led_OFF, "led_OFF", STACK_SIZE, NULL, 1, xStack_B, &xTaskBuffer_B); +} + +void led_ON(void *pvParameters) +{ + (void) pvParameters; + while (1) + { + SERIAL_PORT.println("LED ON!"); + digitalWrite(LED_BUILTIN, HIGH); + vTaskDelay(BLINK_ON_TIME); + } +} + +void led_OFF(void *pvParameters) +{ + (void) pvParameters; + while (1) + { + SERIAL_PORT.println("LED OFF!"); + digitalWrite(LED_BUILTIN, LOW); + vTaskDelay(BLINK_OFF_TIME); + } +} + +void loop() { +} diff --git a/freertos_exercise_3_base.ino b/freertos_exercise_3_base.ino new file mode 100644 index 0000000000000000000000000000000000000000..7a3d699c26a5dfc261f4b7de36169ff31018e1c8 --- /dev/null +++ b/freertos_exercise_3_base.ino @@ -0,0 +1,140 @@ +#include <FreeRTOS.h> +#include <task.h> +#include <semphr.h> +#include <FreeRTOSConfig.h> + +#define SERIAL_PORT Serial + +/* Declare a variable of type QueueHandle_t. This is used to store the handle +to the queue that is accessed by all three tasks. */ +QueueHandle_t xQueue; + +void vPrintString( const char *pcString ) +{ + /* Write the string to stdout, using a critical section as a crude method of + mutual exclusion. */ + taskENTER_CRITICAL(); + { + SERIAL_PORT.println(pcString ); + fflush( stdout ); + } + taskEXIT_CRITICAL(); +} + + +static void vSenderTask( void *pvParameters ) +{ + int32_t lValueToSend; + BaseType_t xStatus; + TickType_t xLastWakeTime = xTaskGetTickCount(); + + /* Two instances of this task are created so the value that is sent to the + queue is passed in via the task parameter - this way each instance can use + a different value. The queue was created to hold values of type int32_t, + so cast the parameter to the required type. */ + lValueToSend = ( int32_t ) pvParameters; + /* As per most tasks, this task is implemented within an infinite loop. */ + for( ;; ) + { + /* Send the value to the queue. + The first parameter is the queue to which data is being sent. The + queue was created before the scheduler was started, so before this task + started to execute. + The second parameter is the address of the data to be sent, in this case + the address of lValueToSend. + The third parameter is the Block time – the time the task should be kept + in the Blocked state to wait for space to become available on the queue + should the queue already be full. In this case a block time is not + specified because the queue should never contain more than one item, and + therefore never be full. */ + xStatus = xQueueSendToBack( xQueue, &lValueToSend, pdMS_TO_TICKS( 1000 ) ); + if( xStatus != pdPASS ) + { + /* The send operation could not complete because the queue was full - + this must be an error as the queue should never contain more than + one item! */ + vPrintString( "Could not send to the queue.\r\n" ); + } + + vTaskDelayUntil( &xLastWakeTime, pdMS_TO_TICKS( 1000 ) ); + + + } +} + + +static void vReceiverTask( void *pvParameters ) +{ + /* Declare the variable that will hold the values received from the queue. */ + int32_t lReceivedValue; + BaseType_t xStatus; + const TickType_t xTicksToWait = pdMS_TO_TICKS( 1200 ); + /* This task is also defined within an infinite loop. */ + for( ;; ) + { + /* This call should always find the queue empty because this task will + immediately remove any data that is written to the queue. */ + if( uxQueueMessagesWaiting( xQueue ) != 0 ) + { + vPrintString( "Queue should have been empty!\r\n" ); + } + /* Receive data from the queue. + The first parameter is the queue from which data is to be received. The + queue is created before the scheduler is started, and therefore before this + task runs for the first time. + The second parameter is the buffer into which the received data will be + placed. In this case the buffer is simply the address of a variable that + has the required size to hold the received data. + The last parameter is the block time – the maximum amount of time that the + task will remain in the Blocked state to wait for data to be available + should the queue already be empty. */ + xStatus = xQueueReceive( xQueue, &lReceivedValue, xTicksToWait ); + if( xStatus == pdPASS ) + { + /* Data was successfully received from the queue, print out the received + value. */ + SERIAL_PORT.println(lReceivedValue ); + + //vPrintStringAndNumber( "Received = ", lReceivedValue ); + } + else + { + /* Data was not received from the queue even after waiting for 100ms. + This must be an error as the sending tasks are free running and will be + continuously writing to the queue. */ + vPrintString( "Could not receive from the queue.\r\n" ); + } + } +} + + +void setup() { + // put your setup code here, to run once; + + /* The queue is created to hold a maximum of 5 values, each of which is + large enough to hold a variable of type int32_t. */ + xQueue = xQueueCreate( 5, sizeof( int32_t ) ); + if( xQueue != NULL ) + { + /* Create two instances of the task that will send to the queue. The task + parameter is used to pass the value that the task will write to the queue, + so one task will continuously write 100 to the queue while the other task + will continuously write 200 to the queue. Both tasks are created at + priority 1. */ + xTaskCreate( vSenderTask, "Sender1", 1000, ( void * ) 100, 1, NULL ); + xTaskCreate( vSenderTask, "Sender2", 1000, ( void * ) 200, 1, NULL ); + /* Create the task that will read from the queue. The task is created with + priority 2, so above the priority of the sender tasks. */ + xTaskCreate( vReceiverTask, "Receiver", 1000, NULL, 2, NULL ); + /* Start the scheduler so the created tasks start executing. */ + } + else + { + /* The queue could not be created. */ + } + +} + +void loop() { + +}