Top.Mail.Ru
Уведомления
Очистить все

[Закреплено] Сообщество | Библиотеки для STM32 на C++

Страница 2 / 3
(@eduard)
Level 5 Moderator

Хочу посоветоваться

изображение

Это список библиотек, зависящих от ядра. Есть полностью готовые, есть готовые частично.

изображение

Это список библиотек не зависимых от ядра.
В какую сторону продолжать дальше двигаться?

Что нужнее?


ОтветитьЦитата
Создатель темы Размещено : 27.02.2022 20:34
Aveal
(@aveal)
Top level Admin

Я думаю из периферии в первую очередь - таймер, USART, SPI. Из внешних устройств - дисплеи.


ОтветитьЦитата
Размещено : 28.02.2022 10:24
(@eduard)
Level 5 Moderator

Сегодня кое как допилил симбиоз I2C и EEPROM AT24Cxx.

Есть такие функции

    // Чтение/запись массива. Формат: Адрес в EEPROM, Буфер, Количество байт
    int16_t Read(uint16_t MemAddress, uint8_t* DataBuff, uint16_t Size);        // Чтение массива
    int16_t Write(uint16_t MemAddress, uint8_t* DataBuff, uint16_t Size);       // Запись массива

    // Чтение/запись одного байта. Формат: Адрес в EEPROM
    int16_t Read(uint16_t MemAddress);                                          // Чтение одного байта
    int16_t Write(uint16_t MemAddress, uint8_t Data);                           // Запись одного байта

Что ещё туда добавлять?

Пока меня прёт.

 


ОтветитьЦитата
Создатель темы Размещено : 01.03.2022 20:38
Aveal
(@aveal)
Top level Admin

Тест

Проверяем уведомления на почту при новом ответе в теме.


ОтветитьЦитата
Размещено : 03.03.2022 11:26
(@eduard)
Level 5 Moderator

@aveal Тест прошёл.

Доделал сегодня датчики BME280, BMP280. По I2C.

Но выложу позже. Сейчас готовлю статью по UART, так как очень удобно отлаживать программу.

 


ОтветитьЦитата
Создатель темы Размещено : 03.03.2022 18:40
Aveal
(@aveal)
Top level Admin

@eduard Вот UART - это просто отлично, и датчики популярные 👍 


ОтветитьЦитата
Размещено : 03.03.2022 18:46
ll47
 ll47
(@ll47)
Level 1

Я провел сравнение по объему занимаемой памяти, что-то результат оказался не так внушителен, как я ожидал... Итак, первый проект - из этой статьи - вообще без изменений:

CPP

И я создал тестовый проект на HAL с инициализацией USART1 и отправкой 32 тестовых байт:

HAL

8.4 КБ флеша против 9.49 КБ.


ОтветитьЦитата
Размещено : 10.03.2022 13:58
(@eduard)
Level 5 Moderator

Вся идея не уменьшении кода, а удобстве пользования.

На МК с малым объёмом памяти - 16 и меньше, HAL забивает вообще 60%.
Здесь можно выборочно взять нужные библиотеки.

Кроме этого. Этот размер занимает вся откомпилированная библиотека. И уже работа с ней отъедает мизер памяти.


ОтветитьЦитата
Создатель темы Размещено : 10.03.2022 18:46
ll47
 ll47
(@ll47)
Level 1
От: @eduard

Вся идея не уменьшении кода, а удобстве пользования.

На МК с малым объёмом памяти - 16 и меньше, HAL забивает вообще 60%.
Здесь можно выборочно взять нужные библиотеки.

Кроме этого. Этот размер занимает вся откомпилированная библиотека. И уже работа с ней отъедает мизер памяти.

Да, понимаю. Также быстродействие будет намного выше я думаю, потому что HAL медленная довольно, даже в некоторых проектах были из-за этого трудности.


ОтветитьЦитата
Размещено : 11.03.2022 11:27
(@eduard)
Level 5 Moderator
От: @ll47

