Initial commit with submodules
This commit is contained in:
+190
@@ -0,0 +1,190 @@
|
||||
#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) {}
|
||||
}
|
||||
Reference in New Issue
Block a user