Эти макросы берутся из хидера от STMicroelectronics, конечно это не исключает возможных ошибок, но шансы столкнуться с ошибками в них довольно малы т.к. эти контроллеры очень широко используют. Разве что какой-нибудь диверсант решит переопределить макрос, думаю что заморочки такого плана могут иметь смысл только в устройствах от которых напрямую зависит безопасность людей. А насчет else if, понятно что тут лишняя проверка в одном из вариантов, но ведь это выражение все равно будет вычислено на этапе компиляции. Честно говоря else if мне не понравился тем что портит выравнивание, увеличивает объем кода и при этом никак не влияет на прошивку, которая окажется в контроллере, так что я оставил просто if :-)
Например, в микроконтроллерах STM есть Bit Banding (атомарная модификация отдельных битов), который полезен для модификации некоторых регистров, но он поддерживается не во всем адресном пространстве, т.е. по хорошему нужно делать валидацию чтобы не дебажить потом часами устройство из-за одной опечатки. Но валидация во время выполнения впустую тратит процессорное время т.к. в большинстве случаев нужный адрес известен уже на этапе компиляции, а самое главное, валидация занимает место во flash памяти, которой зачастую не так много как хотелось бы. В данном случае constexpr подходит просто идеально, позволяя абсолютно бесплатно выполнить вычисление нужного адреса и его валидацию еще на этапе компиляции. PS: На мой взгляд constexpr - фича крайне полезная, в моем случае она позволила убрать кучу проверок и вычислений из рантайма и уменьшить объем прошивки примерно на 20%.
Да, все верно, я не стал экспериментировать с чтением по 4 байта т.к. других проблем хватало, поэтому что будет в этом случае не знаю, да и в даташите про USB четко написано «Dedicated packet buffer memory SRAM access scheme: 1 x 16bit / word».
Поэтому у меня так же чтение/запись по 2 байта, только инкремент указателя на 2 приходится делать. И при чтении я тоже копирую из PMA во внешний буфер, хотя это делалось больше из соображений передачи данных которые могут превышать размер буфера в PMA.
Мне очень помогла эта статья, правда она на немецком и код у них довольно сильно запутан из-за того что все в кучу намешано, но некоторые моменты с логикой работы USB действительно удалось подсмотреть там.
Несколько месяцев назад успешно завершил написание своего USB CDC велосипеда на регистрах, тоже использовал C++, constexpr и шаблоны, правда у меня не настолько все зашаблонизировано.
Для размещения буферов мне показалось проще определить в линкере новую секцию для PMA, дальше достаточно определить обычную переменную с атрибутом __attribute__((section(".usb_pma"), used)) и она автоматом попадет куда нужно, без дополнительных телодвижений.
Правда окончательный адрес и размер буфера для записи в регистры все равно приходится вычислять на этапе выполнения т.к. память PMA мапится на шине контроллера кусками по 2 байта которые выровнены на границу 4 байта (проще говоря с пропусками, ну во всяком случае для STM32F303VCT6), а в constexpr невозможно делить адреса переменных.
Эти макросы берутся из хидера от STMicroelectronics, конечно это не исключает возможных ошибок, но шансы столкнуться с ошибками в них довольно малы т.к. эти контроллеры очень широко используют. Разве что какой-нибудь диверсант решит переопределить макрос, думаю что заморочки такого плана могут иметь смысл только в устройствах от которых напрямую зависит безопасность людей.
А насчет else if, понятно что тут лишняя проверка в одном из вариантов, но ведь это выражение все равно будет вычислено на этапе компиляции. Честно говоря else if мне не понравился тем что портит выравнивание, увеличивает объем кода и при этом никак не влияет на прошивку, которая окажется в контроллере, так что я оставил просто if :-)
Например, в микроконтроллерах STM есть Bit Banding (атомарная модификация отдельных битов), который полезен для модификации некоторых регистров, но он поддерживается не во всем адресном пространстве, т.е. по хорошему нужно делать валидацию чтобы не дебажить потом часами устройство из-за одной опечатки.
Но валидация во время выполнения впустую тратит процессорное время т.к. в большинстве случаев нужный адрес известен уже на этапе компиляции, а самое главное, валидация занимает место во flash памяти, которой зачастую не так много как хотелось бы.
В данном случае constexpr подходит просто идеально, позволяя абсолютно бесплатно выполнить вычисление нужного адреса и его валидацию еще на этапе компиляции.
PS: На мой взгляд constexpr - фича крайне полезная, в моем случае она позволила убрать кучу проверок и вычислений из рантайма и уменьшить объем прошивки примерно на 20%.
Пример кода
Поэтому у меня так же чтение/запись по 2 байта, только инкремент указателя на 2 приходится делать. И при чтении я тоже копирую из PMA во внешний буфер, хотя это делалось больше из соображений передачи данных которые могут превышать размер буфера в PMA.
Мне очень помогла эта статья, правда она на немецком и код у них довольно сильно запутан из-за того что все в кучу намешано, но некоторые моменты с логикой работы USB действительно удалось подсмотреть там.
Для размещения буферов мне показалось проще определить в линкере новую секцию для PMA, дальше достаточно определить обычную переменную с атрибутом __attribute__((section(".usb_pma"), used)) и она автоматом попадет куда нужно, без дополнительных телодвижений.
Правда окончательный адрес и размер буфера для записи в регистры все равно приходится вычислять на этапе выполнения т.к. память PMA мапится на шине контроллера кусками по 2 байта которые выровнены на границу 4 байта (проще говоря с пропусками, ну во всяком случае для STM32F303VCT6), а в constexpr невозможно делить адреса переменных.