Skip to content

sumertsvo/Stm32_Test_Example

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

24 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Пример проекта под МК STM32F405 на C++ с использованием библиотеки m.

  1. Arm GNU Toolchain 13.3.Rel1 + Vscode + Embedded IDE plugin.
  2. Форматирование кода .clang-format Google.
  3. Стиль кода в основном опирается на "Руководство Google по стилю в C++" (Google C++ Style Guide: https://google.github.io/styleguide/cppguide.html).
  4. Не используются: макросы, выделение памяти, RTTI, исключения.
  5. Конфигурация периферии МК - полность из CubeMX.
  6. main.cpp - основной, main.c исключён из проекта (генерируется автоматически из CubeMX).
  7. Для упрощения RTOS не используется.

Базовые принципы:

  1. Для уменьшения связности кода и абстракции от конкретного МК используются интерфейсы.
  2. Вместо наследования предпочитается композиция (за исключением интерфейсов).
  3. Основная логика работы устройства реализуется на конечных автоматах.
  4. Логические блоки строятся на неблокирующих операциях, без активного ожидания (по возможности). Это позволяет обрабатывать их как совместно в бесконечном цикле или прерывании, так и отдельно с применением RTOS.
  5. Для всех операций, которые используют активное ожидание необходимо добавлять остановку по таймауту исполнения.
  6. Вместо выделения памяти в куче используется std::array<uint8_t> в качестве буфера на стеке с дальнейшей передачей через std::span<uint8_t> в соответствующий класс. В редких случаях для стандартных контейнеров используется аллокатор на стеке short_alloc.h от Howard Hinnant.

Краткое описание:

  1. Все задержки, таймауты и т.д. базируются на основе классов TimeUs, TimeMs, которые в свою очередь являются реализациями интерфейсов m::ifc::ITime<Us<uint32_t>> и m::ifc::ITime<Ms<uint32_t>> и предоставлют доступ к отсчёту времени с момента запуска МК в микросекундах и миллисекундах. Основаны на таймере TIM5 и SysTick.
  2. Для работы с GPIO используется класс PinWrapper, наследуемый от m::ifc::mcu::IPin. Предоставляет базовый функции read(),wirte(),toggle().
  3. Для измерения температуры используется класс Adc_1 наследуемый от m::ifc::mcu::IAdcDmaCircularReader<uint16_t> и класс Ntc. Adc_1 реализует запуск АЦП в цикличном DMA режиме с прерываниями при заполнении половины и полного буфера. По прерыванию в пользовательских коллбэках идёт фильтрация данных. Класс Ntc наследуется от m::ifc::ITempSense<std::optional<Celsius<float>>> и m::ifc::ITempSenseError и реализует пересчёт измеренного напряжения в сопротивление ntc термистора, а далее в температуру в градусах Цельсия.
  4. Библиотечный класс m::ic::PY25Q128HA, наследуемый от интерфейса m::ifc::IMemory, реализует функции чтения\записи в память на основе микросхемы PY25Q128HA. Сам класс оперирует интерфейсом синхронного ввода вывода m::ifc::IIO_Sync<Ms<type>>, в данной реализации это класс Spi_1, реализующий блокирующую передачу данных по SPI с применением DMA.
  5. Приём и обработка команд по Modbus RTU реализуется в библиотечном классе m::ModbusRtuProtocol<Us<uint32_t>>, при приёме соответствующих команды вызываются пользовательские коллбэки для их обработки. Приёмопередача пакетов осуществляется в классах Usart_5 & Usart_4, наследуемых от m::ifc::IIO_Async и реализующих асинхронный приём и передачу байт c использованием DMA. Для разделение байт в шине на пакеты используется класс m::DataLinkAsync<Us<uint32_t>>, наследуемый от интерфейса m::ifc::IDataLink и реализующий отделение пакетов на основе временных задержек.
  6. Вместо RTOS используется прерывание с частотой 1кГц, в котором вызывается обработка команд Modbus RTU. Для этого используется класс Tim_7_1kHz наследуемый от m::ifc::mcu::IIt и реализующий вызов пользовательского коллбэка при срабатывании прерывания.
  7. Конечный автомат и некоторая другая логика работают в основном бесконечном цикле.
  8. Для логирования по USART используется библиотечный класс m::IIO_AsyncLog, работающий с классом Usart_1.
  9. Для определения мест и последовательности возникновения ошибок используется библиотечный класс m::SimpleErrorTracer<uint16_t, 100>.

Тестовое задание:

  1. Для управления драйвером шагового двигателем необходимо сгенерировать STEP сигнал, который представляет из себя меандр с изменяющейся частотой и строго определённым количеством периодов.
  2. Задача написать интерфейс и реализацию класса для выполнения этой задачи.
struct Packet{
uint8_t n;
uint16_t freq; // 100Hz - 20'000 Hz
};

У интерфейса должны быть методы для установки сигнала в виде std::span<Packet>, запуска генерации, остановки генерации, определения текущего состояния (идёт генерация или нет). Также должен быть метод возвращающий максимальный поддерживаемый размер генерируемого сигнала. Для упрощения структура сигнала представляет массив с количеством импульсов и их частотой.

  1. Максимальный размер массива сигнала можно ограничить 10 элементами.
  2. Между пачками меандров разной частоты не должно быть дополнительных задержек.
  3. Сгенерировать весь сигнал целиком необходимо полностью аппаратно, без участия CPU на выходе PA8 МК.
  4. При запуске генератора с такими параметрами:
std::array<Packet,3> signal{{{2, 1000},{3, 500},{2, 2000}}};
generator.add(signal);
generator.start();

На выходе должен получиться меандр с общим количеством импульсов 7 штук, где сперва идут 2 с частотой 1000 Гц, затем 3 с частотой 500 Гц и 2 с частотой 2000 Гц.

  1. Если невозможно сгенерировать определённую частоту, то берётся ближайшая поддерживаемая.

About

interesting test case

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • C 99.2%
  • Other 0.8%