Skip to content

Instantly share code, notes, and snippets.

@sdbbs
Last active June 1, 2022 12:33
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sdbbs/652d4abeda027999be9245db0035c78f to your computer and use it in GitHub Desktop.
Save sdbbs/652d4abeda027999be9245db0035c78f to your computer and use it in GitHub Desktop.
freertos_pico_test
#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 */
// 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