STM32 новичку в ARM что к чему

Кто любит RISC в жизни, заходим, не стесняемся.
jcxz
Мудрый кот
Сообщения: 1717
Зарегистрирован: Вт авг 15, 2017 10:51:13

Re: STM32 новичку в ARM что к чему

Сообщение jcxz »

[uquote="ARV",url="/forum/viewtopic.php?p=4711646#p4711646"]a5021 тут недавно практически доказал, что для "перегрузки" байтами USARTа (т.е. для возникновения пропусков) надо создать невероятно дикую нагрузку остальной периферии, что представляется маловероятным.[/uquote]a5021 там написал полнейшую галиматью, из которой только следует, что он совершенно не понял о чём шла речь. Примерно как вы не понимаете очевидных вещей - как делить поток байтов на кадры Modbus-RTU. В этом вы с ним схожи.
Речь не шла ни о какой "перегрузки байтами USARTа". Выше по комментам видно, что другие люди прекрасно поняли о чём шла речь:
[uquote="tonyk",url="/forum/viewtopic.php?p=4711611#p4711611"]Как выше правильно заметили, обычно, у МК есть много более приоритетных задач, чем приём одного байта. Вот поэтому весь обмен через UART нужно строить исключительно с использованием DMA: приняли фрейм, появилось время, тогда и обработали его.[/uquote]не поняли только вы на пару с a5021
Как обычно - "не в коня корм". :dont_know:

Добавлено after 12 minutes 58 seconds:
[uquote="ARV",url="/forum/viewtopic.php?p=4711680#p4711680"]То есть задействование трех периферийных устройств вместо одного считается правильным и эффективным решением?! Мда... Неожиданно.[/uquote]В МК множество периферийных узлов. Они предназначены чтобы разгрузить самый главный узел - CPU. Говнокодеры-ногодрыгатели всё пытаются делать ногодрыгательными методами. Чтобы не читать мануалы на эти периферийные узлы. И у них самая простая задача грузит CPU на 100%. И он только с ней кое-как справляется.
Умные люди - используют разные периферийные блоки. Чтобы сэкономить главный ресурс = время CPU. И используют столько периферийных узлов, сколько нужно. И у них CPU умудряется параллельно выполнять множество задач.

И DMA - как раз один из тех узлов, которые предназначены разгрузить CPU. Вы на пару с a5021 как видно - совершенно не понимаете его предназначения.
А также той простой вещи, что во множестве проектов UART - это совсем не главная вещь, на которую нужно убить всё время CPU. Что там программе нужно ещё много разных функций выполнять. И возможно - гораздо более приоритетных. И что UART-ов в проекте может быть не один, а много. И работать они могут не на 9600, а скажем - на 921600. Завтра вам с вашей реализацией на прерываниях, потребуется увеличить скорость UART. Или добавить ещё пару UART-ов в проект и.... окажется, что производительности CPU уже не хватает. Вся она ушла на перекладывание байтов в UART и из него. И будете всё переписывать по новой, в который раз. :facepalm:


PS: И да что значит "задействование трех периферийных устройств вместо одного"? Как именно вы делите поток байтов на кадры Modbus при помощи одного только UART? Без таймера и без использования аппаратной функции таймаута UART?
Последний раз редактировалось jcxz Вс май 04, 2025 14:05:14, всего редактировалось 2 раза.
Реклама
a5021
Друг Кота
Сообщения: 6452
Зарегистрирован: Пт сен 13, 2013 13:11:31

Re: STM32 новичку в ARM что к чему

Сообщение a5021 »

[uquote="Adrift",url="/forum/viewtopic.php?p=4711661#p4711661"]Теперь еще и единообразие инициализации потеряли[/uquote]
эта музыка будет вечной и вот почему:
СпойлерИзображение
как эта схема спасает от того, что в этот момент пишущий проглотил муху и выбрал не тот пункт из списка? я к чему это.. придумывать различные эксепшены можно бесконечно и всех так и не придумать.
а помогаек всяких без счета сейчас:
СпойлерИзображение

Изображение
не ленись, выбирай, настраивай..

Добавлено after 4 minutes 29 seconds:
[uquote="jcxz",url="/forum/viewtopic.php?p=4711685#p4711685"]a5021 там написал полнейшую галиматью, из которой только следует, что он совершенно не понял о чём шла речь.[/uquote]
и опять ни слова конкретики. на соревнованиях базарных баб ваши шансы не вызывают сомнений.
Вложения
r2.jpg
(35.82 КБ) 577 скачиваний
r1.jpg
(40.68 КБ) 658 скачиваний
Реклама
jcxz
Мудрый кот
Сообщения: 1717
Зарегистрирован: Вт авг 15, 2017 10:51:13

Re: STM32 новичку в ARM что к чему

Сообщение jcxz »

[uquote="a5021",url="/forum/viewtopic.php?p=4711698#p4711698"]и опять ни слова конкретики. на соревнованиях базарных баб ваши шансы не вызывают сомнений.[/uquote]Для вас может быть только одна конкретика: Не занимайтесь программированием. Не ваше это.
Никакой другой конкретики вы понять не в силах.
Adrift
Вымогатель припоя
Сообщения: 540
Зарегистрирован: Вт окт 01, 2024 15:22:33

Re: STM32 новичку в ARM что к чему

Сообщение Adrift »

[uquote="a5021",url="/forum/viewtopic.php?p=4711698#p4711698"]как эта схема спасает от того, что в этот момент пишущий проглотил муху и выбрал не тот пункт из списка?[/uquote]
Функция ждет аргумент типа TimSlaveMode в качестве первого параметра, любое другое значение приведет к ошибке компиляции. В худшем случае из десятка допустимых режимов можно выбрать не тот который требуется, а в рантайме там еще дополнительные проверки есть. У вас можно подставить любой аргумент который приводится к uint32_t.
a5021 писал(а):а помогаек всяких без счета сейчас:
Спойлер
СпойлерИзображение

Здорово, а букву наверно можно наугад вводить? ) И что-то маловат списочек, там должны быть все определения начинающиеся c RCC, RTC и т.д., в том числе ваши сокращения R и RT. Но тут хоть обычно понятно к чему они относятся, а чего вдруг RESET_MODE должен обязательно к таймерам относится? У USB есть поля RESET и RESETM, у CRC, GPDMA и FMAC тоже есть поле RESET... Вон в HAL символы не считают и дали режимам таймера имена начинающиеся с TIM_SLAVEMODE, в частности TIM_SLAVEMODE_RESET, а вы все оптимизациями имен по размеру занимаетесь )
Реклама
Эиком - электронные компоненты и радиодетали
tonyk
Это не хвост, это антенна
Сообщения: 1309
Зарегистрирован: Вт ноя 19, 2019 06:10:18

Re: STM32 новичку в ARM что к чему

Сообщение tonyk »

ARV писал(а):Итак, по сути. Модбас не укладывается в модель OSI, т.к. был придуман еще до его изобретения, если я не ошибаюсь.
Модель ISO/OSI является обобщением полученного опыта, а не высосана из пальца. И Модбас в неё укладывается. Читайте Стандарт, там есть об этом.
ARV писал(а):Итак, по сути. Модбас... Длина пакета него переменная в принципе, хотя наиболее частая длина 8 байт, но при ошибках может быть 6, а при записи большого количества регистров-катушек, как было отмечено, может быть до 257 байт.
ARV писал(а):tonyk писал(а):
В некоторых STM32 встроены полноценные UART с аппаратной поддержкой Модбас.
это вы сейчас утверждаете, или предполагаете? я пока что обнаружил встроенную поддержку аппаратного переключения RX-TX, что и применяю. но никакой дргой поддержки модбас я пока не видел (но я и видел мало, как вы уже ранее верно подметили).
Я это использую. А автоуправление DE никакого отношения к Модбас не имеет.
Максимальная длина пакета в Модбас составляет 256 байт. А вот буфер для его приёма нужно делать 257 байт. Читайте внимательно то, что вам говорят.
ARV писал(а):Не представляю, как еще можно все настроить...
А это потому, что не читаете мурзилки и гордитесь этим. Вы же хотите бездумно тыкать по галкам в КАЛе- вот и результат. Если бы читали, то знали, что полноценный UART, которого лишён попсовый STM32F103, умеет аппаратно выделять Модбас-кадр используя свой специальный таймер, отсчитывающий задержку в количестве битов. Кроме того, такой UART умеет сравнивать байт внутри кадра с заданным. Ну и до кучи можно считать CRC принятого пакета, используя аппаратный блок вычисления CRC вкупе с DMA.
ARV писал(а):я ранее интересовался: а как же девайсы на 8-битниках двадцатилетней давности модбас тянут?!
Ну 1 или 2 порта на 9600- это не проблема. Да и восьмибитников, например, с десятью UART как у STM32, я не встречал. Встречал МК-восьмибитки с 4 UART. И, опять же, читайте внимательно, что вам пишут. А писал я, что МК, помимо 6 Модбас, тянул измерения по 12 каналам, которые не допускают пропусков, ибо на результатах их измерений построены защиты. Вот вам и приоритетные задачи. И как вишенка- рантайм ПЛК.
Реклама
a5021
Друг Кота
Сообщения: 6452
Зарегистрирован: Пт сен 13, 2013 13:11:31

Re: STM32 новичку в ARM что к чему

Сообщение a5021 »

[uquote="Adrift",url="/forum/viewtopic.php?p=4711717#p4711717"]Функция ждет аргумент типа TimSlaveMode в качестве первого параметра, любое другое значение приведет к ошибке компиляции.[/uquote]
еще раз медленно: не то значение из списка. промахнулся.
Здорово, а букву наверно можно наугад вводить?
можно и наугад. и в вашем списке так тоже можно. если совсем не понимать, что делаешь, то ни одна схема не спасет.
а вы все оптимизациями имен по размеру занимаетесь )
ложный вывод. меня больше интересует наглядность.
Реклама
Аватара пользователя
ARV
Ум, честь и совесть. И скромность.
Сообщения: 18546
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск
Контактная информация:

Re: STM32 новичку в ARM что к чему

Сообщение ARV »

jcxz писал(а):завести сигнал RXD на вход сброса/перезагрузки таймера
а это делается программно, или "завести на вход" следует понимать буквально - изменить схему?
jcxz писал(а):ак именно вы делите поток байтов на кадры Modbus при помощи одного только UART? Без таймера и без использования аппаратной функции таймаута UART?
уверен, что рассказывать необязательно, т.к. вне зависимости от того, что именно я делаю, ваш вердикт все равно будет "не правильно". Однако, таймер есть, и он на самом деле ловит таймауты и паузы между пакетами.
jcxz писал(а):Как обычно - "не в коня корм"
на минуточку: вы в теме для начинающих, так что речь не о конях и корме, а о жеребятах и бутылочке с соской. умерьте ваш гонор, а то вам поляки завидуют.
tonyk писал(а):А автоуправление DE никакого отношения к Модбас не имеет.
к драйверу RS485 зато имеет
tonyk писал(а):Если бы читали, то знали, что полноценный UART, которого лишён попсовый STM32F103, умеет аппаратно выделять Модбас-кадр используя свой специальный таймер, отсчитывающий задержку в количестве битов. Кроме того, такой UART умеет сравнивать байт внутри кадра с заданным. Ну и до кучи можно считать CRC принятого пакета, используя аппаратный блок вычисления CRC вкупе с DMA.
ну, вот и спасибо, теперь буду знать.
но ведь DMA не может в два "приемника" данные отправлять? или может? это я к тому, что CRC считать одновременно с "перемещением байта в буфер" все равно не получится?
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
tonyk
Это не хвост, это антенна
Сообщения: 1309
Зарегистрирован: Вт ноя 19, 2019 06:10:18

Re: STM32 новичку в ARM что к чему

Сообщение tonyk »

ARV писал(а):к драйверу RS485 зато имеет
Я использую драйверы без этого сигнала, с автоопределением направления.
ARV писал(а):но ведь DMA не может в два "приемника" данные отправлять? или может? это я к тому, что CRC считать одновременно с "перемещением байта в буфер" все равно не получится?
Дальше как в анекдоте:
Поймал мужик золотую рыбку - та и говорит: "Исполню твое желание, отпусти меня!"
Мужик думал, думал да и говорит: "Хочу ссать водкой!"
Рыбка отвечает - "Запросто!"

Пришел мужик домой, поссал в стакан, к жене : "Выпей!!"
Та :"Да ты че о@ел!". Мужик сам попробовал - нормально, она следом. Ну в общем посидели до утра.

Утром жена приходит со стаканом и с огурчиком - "Опохмелиться бы"

Мужик: "Вчера была презентация - а сегодня за деньги и из горла!"
jcxz
Мудрый кот
Сообщения: 1717
Зарегистрирован: Вт авг 15, 2017 10:51:13

Re: STM32 новичку в ARM что к чему

Сообщение jcxz »

[uquote="ARV",url="/forum/viewtopic.php?p=4711761#p4711761"]а это делается программно, или "завести на вход" следует понимать буквально - изменить схему?[/uquote]Если заранее подумали и заложили такой МК, в котором можно это сделать программно, то ничего в схеме менять не надо.

[uquote="ARV",url="/forum/viewtopic.php?p=4711761#p4711761"]уверен, что рассказывать необязательно, т.к. вне зависимости от того, что именно я делаю, ваш вердикт все равно будет "не правильно".[/uquote]Этим постом:
[uquote="ARV",url="/forum/viewtopic.php?p=4711680#p4711680"]То есть задействование трех периферийных устройств вместо одного считается правильным и эффективным решением?! Мда... Неожиданно.[/uquote]вы намекали, что мой подход "неэффективный". Не приводя никаких аргументов и не показывая "как будет эффективно" по вашему мнению. Какого ответа вы ещё ожидали на свой пост?

[uquote="ARV",url="/forum/viewtopic.php?p=4711761#p4711761"]вы в теме для начинающих ... Умерьте ваш гонор, а то вам поляки завидуют.[/uquote]Может это вам стоит умерить свой гонор? Хотя бы до тех пор, пока наконец-то сможете начать??

А насчёт указывания мне как и кому писать - оставьте ваши советы при себе. Хамлу под ником "a5021" я ответил ещё мягко, после его наезда:
[uquote="a5021",url="/forum/viewtopic.php?p=4711698#p4711698"]на соревнованиях базарных баб ваши шансы не вызывают сомнений.[/uquote]

PS: Чайники, прежде чем указывать кому-то как и что писать, научитесь хотя бы чему то, кроме как хамить. Вам тут никто ничего не должен.
tonyk
Это не хвост, это антенна
Сообщения: 1309
Зарегистрирован: Вт ноя 19, 2019 06:10:18

Re: STM32 новичку в ARM что к чему

Сообщение tonyk »

[uquote="jcxz",url="/forum/viewtopic.php?p=4711786#p4711786"][uquote="ARV",url="/forum/viewtopic.php?p=4711761#p4711761"]вы в теме для начинающих ... Умерьте ваш гонор, а то вам поляки завидуют.[/uquote]Может это вам стоит умерить свой гонор? Хотя бы до тех пор, пока наконец-то сможете начать??

А насчёт указывания мне как и кому писать - оставьте ваши советы при себе. Хамлу под ником "a5021" я ответил ещё мягко, после его наезда:
[uquote="a5021",url="/forum/viewtopic.php?p=4711698#p4711698"]на соревнованиях базарных баб ваши шансы не вызывают сомнений.[/uquote]

PS: Чайники, прежде чем указывать кому-то как и что писать, научитесь хотя бы чему то, кроме как хамить. Вам тут никто ничего не должен.[/uquote]
Двумя руками поддерживаю jcxz. Тоже удивлён хамско-вызывающей манерой общения ARV. Думал, что это касалось только моей персоны, но оказалось, что нет, это тенденция.
Аватара пользователя
ARV
Ум, честь и совесть. И скромность.
Сообщения: 18546
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск
Контактная информация:

Re: STM32 новичку в ARM что к чему

Сообщение ARV »

Видимо, вас недооценивают ваши начальники или кто-то еще... Может, в детстве обижали... В общем, не знаю, что можно сказать хаму, обвиняющего другого в хамстве, но причина явно не техническая, а психологическая.

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

Добавлено after 9 minutes 56 seconds:
P.S. для jcxz, которого я знаю лет этак 20 еще по форуму электроникс, и советами которого ранее я не пренебрегал: я начал примерно 33 года назад, и, вероятно, скоро уже закончу[сь]. А с стм32 я начал три месяца назад, и начал с того, что в первые часы реализовал собственный "оригинальный" вариант того, что активно применялось и применяется на новом месте моей работы. Так что ваши советы "начать" я не особо близко к сердцу принимаю. Но за те крохи пользы, что удалось получить в этой теме, спасибо.
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
a5021
Друг Кота
Сообщения: 6452
Зарегистрирован: Пт сен 13, 2013 13:11:31

Re: STM32 новичку в ARM что к чему

Сообщение a5021 »

опять я в поисках наглядности. показалось, что если наобъявлять макросов в формате

Код: Выделить всё

PERIPHERAL_REGISTER(...)
с переменным числом параметров, которые бы потом разворачивались в список вида

Код: Выделить всё

(PERIPHERAL_REGISTER_BITFIELD1 | PERIPHERAL_REGISTER_BITFIELD2 | ... | PERIPHERAL_REGISTER_BITFIELDn)
где смысл я вижу в том, чтобы в длинной строке

Код: Выделить всё

(TIM_CR1_OPM | TIM_CR1_DIR | TIM_CR1_CEN)
этот самый TIM_CR1 "вынести за скобки" и привести к виду

Код: Выделить всё

TIM_CR1(OPM, DIR, CEN)

в общем, может получиться наглядно и компактно:
Спойлер

Код: Выделить всё

int main(void) {
    // 1. Enable clocks for TIM2 and USART2 peripherals
    RCC->APB1ENR |= RCC_APB1ENR(TIM2EN, USART2EN);

    // 2. Enable clock for GPIOA (for USART2 TX/RX and PWM on PA0)
    RCC->APB2ENR |= RCC_APB2ENR(IOPAEN);

    // 3. Configure PA0 (TIM2_CH1) as alternate function push-pull, 50 MHz
    GPIOA->CRL &= ~GPIO_CRL(MODE0, CNF0);
    GPIOA->CRL |= GPIO_CRL(MODE0_1, MODE0_0, CNF0_1);

    // 4. Configure PA2 (USART2_TX) as alternate function push-pull, 50 MHz
    GPIOA->CRL &= ~GPIO_CRL(MODE2, CNF2);
    GPIOA->CRL |= GPIO_CRL(MODE2_1, MODE2_0, CNF2_1);

    // 5. Configure PA3 (USART2_RX) as input floating
    GPIOA->CRL &= ~GPIO_CRL(MODE3, CNF3);
    GPIOA->CRL |= GPIO_CRL(CNF3_0);

    // --- TIM2 PWM setup on CH1 (PA0) ---
    TIM2->PSC   = 8 - 1;       // 1 MHz timer clock
    TIM2->ARR   = 1000 - 1;    // 1 kHz PWM frequency
    TIM2->CCR1  = 500;         // Initial duty: 50%

    // Set PWM mode 1 on CH1, enable preload
    TIM2->CCMR1 = TIM_CCMR1(OC1M_2, OC1M_1, OC1PE);
    TIM2->CCER  = TIM_CCER(CC1E);
    TIM2->CR1   = TIM_CR1(ARPE, CEN);

    // --- USART2 setup ---
    USART2->BRR = 8000000 / 9600;
    USART2->CR1 = USART_CR1(UE, TE, RE);

    // --- Main loop ---
    while (1) {
        // Poll RXNE (Receive Data Register Not Empty)
        if (USART2->SR & USART_SR(RXNE)) {
            // Read received byte (clears RXNE)
            signed char delta = (signed char)USART2->DR;

            // Adjust duty cycle
            int duty = TIM2->CCR1 + delta;
            if (duty < 0) duty = 0;
            if (duty > TIM2->ARR) duty = TIM2->ARR;
            TIM2->CCR1 = duty;
        }

        // Main loop continues immediately (non-blocking)
    }
}
не стесняемся, подходим, критикуем, разносим в пух и прах...

все, как мы любим -- прием без прерываний и дма, неблокирующий... :-)

ps. aх, да, сами макросы..
Спойлер

Код: Выделить всё

// --- Universal BITS Macro ---
// Helper macro: paste together PREFIX_, REG, and FIELD to form a bitfield macro name
#define _BITS_ONE(PREFIX_, REG, FIELD) PREFIX_##REG##_##FIELD

// Recursive macros to combine 1-16 bitfields with the '|' operator
#define _BITS_1(PREFIX_, REG, A1) _BITS_ONE(PREFIX_, REG, A1)
#define _BITS_2(PREFIX_, REG, A1, ...) _BITS_ONE(PREFIX_, REG, A1) | _BITS_1(PREFIX_, REG, __VA_ARGS__)
#define _BITS_3(PREFIX_, REG, A1, ...) _BITS_ONE(PREFIX_, REG, A1) | _BITS_2(PREFIX_, REG, __VA_ARGS__)
#define _BITS_4(PREFIX_, REG, A1, ...) _BITS_ONE(PREFIX_, REG, A1) | _BITS_3(PREFIX_, REG, __VA_ARGS__)
#define _BITS_5(PREFIX_, REG, A1, ...) _BITS_ONE(PREFIX_, REG, A1) | _BITS_4(PREFIX_, REG, __VA_ARGS__)
#define _BITS_6(PREFIX_, REG, A1, ...) _BITS_ONE(PREFIX_, REG, A1) | _BITS_5(PREFIX_, REG, __VA_ARGS__)
#define _BITS_7(PREFIX_, REG, A1, ...) _BITS_ONE(PREFIX_, REG, A1) | _BITS_6(PREFIX_, REG, __VA_ARGS__)
#define _BITS_8(PREFIX_, REG, A1, ...) _BITS_ONE(PREFIX_, REG, A1) | _BITS_7(PREFIX_, REG, __VA_ARGS__)
#define _BITS_9(PREFIX_, REG, A1, ...) _BITS_ONE(PREFIX_, REG, A1) | _BITS_8(PREFIX_, REG, __VA_ARGS__)
#define _BITS_10(PREFIX_, REG, A1, ...) _BITS_ONE(PREFIX_, REG, A1) | _BITS_9(PREFIX_, REG, __VA_ARGS__)
#define _BITS_11(PREFIX_, REG, A1, ...) _BITS_ONE(PREFIX_, REG, A1) | _BITS_10(PREFIX_, REG, __VA_ARGS__)
#define _BITS_12(PREFIX_, REG, A1, ...) _BITS_ONE(PREFIX_, REG, A1) | _BITS_11(PREFIX_, REG, __VA_ARGS__)
#define _BITS_13(PREFIX_, REG, A1, ...) _BITS_ONE(PREFIX_, REG, A1) | _BITS_12(PREFIX_, REG, __VA_ARGS__)
#define _BITS_14(PREFIX_, REG, A1, ...) _BITS_ONE(PREFIX_, REG, A1) | _BITS_13(PREFIX_, REG, __VA_ARGS__)
#define _BITS_15(PREFIX_, REG, A1, ...) _BITS_ONE(PREFIX_, REG, A1) | _BITS_14(PREFIX_, REG, __VA_ARGS__)
#define _BITS_16(PREFIX_, REG, A1, ...) _BITS_ONE(PREFIX_, REG, A1) | _BITS_15(PREFIX_, REG, __VA_ARGS__)

// Macro to count the number of variadic arguments (up to 16)
#define _BITS_NARG(...) _BITS_NARG_(__VA_ARGS__,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1)
#define _BITS_NARG_(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,N,...) N

// Macro chooser: selects the correct _BITS_N macro based on argument count
#define _BITS_CHOOSER2(count) _BITS_##count
#define _BITS_CHOOSER1(count) _BITS_CHOOSER2(count)
#define _BITS_CHOOSER(count)  _BITS_CHOOSER1(count)

// Main macro: expands to a mask of all requested bitfields for a given peripheral register
#define BITS(PREFIX_, REG, ...) \
    (_BITS_CHOOSER(_BITS_NARG(__VA_ARGS__))(PREFIX_, REG, __VA_ARGS__))

// --- Peripheral Type Wrappers ---
// These wrappers make it easy to use the BITS macro for each peripheral type.
// Example: RCC_BITS(APB2ENR, IOPAEN, AFIOEN) expands to (RCC_APB2ENR_IOPAEN | RCC_APB2ENR_AFIOEN)

#define RCC_BITS(reg, ...)      BITS(RCC_, reg, __VA_ARGS__)    // For RCC registers
#define GPIO_BITS(reg, ...)     BITS(GPIO_, reg, __VA_ARGS__)   // For GPIO registers
#define AFIO_BITS(reg, ...)     BITS(AFIO_, reg, __VA_ARGS__)   // For AFIO registers
#define TIM_BITS(reg, ...)      BITS(TIM_, reg, __VA_ARGS__)    // For TIM registers
#define USART_BITS(reg, ...)    BITS(USART_, reg, __VA_ARGS__)  // For USART registers
#define UART_BITS(reg, ...)     BITS(UART_, reg, __VA_ARGS__)   // For UART registers
#define SPI_BITS(reg, ...)      BITS(SPI_, reg, __VA_ARGS__)    // For SPI registers
#define I2C_BITS(reg, ...)      BITS(I2C_, reg, __VA_ARGS__)    // For I2C registers
#define CAN_BITS(reg, ...)      BITS(CAN_, reg, __VA_ARGS__)    // For CAN registers
#define ADC_BITS(reg, ...)      BITS(ADC_, reg, __VA_ARGS__)    // For ADC registers
#define DAC_BITS(reg, ...)      BITS(DAC_, reg, __VA_ARGS__)    // For DAC registers
#define CRC_BITS(reg, ...)      BITS(CRC_, reg, __VA_ARGS__)    // For CRC registers
#define USB_BITS(reg, ...)      BITS(USB_, reg, __VA_ARGS__)    // For USB registers
#define BKP_BITS(reg, ...)      BITS(BKP_, reg, __VA_ARGS__)    // For BKP registers
#define PWR_BITS(reg, ...)      BITS(PWR_, reg, __VA_ARGS__)    // For PWR registers
#define FLASH_BITS(reg, ...)    BITS(FLASH_, reg, __VA_ARGS__)  // For FLASH registers
#define DBGMCU_BITS(reg, ...)   BITS(DBGMCU_, reg, __VA_ARGS__) // For DBGMCU registers
#define WWDG_BITS(reg, ...)     BITS(WWDG_, reg, __VA_ARGS__)   // For WWDG registers
#define IWDG_BITS(reg, ...)     BITS(IWDG_, reg, __VA_ARGS__)   // For IWDG registers
#define RTC_BITS(reg, ...)      BITS(RTC_, reg, __VA_ARGS__)    // For RTC registers
#define EXTI_BITS(reg, ...)     BITS(EXTI_, reg, __VA_ARGS__)   // For EXTI registers

// --- RCC ---
#define RCC_CR(...)           BITS(RCC_, CR, __VA_ARGS__)
#define RCC_CFGR(...)         BITS(RCC_, CFGR, __VA_ARGS__)
#define RCC_CIR(...)          BITS(RCC_, CIR, __VA_ARGS__)
#define RCC_APB2RSTR(...)     BITS(RCC_, APB2RSTR, __VA_ARGS__)
#define RCC_APB1RSTR(...)     BITS(RCC_, APB1RSTR, __VA_ARGS__)
#define RCC_AHBENR(...)       BITS(RCC_, AHBENR, __VA_ARGS__)
#define RCC_APB2ENR(...)      BITS(RCC_, APB2ENR, __VA_ARGS__)
#define RCC_APB1ENR(...)      BITS(RCC_, APB1ENR, __VA_ARGS__)
#define RCC_BDCR(...)         BITS(RCC_, BDCR, __VA_ARGS__)
#define RCC_CSR(...)          BITS(RCC_, CSR, __VA_ARGS__)

// --- GPIO ---
#define GPIO_CRL(...)         BITS(GPIO_, CRL, __VA_ARGS__)
#define GPIO_CRH(...)         BITS(GPIO_, CRH, __VA_ARGS__)
#define GPIO_IDR(...)         BITS(GPIO_, IDR, __VA_ARGS__)
#define GPIO_ODR(...)         BITS(GPIO_, ODR, __VA_ARGS__)
#define GPIO_BSRR(...)        BITS(GPIO_, BSRR, __VA_ARGS__)
#define GPIO_BRR(...)         BITS(GPIO_, BRR, __VA_ARGS__)
#define GPIO_LCKR(...)        BITS(GPIO_, LCKR, __VA_ARGS__)

// --- AFIO ---
#define AFIO_EVCR(...)        BITS(AFIO_, EVCR, __VA_ARGS__)
#define AFIO_MAPR(...)        BITS(AFIO_, MAPR, __VA_ARGS__)
#define AFIO_EXTICR1(...)     BITS(AFIO_, EXTICR1, __VA_ARGS__)
#define AFIO_EXTICR2(...)     BITS(AFIO_, EXTICR2, __VA_ARGS__)
#define AFIO_EXTICR3(...)     BITS(AFIO_, EXTICR3, __VA_ARGS__)
#define AFIO_EXTICR4(...)     BITS(AFIO_, EXTICR4, __VA_ARGS__)
#define AFIO_MAPR2(...)       BITS(AFIO_, MAPR2, __VA_ARGS__)

// --- TIM (general purpose and advanced) ---
#define TIM_CR1(...)          BITS(TIM_, CR1, __VA_ARGS__)
#define TIM_CR2(...)          BITS(TIM_, CR2, __VA_ARGS__)
#define TIM_SMCR(...)         BITS(TIM_, SMCR, __VA_ARGS__)
#define TIM_DIER(...)         BITS(TIM_, DIER, __VA_ARGS__)
#define TIM_SR(...)           BITS(TIM_, SR, __VA_ARGS__)
#define TIM_EGR(...)          BITS(TIM_, EGR, __VA_ARGS__)
#define TIM_CCMR1(...)        BITS(TIM_, CCMR1, __VA_ARGS__)
#define TIM_CCMR2(...)        BITS(TIM_, CCMR2, __VA_ARGS__)
#define TIM_CCER(...)         BITS(TIM_, CCER, __VA_ARGS__)
#define TIM_CNT(...)          BITS(TIM_, CNT, __VA_ARGS__)
#define TIM_PSC(...)          BITS(TIM_, PSC, __VA_ARGS__)
#define TIM_ARR(...)          BITS(TIM_, ARR, __VA_ARGS__)
#define TIM_CCR1(...)         BITS(TIM_, CCR1, __VA_ARGS__)
#define TIM_CCR2(...)         BITS(TIM_, CCR2, __VA_ARGS__)
#define TIM_CCR3(...)         BITS(TIM_, CCR3, __VA_ARGS__)
#define TIM_CCR4(...)         BITS(TIM_, CCR4, __VA_ARGS__)
#define TIM_DCR(...)          BITS(TIM_, DCR, __VA_ARGS__)
#define TIM_DMAR(...)         BITS(TIM_, DMAR, __VA_ARGS__)

// --- USART ---
#define USART_SR(...)         BITS(USART_, SR, __VA_ARGS__)
#define USART_DR(...)         BITS(USART_, DR, __VA_ARGS__)
#define USART_BRR(...)        BITS(USART_, BRR, __VA_ARGS__)
#define USART_CR1(...)        BITS(USART_, CR1, __VA_ARGS__)
#define USART_CR2(...)        BITS(USART_, CR2, __VA_ARGS__)
#define USART_CR3(...)        BITS(USART_, CR3, __VA_ARGS__)
#define USART_GTPR(...)       BITS(USART_, GTPR, __VA_ARGS__)

// --- SPI ---
#define SPI_CR1(...)          BITS(SPI_, CR1, __VA_ARGS__)
#define SPI_CR2(...)          BITS(SPI_, CR2, __VA_ARGS__)
#define SPI_SR(...)           BITS(SPI_, SR, __VA_ARGS__)
#define SPI_DR(...)           BITS(SPI_, DR, __VA_ARGS__)
#define SPI_CRCPR(...)        BITS(SPI_, CRCPR, __VA_ARGS__)
#define SPI_RXCRCR(...)       BITS(SPI_, RXCRCR, __VA_ARGS__)
#define SPI_TXCRCR(...)       BITS(SPI_, TXCRCR, __VA_ARGS__)
#define SPI_I2SCFGR(...)      BITS(SPI_, I2SCFGR, __VA_ARGS__)
#define SPI_I2SPR(...)        BITS(SPI_, I2SPR, __VA_ARGS__)

// --- I2C ---
#define I2C_CR1(...)          BITS(I2C_, CR1, __VA_ARGS__)
#define I2C_CR2(...)          BITS(I2C_, CR2, __VA_ARGS__)
#define I2C_OAR1(...)         BITS(I2C_, OAR1, __VA_ARGS__)
#define I2C_OAR2(...)         BITS(I2C_, OAR2, __VA_ARGS__)
#define I2C_DR(...)           BITS(I2C_, DR, __VA_ARGS__)
#define I2C_SR1(...)          BITS(I2C_, SR1, __VA_ARGS__)
#define I2C_SR2(...)          BITS(I2C_, SR2, __VA_ARGS__)
#define I2C_CCR(...)          BITS(I2C_, CCR, __VA_ARGS__)
#define I2C_TRISE(...)        BITS(I2C_, TRISE, __VA_ARGS__)

// --- ADC ---
#define ADC_SR(...)           BITS(ADC_, SR, __VA_ARGS__)
#define ADC_CR1(...)          BITS(ADC_, CR1, __VA_ARGS__)
#define ADC_CR2(...)          BITS(ADC_, CR2, __VA_ARGS__)
#define ADC_SMPR1(...)        BITS(ADC_, SMPR1, __VA_ARGS__)
#define ADC_SMPR2(...)        BITS(ADC_, SMPR2, __VA_ARGS__)
#define ADC_JOFR1(...)        BITS(ADC_, JOFR1, __VA_ARGS__)
#define ADC_JOFR2(...)        BITS(ADC_, JOFR2, __VA_ARGS__)
#define ADC_JOFR3(...)        BITS(ADC_, JOFR3, __VA_ARGS__)
#define ADC_JOFR4(...)        BITS(ADC_, JOFR4, __VA_ARGS__)
#define ADC_HTR(...)          BITS(ADC_, HTR, __VA_ARGS__)
#define ADC_LTR(...)          BITS(ADC_, LTR, __VA_ARGS__)
#define ADC_SQR1(...)         BITS(ADC_, SQR1, __VA_ARGS__)
#define ADC_SQR2(...)         BITS(ADC_, SQR2, __VA_ARGS__)
#define ADC_SQR3(...)         BITS(ADC_, SQR3, __VA_ARGS__)
#define ADC_JSQR(...)         BITS(ADC_, JSQR, __VA_ARGS__)
#define ADC_JDR1(...)         BITS(ADC_, JDR1, __VA_ARGS__)
#define ADC_JDR2(...)         BITS(ADC_, JDR2, __VA_ARGS__)
#define ADC_JDR3(...)         BITS(ADC_, JDR3, __VA_ARGS__)
#define ADC_JDR4(...)         BITS(ADC_, JDR4, __VA_ARGS__)
#define ADC_DR(...)           BITS(ADC_, DR, __VA_ARGS__)

// --- EXTI ---
#define EXTI_IMR(...)         BITS(EXTI_, IMR, __VA_ARGS__)
#define EXTI_EMR(...)         BITS(EXTI_, EMR, __VA_ARGS__)
#define EXTI_RTSR(...)        BITS(EXTI_, RTSR, __VA_ARGS__)
#define EXTI_FTSR(...)        BITS(EXTI_, FTSR, __VA_ARGS__)
#define EXTI_SWIER(...)       BITS(EXTI_, SWIER, __VA_ARGS__)
#define EXTI_PR(...)          BITS(EXTI_, PR, __VA_ARGS__)

// --- PWR ---
#define PWR_CR(...)           BITS(PWR_, CR, __VA_ARGS__)
#define PWR_CSR(...)          BITS(PWR_, CSR, __VA_ARGS__)

// --- FLASH ---
#define FLASH_ACR(...)        BITS(FLASH_, ACR, __VA_ARGS__)
#define FLASH_KEYR(...)       BITS(FLASH_, KEYR, __VA_ARGS__)
#define FLASH_OPTKEYR(...)    BITS(FLASH_, OPTKEYR, __VA_ARGS__)
#define FLASH_SR(...)         BITS(FLASH_, SR, __VA_ARGS__)
#define FLASH_CR(...)         BITS(FLASH_, CR, __VA_ARGS__)
#define FLASH_AR(...)         BITS(FLASH_, AR, __VA_ARGS__)
#define FLASH_OBR(...)        BITS(FLASH_, OBR, __VA_ARGS__)
#define FLASH_WRPR(...)       BITS(FLASH_, WRPR, __VA_ARGS__)

// --- BKP ---
#define BKP_DR1(...)          BITS(BKP_, DR1, __VA_ARGS__)
#define BKP_DR2(...)          BITS(BKP_, DR2, __VA_ARGS__)
// ...repeat for all BKP_DRx as needed
#define BKP_RTCCR(...)        BITS(BKP_, RTCCR, __VA_ARGS__)
#define BKP_CR(...)           BITS(BKP_, CR, __VA_ARGS__)
#define BKP_CSR(...)          BITS(BKP_, CSR, __VA_ARGS__)

// --- CRC ---
#define CRC_DR(...)           BITS(CRC_, DR, __VA_ARGS__)
#define CRC_IDR(...)          BITS(CRC_, IDR, __VA_ARGS__)
#define CRC_CR(...)           BITS(CRC_, CR, __VA_ARGS__)

// --- WWDG ---
#define WWDG_CR(...)          BITS(WWDG_, CR, __VA_ARGS__)
#define WWDG_CFR(...)         BITS(WWDG_, CFR, __VA_ARGS__)
#define WWDG_SR(...)          BITS(WWDG_, SR, __VA_ARGS__)

// --- IWDG ---
#define IWDG_KR(...)          BITS(IWDG_, KR, __VA_ARGS__)
#define IWDG_PR(...)          BITS(IWDG_, PR, __VA_ARGS__)
#define IWDG_RLR(...)         BITS(IWDG_, RLR, __VA_ARGS__)
#define IWDG_SR(...)          BITS(IWDG_, SR, __VA_ARGS__)

// --- RTC ---
#define RTC_CRH(...)          BITS(RTC_, CRH, __VA_ARGS__)
#define RTC_CRL(...)          BITS(RTC_, CRL, __VA_ARGS__)
#define RTC_PRLH(...)         BITS(RTC_, PRLH, __VA_ARGS__)
#define RTC_PRLL(...)         BITS(RTC_, PRLL, __VA_ARGS__)
#define RTC_DIVH(...)         BITS(RTC_, DIVH, __VA_ARGS__)
#define RTC_DIVL(...)         BITS(RTC_, DIVL, __VA_ARGS__)
#define RTC_CNTH(...)         BITS(RTC_, CNTH, __VA_ARGS__)
#define RTC_CNTL(...)         BITS(RTC_, CNTL, __VA_ARGS__)
#define RTC_ALRH(...)         BITS(RTC_, ALRH, __VA_ARGS__)
#define RTC_ALRL(...)         BITS(RTC_, ALRL, __VA_ARGS__)
Adrift
Вымогатель припоя
Сообщения: 540
Зарегистрирован: Вт окт 01, 2024 15:22:33

Re: STM32 новичку в ARM что к чему

Сообщение Adrift »

[uquote="a5021",url="/forum/viewtopic.php?p=4713497#p4713497"]

Код: Выделить всё

TIM_CR1(OPM, DIR, CEN)
[/uquote]
Проходили же это уже, или думаете поле RESET есть у множественной периферии, а с тем же DIR будет иначе? Если у TIMx это 4-й бит, то у LPTIM/HRTIM - 16-й. Молчу уже про DMA/USB/I2C...
Уош
Опытный кот
Сообщения: 700
Зарегистрирован: Вс мар 23, 2025 14:56:55

Re: STM32 новичку в ARM что к чему

Сообщение Уош »

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

Код: Выделить всё

GPIOA->CRL &= 
GPIOA->CRL |= 
будет одна

Код: Выделить всё

GPIOA->CRL =
, а что такое 0xabcd напишется в комментарии.
Хотя, при поиске ошибки, конечно, удобнее вместо 0xabcd увидеть человеческое.
a5021
Друг Кота
Сообщения: 6452
Зарегистрирован: Пт сен 13, 2013 13:11:31

Re: STM32 новичку в ARM что к чему

Сообщение a5021 »

