Перейти к содержанию

Знакомство с периферией

Эти руководства продолжают раздел «Начало работы». До их выполнения установите инструментарий SiFli-SDK, хотя бы один раз прошейте пример hello_world и научитесь открывать консоль последовательного порта. Каждое упражнение намеренно небольшое: одна идея, один периферийный блок и понятный критерий успеха.

В примерах предполагается плата класса SF32LB52-DevKit-LCD, например с именем sf32lb52-lcd_n16r8. Если используется другая плата, замените имя в команде сборки и проверьте названия выводов, экземпляры периферийных блоков и разметку накопителя в файлах поддержки этой платы.

Эта серия помогает выработать надёжный подход: проверяйте одно аппаратное поведение за раз, задавайте чёткий критерий успеха и сохраняйте рабочую базовую конфигурацию перед переходом к следующему блоку. Материал рассчитан на разработчиков, которые только начинают работать с SDK SF32, даже если они уже знакомы с программированием встраиваемых систем на C.

Перед началом

Для каждого упражнения придерживайтесь одного и того же порядка действий:

scons --board=<board_name> -j8
# then flash with the download script or tool used in Get Started

Не закрывайте терминал последовательного порта. Большинство типичных ошибок проще найти, когда видны сообщения rt_kprintf() и приглашение FinSH msh>.

Примеры на C — это фрагменты, а не полные исходные файлы. Добавьте необходимые для проекта и версии SDK заголовки, объявления, инициализацию платы, проверку возвращаемых значений и освобождение ресурсов.

Таблица: перед началом работы
Пункт Проверка
Имя платы Совпадает с одной из поддерживаемых конфигураций платы.
Последовательный порт Открывается без ошибок и показывает загрузочные сообщения.
Инструмент прошивки Позволяет многократно прошивать плату без замены кабелей.
Схема или файлы платы Доступны до выбора ресурсов GPIO, ADC, PWM или RTC.
Одно изменение за раз После каждого небольшого изменения выполните сборку, прошивку и проверку.

Цель: управлять выводом GPIO из прошивки — аналог первой успешной сборки в мире встраиваемых систем.

Время: 15 минут

Начните с: example/hal/gpio или example/rt_device/gpio

В SDK SF32 на базе RT-Thread GPIO доступен через стандартный API RT-Thread для устройств PIN device. Простейший цикл мигания выглядит так:

#include <rtthread.h>
#include <rtdevice.h>

#define LED_PIN GET_PIN(1, 0)  /* replace with your board's LED pin */

int main(void)
{
    rt_pin_mode(LED_PIN, PIN_MODE_OUTPUT);

    while (1)
    {
        rt_pin_write(LED_PIN, PIN_HIGH);
        rt_thread_mdelay(500);
        rt_pin_write(LED_PIN, PIN_LOW);
        rt_thread_mdelay(500);
    }
}
  1. Скопируйте наиболее подходящий пример GPIO в каталог своего проекта или изменяйте его на месте, пока учитесь.
  2. Найдите вывод светодиода в схеме или файлах поддержки платы. Не угадывайте номер порта и вывода.
  3. Соберите и прошейте проект, указав то же имя платы, что и для hello_world.
  4. Убедитесь, что светодиод мигает с ожидаемой частотой.
  5. Измените задержку на 100 ms, пересоберите прошивку и проверьте, что частота мигания изменилась.

Критерий успеха: светодиод непрерывно переключается, в консоли последовательного порта по-прежнему отображаются обычные сообщения загрузки, а изменение задержки меняет частоту мигания.

Если не работает: проверьте активный уровень, подключён ли светодиод через транзистор, не используется ли вывод другой функцией и соответствует ли имя платы установленному оборудованию.

Что вы узнали: об абстракции PIN device, назначении выводов для конкретной платы и основном цикле «изменение — сборка — прошивка».

Считывайте состояние кнопки через GPIO

Цель: считывать цифровой вход и реагировать на нажатие кнопки.

Время: 20 минут

Начните с: example/rt_device/gpio

Для чтения кнопки используется тот же PIN API, но в режиме входа. Сначала выполните простое чтение, чтобы проверить подключение и логический уровень:

В SiFli-SDK API RT-Thread PIN device не позволяет настроить подтяжку вывода вверх или вниз через rt_pin_mode(). Для кнопки, активной по низкому уровню, убедитесь, что на плате есть резистор подтяжки вверх, либо настройте подтяжку через pinmux с помощью HAL_PIN_Set(...) согласно конфигурации этой платы. Площадка, функция и домен процессора зависят от платы; не копируйте назначение вывода без проверки.

rt_pin_mode(BUTTON_PIN, PIN_MODE_INPUT);

if (rt_pin_read(BUTTON_PIN) == PIN_LOW)
{
    /* button pressed, active-low */
}

Для задач, выходящих за рамки быстрой проверки, используйте прерывание вместо непрерывного опроса вывода в активном цикле. Тогда прошивка сможет реагировать на фронт сигнала, не проверяя вывод снова и снова; если остальная схема позволяет процессору спать между событиями, это также может снизить энергопотребление:

