Skip to content

Instantly share code, notes, and snippets.

@sdbbs
Created June 21, 2022 08:28
Show Gist options
  • Save sdbbs/b1410cd45106e0c0ee599f7fcdbb8f90 to your computer and use it in GitHub Desktop.
Save sdbbs/b1410cd45106e0c0ee599f7fcdbb8f90 to your computer and use it in GitHub Desktop.
rp2040_fros_tmrisr_ex
rp2040_fros_tmrisr_ex
cmake_minimum_required(VERSION 3.13)
# also include .h files from the current source directory
SET(CMAKE_INCLUDE_CURRENT_DIR ON)
# Pull in SDK (must be before project)
set(PICO_PLATFORM rp2040)
include(pico_sdk_import.cmake)
# Pull in FreeRTOS
# explicit FREERTOS path - use "mixed" mode for MINGW64 Windows paths (with `C:` drive identifier, but with forward slash)
set(FREERTOS_KERNEL_PATH "C:/src/rp2040_pico/FreeRTOS-Kernel-SMP")
include(FreeRTOS_Kernel_import.cmake)
# note that FreeRTOS_Kernel_import.cmake does not print message if FREERTOS_KERNEL_PATH set explicitly,
# so let's print it out here (so we don't change the "vanilla" FreeRTOS_Kernel_import.cmake file):
message("The FREERTOS_KERNEL_PATH is '${FREERTOS_KERNEL_PATH}'")
message("The FREERTOS_KERNEL_RP2040_RELATIVE_PATH is '${FREERTOS_KERNEL_PATH}/${FREERTOS_KERNEL_RP2040_RELATIVE_PATH}'")
project(rp2040_fros_tmrisr_ex C CXX ASM)
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)
if (PICO_SDK_VERSION_STRING VERSION_LESS "1.3.0")
message(FATAL_ERROR "Raspberry Pi Pico SDK version 1.3.0 (or later) required. Your version is ${PICO_SDK_VERSION_STRING}")
endif()
# Initialize the SDK
pico_sdk_init()
add_executable(rp2040_fros_tmrisr_ex
main.c
)
target_compile_definitions(rp2040_fros_tmrisr_ex PRIVATE
PICO_STDIO_STACK_BUFFER_SIZE=64 # use a small printf on stack buffer
)
add_compile_options(-Wall
-Wno-format # int != int32_t as far as the compiler is concerned because gcc has int32_t as long int
-Wno-unused-function # we have some for the docs that aren't called
-Wno-maybe-uninitialized
)
# pull in common dependencies and additional uart hardware support
target_link_libraries(rp2040_fros_tmrisr_ex
FreeRTOS-Kernel
FreeRTOS-Kernel-Heap1
pico_stdlib
pico_multicore
hardware_uart
)
# create map/bin/hex file etc.
pico_add_extra_outputs(rp2040_fros_tmrisr_ex)
# this will hopefully enable `printf` printouts via USB Serial ports
pico_enable_stdio_usb(rp2040_fros_tmrisr_ex 1)
# # enable usb output, disable uart output?
pico_enable_stdio_uart(rp2040_fros_tmrisr_ex 0)
#ifndef FREERTOS_CONFIG_H
#define FREERTOS_CONFIG_H
// #pragma message("FREERTOS_CONFIG_H included!")
/* 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 // must be 1 in addition to configUSE_TRACE_FACILITY so we get vTaskList function
/* 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]
*/
//#define configMAX_SYSCALL_INTERRUPT_PRIORITY 0b01000000 // causes recompile, but not sure if it makes a difference on RP2040 at all
/* SMP port only */
#define configNUM_CORES 2
#define configTICK_CORE 0 // "Core in which tick should run"
#define configRUN_MULTIPLE_PRIORITIES 1 // must be 1 to use core affinity/"core exclusion"
#define configUSE_CORE_AFFINITY 1 // "configUSE_CORE_AFFINITY must be defined as 1
// for vTaskCoreAffinitySet to be available."
/* 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 <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>
// GP2 (pin 3) to duplicate the PICO_DEFAULT_LED_PIN, so we can capture it on scope
#define ISR_COPY_PIN 1
#define LED_COPY_PIN 2
// forward declares:
static void prvSetupHardware( void );
static void setup_timer_isr( void );
static void init_freertos_tasks( void );
#define ALARM_NUM 2
#define ALARM_IRQ TIMER_IRQ_2
//~ #define USE_HARDWARE_ALARM_API
#ifndef USE_HARDWARE_ALARM_API
static void __not_in_flash_func(timer_alarm_isr)(void);
#else
static void __not_in_flash_func(timer_alarm_isr)(uint timer);
#endif
static void __not_in_flash_func(restart_timer_alarm)(void);
void led_task( void* pvParameters );
volatile uint8_t timer_counter = 0;
volatile uint16_t last_data_result = 0;
// note: by default, configMAX_SYSCALL_INTERRUPT_PRIORITY is not defined at all:
#ifndef configMAX_SYSCALL_INTERRUPT_PRIORITY
#pragma message " configMAX_SYSCALL_INTERRUPT_PRIORITY is NOT defined!"
#endif
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){};
}
//////////////////////////////////////////////////////
#ifndef USE_HARDWARE_ALARM_API
static void __not_in_flash_func(timer_alarm_isr)(void) {
#else
static void __not_in_flash_func(timer_alarm_isr)(uint timer) {
#endif
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 |= (rosc_hw->randombit << i);
}
last_data_result = (timer_counter << 8) | randomnum;
restart_timer_alarm();
gpio_put(ISR_COPY_PIN, 0);
// switch context if necessary
if( xHigherPriorityTaskWoken ) {
// Actual macro used here is port specific.
//taskYIELD_FROM_ISR ();
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
//portEND_SWITCHING_ISR(xHigherPriorityTaskWoken);
}
static void __not_in_flash_func(restart_timer_alarm)(void) {
static const uint32_t delay_us = 250;
#ifndef USE_HARDWARE_ALARM_API
// 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;
#else
hardware_alarm_set_target(ALARM_NUM, make_timeout_time_us( delay_us ) );
#endif
}
//////////////////////////////////////////////////////
// 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);
gpio_init(LED_COPY_PIN);
gpio_set_dir(LED_COPY_PIN, GPIO_OUT);
gpio_put(LED_COPY_PIN, 0);
setup_timer_isr();
// Set up USB serial port (printf over USB serial port)
stdio_init_all();
}
static void setup_timer_isr( void ) {
// 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);
#ifndef USE_HARDWARE_ALARM_API
// Set irq handler for alarm irq // pico-examples/blob/master/timer/timer_lowlevel/timer_lowlevel.c
irq_set_exclusive_handler(ALARM_IRQ, timer_alarm_isr);
#else
hardware_alarm_claim(ALARM_NUM); // FreeRTOS/Demo/CORTEX_M0+_RP2040/Standard/IntQueueTimer.c
hardware_alarm_set_callback(ALARM_NUM, timer_alarm_isr);
#endif
// Enable the alarm irq - not here, from a task!
//irq_set_enabled(ALARM_IRQ, true);
// "Hardware priorities range from 0 (highest priority) to 255 (lowest priority) though only the top 2 bits are significant on ARM Cortex-M0+."
// attempt to assign a higher priority (lower priority number); available are: 0b11000000 = 192 = 0xc0; 0b10000000 = 128 = 0x80; 0b01000000 = 64 = 0x40; 0b00000000 = 0 = 0x00;
irq_set_priority(ALARM_IRQ, 0b01000000);
}
static void init_freertos_tasks( void ) {
// NOTE: FreeRTOS own "Tmr Svc" already has priority configMAX_PRIORITIES-1!
// should probably use less than that for our tasks:
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 );
vTaskSetTaskNumber(xLedTaskHandle, 1);
// run led_task on cpu core 1
vTaskCoreAffinitySet( xLedTaskHandle, 0b10 );
}
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(LED_COPY_PIN, 1);
vTaskDelay(500); // ms
gpio_put(PICO_DEFAULT_LED_PIN, 0);
gpio_put(LED_COPY_PIN, 0);
vTaskDelay(500); // ms
}
}
#if ( configCHECK_FOR_STACK_OVERFLOW > 0 )
void vApplicationStackOverflowHook( TaskHandle_t xTask, char *pcTaskName ) {
configASSERT(0);
}
#endif
#if ( configUSE_MALLOC_FAILED_HOOK > 0 )
void vApplicationMallocFailedHook( void ) {
configASSERT(0);
}
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment