Last active
June 1, 2022 12:33
-
-
Save sdbbs/652d4abeda027999be9245db0035c78f to your computer and use it in GitHub Desktop.
freertos_pico_test
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef FREERTOS_CONFIG_H | |
#define FREERTOS_CONFIG_H | |
/* Use Pico SDK ISR handlers */ | |
#define vPortSVCHandler isr_svcall | |
#define xPortPendSVHandler isr_pendsv | |
#define xPortSysTickHandler isr_systick | |
/*----------------------------------------------------------- | |
* Application specific definitions. | |
* | |
* These definitions should be adjusted for your particular hardware and | |
* application requirements. | |
* | |
* THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE | |
* FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE. | |
* | |
* See http://www.freertos.org/a00110.html | |
*----------------------------------------------------------*/ | |
/* Scheduler Related */ | |
#define configUSE_PREEMPTION 1 | |
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0 | |
#define configUSE_TICKLESS_IDLE 0 | |
#define configCPU_CLOCK_HZ 133000000 | |
#define configTICK_RATE_HZ ( ( TickType_t ) 1000 ) | |
#define configMAX_PRIORITIES 32 | |
#define configMINIMAL_STACK_SIZE ( configSTACK_DEPTH_TYPE ) 256 | |
#define configMAX_TASK_NAME_LEN 16 | |
#define configUSE_16_BIT_TICKS 0 | |
#define configIDLE_SHOULD_YIELD 1 | |
#define configUSE_TASK_NOTIFICATIONS 1 | |
#define configTASK_NOTIFICATION_ARRAY_ENTRIES 3 | |
/* Synchronization Related */ | |
#define configUSE_MUTEXES 1 | |
#define configUSE_RECURSIVE_MUTEXES 1 | |
#define configUSE_APPLICATION_TASK_TAG 0 | |
#define configUSE_COUNTING_SEMAPHORES 1 | |
#define configQUEUE_REGISTRY_SIZE 8 | |
#define configUSE_QUEUE_SETS 1 | |
#define configUSE_TIME_SLICING 1 | |
#define configUSE_NEWLIB_REENTRANT 0 | |
#define configENABLE_BACKWARD_COMPATIBILITY 0 | |
#define configNUM_THREAD_LOCAL_STORAGE_POINTERS 5 | |
/* System */ | |
#define configSTACK_DEPTH_TYPE uint32_t | |
#define configMESSAGE_BUFFER_LENGTH_TYPE size_t | |
/* Memory allocation related definitions. */ | |
#define configSUPPORT_STATIC_ALLOCATION 0 | |
#define configSUPPORT_DYNAMIC_ALLOCATION 1 | |
#define configTOTAL_HEAP_SIZE (128*1024) | |
#define configAPPLICATION_ALLOCATED_HEAP 0 | |
/* Hook function related definitions. */ | |
#define configUSE_IDLE_HOOK 0 | |
#define configUSE_TICK_HOOK 0 | |
#define configCHECK_FOR_STACK_OVERFLOW 2 | |
#define configUSE_MALLOC_FAILED_HOOK 1 | |
#define configUSE_DAEMON_TASK_STARTUP_HOOK 0 | |
/* Run time and task stats gathering related definitions. */ | |
#define configGENERATE_RUN_TIME_STATS 0 | |
#define configUSE_TRACE_FACILITY 1 | |
#define configUSE_STATS_FORMATTING_FUNCTIONS 1 | |
/* Co-routine related definitions. */ | |
#define configUSE_CO_ROUTINES 0 | |
#define configMAX_CO_ROUTINE_PRIORITIES 1 | |
/* Software timer related definitions. */ | |
#define configUSE_TIMERS 1 | |
#define configTIMER_TASK_PRIORITY ( configMAX_PRIORITIES - 1 ) | |
#define configTIMER_QUEUE_LENGTH 10 | |
#define configTIMER_TASK_STACK_DEPTH 1024 | |
/* Interrupt nesting behaviour configuration. */ | |
/* | |
#define configKERNEL_INTERRUPT_PRIORITY [dependent of processor] | |
#define configMAX_SYSCALL_INTERRUPT_PRIORITY [dependent on processor and application] | |
#define configMAX_API_CALL_INTERRUPT_PRIORITY [dependent on processor and application] | |
*/ | |
/* SMP port only */ | |
#define configNUM_CORES 2 | |
#define configTICK_CORE 0 | |
#define configRUN_MULTIPLE_PRIORITIES 1 | |
#define configUSE_CORE_AFFINITY 1 | |
/* RP2040 specific */ | |
#define configSUPPORT_PICO_SYNC_INTEROP 1 | |
#define configSUPPORT_PICO_TIME_INTEROP 1 | |
#include <assert.h> | |
/* Define to trap errors during development. */ | |
#define configASSERT(x) assert(x) | |
/* Set the following definitions to 1 to include the API function, or zero | |
to exclude the API function. */ | |
/* Optional functions - most linkers will remove unused functions anyway. */ | |
#define INCLUDE_vTaskPrioritySet 1 | |
#define INCLUDE_uxTaskPriorityGet 1 | |
#define INCLUDE_vTaskDelete 1 | |
#define INCLUDE_vTaskSuspend 1 | |
#define INCLUDE_xResumeFromISR 1 | |
#define INCLUDE_vTaskDelayUntil 1 | |
#define INCLUDE_vTaskDelay 1 | |
#define INCLUDE_xTaskGetSchedulerState 1 | |
#define INCLUDE_xTaskGetCurrentTaskHandle 1 | |
#define INCLUDE_uxTaskGetStackHighWaterMark 1 | |
#define INCLUDE_xTaskGetIdleTaskHandle 1 | |
#define INCLUDE_eTaskGetState 1 | |
#define INCLUDE_xEventGroupSetBitFromISR 1 | |
#define INCLUDE_xTimerPendFunctionCall 1 | |
#define INCLUDE_xTaskAbortDelay 1 | |
#define INCLUDE_xTaskGetHandle 1 | |
#define INCLUDE_xTaskResumeFromISR 1 | |
#define INCLUDE_xQueueGetMutexHolder 1 | |
/* A header file that defines trace macro can be included here. */ | |
#endif /* FREERTOS_CONFIG_H */ | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// made vs. pico-sdk commit 2062372; FreeRTOS smp branch commit a97741a08 | |
#include <inttypes.h> //PRIu64 | |
/* (FreeRTOS) Kernel includes. */ | |
#include <FreeRTOS.h> // Must come first. (this also includes the FreeRTOSConfig.h file in this dir) | |
#include <task.h> // RTOS task related API prototypes. // TaskHandle_t | |
#include <queue.h> // RTOS queue related API prototypes. // QueueHandle_t | |
#include <stdio.h> // as in pico-examples/hello_world/usb/hello_usb.c | |
#include "pico/stdlib.h" | |
#include "pico/multicore.h" // multicore_launch_core1 | |
#include "hardware/clocks.h" // clk_sys | |
#include "hardware/irq.h" // Pico SDK: UART0_IRQ, UART1_IRQ | |
#include "hardware/structs/rosc.h" // rosc_hw | |
#include <string.h> | |
// GP1 (pin 2) to duplicate the PICO_DEFAULT_LED_PIN, so we can capture it on scope | |
#define ISR_COPY_PIN 1 | |
// for disabling printf | |
#define printf(fmt, ...) (0) | |
//#define USE_TASKNOTIF_UNINDEXED | |
//~ #define BUILD_MY_PRINTER | |
TaskHandle_t working_01_taskhandle = NULL; | |
TaskHandle_t working_02_taskhandle = NULL; | |
TaskHandle_t working_03_taskhandle = NULL; | |
#ifdef BUILD_MY_PRINTER | |
TaskHandle_t my_printer_taskhandle = NULL; | |
#endif | |
// forward declares: | |
static void prvSetupHardware( void ); | |
static void init_freertos_tasks( void ); | |
#define ALARM_NUM 0 | |
#define ALARM_IRQ TIMER_IRQ_0 | |
static void timer_alarm_isr(void); | |
static void restart_timer_alarm(void); | |
void led_task( void* pvParameters ); | |
void working_01_task( void* pvParameters ); | |
void working_02_task( void* pvParameters ); | |
void working_03_task( void* pvParameters ); | |
#ifdef BUILD_MY_PRINTER | |
void my_printer_task( void* pvParameters ); | |
#endif | |
#define QUEUE_01_SIZE 16 | |
QueueHandle_t queue_01 = NULL; | |
#define QUEUE_02_SIZE 16 | |
QueueHandle_t queue_02 = NULL; | |
uint8_t buf1[256] = { 0 }; | |
uint8_t buf2[256] = { 0 }; | |
volatile uint8_t buf1_ptr = 0; | |
volatile uint8_t buf2_ptr = 0; | |
char buf1_report[1024]; | |
char buf2_report[1024]; | |
volatile uint8_t timer_counter = 0; | |
int main(void) { | |
prvSetupHardware(); | |
init_freertos_tasks(); | |
// Start the tasks and timers running. | |
vTaskStartScheduler(); | |
// should never reach here (FreeRTOS-SMP-Demos/FreeRTOS/Demo/CORTEX_M0+_RP2040/OnEitherCore/main.c) | |
panic_unsupported(); | |
//while(1){}; | |
} | |
////////////////////////////////////////////////////// | |
bool get_random_bit() { | |
// https://github.com/raspberrypi/pico-sdk/issues/569 | |
return rosc_hw->randombit; | |
} | |
static void timer_alarm_isr(void) { | |
BaseType_t xHigherPriorityTaskWoken = pdFALSE; | |
gpio_put(ISR_COPY_PIN, 1); | |
// Clear the alarm irq | |
hw_clear_bits(&timer_hw->intr, 1u << ALARM_NUM); | |
timer_counter = (timer_counter + 1) % 10; | |
uint8_t randomnum = 0; | |
for (uint8_t i = 0; i < 8; i++) { | |
randomnum |= (get_random_bit() << i); | |
} | |
uint16_t result = (timer_counter << 8) | randomnum; | |
// Assume alarm 0 has fired | |
printf("a\n"); | |
//alarm_fired = true; | |
xHigherPriorityTaskWoken = xTaskResumeFromISR( working_01_taskhandle ); | |
if (xQueueSendFromISR(queue_01, (void *)&result, &xHigherPriorityTaskWoken ) != pdTRUE) { | |
//printf("Queue full"); | |
} | |
// switch context if necessary | |
if( xHigherPriorityTaskWoken ) { | |
// Actual macro used here is port specific. | |
//taskYIELD_FROM_ISR (); | |
portYIELD_FROM_ISR(xHigherPriorityTaskWoken); | |
} | |
gpio_put(ISR_COPY_PIN, 0); | |
restart_timer_alarm(); | |
} | |
static void restart_timer_alarm(void) { | |
uint32_t delay_us = 250; | |
// Alarm is only 32 bits so if trying to delay more | |
// than that need to be careful and keep track of the upper | |
// bits | |
uint64_t target = timer_hw->timerawl + delay_us; | |
// Write the lower 32 bits of the target time to the alarm which | |
// will arm it | |
timer_hw->alarm[ALARM_NUM] = (uint32_t) target; | |
} | |
////////////////////////////////////////////////////// | |
// as in FreeRTOS-SMP-Demos\FreeRTOS\Demo\CORTEX_M0+_RP2040\OnEitherCore\main.c | |
static void prvSetupHardware( void ) { | |
set_sys_clock_pll(1596000000, 6, 2); // change sys clk to 133 MHz | |
// Set up PICO_DEFAULT_LED_PIN as output | |
gpio_init(PICO_DEFAULT_LED_PIN); | |
gpio_set_dir(PICO_DEFAULT_LED_PIN, GPIO_OUT); | |
gpio_put(PICO_DEFAULT_LED_PIN, 0); | |
// debug pins | |
gpio_init(ISR_COPY_PIN); | |
gpio_set_dir(ISR_COPY_PIN, GPIO_OUT); | |
gpio_put(ISR_COPY_PIN, 0); | |
// also set the debug pins for FE/PE/BE/OE | |
// use GP2 (pin 4) to GP5 (pin 7) to show the four UART error states | |
gpio_init(2); | |
gpio_set_dir(2, GPIO_OUT); | |
gpio_put(2, 0); | |
gpio_init(3); | |
gpio_set_dir(3, GPIO_OUT); | |
gpio_put(3, 0); | |
gpio_init(4); | |
gpio_set_dir(4, GPIO_OUT); | |
gpio_put(4, 0); | |
gpio_init(5); | |
gpio_set_dir(5, GPIO_OUT); | |
gpio_put(5, 0); | |
// set up timer hw interrupt // pico-examples/blob/master/timer/timer_lowlevel/timer_lowlevel.c | |
// Enable the interrupt for our alarm (the timer outputs 4 alarm irqs) | |
hw_set_bits(&timer_hw->inte, 1u << ALARM_NUM); | |
// Set irq handler for alarm irq | |
irq_set_exclusive_handler(ALARM_IRQ, timer_alarm_isr); | |
// Enable the alarm irq - not here, from a task! | |
//irq_set_enabled(ALARM_IRQ, true); | |
// Set up USB serial port (printf over USB serial port) | |
stdio_init_all(); | |
} | |
static void init_freertos_tasks( void ) { | |
queue_01 = xQueueCreate(QUEUE_01_SIZE, sizeof(uint16_t)); | |
queue_02 = xQueueCreate(QUEUE_02_SIZE, sizeof(uint8_t)); | |
TaskHandle_t xLedTaskHandle = NULL; // see https://www.freertos.org/a00125.html | |
// Create the task | |
xTaskCreate( | |
led_task, // The function that implements the task. | |
"LED_Task", // Text name for the task, just to help debugging. | |
configMINIMAL_STACK_SIZE, // The size (in words) of the stack that should be created for the task. | |
NULL, // A parameter that can be passed into the task. Not used here | |
1, // The priority to assign to the task. tskIDLE_PRIORITY (which is 0) is | |
// the lowest priority. configMAX_PRIORITIES-1 is the highest priority. | |
//NULL // Used to obtain a handle to the created task. When not used here, set to NULL. | |
&xLedTaskHandle // Used to obtain a handle to the created task. | |
); | |
configASSERT( xLedTaskHandle ); | |
// run led_task on cpu core 1 | |
vTaskCoreAffinitySet( xLedTaskHandle, 0b10 ); | |
// Create the task | |
xTaskCreate( | |
working_01_task, | |
"working_01_task", | |
configMINIMAL_STACK_SIZE, | |
NULL, | |
configMAX_PRIORITIES-1, | |
&working_01_taskhandle | |
); | |
configASSERT( working_01_taskhandle ); | |
// run working_01_task on cpu core 0 | |
vTaskCoreAffinitySet( working_01_taskhandle, 0b01 ); | |
// Create the task | |
xTaskCreate( | |
working_02_task, | |
"working_02_task", | |
configMINIMAL_STACK_SIZE, | |
NULL, | |
configMAX_PRIORITIES-2, | |
&working_02_taskhandle | |
); | |
configASSERT( working_02_taskhandle ); | |
// run working_02_task on cpu core 1 | |
vTaskCoreAffinitySet( working_02_taskhandle, 0b10 ); | |
// Create the task | |
xTaskCreate( | |
working_03_task, | |
"working_03_task", | |
configMINIMAL_STACK_SIZE, | |
NULL, | |
configMAX_PRIORITIES-3, | |
&working_03_taskhandle | |
); | |
configASSERT( working_03_taskhandle ); | |
// run working_03_task on cpu core 1 | |
vTaskCoreAffinitySet( working_03_taskhandle, 0b10 ); | |
#ifdef BUILD_MY_PRINTER | |
// Create the task | |
BaseType_t ret; | |
ret = xTaskCreate( | |
my_printer_task, | |
"my_printer_task", | |
configMINIMAL_STACK_SIZE, | |
NULL, | |
configMAX_PRIORITIES-4, | |
&my_printer_taskhandle | |
); | |
configASSERT( my_printer_taskhandle ); | |
configASSERT( ret == pdPASS ); | |
// run my_printer_task on cpu core 0; | |
vTaskCoreAffinitySet( my_printer_taskhandle, 0b01 ); | |
#endif | |
} | |
void led_task( void* pvParameters ) { | |
// start the timer interrupts and the timer | |
if (!(irq_is_enabled(ALARM_IRQ))) { | |
irq_set_enabled(ALARM_IRQ, true); | |
restart_timer_alarm(); | |
} | |
while (true) { | |
gpio_put(PICO_DEFAULT_LED_PIN, 1); | |
gpio_put(2, 1); | |
printf("led_task ON (core: %d)\n", get_core_num()); | |
vTaskDelay(500); // ms | |
gpio_put(PICO_DEFAULT_LED_PIN, 0); | |
gpio_put(2, 0); | |
printf("led_task OFF (core: %d)\n", get_core_num()); | |
vTaskDelay(500); // ms | |
} | |
} | |
void working_01_task( void* pvParameters ) { | |
uint16_t queuedataitem; | |
// Loop forever | |
while (1) { | |
uint8_t reccount = 0; | |
// wait for - and also, "flush" queue (read all available items) | |
// however, if we have a timeout on xQueueReceive here, xQueueReceive will keep blocking, and processing ISR bytes, until it eventually sees an empty queue (which depending on the timeout, it might not). | |
//while (xQueueReceive(queue_01, (void *)&queuedataitem, 1) == pdTRUE) { // portMAX_DELAY | |
// therefore, we first determine number of items in "queue", we "flush" only those, and then yield to other tasks | |
gpio_put(3, 1); | |
UBaseType_t uxNumQueueItems01 = QUEUE_01_SIZE - uxQueueSpacesAvailable(queue_01); | |
if (uxNumQueueItems01) { | |
while (uxNumQueueItems01) { // portMAX_DELAY | |
if (xQueueReceive(queue_01, (void *)&queuedataitem, 0) == pdTRUE) { | |
uint8_t temp_timer_counter = (uint8_t) (queuedataitem >> 8); | |
uint8_t temp_random = (uint8_t) (queuedataitem | 0b0000000011111111); | |
if (temp_timer_counter%2 == 0) { | |
buf1[buf1_ptr++] = temp_random; | |
} else { | |
buf2[buf2_ptr++] = temp_random; | |
} | |
reccount++; | |
uxNumQueueItems01--; | |
} | |
} // end while (uxNumQueueItems01 | |
if (reccount%2 == 0) { | |
#ifdef USE_TASKNOTIF_UNINDEXED | |
xTaskNotifyGive( working_02_taskhandle ); | |
#else | |
xTaskNotifyGiveIndexed( working_02_taskhandle, 0 ); | |
#endif | |
} else { | |
#ifdef USE_TASKNOTIF_UNINDEXED | |
xTaskNotifyGive( working_03_taskhandle ); | |
#else | |
xTaskNotifyGiveIndexed( working_03_taskhandle, 1 ); | |
#endif | |
} | |
} // end if (uxNumQueueItems01 | |
gpio_put(3, 0); | |
printf("working_01_task"); | |
//// all done, yield for 1 tick (1 ms); | |
//vTaskDelay((TickType_t) 1); | |
// yield by suspending ourselves. | |
vTaskSuspend( NULL ); | |
} // end while(1) | |
} | |
void working_02_task( void* pvParameters ) { | |
while (1) { | |
#ifdef USE_TASKNOTIF_UNINDEXED | |
ulTaskNotifyTake(pdTRUE, portMAX_DELAY); | |
#else | |
ulTaskNotifyTakeIndexed( 0, pdTRUE, portMAX_DELAY ); | |
#endif | |
gpio_put(4, 1); | |
// prepare buf1_report, and signal | |
char* pwriter = &buf1_report[0]; | |
sprintf(pwriter, "buf1[%d]: ", buf1_ptr+1); | |
pwriter += strlen(pwriter); | |
for(uint8_t i=0; i<buf1_ptr; i++) { | |
pwriter += sprintf(pwriter, "%d, ", buf1[i]); | |
} | |
buf1_ptr = 0; | |
#ifdef BUILD_MY_PRINTER | |
// write "1" to queue to signal my_printer_task | |
uint8_t send_data = 1; | |
if (xQueueSend(queue_02, (void *)&send_data, (TickType_t) 0 ) != pdTRUE) { | |
//printf("Queue full"); | |
} | |
#endif | |
gpio_put(4, 0); | |
printf("working_02_task"); | |
} // end while(1) | |
} | |
void working_03_task( void* pvParameters ) { | |
while (1) { | |
#ifdef USE_TASKNOTIF_UNINDEXED | |
ulTaskNotifyTake(pdTRUE, portMAX_DELAY); | |
#else | |
ulTaskNotifyTakeIndexed( 1, pdTRUE, portMAX_DELAY ); | |
#endif | |
gpio_put(5, 1); | |
// prepare buf2_report, and signal | |
char* pwriter = &buf2_report[0]; | |
sprintf(pwriter, "buf2[%d]: ", buf2_ptr+1); | |
pwriter += strlen(pwriter); | |
for(uint8_t i=0; i<buf2_ptr; i++) { | |
pwriter += sprintf(pwriter, "%d, ", buf2[i]); | |
} | |
buf2_ptr = 0; | |
#ifdef BUILD_MY_PRINTER | |
// write "2" to queue to signal my_printer_task | |
uint8_t send_data = 2; | |
if (xQueueSend(queue_02, (void *)&send_data, (TickType_t) 0 ) != pdTRUE) { | |
//printf("Queue full"); | |
} | |
#endif | |
gpio_put(5, 0); | |
printf("working_03_task"); | |
} // end while(1) | |
} | |
#ifdef BUILD_MY_PRINTER | |
void my_printer_task( void* pvParameters ) { | |
uint8_t queuedataitem; | |
// Loop forever | |
while (1) { | |
uint8_t reccount = 0; | |
// wait for - and also, "flush" queue (read all available items) | |
while (xQueueReceive(queue_02, (void *)&queuedataitem, 1) == pdTRUE) { // portMAX_DELAY | |
if (queuedataitem == 1) { | |
printf("my_printer_task buf1: %s\n", buf1_report); | |
buf1_report[0] = '\0'; | |
} else if (queuedataitem == 2) { | |
printf("my_printer_task buf2: %s\n", buf2_report); | |
buf2_report[0] = '\0'; | |
} | |
} | |
} // end while(1) | |
} | |
#endif | |
#if ( configCHECK_FOR_STACK_OVERFLOW > 0 ) | |
void vApplicationStackOverflowHook( TaskHandle_t xTask, char *pcTaskName ) { | |
printf("STACK OVERFLOW: pcTaskName %s !!\n", pcTaskName); | |
configASSERT(0); | |
} | |
#endif | |
#if ( configUSE_MALLOC_FAILED_HOOK > 0 ) | |
void vApplicationMallocFailedHook( void ) { | |
printf("MALLOC FAILED !!\n"); | |
configASSERT(0); | |
} | |
#endif | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment