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

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

Вс май 04, 2025 14:00:05

a5021 тут недавно практически доказал, что для "перегрузки" байтами USARTа (т.е. для возникновения пропусков) надо создать невероятно дикую нагрузку остальной периферии, что представляется маловероятным.
a5021 там написал полнейшую галиматью, из которой только следует, что он совершенно не понял о чём шла речь. Примерно как вы не понимаете очевидных вещей - как делить поток байтов на кадры Modbus-RTU. В этом вы с ним схожи.
Речь не шла ни о какой "перегрузки байтами USARTа". Выше по комментам видно, что другие люди прекрасно поняли о чём шла речь:
Как выше правильно заметили, обычно, у МК есть много более приоритетных задач, чем приём одного байта. Вот поэтому весь обмен через UART нужно строить исключительно с использованием DMA: приняли фрейм, появилось время, тогда и обработали его.
не поняли только вы на пару с a5021
Как обычно - "не в коня корм". :dont_know:

Добавлено after 12 minutes 58 seconds:
То есть задействование трех периферийных устройств вместо одного считается правильным и эффективным решением?! Мда... Неожиданно.
В МК множество периферийных узлов. Они предназначены чтобы разгрузить самый главный узел - 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 раз(а).

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

Вс май 04, 2025 14:07:03

Теперь еще и единообразие инициализации потеряли

эта музыка будет вечной и вот почему:
СпойлерИзображение

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

Изображение

не ленись, выбирай, настраивай..

Добавлено after 4 minutes 29 seconds:
a5021 там написал полнейшую галиматью, из которой только следует, что он совершенно не понял о чём шла речь.

и опять ни слова конкретики. на соревнованиях базарных баб ваши шансы не вызывают сомнений.
Вложения
r2.jpg
(35.82 KiB) Скачиваний: 450
r1.jpg
(40.68 KiB) Скачиваний: 530

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

Вс май 04, 2025 14:10:23

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

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

Вс май 04, 2025 14:52:22

как эта схема спасает от того, что в этот момент пишущий проглотил муху и выбрал не тот пункт из списка?

Функция ждет аргумент типа TimSlaveMode в качестве первого параметра, любое другое значение приведет к ошибке компиляции. В худшем случае из десятка допустимых режимов можно выбрать не тот который требуется, а в рантайме там еще дополнительные проверки есть. У вас можно подставить любой аргумент который приводится к uint32_t.

a5021 писал(а):а помогаек всяких без счета сейчас:
Спойлер[spoiler]Изображение

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

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

Вс май 04, 2025 15:05:28

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 каналам, которые не допускают пропусков, ибо на результатах их измерений построены защиты. Вот вам и приоритетные задачи. И как вишенка- рантайм ПЛК.

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

Вс май 04, 2025 15:43:21

Функция ждет аргумент типа TimSlaveMode в качестве первого параметра, любое другое значение приведет к ошибке компиляции.

еще раз медленно: не то значение из списка. промахнулся.

Здорово, а букву наверно можно наугад вводить?

можно и наугад. и в вашем списке так тоже можно. если совсем не понимать, что делаешь, то ни одна схема не спасет.

а вы все оптимизациями имен по размеру занимаетесь )

ложный вывод. меня больше интересует наглядность.

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

Вс май 04, 2025 16:42:38

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

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

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

Вс май 04, 2025 17:20:38

ARV писал(а):к драйверу RS485 зато имеет

Я использую драйверы без этого сигнала, с автоопределением направления.
ARV писал(а):но ведь DMA не может в два "приемника" данные отправлять? или может? это я к тому, что CRC считать одновременно с "перемещением байта в буфер" все равно не получится?

Дальше как в анекдоте:
Поймал мужик золотую рыбку - та и говорит: "Исполню твое желание, отпусти меня!"
Мужик думал, думал да и говорит: "Хочу ссать водкой!"
Рыбка отвечает - "Запросто!"

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

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

Мужик: "Вчера была презентация - а сегодня за деньги и из горла!"

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

Вс май 04, 2025 17:53:39

а это делается программно, или "завести на вход" следует понимать буквально - изменить схему?
Если заранее подумали и заложили такой МК, в котором можно это сделать программно, то ничего в схеме менять не надо.

уверен, что рассказывать необязательно, т.к. вне зависимости от того, что именно я делаю, ваш вердикт все равно будет "не правильно".
Этим постом:
То есть задействование трех периферийных устройств вместо одного считается правильным и эффективным решением?! Мда... Неожиданно.
вы намекали, что мой подход "неэффективный". Не приводя никаких аргументов и не показывая "как будет эффективно" по вашему мнению. Какого ответа вы ещё ожидали на свой пост?

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

А насчёт указывания мне как и кому писать - оставьте ваши советы при себе. Хамлу под ником "a5021" я ответил ещё мягко, после его наезда:
на соревнованиях базарных баб ваши шансы не вызывают сомнений.


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

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

Вс май 04, 2025 19:02:21

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