потому что HAL медленная довольно, даже в некоторых проектах были из-за этого трудности.

У меня знакомец пишет на HAL.
Когда писал трёхфазный двигатель на таймере, инициализацию делал на HAL. А всё остальное на CMSIS. Почему то на HAL не хотело работать хоть тресни. А там всего то таблица синусов да перегон её в таймер через DMA.

Я то же начинал писать на HAL. Один раз столкнулся с тем, что HAL ни в какую не хотел запускать таймер в одноимпульсном режиме. Один раз запустил и больше не захотел. В чём дело, так и не нашёл.

А насчёт того, что Вы говорили, что переводить старые проекты на новый тип программирования. Зачем. У меня запущен проект на чистом HAL. Потом появились проекты где я HAL обернул в классы. Потом начал куски HAL переводить на прямую работу с регистрами. А потом просто начал писать библиотеки и постепенно в каждом следующем проекте доля написанных библиотек увеличивалась.

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


ОтветитьЦитата
Создатель темы Размещено : 11.03.2022 17:27
(@boris-d)
New member

Случайно наткнулся на этот цикл статей, автору респект громадный, делает свои библиотеки, делится ими, так еще и описывает в статьях.


ОтветитьЦитата
Размещено : 23.03.2022 10:11
(@eduard)
Level 5 Moderator

Всем, кто пользуется библиотеками, так как я начал выкладывать библиотеки без их описаний для разных ядер.

У вас могут возникнуть проблемы с компиляцией. Например есть ядро, для которого не написан SPI, а в библиотеке лежит драйвер дисплея работающего по SPI, компилятор будет ругаться.

Вот здесь ругается на драйвер дисплея:

изображение

Заметьте, что крестик стоит напротив *.h и *.cpp, чаще всего он стоит напротив *.h файла.

Что бы этого не происходило, необходимо исключить библиотеку из компиляции.

Делается это таким образом:

Правой кнопкой мыши щёлкаем на соответствующем *.cpp файле и выбираем

изображение

Ставим галочки и нажимаем ОК. Больше он нам мешать не будет. Так делается на всех файлах, на которые будет ругаться.

изображение

Есть нюансик с SPI. Драйвер зависимый от ядра лежит в каталоге драйверов. "Софтварный" SPI лежит в каталоге библиотек. Вместе они компилиться не будут. Так как они одинаковы по структуре и переменным. Только часть отвечающая за передачу разная. Поэтому нужно исключить из компиляции именно тот, который не собираетесь использовать. Позже могут ещё появиться такие дубликаты. С ними придётся поступать так же.


ОтветитьЦитата
Создатель темы Размещено : 10.09.2022 13:57
(@yumayuma)
Level 1

От любопытства посмотрел либлиотеки. Мдяяяя... От C++ тут кроме точек :: ничего и нету 🙂 Афтару - глубжее и четчее изучать изык С++! Конкретно - изучить КЛАССЫ и ШАБЛОНЫ. Потому как единственный вменяемый способ описания работы с периферией микроконтроллера, такой как GPIO, SPI, I2C и проч - шаблонные классы со статическими методами. На примере GPIO конечный результат должен выглядеть так:

using pa0 = GpioA::pin0;
using pb5 = GpioB::pin5;
pa0::Set();
if(pa0 == pa0::State::SET) pb5::Reset();

GpioA::Configure<pin0_msk | pin2_msk>::AsOutputPins<OutType::PP, Speed::MED>();

на примере SPI - так:

Spi1::Configure<
    Role::MASTER,
    FrameSize::_8bit,
    Endian::MSB,
    Duplex::FULL,
    ClockDiv::_8,
    ClockMode::M0,
    SS_Input::SW_NOSEL,
    SS_Out::DISABLE>();

Spi1::Enable();
Spi1::Send(0x45);

Spi1::Dma::Tx::Enable();

while(Spi1::Flags::IsTXE());
while(Spi1::Flags::IsBusy());
Spi1::Disable();

То есть, благодаря шаблонам (template), не требуется заводить переменные для хранения конфигурации. 

При этом, класс тоже должен быть шаблонным:

template<Letter Name> Gpio; 
template<int N> Spi;

то есть, конкретный модуль GPIOA, GPIOB или SPI1, SPI2 и тд вычисляется на этапе компиляции посредством constexpr:

template<int N> Spi {
public:

private:
    static constexpr SPI_Typedef* GetBase();
    static constexpr SPI_Typedef* spi =  GetBase();
};

А чтобы сократить запись, используем using:

#ifdef GPIOA
  using GpioA = Gpio<Letter::A>;
#endif
#ifdef GPIOB
  using GpioB = Gpio<Letter::B>;
#endif

#ifdef SPI1
  using Spi1 = Spi<1>;
#endif
#ifdef SPI2
  using Spi2 = Spi<2>;
#endif

#ifdef здесь особенно актуален для Gpio, поскольку в разных МК разное количество доступных портов, а всего по максимуму их - от GPIOA до GPIOK. И если в заголовочнике МК определен например GPIOK, будет доступен этот вариант, а если нет - то недоступен. Чтобы не переписывать каждый раз список портов. Аналогично можно поступать и с остальной периферией.

Ну и для Gpio ради типобезопасности введен 

enum class Letter {A, B, C, D, ... и так далее

Аналогично поступаем и с остальной периферией.

Например, для осцилляторов:

class Hse {
public:
    enum class Source {XTAL = 0, GEN = RCC_CR_HSEBYP};
    template<Source Source> static void Enable();
    static void Disable();
    static bool IsReady();
    struct Irq {
        static void Enable();
 .... и так далее ....

применение:

Hse::Enable<Hse::Source::XTAL>();
while(Hse::IsReady != true);

В общем, вектор движения ясен? Вот это уже будет C++. А то, что здесь в библиотеке написано - это обычный "Си с классами".


ОтветитьЦитата
Размещено : 14.11.2025 16:58
(@yumayuma)
Level 1

Продолжая тему...

Посмотрел несколько файлов топикстартера. Ну, всё по-классике - типовая ошибка в смешивании функционала. Так называемый "побочный эффект функции". То есть, функция (в С++ - метод) называется I2C::Init(). Её основное назначение - настройка модуля I2C. А у автора в ней прописана и настройка пинов, и подключение тактирования модуля. Это - и есть "побочный эффект функции". То есть, по названию I2C мы понимаем, что работаем только с I2C. Но по факту там работа и с GPIO, и с RCC. Особенно лишнее здесь GPIO. Просто потому, что I2C, как и многие другие модули, не фиксированы жестко на конкретных пинах, они могут быть перенесены. Следовательно, привязываться к пинам в функции настройки модуля - совершенно излишне. 
Включение тактирования модуля в I2C::Init() хоть и не сильно мешается, но тоже побочный эффект. Оставить можно, но это будет не совсем чисто, так сказать. Потому как например SPI, и особенно DMA можно перенастраивать в течение работы программы. И повторное включение тактирования будет лишним. Особенно это заметно в DMA.

 

 


ОтветитьЦитата
Размещено : 15.11.2025 19:06
(@eduard)
Level 5 Moderator

@yumayuma Спасибо за подсказки.

Я прекрасно понимаю, что как программист я не очень. Всю жизнь писал на ассемблере.

Нужда заставила перейти на С++, когда перешёл на STM.

И я оказался одним из первых, кто занялся библиотеками для него. Все используют HAL и говорят, что С++ не нужен.

Я начал писать всё это, когда не совсем понимал, как лучше сделать. За пример брал Ардуиновские библиотеки, которые не могут быть эталоном.

Я уже начал переписывать их, правда сюда не выкладывал. Как Вы и говорите, я начал отделять "Мух от мёда".

Все, понимающие больше меня почему то не хотят с этим связываться.


ОтветитьЦитата
Создатель темы Размещено : 16.11.2025 10:53
Страница 2 / 3
Поделиться:
Обзор конфиденциальности

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