[uquote="Adrift",url="/forum/viewtopic.php?p=4713501#p4713501"]Проходили же это уже, или думаете поле RESET есть у множественной периферии, а с тем же DIR будет иначе? Если у TIMx это 4-й бит, то у LPTIM/HRTIM - 16-й. Молчу уже про DMA/USB/I2C...[/uquote]
с макросами вида PERIPH_REG(..) будет ровно то, что описано в CMSIS заголовочнике на соотв. камень, а TIM_CR1(...) и LPTIM_CR(..) -- это разные макросы, которые порождают разные наборы битов. позиции битов пусть считают те, у кого времени много. я, как раз, пытаюсь в обратном направлении двигаться.
Adrift
Вымогатель припоя
Сообщения: 540
Зарегистрирован: Вт окт 01, 2024 15:22:33

Re: STM32 новичку в ARM что к чему

Сообщение Adrift »

Ага, этот DIR и т.д. не задефайнены, а просто склеиваются, тогда в принципе можно так делать, но все равно вряд ли нужно ) Допустим было TIM_CCER_CC1E, можно навести на него мышей и получить подсказку, а если станет просто CC1E, то даже этого не будет. Опять же раньше набрал "TIM_CCER_" и видишь все поля, теперь нужно набирать вслепую. Плюс куча макросов нужна или вы для всех серий уже готовые и проверенные поставляете? )
a5021
Друг Кота
Сообщения: 6452
Зарегистрирован: Пт сен 13, 2013 13:11:31

Re: STM32 новичку в ARM что к чему

Сообщение a5021 »

[uquote="Уош",url="/forum/viewtopic.php?p=4713502#p4713502"]И вместо двух строчек

Код: Выделить всё

GPIOA->CRL &= 
GPIOA->CRL |= 
будет одна[/uquote]
да хоть в оба регистра сразу

Код: Выделить всё

#define PORT_A_CONFIG ...чего-то-там
*(__IO uint64_t*) GPIOA_BASE = PORT_A_CONFIG;
важно не это, а то, чтобы PORT_A_CONFIG состоял из понятных определений.

Добавлено after 12 minutes 42 seconds:
[uquote="Adrift",url="/forum/viewtopic.php?p=4713510#p4713510"]Допустим было TIM_CCER_CC1E, можно навести на него мышей и получить подсказку, ... раньше набрал "TIM_CCER_" и видишь все поля[/uquote]
каким образом существование каких-либо макросов может отобрать эту возможность у IDE? и я уже говорил, что если не лениться, то показывать оно может начать чего только захочешь.
Плюс куча макросов нужна или вы для всех серий уже готовые и проверенные поставляете?
я написал их сегодня в ходе обдумывания концепта. не сказать, чтобы надорвался.
Adrift
Вымогатель припоя
Сообщения: 540
Зарегистрирован: Вт окт 01, 2024 15:22:33

Re: STM32 новичку в ARM что к чему

Сообщение Adrift »

[uquote="a5021",url="/forum/viewtopic.php?p=4713519#p4713519"]каким образом существование каких-либо макросов может отобрать эту возможность у IDE? и я уже говорил, что если не лениться, то показывать оно может начать чего только захочешь.[/uquote]
Покажите мне подсказку для CC1E, потому что у меня с решарпером ее нет, а мощнее решарпера я ничего не знаю.
a5021 писал(а):я написал их сегодня в ходе обдумывания концепта. не сказать, чтобы надорвался.
Но писать то придется, а преимущества вашего подхода слишком незначительны чтобы компенсировать это вместе с прочими недостатками. И писали вы для одного из самых примитивных мк. Структуры для F103 в стандартном хедере занимают 420 строк, а для H563 - 1450. Для H503 хедер другой, т.е. даже в рамках одной серии не надорваться нужно раз 6, а серий полно, мне нужно хотя бы 5. По нормальному это уже нужно утилитку писать )
Аватара пользователя
ARV
Ум, честь и совесть. И скромность.
Сообщения: 18546
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск
Контактная информация:

Re: STM32 новичку в ARM что к чему

Сообщение ARV »

Это всё для темы про С/С++, так как к STM32 непосредственно не относится.
Сам подход переноса специфических макросов внутрь универсальных представляется вполне логичным, но только в том случае, если одинаковые периферийные сущности в разных МК описаны разными макросами. Ранее этим, например, страдал Атмел AVR, у которых для некоторых МК таймеры описывались макросами TIMERn_****, для других TIMn_**** и так далее.
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Аватара пользователя
КРАМ
Друг Кота
Сообщения: 25220
Зарегистрирован: Чт янв 10, 2008 22:01:02
Откуда: Московская область, Фрязино

Re: STM32 новичку в ARM что к чему

Сообщение КРАМ »

[uquote="Уош",url="/forum/viewtopic.php?p=4713502#p4713502"]что такое 0xabcd напишется в комментарии.
Хотя, при поиске ошибки, конечно, удобнее вместо 0xabcd увидеть человеческое.[/uquote]
Тут есть нюанс.
При работе с кодом часто требуется оперативно копипастить и менять некоторое количество бит.
Например, потребовалось применить еще один таймер. Копируется инит близкого ему по функционалу другого и оперативно изменяются настройки. Тут и открывается как удобно, а как нет.
Я не программист. Я просто погулять вышел. И мне создавать макросы нахрен не облокотилось. Поэтому применяются хедеры производителя.
Приступив к работе с Артери вместо СТМ, я внезапно обнаружил, что, несмотря на идентичность почти всей периферии, хедеры написаны не в дефайнах констант, а как структуры. Дефайны конечно тоже есть, но они для читабельности значений полей структур. И они не требуют перректальных инверсий и логических операций в ините.
И потому очень наглядная настройка посредством определения значения поля структуры стала чрезвычайно читабельной и удобной. В отличии от.
:)
ЗЫ. К слову. У Микрочипа в XC8/XC16/XC32 сделано тоже с помощью структур.
Ответить

Вернуться в «ARM»