А насчёт указывания мне как и кому писать - оставьте ваши советы при себе. Хамлу под ником "a5021" я ответил ещё мягко, после его наезда:
на соревнованиях базарных баб ваши шансы не вызывают сомнений.


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

Двумя руками поддерживаю jcxz. Тоже удивлён хамско-вызывающей манерой общения ARV. Думал, что это касалось только моей персоны, но оказалось, что нет, это тенденция.

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

Вс май 04, 2025 19:31:38

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

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

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

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

Пт май 09, 2025 22:51:49

опять я в поисках наглядности. показалось, что если наобъявлять макросов в формате
Код:
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__)

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

Пт май 09, 2025 23:26:27

Код:
TIM_CR1(OPM, DIR, CEN)

Проходили же это уже, или думаете поле RESET есть у множественной периферии, а с тем же DIR будет иначе? Если у TIMx это 4-й бит, то у LPTIM/HRTIM - 16-й. Молчу уже про DMA/USB/I2C...

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

Пт май 09, 2025 23:27:22

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

будет одна
Код:
GPIOA->CRL =
, а что такое 0xabcd напишется в комментарии.
Хотя, при поиске ошибки, конечно, удобнее вместо 0xabcd увидеть человеческое.

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

Пт май 09, 2025 23:48:49

Проходили же это уже, или думаете поле RESET есть у множественной периферии, а с тем же DIR будет иначе? Если у TIMx это 4-й бит, то у LPTIM/HRTIM - 16-й. Молчу уже про DMA/USB/I2C...

с макросами вида PERIPH_REG(..) будет ровно то, что описано в CMSIS заголовочнике на соотв. камень, а TIM_CR1(...) и LPTIM_CR(..) -- это разные макросы, которые порождают разные наборы битов. позиции битов пусть считают те, у кого времени много. я, как раз, пытаюсь в обратном направлении двигаться.

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

Пт май 09, 2025 23:52:18

Ага, этот DIR и т.д. не задефайнены, а просто склеиваются, тогда в принципе можно так делать, но все равно вряд ли нужно ) Допустим было TIM_CCER_CC1E, можно навести на него мышей и получить подсказку, а если станет просто CC1E, то даже этого не будет. Опять же раньше набрал "TIM_CCER_" и видишь все поля, теперь нужно набирать вслепую. Плюс куча макросов нужна или вы для всех серий уже готовые и проверенные поставляете? )

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

Сб май 10, 2025 01:04:34

И вместо двух строчек
Код:
GPIOA->CRL &=
GPIOA->CRL |=

будет одна

да хоть в оба регистра сразу
Код:
#define PORT_A_CONFIG ...чего-то-там
*(__IO uint64_t*) GPIOA_BASE = PORT_A_CONFIG;

важно не это, а то, чтобы PORT_A_CONFIG состоял из понятных определений.

Добавлено after 12 minutes 42 seconds:
Допустим было TIM_CCER_CC1E, можно навести на него мышей и получить подсказку, ... раньше набрал "TIM_CCER_" и видишь все поля

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

Плюс куча макросов нужна или вы для всех серий уже готовые и проверенные поставляете?

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

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

Сб май 10, 2025 01:36:15

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

Покажите мне подсказку для CC1E, потому что у меня с решарпером ее нет, а мощнее решарпера я ничего не знаю.

a5021 писал(а):я написал их сегодня в ходе обдумывания концепта. не сказать, чтобы надорвался.

Но писать то придется, а преимущества вашего подхода слишком незначительны чтобы компенсировать это вместе с прочими недостатками. И писали вы для одного из самых примитивных мк. Структуры для F103 в стандартном хедере занимают 420 строк, а для H563 - 1450. Для H503 хедер другой, т.е. даже в рамках одной серии не надорваться нужно раз 6, а серий полно, мне нужно хотя бы 5. По нормальному это уже нужно утилитку писать )

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

Сб май 10, 2025 07:28:38

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

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

Сб май 10, 2025 07:45:27

что такое 0xabcd напишется в комментарии.
Хотя, при поиске ошибки, конечно, удобнее вместо 0xabcd увидеть человеческое.

Тут есть нюанс.
При работе с кодом часто требуется оперативно копипастить и менять некоторое количество бит.
Например, потребовалось применить еще один таймер. Копируется инит близкого ему по функционалу другого и оперативно изменяются настройки. Тут и открывается как удобно, а как нет.
Я не программист. Я просто погулять вышел. И мне создавать макросы нахрен не облокотилось. Поэтому применяются хедеры производителя.
Приступив к работе с Артери вместо СТМ, я внезапно обнаружил, что, несмотря на идентичность почти всей периферии, хедеры написаны не в дефайнах констант, а как структуры. Дефайны конечно тоже есть, но они для читабельности значений полей структур. И они не требуют перректальных инверсий и логических операций в ините.
И потому очень наглядная настройка посредством определения значения поля структуры стала чрезвычайно читабельной и удобной. В отличии от.
:)
ЗЫ. К слову. У Микрочипа в XC8/XC16/XC32 сделано тоже с помощью структур.
Ответить