rt_pin_attach_irq(BUTTON_PIN, PIN_IRQ_MODE_FALLING, button_isr, RT_NULL);
rt_pin_irq_enable(BUTTON_PIN, PIN_IRQ_ENABLE);
  1. Найдите на плате доступную кнопку или входной вывод.
  2. Начните с чтения в цикле и выводите исходное значение при нажатии и отпускании кнопки.
  3. Определите, активна ли кнопка по высокому или низкому уровню.
  4. Когда простое чтение заработает, перейдите к обработчику прерывания.
  5. Переключайте светодиод из упражнения 1 при каждом нажатии кнопки.
  6. Добавьте простую защиту от дребезга: игнорируйте события в течение короткого интервала или проверяйте уровень после небольшой задержки.

Критерий успеха: одно физическое нажатие вызывает одно ожидаемое действие прошивки, без повторных срабатываний из-за дребезга.

Если не работает: проверьте, предусмотрена ли на плате нужная подтяжка вверх или вниз либо настроена ли она через pinmux. Затем проверьте активный уровень кнопки, выбор фронта прерывания и не используется ли вывод для режима загрузки, отладки или другой периферии.

Что вы узнали: о настройке цифрового входа, логике active-high и active-low, обработке прерываний и о том, почему постоянный опрос может расходовать энергию. Системное обоснование см. в разделе «Обзор энергосберегающего проектирования».

Используйте оболочку и выводите отладочные сообщения

Цель: освоить консоль FinSH и rt_kprintf() до того, как отладка станет сложнее.

Время: 15 минут

Начните с: example/system/finsh

Оболочка FinSH в RT-Thread предоставляет интерактивное приглашение msh> через тот же UART, по которому выводятся загрузочные сообщения. С самого начала выработайте следующие привычки:

  • Для кратких отладочных сообщений используйте rt_kprintf(), а не прямую запись в UART.
  • Проверяйте работающую систему встроенными командами оболочки, например list_thread, list_device и командами просмотра памяти и статуса.
  • Делайте журналы короткими и информативными: избыточный вывод может изменить временные характеристики и энергопотребление.

  • Прошейте любой из предыдущих примеров и снова откройте терминал последовательного порта.

  • Нажмите Enter, чтобы открыть приглашение msh>.
  • Выполните list_thread и list_device.
  • Добавьте вызовы rt_kprintf() в обработчик кнопки из упражнения 2.
  • Убедитесь, что при нажатии кнопки появляются сообщения.

Критерий успеха: вы можете просматривать потоки и устройства из оболочки и сопоставлять собственные сообщения журнала с физическими событиями.

Если не работает: проверьте скорость последовательного порта, правильность выбора порта, включён ли компонент оболочки и не удерживает ли порт открытым другая программа.

Что вы узнали: как проверять работающую систему без подключённого отладчика и легко добавлять полезные журналы, не превращая каждую проблему в догадки о прошивке.

Считывайте аналоговый сигнал через ADC

Цель: измерить аналоговое напряжение на потенциометре, простом датчике или входе измерения батареи.

Время: 20 минут

Начните с: example/rt_device/adc/channel

Для этого примера RT-Thread включите BSP_USING_ADC, BSP_USING_ADC1 и RT_USING_ADC; иначе SDK не зарегистрирует bat1. На SF32LB52 канал 7 внутри микросхемы подключён к VBAT, поэтому его нельзя использовать как обычный вход внешнего датчика. Выберите канал ADC и настройте pinmux с учётом конкретной микросхемы и платы. В документированном примере для SF32LB52 канал 0 использует PA28. В текущем примере SDK SiFli функция rt_adc_read() возвращает значение напряжения, масштабированное в единицах 0,1 mV, а не необработанные коды ADC. Проверьте единицы и пересчёт для конкретной микросхемы и версии драйвера, которые вы используете.

rt_adc_device_t adc = (rt_adc_device_t)rt_device_find("bat1");
rt_adc_enable(adc, channel);
rt_uint32_t voltage_0p1mV = rt_adc_read(adc, channel);
  1. Найдите на плате вывод, поддерживающий ADC, и соответствующий канал.
  2. Проверьте диапазон входного напряжения, наличие делителя или аналогового входного каскада.
  3. Найдите зарегистрированное устройство ADC, включите канал и прочитайте его значение.
  4. Выполните пересчёт, указанный для этого драйвера. В текущем примере SF32LB52 разделите возвращённое значение на 10, чтобы получить милливольты; не применяйте повторно формулу для исходных кодов и опорного напряжения. Если на плате есть внешний делитель, учитывайте его коэффициент при расчёте напряжения до делителя.
  5. Выведите результат в оболочку из упражнения 3.
  6. Медленно изменяйте входное напряжение и убедитесь, что показания меняются плавно.

Критерий успеха: показания меняются в ожидаемом направлении и после применения документированного масштаба и коэффициента делителя соответствуют правдоподобному входному напряжению.

Если не работает: проверьте настройку мультиплексора выводов, номер канала, документированные масштаб и калибровку драйвера, допустимый диапазон входа, не оставлен ли вход плавающим, а также требует ли датчик питания или времени установления перед измерением.

Что вы узнали: о шаблоне rt_device_find(), который используется в драйверах устройств RT-Thread. Он пригодится для I2C, SPI, PWM, накопителей и собственных драйверов.

Управляйте выходом PWM

Цель: сформировать сигнал PWM для регулировки яркости светодиода или управления простым зуммером.

Время: 20 минут

Начните с: example/rt_device/pwm

Имя устройства PWM зависит от драйвера таймера, включённого для платы. В SDK используются имена вроде pwm3, pwmlp1 и pwma1; pwm3 ниже приведён только как пример, это не универсальное имя. Проверьте зарегистрированное имя устройства и настройку мультиплексора выводов в конфигурации платы.

struct rt_device_pwm *pwm = (struct rt_device_pwm *)rt_device_find("pwm3");
rt_pwm_set(pwm, channel, period_ns, pulse_ns);
rt_pwm_enable(pwm, channel);
  1. Выберите канал PWM и проверьте настройку мультиплексора вывода.
  2. Выберите подходящий период: достаточно высокий, чтобы мерцание светодиода было незаметным, или в слышимом диапазоне для зуммера.
  3. Меняйте коэффициент заполнения, чтобы плавно изменять яркость светодиода.
  4. Изменяя период, задайте несколько фиксированных тонов зуммера.
  5. Отключите PWM и убедитесь, что выход возвращается в безопасное состояние покоя.

Критерий успеха: изменение коэффициента заполнения меняет яркость или изменение периода меняет тон, а после отключения PWM выход оказывается в ожидаемом состоянии.

Если не работает: проверьте, подключён ли вывод к нужному экземпляру PWM, правильно ли указан номер канала, задаются ли период и импульс в наносекундах и нужен ли внешней нагрузке управляющий транзистор.

Что вы узнали: о настройке периода и коэффициента заполнения, а также о применении шаблона драйвера устройства из упражнения 4 к другому классу периферии.

Работайте с RTC

Цель: читать и задавать календарное время с помощью встроенного RTC.

Время: 15 минут

Начните с: example/rt_device/rtc

time_t now = time(RT_NULL);
struct tm *tm_now = localtime(&now);
rt_kprintf("%04d-%02d-%02d %02d:%02d:%02d\n",
           tm_now->tm_year + 1900, tm_now->tm_mon + 1, tm_now->tm_mday,
           tm_now->tm_hour, tm_now->tm_min, tm_now->tm_sec);
  1. Один раз задайте время RTC поддерживаемым способом, например командой оболочки.
  2. Периодически выводите текущее время.
  3. Выключите и снова включите питание платы и проверьте, сохранилось ли время.
  4. Если время не сохраняется, проверьте схему резервного питания платы, прежде чем менять прошивку.

При проверке сохранения не сбрасывайте RTC безусловно при каждой загрузке: это скроет, сохранилось ли предыдущее значение времени.

Критерий успеха: при включённом питании время идёт правильно, а поведение сохранения соответствует аппаратной части платы.

Если не работает: проверьте, включён ли компонент RTC, источник тактирования, резервное питание и не сбрасывает ли плата состояние RTC при загрузке.

Что вы узнали: о стандартном API времени C поверх устройства RTC в RT-Thread, а также о том, как поведение прошивки зависит от аппаратной схемы.

Мини-проект: сбор данных с датчика по нажатию кнопки

После завершения шести коротких упражнений объедините их в небольшой проект:

  1. Включайте мигание светодиода при загрузке.
  2. Используйте кнопку, чтобы запускать и останавливать измерения.
  3. Пока измерения активны, раз в секунду считывайте одно значение ADC.
  4. Выводите показания с отметкой времени через FinSH.
  5. Для индикации активного сбора данных меняйте яркость светодиода с помощью PWM или тон зуммера.

Критерий готовности: проект работает несколько минут без повторных срабатываний кнопки, бесконтрольного потока сообщений или неожиданных сбросов.

Чек-лист проверки первых периферийных устройств

  • Имя платы, последовательный порт и процесс прошивки проверены.
  • Выход GPIO работает на реальном светодиоде или измеряемом выводе.
  • Вход GPIO работает с подтверждённой полярностью и защитой от дребезга.
  • Оболочка FinSH доступна; команды list_thread и list_device работают.
  • Показания ADC правдоподобны и пересчитаны в инженерные единицы.
  • Период и коэффициент заполнения PWM дают ожидаемый физический результат.
  • Поведение RTC понятно, включая ограничения сохранения времени.

Что делать дальше

Когда эти упражнения станут привычными, переходите к разделу «Объединение подсистем». Следующий этап сочетает периферию с промежуточным ПО (middleware): датчиками I2C, LVGL, BLE, воспроизведением аудио, хранением данных и целенаправленной проверкой совместной работы.

Последнее обновление: