Кто любит RISC в жизни, заходим, не стесняемся.
Ответить

Re: Stm32 с чего начать изучение...

Вт фев 04, 2020 01:38:58

Не могу не высказаться про "отладку" применительно к 32 разрядным микроконтроллерам. Особенно после строк Alex-lab "Постоянно работаю с таймерами на 103ем процессоре для управления 8кВт преобразователем." К примеру, некто акцентирует внимание, что отладка может пригодиться для случая с HardFault, а иначе, говорит автор, пришлось бы много времени потратить на анализ кода. А с отладкой, при ощущении зависания???, просто стопорим процик и, смотрим что находимся в HardFault. Какой неудачный пример с точки зрения ленности программеров!!! Мои пояснения. Обычно в HardFault, по умолчанию, стоит заглушка в виде зацикливания. Там мы и оказываемся применив "стоп кран" отладчика. А теперь внимание, что стоило эту примитивную заглушку расширить выводом сообщения по какому либо серийному фейсу? И, хард отладка становиться ненужной. Почему я с хард отладкой больше не дружу? А вот почему. 1. Накопил опыт, чтобы не попадать в такие простенькие ловушки 2. Специфика ПО жесткого реального времени (степень жесткости десяток другой микросекунд) не дает возможности исследовать поведение ПО отладчиком, поскольку у меня речь идет не о примитивных ситуациях в виде порчи памяти или нарушении элементарной логики, а о фазовом дребезге протоколов порядка десятков микросекунд. Как может хард отладчик помочь выявить причину повышенного фазового дребезга при вызове прерывания? при том, что нельзя стопорить ПО на время больше нескольких микросекунд, иначе разрушиться логика, к примеру, скоростного регулятора с итерацией порядка десятков микросекунд. И, я совершенствую "заглушки", стараясь в каждую из них вставить соответствующее сообщение по какому либо последовательному интерфейсу и, максимально полно охватить все возможные "заглушки" ничего не забыв.

Добавлено after 12 minutes 15 seconds:
Очень разочаровывает поведение даже "взрослых" систем (хотя Windows радует что ситуация постепенно исправляется) когда, очередная "заглушка" выдает сообщение типа "Ой, о Мы Вас здесь не ждали" и, это при гигантском объеме кода????, тяжеловесных фреймворках и наличии прочих свистелок и перделок. И ("вновь продолжается бой, и сердцу тревожно в груди..."), продолжается процесс поиска "серебряной пули" вместо кропотливого затыкания очевидных дыр...

Re: Stm32 с чего начать изучение...

Вт фев 04, 2020 03:03:08

Lum1noFor писал(а):при досчитывании таймером до значения регистра ARR таймер сбрасывается и генерируется событие, так?


Как вариант, для одностороннего счета вверх.
Но это не так при двухстороннем счете. А так же при ненулевом значении регистра повторения RСR. В этом случае событие генерируется только после каждого i-ого достижения значения ARR.
Если проблема с языком, есть более или менее внятное описание регистров STM32F100 серии на русском языке в этом документе: https://yadi.sk/i/7lHDfGRvBwZOkg

Добавлено after 6 minutes 58 seconds:
astrahard, Я вас поддерживаю. Отладку вообще не использую. Считаю её не нужной в своих проектах, особенно с учетом потактовой подстройки ШИМ с регулятором, где все впритык по времени. Если нужно что-то посмотреть либо вывожу на пин, либо в порт, либо на дисплей.
По моему мнению отладчик развращает начинающих, является медвежьей услугой в сравнительно простых проектах. Позволяет не разбираться в деталях, а по сути перебором подобрать значения или обнаружить косяк. Я понимаю, что могут быть очень сложные проекты, где без нее никак. Но это редкость.

Re: Stm32 с чего начать изучение...

Вт фев 04, 2020 07:30:36

Спасибо за разъяснение!

Отладка в приложениях реального времени вообще вещь бесполезная - год назад делал систему, которая должна контролировать поступающие с генератора импульсы - контролировать их длительность, скважность, частоту. Параметры сигнала такие: длительность импульса - от 200 наносекунд до 2 мкс, скважность от 100. Причём в ТЗ было сказано, что нужно проверять все параметры каждого импульса, и выдавать на выход точно такой же импульс, если параметры не выходят за пределы ТЗ. Самое сложное - это просчитать, как система поведёт себя при бесконечном выполнении «по кругу». И здесь отладчик вообще никак не поможет потому, что нужна синхронизация с входным сигналом.

Re: Stm32 с чего начать изучение...

Вт фев 04, 2020 09:21:55

Вот еще интересная мысль, которая меня все чаще посещает. Нас на каждом шагу призывают придерживаться стандартов в написании кода на С, обычно запугивая сложностью портирования кода в противном случае. И, вроде это разумное предостережение но, сами вендоры постоянно занимаются рефакторингом стандартов, уже не говоря о том, что каждый вендор в порыве конкурентной борьбы имеет собственное представление о стандартах. Их, этих стандартов, уже так много, что теряется сама философия этого термина. А раз философия термина уже почти полностью потеряна, то я не вижу причины и пользователям продолжать придерживаться "Стандартов" и критиковать друг друга за это. Так усе-же, особенно для начинающего, стоит-ли стремиться стандартизировать свой код, в слабой надежде на легкое портирование куда нибудь в будущем? ИЛИ, все-же, постоянный рефакторинг предпочтительнее, в конце концов, так себя ведут большинство вендоров. Рефакторинг уже, по крайней мере в мире микроконтроллеров, теперь мейнстрим, а не надежда на легкое портирование. Видимо еще рано ориентироваться в сфере микроконтроллеров на сложившуюся практику из мира "Взрослых систем", да и там это портирование немного уже достало, но там рефакторинг это так дорого, что его применяют уже когда ничего не помогает, и пользователи толпами бегут к конкурентам.

Re: Stm32 с чего начать изучение...

Вт фев 04, 2020 09:36:52

astrahard, какое отношение стандарт языка имеет к портированию?
Подскажу: абсолютно никакого!

Re: Stm32 с чего начать изучение...

Вт фев 04, 2020 09:49:52

Я не о стандарте языка, а о стандартах написания идентификаторов и управления ими. Кроме того, что касается портирования. То как Вы заметили, я пытался осудить это, противопоставив рефакторингу. Притягивание за уши методов из мира "взрослых" систем, в сферу микроконтроллеров, вызывает отток энтузиастов и, вообще, на мой взгляд, вредно.

Добавлено after 10 minutes 30 seconds:
То-есть, основной рефрен сказанного, это беспокойство о том, что энтузиасты пасуют перед кажущейся сложностью новых чипов. И мне хочется призвать эту братию, пишите как хотите, главное пишите, для новых чипов разумеется, да хоть на чем и хоть как. Просто, достало, постоянные критические вбросы, что так "плохо" и так "плохо", что нужно только "Вот так". Берите пример с Вендоров, кои никогда, Них---я не придерживаются даже своих вчерашних рекомендаций, а находятся в состоянии постоянного поиска.

Re: Stm32 с чего начать изучение...

Вт фев 04, 2020 10:29:46

Вот "хоть как" не надо. Насмотрелся я на китайский говнокод, спасибо!
А другой пример - SPL и калокуб. Тоже творчество великих рукожопов, но еще и навязываемое как образец для подражания!

Главное правило, которым следует руководствоваться при написании кода, не "тяп-ляп — и в продакшн", а "мне это, возможно, через 10 лет придется поддерживать"! Т.е. как можно больше комментариев (хоть на рунглише, лишь бы не на "национальных языках"), как можно меньше "магических чисел"... Ну и копипасту использовать крайне осторожно, чтобы не было, как у говнокодеров в инициализации дисплеев (когда вместо вызова команды с разными аргументами в цикле, беря аргументы из массива, тупо копируют 100500 раз вызов команды, заменяя аргумент).

Вот посмотрите на код VladislavS: если бы это был С, а не С++, я вообще бы назвал это образцом, достойным подражания!

Re: Stm32 с чего начать изучение...

Вт фев 04, 2020 10:38:14

Прямо бунт на корабле какой-то сегодня :)

Re: Stm32 с чего начать изучение...

Вт фев 04, 2020 10:43:43

Это Вы. Инициировали, это Вас я решил поддержать. Поменьше слов "Говнокод" Китайцы, только не на национальном языке. Это все отсутствие уважения (толерантности). ??? тупо копируют 100500 раз вызов команды, а Ви думаете в этом нет смысла? А премию получить за то что код быстрее на х%. Ведь никто не ругается на размер теперь. Кстати, с точки зрения теории, это классический inline. А вовсе не говнокод, как Вам показалось, просто Вы не толерантны.

P.S. Именно Вендоры придумали понятие ИНКАПСУЛЯЦИЯ, что аналогично детскому "А я в домике..." и, страхует от критики. И еще, переношу бунтовской пост из другой темы, неизвестный автор "Велосипеды - это не всегда плохо. А свой велосипед - это свой велосипед )) Его всегда можно легко доработать и сделать с преферансом и куртизанками ))"

Мой ответ "А бываю-ли ВЕЛОСИПЕДЫ или это миф? На мой скромный взгляд, процесс вызревания стандарта на века, это редкий уникальный случай, в основном за ВЕЛОСИПЕД выдают свой собственный СУБЪЕКТИВНЫЙ (стандарт на века) взгляд на реальность и, надо сказать, что большинство, научилось делать это столь настойчиво, что нет нет да поверишь, вот он ВЕЛОСИПЕД (стандарт на века), ан нет опять ложный опенок от уважаемого вендора. Так что, прочь стеснительность, оправдательный тон и прочую шелуху, как говорил один инструктор по вождению автомобиля, "если нарушаете, нарушайте уверенно...""

Re: Stm32 с чего начать изучение...

Вт фев 04, 2020 11:40:56

Толерастия до добра никогда не доводит. Если что, полная толерантность организма называется ВИЧ (правда, полная нетолерантность - это анафилактический шок, что тоже не очень)!
А насчет кода - сравните на досуге разницу выполнения 100500 команд в цикле или же последовательно. Накладных расходов будет минимум, зато сколько флеша попусту будет растрачено... Я уж не говорю о том, что второй вариант еще и выглядит уродливо.

Re: Stm32 с чего начать изучение...

Вт фев 04, 2020 12:51:26

Я согласен, но просто напомнил, как Китайцам можно оправдаться. А первое предложение мне приглянулось, это правда.

Добавлено after 1 hour 6 minutes 7 seconds:
Теперь я начинаю понимать почему такое неприятие CPP который только был обозначен VladislavS. Мне кажется, что только инкапсуляция прижилась на всю катушку ибо толерастия (Я в домике.), ну еще наследование живет не шатко ни валко, что касается полиморфизма, ребенок видимо скоропостижно скончался в младенчестве.

Re: Stm32 с чего начать изучение...

Вт фев 04, 2020 14:07:06

astrahard, вы почитайте на досуге стандарт С++17. Туда столько говна засунули, аж жутко становится!!!
Вот если бы С++ оставался той надстройкой над С, что придумал Страуструп, еще ладно. Но все эти шаблоны и т.п. просто взрывают мой мозг.

Re: Stm32 с чего начать изучение...

Вт фев 04, 2020 14:21:51

Поддержу бунт. Работать с RM это очень хорошо! Но делать это надо один раз, причём очень основательно, чтобы потом не лазить в него совсем. Вот примерчик моей билиотеки GPIO.
Изображение

Всё что справа от красной линии делается на основании RM для конкретного(ых) чипов. Там учтены все особенности их поведения вместе с Errata. Сейчас у меня таких модулей 4: для STM32, STM32F1, один миландровский чип, виртуальный порт.
Всё что слева от красной черты - уровень, на котором я ничего не знаю про чип на котором работаю, а просто программирую прикладные задачи.

То же самое и для других модулей. Кто смотрел мою реализацию USB, видели что там три уровня: "чип" -> USB Device -> USB Class. Я запросто могу заменить уровень "чип" и остальной код даже не заметит, как переехал на другое семейство микроконтроллеров.

В принципе, это то же что делают всякие HAL-ы, но на другом уровне. Они ограничили себя возможностями С и это ведёт к большим накладным расходам. Уходя в С++ мы с одной стороны попадаем в сумеречную зону, а с другой получаем удивительную эффективность кода. Не забываем, что мы эмбеддеры и результат нашей работы это максимальная скорость, минимальный размер и отсутствие ошибок.

Под спойлером пример реализаций того что справа от красной черты. Слабонервным не смотреть.
СпойлерЯ предупреждал :shock:
Код:
#pragma once

//========================
// STM32F0, STM32F3, STM32F4, STM32L0  GPIO Port
//========================

#include "../../PinModeList.h"

namespace STM32Fx_GPIO
{

using namespace PIN_MODE_LIST;

template<STM32Fx_PinMode Mode>
_static_always_inline_ constexpr bool isAnalog() { return Mode == STM32Fx_PinMode::Analog; }

template<STM32Fx_PinMode Mode>
_static_always_inline_ constexpr bool isAfMode() { return (uint32_t(Mode) & 3) == 2; }

template<STM32Fx_PinMode Mode>
_static_always_inline_ constexpr bool isOpenDrain() { return uint32_t(Mode) & 0x10; }

template<STM32Fx_PinMode Mode>
_static_always_inline_ constexpr bool isInputMode()
{
  if constexpr ( Mode == STM32Fx_PinMode::Input_Floating || Mode == STM32Fx_PinMode::Input_PullUp ||
                 Mode == STM32Fx_PinMode::Input_PullDown || Mode == STM32Fx_PinMode::Analog )
    return true;
  else
    return false;
}

template<STM32Fx_PinMode Mode, uint32_t AF>
_static_always_inline_ constexpr bool isOutputStateDefined()
{
  return (isAfMode<Mode>() || isInputMode<Mode>()) ? false : (AF<2) ? true : false;
}

template<uint32_t GpioID, uint32_t PinsMask, typename TPM = STM32Fx_MODE::NotDefined,
         uint32_t pwr_moder=0, uint32_t pwr_ospeedr=0, uint32_t pwr_pupdr=0>
class TSTM32Fx_GPIO : public GpioTemplate<GpioID, 16, PinsMask, TPM>
{
  static_assert(PinsMask<=makeMask(16), "MAX port width is 16 bits");
private:
  _static_always_inline_ auto base() { return (GPIO_TypeDef*)GpioID; }
  using pVU8 = volatile uint8_t*;
  using pVU16 = volatile uint16_t*;
  using pVU32 = volatile uint32_t*;
public:
  static constexpr uint32_t pwrModer = pwr_moder;
  static constexpr uint32_t pwrOspeedr = pwr_ospeedr;
  static constexpr uint32_t pwrPupdr = pwr_pupdr;

  constexpr _always_inline_ TSTM32Fx_GPIO() = default;

  template<uint32_t NewPinsMask, uint32_t NewGpioID=GpioID, typename NewTPM = TPM>
  _static_always_inline_ constexpr auto clone() { return TypeBox<TSTM32Fx_GPIO<NewGpioID,NewPinsMask,NewTPM>>{}; }

  _always_inline_ TSTM32Fx_GPIO& operator=(const TSTM32Fx_GPIO& gpio)
  {
    write(gpio.read());
    return *this;
  }

  _always_inline_ TSTM32Fx_GPIO& operator=(uint32_t value)
  {
    write(value);
    return *this;
  }

  _always_inline_ operator uint32_t() const { return read(); }

  template<uint32_t PM=PinsMask>
  _static_always_inline_ void write(uint32_t data)  // Тут вроде uint16_t надо
  {
    if constexpr (PM==0) return;
    if constexpr (PM == 0xFFFF)
      base()->ODR = data;
    else if constexpr (PM == 0x00FF)
      *pVU8(&base()->ODR) = data;
    else if constexpr (PM == 0xFF00)
      *(pVU8(&base()->ODR) + 1) = data >> 8;
    else
      base()->BSRR = (PM << 16) | (data & PM);
  }

  template<uint32_t PM=PinsMask, typename... SortedPins> // SortedPins надо для Dummy
  _static_always_inline_ uint32_t read(TypeList<SortedPins...> pins = {})
  {
    return readReg16<PM>(&base()->IDR);
  }

  template<uint32_t PM=PinsMask>
  _static_always_inline_ uint32_t readOutput()
  {
    return readReg16<PM>(&base()->ODR);
  }

  template<uint32_t PM=PinsMask>
  _static_always_inline_ void set()
  {
    if constexpr((PM & 0xFF)==0)
      *(pVU8(&base()->BSRR)+1) = PM>>8;
    else
      base()->BSRR = PM;
  }

  template<uint32_t PM=PinsMask>
  _static_always_inline_ void clear()
  {
    if constexpr (PM == 0xFFFF)
      base()->ODR = 0;
    else if constexpr (PM == 0x00FF)
      *pVU8(&base()->ODR) = 0;
    else if constexpr (PM == 0xFF00)
      *(pVU8(&base()->ODR) + 1) = 0;
    else if constexpr((PM & 0xFF)==0)
      *(pVU8(&base()->BSRR)+3) = PM>>8;
    else
      *(pVU16(&base()->BSRR)+1) = PM;
  }

  template<uint32_t PM=PinsMask>
  _static_always_inline_ void toggle()
  {
    if constexpr (PM == 0xFFFF)
      base()->ODR = ~base()->ODR;
    if constexpr (PM == 0x00FF)
      *pVU8(&base()->ODR) = ~*pVU8(&base()->ODR);
    else if constexpr (PM == 0xFF00)
      *(pVU8(&base()->ODR) + 1) = ~*(pVU8(&base()->ODR) + 1);
    else
      base()->BSRR = (PM << 16) | (~base()->ODR & PM);
  }

  template<uint32_t PM=PinsMask>
  _static_always_inline_ void lock()
  {
    base()->LCKR = PM | GPIO_LCKR_LCKK;
    base()->LCKR = PM;
    base()->LCKR = PM | GPIO_LCKR_LCKK;
  }

  // Same mode for all pins set
  _static_always_inline_ void mode()
  {
    static constexpr auto mode_list = generate<countSetBits(PinsMask),TPM>();
    mode_<false,PinsMask>(mode_list);
  }
   
  // Same mode for all pins set
  template<typename T, typename = std::enable_if_t<IsPinMode<T>() > >
  _static_always_inline_ void mode()
  {
    static constexpr auto mode_list = generate<countSetBits(PinsMask),T>();
    mode_<false,PinsMask>(mode_list);
  }
 
  template<typename ML, typename = std::enable_if_t<IsPinModeList<ML>()>>
  _static_always_inline_ void modes()
  {
    static_assert(countSetBits(PinsMask) == ML::Size, "ModeList and Port size is not Equal!");
    mode_<false,PinsMask>(ML::modes_);
  }

  template<bool UsePwrCfg=false, uint32_t PM=PinsMask, typename... ML>
  _static_always_inline_ void modes(TypeList<ML...> modes)
  {
    static_assert(countSetBits(PM) == sizeof...(ML), "ModeList and Port size is not Equal!");
    mode_<UsePwrCfg,PM>(modes);
  }

private:
  enum class GpioRegs { Ospeedr = 1, Otyper = 2, Pupdr = 4, AfrL = 8, AfrH = 16, State = 32 };

  template<uint32_t dmask>
  _static_always_inline_ void writeReg32(pVU32 reg, uint32_t value)
  {
    if constexpr (dmask==0) return;
    if constexpr (dmask == 0xFFFF'FFFF)
      *reg = value;
    else if constexpr (dmask == 0x0000'FFFF)
      *pVU16(reg) = value;
    else if constexpr (dmask == 0xFFFF'0000)
      *(pVU16(reg) + 1) = value >> 16;
    else if constexpr (dmask == 0x0000'00FF)
      *pVU8(reg) = value;
    else if constexpr (dmask == 0x0000'FF00)
      *(pVU8(reg) + 1) = value >> 8;
    else if constexpr (dmask == 0x00FF'0000)
      *(pVU8(reg) + 2) = value >> 16;
    else if constexpr (dmask == 0xFF00'0000)
      *(pVU8(reg) + 3) = value >> 24;
    else if constexpr ((dmask & 0xFFFF'FF00)==0)
      *pVU8(reg) = (*pVU8(reg) & ~dmask) | value;
    else if constexpr (!(dmask & 0xFFFF'00FF))
      *(pVU8(reg) + 1) = (*(pVU8(reg) + 1) & ~(dmask >> 8)) | (value >> 8);
    else if constexpr (!(dmask & 0xFF00'FFFF))
      *(pVU8(reg) + 2) = (*(pVU8(reg) + 2) & ~(dmask >> 16)) | (value >> 16);
    else if constexpr (!(dmask & 0x00FF'FFFF))
      *(pVU8(reg) + 3) = (*(pVU8(reg) + 3) & ~(dmask >> 24)) | (value >> 24);
    else if constexpr (!(dmask & 0xFFFF'0000))
      *pVU16(reg) = (*pVU16(reg) & ~dmask) | value;
    else if constexpr (!(dmask & 0x0000'FFFF))
      *(pVU16(reg) + 1) = (*(pVU16(reg) + 1) & ~(dmask >> 16)) | (value >> 16);
    else
        *reg = (*reg & ~dmask) | value;
  }

  template<uint32_t pmask>
  _static_always_inline_ void writeReg16(pVU32 reg, uint32_t value)
  {
    if constexpr (pmask==0) return;
    if constexpr (pmask==0xFFFF)
      *pVU16(reg) = value;
    else if constexpr (pmask==0x00FF)
      *pVU8(reg) = value;
    else if constexpr (pmask==0xFF00)
      *(pVU8(reg) + 1) = value >> 8;
    else if constexpr (!(pmask & 0xFF00))
      *pVU8(reg) = (*pVU8(reg) & ~pmask) | value;
    else if constexpr ((pmask & 0x00FF)==0)
      *(pVU8(reg) + 1) = (*(pVU8(reg) + 1) & ~(pmask>>8)) | (value>>8);
    else
      *reg = (*reg & ~pmask) | value;
  }

  template<uint32_t pmask>
  _static_always_inline_ uint32_t readReg16(pVU32 reg)
  {
    if constexpr (pmask == 0xFFFF)
      return *reg;
    else if constexpr (pmask == 0x00FF)
      return *pVU8(reg);
    else if constexpr (pmask == 0xFF00)
      return *(pVU8(reg) + 1)<<8;
    else
      return *reg & pmask;
  }

  template<uint32_t DMask, uint32_t Regmask>
  _static_always_inline_ constexpr uint32_t OptimizeDMask()
  {
    if constexpr      ((DMask==0) || (Regmask==0)) return 0;
    else if constexpr (((DMask & 0x0000'00FF)==0x0000'00FF) && !(Regmask & 0xFFFF'FF00)) return 0x0000'00FF;
    else if constexpr (((DMask & 0x0000'FF00)==0x0000'FF00) && !(Regmask & 0xFFFF'00FF)) return 0x0000'FF00;
    else if constexpr (((DMask & 0x00FF'0000)==0x00FF'0000) && !(Regmask & 0xFF00'FFFF)) return 0x00FF'0000;
    else if constexpr (((DMask & 0xFF00'0000)==0xFF00'0000) && !(Regmask & 0x00FF'FFFF)) return 0xFF00'0000;
    else if constexpr (((DMask & 0x0000'FFFF)==0x0000'FFFF) && !(Regmask & 0xFFFF'0000)) return 0x0000'FFFF;
    else if constexpr (((DMask & 0xFFFF'0000)==0xFFFF'0000) && !(Regmask & 0x0000'FFFF)) return 0xFFFF'0000;
    else if constexpr (DMask==0xFFFF'FFFF) return 0xFFFF'FFFF;
    else return Regmask;
  }

  template<uint32_t Mask, uint32_t Regmask>
  _static_always_inline_ constexpr uint32_t OptimizeMask()
  {
    if constexpr      ((Mask==0)||(Regmask==0)) return 0;
    else if constexpr (((Mask & 0x00FF)==0x00FF) && !(Regmask & 0xFF00)) return 0x00FF;
    else if constexpr (((Mask & 0xFF00)==0xFF00) && !(Regmask & 0x00FF)) return 0xFF00;
    else if constexpr (Mask==0xFFFF) return 0xFFFF;
    else return Regmask;
  }

  template<bool UsePwrCfg=false, uint32_t PMask, typename... Modes>
  _static_always_inline_ void mode_(TypeList<Modes...> modes)
  {
    static_assert(countSetBits(PMask) == PinModeList<Modes...>::Size, "ModeList and Port size is not Equal!");

    static constexpr uint32_t dm = dmask(PMask);

    static constexpr auto modeTuple = getModeValues<PMask>(PinModeList<Modes...>::modes_);
    [[maybe_unused]] static constexpr auto UsedRegs    = std::get< 0>(modeTuple);
    [[maybe_unused]] static constexpr auto Moder       = std::get< 1>(modeTuple);
    [[maybe_unused]] static constexpr auto Ospeedr     = std::get< 2>(modeTuple);
    [[maybe_unused]] static constexpr auto OspeedrMask = std::get< 3>(modeTuple);
    [[maybe_unused]] static constexpr auto Pupdr       = std::get< 4>(modeTuple);
    [[maybe_unused]] static constexpr auto PupdrMask   = std::get< 5>(modeTuple);
    [[maybe_unused]] static constexpr auto Otyper      = std::get< 6>(modeTuple);
    [[maybe_unused]] static constexpr auto OtyperMask  = std::get< 7>(modeTuple);
    [[maybe_unused]] static constexpr auto AfrL        = std::get< 8>(modeTuple);
    [[maybe_unused]] static constexpr auto AfrLMask    = std::get< 9>(modeTuple);
    [[maybe_unused]] static constexpr auto AfrH        = std::get<10>(modeTuple);
    [[maybe_unused]] static constexpr auto AfrHMask    = std::get<11>(modeTuple);
    [[maybe_unused]] static constexpr auto State       = std::get<12>(modeTuple);
    [[maybe_unused]] static constexpr auto StateMask   = std::get<13>(modeTuple);


    writeReg32<UsePwrCfg ? OptimizeDMask<dm,Moder^pwrModer>() : dm>(&base()->MODER,Moder);

    if constexpr (hasFlag(UsedRegs, GpioRegs::Pupdr))
      writeReg32<OptimizeDMask<dm, PupdrMask&(UsePwrCfg?(Pupdr^pwrPupdr):0xFFFFFFFF)>()>(&base()->PUPDR, Pupdr);

    if constexpr (hasFlag(UsedRegs, GpioRegs::Ospeedr))
      writeReg32<OptimizeDMask<dm, OspeedrMask&(UsePwrCfg?(Ospeedr^pwrOspeedr):0xFFFFFFFF)>()>(&base()->OSPEEDR, Ospeedr);

    if constexpr (hasFlag(UsedRegs, GpioRegs::Otyper))
    {
      if constexpr ( !UsePwrCfg || (UsePwrCfg && (Otyper!=0)) )
      {
#ifdef STM32L0_ERRATA  //Errata: 2.1.1 Writing in byte mode to the GPIOx_OTYPER register does not work
        if constexpr (PMask==0xFFFF)
          base()->OTYPER = Otyper;  //+
        else
          base()->OTYPER = (base()->OTYPER & ~PMask) | Otyper;      //+
#else
        writeReg16<OptimizeMask<PMask, OtyperMask>()>(&base()->OTYPER, Otyper);
#endif
      }
    }

    if constexpr (hasFlag(UsedRegs, GpioRegs::AfrL))
      writeReg32<OptimizeDMask<qmask(PMask), AfrLMask&(UsePwrCfg?AfrL:0xFFFFFFFF)>()>(&base()->AFR[0], AfrL);

    if constexpr (hasFlag(UsedRegs, GpioRegs::AfrH))
      writeReg32<OptimizeDMask<qmask(PMask>>8), AfrHMask&(UsePwrCfg?AfrH:0xFFFFFFFF)>()>(&base()->AFR[1], AfrH);

    if constexpr (hasFlag(UsedRegs, GpioRegs::State))
      write<StateMask&(UsePwrCfg?State:0xFFFFFFFF)>(State);
  }

  template<uint32_t PMask, GpioRegs Regs=GpioRegs(0), uint32_t Moder=0, uint32_t Ospeedr=0, uint32_t OspeedrMask=0,
           uint32_t Pupdr=0, uint32_t PupdrMask=0, uint32_t Otyper=0, uint32_t OtyperMask=0,
           uint32_t AfrL=0, uint32_t AfrLMask=0, uint32_t AfrH=0, uint32_t AfrHMask=0,
           uint32_t State=0, uint32_t StateMask=0, typename... Modes>
  _static_always_inline_ constexpr auto getModeValues(TypeList<Modes...> modes)
  {
    if constexpr(!empty(modes))
    {
      constexpr uint32_t msb_num = MostSignificantBitNum(PMask);
      constexpr uint32_t msb = 1U<<msb_num;
      constexpr auto mode = decltype(head(modes))::pin_mode;
      static_assert(mode!=STM32Fx_PinMode::NotDefined,"Pin mode undefined");
      constexpr uint32_t af = decltype(head(modes))::af;
      static_assert( (isAfMode<mode>() && (af<16)) || !isAfMode<mode>(), "Alternate Function is not defined");

      constexpr auto UsedRegs = ( !isInputMode<mode>() ? GpioRegs::Otyper | GpioRegs::Ospeedr : GpioRegs(0) ) |
                                ( isOutputStateDefined<mode,af>() ? GpioRegs::State : GpioRegs(0) )           |
                                ( (isAfMode<mode>() && (msb&0x00FF)) ? GpioRegs::AfrL : GpioRegs(0) )         |
                                ( (isAfMode<mode>() && (msb&0xFF00)) ? GpioRegs::AfrH : GpioRegs(0) )         |
                                ( !isAnalog<mode>() ? GpioRegs::Pupdr : GpioRegs(0) ) |  Regs;

      constexpr uint32_t moder = Moder | (uint32_t(mode) & 3) << msb_num * 2;
      constexpr uint32_t ospeedr = Ospeedr | ((uint32_t(mode) >> 2) & 3) << msb_num * 2;
      constexpr uint32_t ospeedrmask = OspeedrMask | ((isInputMode<mode>() ? 0 : 3U) << msb_num * 2);
      constexpr uint32_t pupdr = Pupdr | ((uint32_t(mode) >> 5) & 3) << msb_num * 2;
      constexpr uint32_t pupdrmask = PupdrMask | ((isAnalog<mode>() ? 0 : 3U) << msb_num * 2);
      constexpr uint32_t otyper = Otyper | ((uint32_t(mode) >> 4) & 1) << msb_num;
      constexpr uint32_t otypermask = OtyperMask | ((isInputMode<mode>() ? 0 : 1U) << msb_num);
      constexpr uint32_t afrl = AfrL | ((msb&0x00FF)? (af&0xF) << msb_num * 4 : 0);
      constexpr uint32_t afrlmask = AfrLMask | ((isAfMode<mode>() && (msb&0x00FF)) ? 0xFU << msb_num * 4 : 0);
      constexpr uint32_t afrh = AfrH | ((msb&0xFF00)? (af&0xF) << (msb_num-8) * 4 : 0);
      constexpr uint32_t afrhmask = AfrHMask | ((isAfMode<mode>() && (msb&0xFF00)) ? 0xFU << (msb_num-8) * 4 : 0);
      constexpr uint32_t state = State | (isOutputStateDefined<mode,af>() ? af*msb : 0);
      constexpr uint32_t statemask = StateMask | (isOutputStateDefined<mode,af>() ? msb : 0);

      return getModeValues< PMask&~msb, UsedRegs, moder, ospeedr, ospeedrmask, pupdr, pupdrmask,
                            otyper, otypermask, afrl, afrlmask, afrh, afrhmask, state, statemask>(pop_front(modes));
    }
    return std::make_tuple(Regs, Moder, Ospeedr, OspeedrMask, Pupdr, PupdrMask, Otyper, OtyperMask,
                           AfrL, AfrLMask, AfrH, AfrHMask, State, StateMask);
  }
};

#define MAKE_PORT(PORT_NAME, PWR_CFG) \
template<uint32_t PinsMask = 0xFFFF, typename TPM = STM32Fx_MODE::NotDefined> \
using Gpio##PORT_NAME = TSTM32Fx_GPIO<GPIO##PORT_NAME##_BASE, PinsMask, TPM, PWR_CFG>;\
 
#ifdef GPIOA
  MAKE_PORT(A,PWR_CFG_A)
  MAKE_16PINS(GpioA,A)
#endif
#ifdef GPIOB
  MAKE_PORT(B,PWR_CFG_B)
  MAKE_16PINS(GpioB,B)
#endif
#ifdef GPIOC
  MAKE_PORT(C,PWR_CFG_C)
  MAKE_16PINS(GpioC,C)
#endif
#ifdef GPIOD
  MAKE_PORT(D,PWR_CFG_D)
  MAKE_16PINS(GpioD,D)
#endif
#ifdef GPIOE
  MAKE_PORT(E,PWR_CFG_E)
  MAKE_16PINS(GpioE,E)
#endif
#ifdef GPIOF
  MAKE_PORT(F,PWR_CFG_F)
  MAKE_16PINS(GpioF,F)
#endif
#ifdef GPIOG
  MAKE_PORT(G,PWR_CFG_G)
  MAKE_16PINS(GpioG,G)
#endif
#ifdef GPIOH
  MAKE_PORT(H,PWR_CFG_H)
  MAKE_16PINS(GpioH,H)
#endif
 
}  //namespace STM32Fx_GPIO
При том что самая жесть на самом деле слева от черты.
GPIO_.png
(84.89 KiB) Скачиваний: 527


Добавлено after 6 minutes 54 seconds:
вы почитайте на досуге стандарт С++17. Туда столько говна засунули, аж жутко становится!!!
Это от непонимания. В С++20 будет ещё много вкусностей :)

Вот если бы С++ оставался той надстройкой над С, что придумал Страуструп, еще ладно.
Тогда бы он как раз был бы бесполезен для эмбедда. Кстати, Бьерн всё ещё не последний человек, двигающий С++ вперёд.

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

Re: Stm32 с чего начать изучение...

Вт фев 04, 2020 14:53:10

VladislavS писал(а):Прямо бунт на корабле какой-то сегодня
Ага, отладкофобы форум атакуют! :)))

Eddy_Em писал(а):Толерастия до добра никогда не доводит.
Расизм, нацизм, фашизм и т. д. тоже! :facepalm:

Re: Stm32 с чего начать изучение...

Ср фев 05, 2020 10:05:07

VladislavS писал(а):Вот примерчик моей билиотеки GPIO.
Круто! Только вот представить, какой там жуткий оверхед!..

Я для своей конкретной задачи для работы с GPIO сочинил несколько макросов, всего полстранички текста. Делал для F103. Задефайнил несколько GPIO, присвоив им свои имена в задаче, и простые макросы: переключить GPIO порта данных на ввод или вывод, прочитать порт данных, записать в порт данных, взвести/сбросить один или несколько битов управления (биты другого GPIO), потестить один или несколько битов состояния (биты третьего GPIO), и все! Когда переходил с F103ZET6 на F103VET7, и переставил некоторые биты управления и состояния, то просто поменял соответствующие дефайны. А когда стал переносить код на F407VET6 и обнаружил, что у него нет регистра GPIOx.BRR, да и инитятся они чуть по-другому, подправил макросы (инит мне переписал CubeMX, но переключение порта данных на ввод или вывод пришлось изменить). Один вечер ненапряжной работы, включая замену в макете моего изделия китайской платы с F103 на китайскую плату с F407 - переткнуть штук 50 ардуиновских проводков и ни разу не ошибиться...

Re: Stm32 с чего начать изучение...

Ср фев 05, 2020 10:37:01

Круто! Только вот представить, какой там жуткий оверхед! Я для своей конкретной задачи для работы с GPIO сочинил несколько макросов, всего полстранички текста.

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

Re: Stm32 с чего начать изучение...

Ср фев 05, 2020 10:41:22

afz, оверхеда там нет. Владислав листинги приводил в пример.
Другое дело, что в С++ даже с двумя поллитрами не разберешься. А в С с макросами и инлайнами все очень просто.

А для ногодрыга у меня вот такие макросы. С настройками пинов в 0-й серии тоже все просто, а вот для дебильных F103 пришлось дополнительные макросы писать. И при инициализации пишем что-то вроде
Код:
GPIOC->CRH = CRH(13, CNF_PPOUTPUT|MODE_SLOW);

чтобы PC13 настроить в режиме push-pull, 2MHz. Понятно, что проверок нет. И если вместо MODE_SLOW напишешь MODE_INPUT, никаких матюгов не будет (иначе - оверхед!), а нога тупо останется в режиме аналогового входа.
В крестах же на стадии препроцессора будет проверено что нужно с соответствующими матюками. Но какие предварительно простыни кода нужно написать, вы видели… Это ужас (тем более, что я в С++ вообще не разбираюсь)!

Re: Stm32 с чего начать изучение...

Ср фев 05, 2020 13:42:31

astrahard, вы почитайте на досуге стандарт С++17. Туда столько говна засунули, аж жутко становится!!!
Вот если бы С++ оставался той надстройкой над С, что придумал Страуструп, еще ладно. Но все эти шаблоны и т.п. просто взрывают мой мозг.

Александрески почитайте - программирование на основе стратегий поведения. Шаблоны отдыхают.

Re: Stm32 с чего начать изучение...

Ср фев 05, 2020 17:37:45

Александрески почитайте
Он почему (такой злой был) так сложно писал? От того что у него тогда С++20 не было! Сейчас всё намного проще можно писать.

Re: Stm32 с чего начать изучение...

Ср фев 05, 2020 18:11:49

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