FreeRTOS Symmetric Multiprocessing (SMP) is a recent version of the RTOS that can schedule tasks across multiple controller cores. It's currently in test phase, and they have a version for the RP2040. In this blog post, I add a second ADC task to my own little SMP project in VSCode. It will compete with the task from the previous blog for the ADC peripheral. |
Separate source files
Up till now, I've added everything in the project to main.c. For this exercise, let's start with dedicated c and header files.
#ifndef __V5VTASK_H #define __V5VTASK_H #include "FreeRTOS.h" #include "task.h" #define V5V_TASK_PRIORITY (tskIDLE_PRIORITY +1) #define V5V_TASK_FREQUENCY_MS (5000 / portTICK_PERIOD_MS) /******************************************************************************* * Function Prototypes ********************************************************************************/ void prv5vTask(void *pvParameters); #endif // __V5VTASK_H
#include "FreeRTOS.h" #include "semphr.h" #include "task.h" #include <stdio.h> #include "pico/stdlib.h" #include "v5vtask.h" #include "hardware/adc.h" // handles extern SemaphoreHandle_t xADCMutex; void prv5vTask(void *pvParameters) { (void)pvParameters; TickType_t xNextWakeTime; /* Initialise xNextWakeTime - this only needs to be done once. */ xNextWakeTime = xTaskGetTickCount(); // Make sure GPIO is high-impedance, no pullups etc adc_gpio_init(29); // gpio29 is adc0 for (;;) { xSemaphoreTake(xADCMutex, portMAX_DELAY); // switch to the temperature mux if needed if (adc_get_selected_input() != 3) { adc_select_input(3); } // 12-bit conversion, assume max value == ADC_VREF == 3.3 V const float conversion_factor = 3.3f / (1 << 12); uint16_t result = adc_read(); xSemaphoreGive(xADCMutex); printf("Raw value: 0x%03x, voltage: %f V\n", result, result * conversion_factor); xTaskDelayUntil(&xNextWakeTime, V5V_TASK_FREQUENCY_MS); } }
Because the task changes an ADC setting (the active channel), it's possibly conflicting with what the temperature task from the previous blog did. The mutex we created, solves this possible interference.
The expected result is 5V measured over a divide by 3 network: VSYS * (R6/(R5+R6)) = 1.67 V
#include "v5vtask.h" // ... // handles SemaphoreHandle_t xADCMutex; // ... /* Configure the hardware ready to run the demo. */ prvSetupHardware(); xTaskCreate(prvBlinkTask, "blink", configMINIMAL_STACK_SIZE, NULL, mainBLINK_TASK_PRIORITY, NULL); xTaskCreate(prvTemperatureTask, "temperature", configMINIMAL_STACK_SIZE, NULL, mainTEMPERATURE_TASK_PRIORITY, NULL); xTaskCreate(prv5vTask, "v5vtask", configMINIMAL_STACK_SIZE, NULL, V5V_TASK_PRIORITY, NULL); /* Create a mutex type semaphore. */ xADCMutex = xSemaphoreCreateMutex(); /* Start the tasks and timer running. */ vTaskStartScheduler(); // ...
add_executable(project0 source/main.c source/v5vtask.c )