Files

191 lines
8.3 KiB
C++

#include <stdio.h>
#include "pico/stdlib.h"
#include "FreeRTOS.h"
#include "task.h"
#include "pico/multicore.h" // Required for interacting with the second core / Обязательно для работы со вторым ядром
#include "hardware/sync.h" // For safe data increment between cores / Для безопасного инкремента данных между ядрами
/**
* @brief Global counter incremented by Core 1 via hardware timer.
* volatile ensures the compiler doesn't cache the value in registers.
* @brief Глобальный счетчик, который увеличивается Ядром 1 через аппаратный таймер.
* volatile гарантирует, что компилятор не будет кэшировать значение в регистрах.
*/
volatile uint32_t core1_counter = 0;
/**
* @brief Pointer to an individual interrupt pool for Core 1
* @brief Указатель на индивидуальный пул прерываний для Ядра 1
*/
alarm_pool_t *core1_alarm_pool = nullptr;
/**
* @brief Maximum number of simultaneous timers in Core 1 pool
* @brief Максимальное количество одновременных таймеров в пуле Ядра 1
*/
const uint CORE1_MAX_TIMERS = 4;
/**
* @brief Structure for storing Core 1 hardware timer information
* @brief Структура для хранения информации об аппаратном таймере Ядра 1
*/
struct repeating_timer timer_core1;
/**
* @brief Pin of the built-in LED on Raspberry Pi Pico 2
* @brief Пин встроенного светодиода на Raspberry Pi Pico 2
*/
const uint LED_PIN = 25;
// ======================================================================================
// User-defined class for LED control
// Пользовательский класс для управления светодиодом
// ======================================================================================
class Pico2LED {
private:
uint m_pin; // GPIO pin number / Номер GPIO пина
public:
/**
* @brief Constructor initializes the GPIO pin
* @brief Конструктор инициализирует GPIO пин
* @param pin The GPIO pin to use / Используемый GPIO пин
*/
Pico2LED(uint pin) : m_pin(pin) {
gpio_init(m_pin);
gpio_set_dir(m_pin, GPIO_OUT);
}
/**
* @brief Turns the LED on
* @brief Включает светодиод
*/
void turnOn() {
gpio_put(m_pin, 1);
}
/**
* @brief Turns the LED off
* @brief Выключает светодиод
*/
void turnOff() {
gpio_put(m_pin, 0);
}
};
/**
* @brief Функция обратного вызова для аппаратного таймера Ядра 1
* Вызывается автоматически каждые 1000 мс прерыванием таймера НА ЯДРЕ 1.
*/
bool core1_timer_callback(struct repeating_timer *t) {
// Безопасно увеличиваем счетчик в многоядерной среде
core1_counter++;
return true; // Возвращаем true, чтобы таймер продолжил циклически работать
}
/**
* @brief Главная функция, выполняемая Ядром 1
*/
void core1_entry() {
// 1. Создаем выделенный пул аппаратных прерываний (таймеров) специально для Ядра 1.
// Функция привязывает этот пул к аппаратному аппаратному контроллеру прерываний Core 1.
core1_alarm_pool = alarm_pool_create_with_unused_hardware_alarm(CORE1_MAX_TIMERS);
if (core1_alarm_pool != nullptr) {
// 2. Добавляем циклический таймер именно в НАШ созданный пул Ядра 1.
// Теперь прерывание гарантированно будет обрабатываться только на Core 1.
alarm_pool_add_repeating_timer_ms(
core1_alarm_pool, // Наш кастомный пул
1000, // Период (1000 мс)
core1_timer_callback,// Функция обратного вызова
NULL, // Пользовательские параметры
&timer_core1 // Структура таймера
);
} else {
// Ошибка создания пула (например, если закончились аппаратные таймеры)
printf("Ошибка: Не удалось создать alarm pool на Ядре 1!\n");
}
// Вечный цикл (пул) Ядра 1
while (true) {
__wfi(); // Спим до тех пор, пока не сработает прерывание таймера на Core 1
}
}
// ======================================================================================
// STANDARD FREERTOS TASKS (Simple functions)
// ОБЫЧНЫЕ ЗАДАЧИ FREERTOS (Простые функции)
// ======================================================================================
/**
* @brief Task 1: Blinks the LED using the Pico2LED class locally
* @brief Задача 1: Мигает светодиодом, используя класс Pico2LED локально
* @param pvParameters Task parameters (unused) / Параметры задачи (не используются)
*/
void led_blink_task(void *pvParameters) {
// Create an object of the class directly inside the task
// Создаем объект класса прямо внутри задачи
Pico2LED my_led(25); // 25 - built-in LED on Pico 2 / 25 - встроенный LED на Pico 2
while (true) {
my_led.turnOn();
vTaskDelay(pdMS_TO_TICKS(200)); // Delay for 200ms / Задержка 200мс
my_led.turnOff();
vTaskDelay(pdMS_TO_TICKS(200)); // Delay for 200ms / Задержка 200мс
}
}
/**
* @brief Task 2: Prints a counter to the USB console
* @brief Задача 2: Выводит счетчик в USB консоль
* @param pvParameters Task parameters (unused) / Параметры задачи (не используются)
*/
void usb_print_task(void *pvParameters) {
int core0_counter = 0;
while (true) {
// Выводим в консоль счетчик FreeRTOS (Core 0) и аппаратный счетчик из Core 1
printf("Core 0 (FreeRTOS) tics: %d | Core 1 (Timer bare-metal) counter: %lu\n",
core0_counter++, core1_counter);
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
// ======================================================================================
// MAIN FUNCTION
// Главная функция
// ======================================================================================
int main() {
// Initialize all standard I/O (USB/UART)
// Инициализация всех стандартных средств ввода-вывода (USB/UART)
stdio_init_all();
// Launch Core 1 BEFORE starting the FreeRTOS scheduler.
// Pass the core1_entry function as the entry point.
// Запускаем Ядро 1 ДО старта планировщика FreeRTOS.
// Передаем ему функцию входа core1_entry.
multicore_launch_core1(core1_entry);
/**
* Create standard tasks by passing function pointers
* Создаем обычные задачи, передавая указатели на функции
*
* xTaskCreate parameters:
* 1. Task function / Функция задачи
* 2. Task name / Имя задачи
* 3. Stack size / Размер стека
* 4. Parameters / Параметры
* 5. Priority / Приоритет
* 6. Task handle / Хэндл задачи
*/
xTaskCreate(led_blink_task, "LED_Task", 256, NULL, 1, NULL);
xTaskCreate(usb_print_task, "Print_Task", 256, NULL, 1, NULL);
// Start the FreeRTOS scheduler
// Запуск планировщика FreeRTOS
vTaskStartScheduler();
// Should never reach here
// Сюда выполнение не должно дойти
while (true) {}
}