I'm trying to run FreeRTOS on a Raspberry Pi PicoW. I'm using Visual Studio Code with PlatformIO to connect to the Pico. I have a folder for the project where I put the FreeRTOS include files and the .c files (these files were downloaded from freertos.org, they're the FreeRTOS source files).
When I try to upload the program I get the following errors, which don't make sense since I already included the FreeRTOS source files and headers and there is no compilation error, only linker error:
Executing task: C:\Users\my_name\.platformio\penv\Scripts\platformio.exe run
Processing pico (platform: raspberrypi; board: pico)
---------------------------------------------------------------------------------------------------------------------------Verbose mode can be enabled via -v, --verbose option
CONFIGURATION: https://docs.platformio.org/page/boards/raspberrypi/pico.html
PLATFORM: Raspberry Pi RP2040 (1.7.0) > Raspberry Pi Pico
HARDWARE: RP2040 133MHz, 264KB RAM, 2MB Flash
DEBUG: Current (cmsis-dap) External (cmsis-dap, jlink, raspberrypi-swd)
PACKAGES:
- tool-rp2040tools @ 1.0.2
- toolchain-gccarmnoneeabi @ 1.90201.191206 (9.2.1)
LDF: Library Dependency Finder -> https://bit.ly/configure-pio-ldf
LDF Modes: Finder ~ chain, Compatibility ~ soft
Found 0 compatible libraries
Scanning dependencies...
No dependencies
Building in release mode
Compiling .pio\build\pico\src\Overload_PICO.o
Linking .pio\build\pico\firmware.elf
c:/users/my_name/.platformio/packages/toolchain-gccarmnoneeabi/bin/../lib/gcc/arm-none-eabi/9.2.1/../../../../arm-none-eabi/bin/ld.exe: .pio\build\pico\src\Overload_PICO.o: in function task1': Overload_PICO.c:(.text.task1+0x2): undefined reference toxTaskGetTickCount'
c:/users/my_name/.platformio/packages/toolchain-gccarmnoneeabi/bin/../lib/gcc/arm-none-eabi/9.2.1/../../../../arm-none-eabi/bin/ld.exe: Overload_PICO.c:(.text.task1+0x14): undefined reference to xTaskGetTickCount' c:/users/my_name/.platformio/packages/toolchain-gccarmnoneeabi/bin/../lib/gcc/arm-none-eabi/9.2.1/../../../../arm-none-eabi/bin/ld.exe: Overload_PICO.c:(.text.task1+0x28): undefined reference toxTaskDelayUntil'
c:/users/my_name/.platformio/packages/toolchain-gccarmnoneeabi/bin/../lib/gcc/arm-none-eabi/9.2.1/../../../../arm-none-eabi/bin/ld.exe: .pio\build\pico\src\Overload_PICO.o: in function task2': Overload_PICO.c:(.text.task2+0x2): undefined reference toxTaskGetTickCount'
c:/users/my_name/.platformio/packages/toolchain-gccarmnoneeabi/bin/../lib/gcc/arm-none-eabi/9.2.1/../../../../arm-none-eabi/bin/ld.exe: Overload_PICO.c:(.text.task2+0x14): undefined reference to xTaskGetTickCount' c:/users/my_name/.platformio/packages/toolchain-gccarmnoneeabi/bin/../lib/gcc/arm-none-eabi/9.2.1/../../../../arm-none-eabi/bin/ld.exe: Overload_PICO.c:(.text.task2+0x2a): undefined reference toxTaskDelayUntil'
c:/users/my_name/.platformio/packages/toolchain-gccarmnoneeabi/bin/../lib/gcc/arm-none-eabi/9.2.1/../../../../arm-none-eabi/bin/ld.exe: .pio\build\pico\src\Overload_PICO.o: in function task3': Overload_PICO.c:(.text.task3+0x2): undefined reference toxTaskGetTickCount'
c:/users/my_name/.platformio/packages/toolchain-gccarmnoneeabi/bin/../lib/gcc/arm-none-eabi/9.2.1/../../../../arm-none-eabi/bin/ld.exe: Overload_PICO.c:(.text.task3+0x14): undefined reference to xTaskGetTickCount' c:/users/my_name/.platformio/packages/toolchain-gccarmnoneeabi/bin/../lib/gcc/arm-none-eabi/9.2.1/../../../../arm-none-eabi/bin/ld.exe: Overload_PICO.c:(.text.task3+0x2a): undefined reference toxTaskDelayUntil'
c:/users/my_name/.platformio/packages/toolchain-gccarmnoneeabi/bin/../lib/gcc/arm-none-eabi/9.2.1/../../../../arm-none-eabi/bin/ld.exe: .pio\build\pico\src\Overload_PICO.o: in function main': Overload_PICO.c:(.text.startup.main+0x12): undefined reference toxTaskCreate'
c:/users/my_name/.platformio/packages/toolchain-gccarmnoneeabi/bin/../lib/gcc/arm-none-eabi/9.2.1/../../../../arm-none-eabi/bin/ld.exe: Overload_PICO.c:(.text.startup.main+0x24): undefined reference to xTaskCreate' c:/users/my_name/.platformio/packages/toolchain-gccarmnoneeabi/bin/../lib/gcc/arm-none-eabi/9.2.1/../../../../arm-none-eabi/bin/ld.exe: Overload_PICO.c:(.text.startup.main+0x36): undefined reference toxTaskCreate'
c:/users/my_name/.platformio/packages/toolchain-gccarmnoneeabi/bin/../lib/gcc/arm-none-eabi/9.2.1/../../../../arm-none-eabi/bin/ld.exe: Overload_PICO.c:(.text.startup.main+0x3a): undefined reference to `vTaskStartScheduler'
collect2.exe: error: ld returned 1 exit status
*** [.pio\build\pico\firmware.elf] Error 1
=============================================== [FAILED] Took 2.80 seconds ===============================================
Files I think are useful to know to answer my question
This is the FreeRTOSConfig.h I'm using:
#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
#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 100
#define configMAX_PRIORITIES 5
#define configMINIMAL_STACK_SIZE 128
#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
#define configUSE_MUTEXES 0
#define configUSE_RECURSIVE_MUTEXES 0
#define configUSE_COUNTING_SEMAPHORES 0
#define configQUEUE_REGISTRY_SIZE 10
#define configUSE_QUEUE_SETS 0
#define configUSE_TIME_SLICING 0
#define configUSE_NEWLIB_REENTRANT 0
#define configENABLE_BACKWARD_COMPATIBILITY 0
#define configNUM_THREAD_LOCAL_STORAGE_POINTERS 5
#define configSTACK_DEPTH_TYPE uint16_t
#define configMESSAGE_BUFFER_LENGTH_TYPE size_t
/* Memory allocation related definitions. */
#define configSUPPORT_STATIC_ALLOCATION 0
#define configSUPPORT_DYNAMIC_ALLOCATION 1
#define configAPPLICATION_ALLOCATED_HEAP 1
/* Hook function related definitions. */
#define configUSE_IDLE_HOOK 0
#define configUSE_TICK_HOOK 0
#define configCHECK_FOR_STACK_OVERFLOW 0
#define configUSE_MALLOC_FAILED_HOOK 0
#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 0
#define configUSE_STATS_FORMATTING_FUNCTIONS 0
/* 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 3
#define configTIMER_QUEUE_LENGTH 10
#define configTIMER_TASK_STACK_DEPTH configMINIMAL_STACK_SIZE
/* Define to trap errors during development. */
#define configASSERT( x )
/* 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 0
#define INCLUDE_xTaskGetIdleTaskHandle 0
#define INCLUDE_eTaskGetState 0
#define INCLUDE_xEventGroupSetBitFromISR 1
#define INCLUDE_xTimerPendFunctionCall 0
#define INCLUDE_xTaskAbortDelay 0
#define INCLUDE_xTaskGetHandle 0
#define INCLUDE_xTaskResumeFromISR 1
/* A header file that defines trace macro can be included here. */
#endif /* FREERTOS_CONFIG_H */
This is the platformio.ini I'm using:
[env:pico]
platform = raspberrypi
board = pico
monitor_speed = 115200
This is the portmacro.h I'm using, I'm not sure if this one is correct for the PicoW, I searched the internet and found that the Pico uses an ARM-Cortex M0 processor so I assumed this is the correct portmacro:
/*
* FreeRTOS Kernel V10.4.6
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* SPDX-License-Identifier: MIT
*
* 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.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*
*/
#ifndef PORTMACRO_H
#define PORTMACRO_H
#ifdef __cplusplus
extern "C" {
#endif
/*-----------------------------------------------------------
- Port specific definitions.
- The settings in this file configure FreeRTOS correctly for the
- given hardware and compiler.
- These settings should not be altered.
-----------------------------------------------------------
/
/* Type definitions. */
#define portCHAR char
#define portFLOAT float
#define portDOUBLE double
#define portLONG long
#define portSHORT short
#define portSTACK_TYPE uint32_t
#define portBASE_TYPE long
typedef portSTACK_TYPE StackType_t;
typedef long BaseType_t;
typedef unsigned long UBaseType_t;
#if ( configUSE_16_BIT_TICKS == 1 )
typedef uint16_t TickType_t;
#define portMAX_DELAY ( TickType_t ) 0xffff
#else
typedef uint32_t TickType_t;
#define portMAX_DELAY ( TickType_t ) 0xffffffffUL
/* 32-bit tick type on a 32-bit architecture, so reads of the tick count do
- not need to be guarded with a critical section. */
#define portTICK_TYPE_IS_ATOMIC 1
#endif
/-----------------------------------------------------------/
/* Architecture specifics. /
#define portSTACK_GROWTH ( -1 )
#define portTICK_PERIOD_MS ( ( TickType_t ) 1000 / configTICK_RATE_HZ )
#define portBYTE_ALIGNMENT 8
#define portDONT_DISCARD attribute( ( used ) )
/-----------------------------------------------------------*/
/* Scheduler utilities. /
extern void vPortYield( void );
#define portNVIC_INT_CTRL_REG ( ( ( volatile uint32_t * ) 0xe000ed04 ) )
#define portNVIC_PENDSVSET_BIT ( 1UL << 28UL )
#define portYIELD() vPortYield()
#define portEND_SWITCHING_ISR( xSwitchRequired ) do { if( xSwitchRequired ) portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT; } while( 0 )
#define portYIELD_FROM_ISR( x ) portEND_SWITCHING_ISR( x )
/-----------------------------------------------------------/
/* Critical section management. */
extern void vPortEnterCritical( void );
extern void vPortExitCritical( void );
extern uint32_t ulSetInterruptMaskFromISR( void ) attribute( ( naked ) );
extern void vClearInterruptMaskFromISR( uint32_t ulMask ) attribute( ( naked ) );
#define portSET_INTERRUPT_MASK_FROM_ISR() ulSetInterruptMaskFromISR()
#define portCLEAR_INTERRUPT_MASK_FROM_ISR( x ) vClearInterruptMaskFromISR( x )
#define portDISABLE_INTERRUPTS() __asm volatile ( " cpsid i " ::: "memory" )
#define portENABLE_INTERRUPTS() __asm volatile ( " cpsie i " ::: "memory" )
#define portENTER_CRITICAL() vPortEnterCritical()
#define portEXIT_CRITICAL() vPortExitCritical()
/-----------------------------------------------------------/
/* Tickless idle/low power functionality. /
#ifndef portSUPPRESS_TICKS_AND_SLEEP
extern void vPortSuppressTicksAndSleep( TickType_t xExpectedIdleTime );
#define portSUPPRESS_TICKS_AND_SLEEP( xExpectedIdleTime ) vPortSuppressTicksAndSleep( xExpectedIdleTime )
#endif
/-----------------------------------------------------------*/
/* Task function macros as described on the FreeRTOS.org WEB site. /
#define portTASK_FUNCTION_PROTO( vFunction, pvParameters ) void vFunction( void pvParameters )
#define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void * pvParameters )
#define portNOP()
#define portMEMORY_BARRIER() __asm volatile ( "" ::: "memory" )
#ifdef __cplusplus
}
#endif
#endif /* PORTMACRO_H */
Code I'm trying to upload:
#include <FreeRTOS.h>
#include <task.h>
#include <stdio.h>
#include <time.h>
//Overload happens if xTaskGetTickCount – lastTickCount (the first parm to vTaskDelayUntil) is >= period in ticks
void delay(int number_of_seconds)
{
// Converting time into milli_seconds
int milli_seconds = 1000 * number_of_seconds;
// Storing start time
clock_t start_time = clock();
// looping till required time is not achieved
while (clock() < start_time + milli_seconds)
;
}
void task1();
void task2();
void task3();
int main() {
//Create tasks
//xTaskCreate(Task function, Task name, , Task parameter, Task priority, );
xTaskCreate(task1, "task1", 128, NULL, 1, NULL);
xTaskCreate(task2, "task2", 128, NULL, 2, NULL);
xTaskCreate(task3, "task3", 128, NULL, 3, NULL);
vTaskStartScheduler();
}
void loop() {}
void task1() {
TickType_t waketime, period = 10 / portTICK_PERIOD_MS;
waketime = xTaskGetTickCount();
while(1) {
printf("M"); //This happens almost immediately, so we need to add an artificial delay, a to simulate a task running for a few ms, it only serves as a notification that the task started
delay(100);
if(xTaskGetTickCount() - waketime >= period) printf("Overload in task 1");
vTaskDelayUntil(&waketime, period);
}
}
void task2() {
TickType_t waketime, period = 1000 / portTICK_PERIOD_MS;
waketime = xTaskGetTickCount();
while(1) {
printf("E"); //This happens almost immediately, so we need to add an artificial delay, a to simulate a task running for a few ms, it only serves as a notification that the task started
delay(10);
if(xTaskGetTickCount() - waketime >= period) printf("Overload in task 2");
vTaskDelayUntil(&waketime, period);
}
}
void task3() {
TickType_t waketime, period = 1000 / portTICK_PERIOD_MS;
waketime = xTaskGetTickCount();
while(1) {
printf("S"); //This happens almost immediately, so we need to add an artificial delay, a to simulate a task running for a few ms, it only serves as a notification that the task started
delay(10);
if(xTaskGetTickCount() - waketime >= period) printf("Overload in task 3");
vTaskDelayUntil(&waketime, period);
}
}