Все, кто пользовался отладкой на уровне регистров под STM32CubeIDE, замечал, что список регистров идёт вразнобой, без какой-либо логики. Например, список для типичного STM32F407xx выглядит таким образом, здесь у нас порты ввода/вывода:

Это у нас UART/USART:
Это таймеры:
Как видим, все устройства идут не по порядку, а вразнобой. И это ещё цветочки. Есть МК, где всё это перемешано ещё хуже, и приходится искать, где и что у нас находится. Кроме этого, если присмотреться, есть периферия, которой на данном кристалле вообще нет. Такой подход очень неудобен и мешает отладке.
С первого взгляда может показаться, что нет никакой логики, но посмотрев даташит, раздел распределения памяти, можно увидеть, что таблица периферии повторяет порядок следования регистров в отладчике. Я задавал вопрос фирме ST, какого ... так сделано. Мне ответили, что у них работы много, а людей мало, вам надо, вы и занимайтесь этим. Ну я и занялся. Для этого нужно всего ничего, найти файл вот по этому пути в каталоге с установленной STM32CubeIDE:
/plugin/com.st.stm32cube.ide.mcu.productdb.debug/resources/cmsis/STMicroelectronics_CMSIS_SVD/STM32F407.svd
Затем я скопировал его в каталог, где у меня находятся все драйвера данного кристалла, назвал STM32F407_main.svd и, первым делом, отсортировал всю периферию. Получил вот такой порядок:
Т. е. я разбил по группам и сделал сортировку в группе, группы получились такие:
- аналоговая периферия
- порты ввода/вывода
- таймеры
- внешние интерфейсы
- остальное
В каждой группе периферия идёт примерно в том порядке, в каком она идёт в STM32CubeMX.
Дальше я скопировал получившийся файл в тот же каталог с именем, схожим с маркировкой кристалла. В моём случае - STM32F407VET.svd - и грохнул там упоминание о периферии, которой нет на этом кристалле. Грохнул не всё, в разделе "Остальное" остались описания регистров, с которыми было лень возиться. Теперь список периферии выглядит так:
Ушла часть портов GPIO и так, по мелочи. А теперь о том, что это за файл и как устроен. Подключается файл здесь:
Выбираем слева "CMSIS-SVD Settings" и кнопкой "Browse" выбираем нужный нам файл. Структура файла такова - первым идёт заголовок, он нам неинтересен, и менять его не стоит. А интересует нас всё, что заключено между тегами <peripherals> ... <peripherals>.
Здесь и находится описание периферии, регистров и битов регистров:
<peripherals>
<peripheral> <!--Ветка описания одного устройства-->
<name>RCC</name> <!--Имя устройства-->
<description>Reset and clock control</description> <!--Описание, (для чего оно)-->
<groupName>RCC</groupName> <!--Группа к которой относится устройство-->
<baseAddress>0x40023800</baseAddress> <!--Стартовый адрес в памяти-->
<addressBlock> <!--Занимаемое адресное пространство-->
<offset>0x0</offset> <!--Смещение от базового адреса-->
<size>0x400</size> <!--Размер занимаемого блока-->
<usage>registers</usage> <!--Используется регистрами-->
</addressBlock>
<interrupt> <!--Блок прерывания-->
<name>RCC</name> <!--Имя прерывания-->
<description>RCC global interrupt</description> <!--Описание-->
<value>5</value> <!--Номер вектора прерывания-->
</interrupt>
<registers> <!--Регистры-->
<register>
<name>CR</name> <!--Имя регистра-->
<displayName>CR</displayName> <!--Имя показываемое в списке-->
<description>clock control register</description>
<addressOffset>0x0</addressOffset> <!--Смещение от базового адреса-->
<size>0x20</size> <!--Количество занимаемых бит-->
<resetValue>0x00000083</resetValue> <!--Значение при сбросе-->
<fields> <!--Блок полей-->
<field> <!--Поле-->
<name>PLLI2SRDY</name> <!--Имя поля-->
<description>PLLI2S clock ready flag</description> <!--Описание-->
<bitOffset>27</bitOffset> <!--Смещение поля относительно начала регистра-->
<bitWidth>1</bitWidth> <!--Количество бит в поле-->
<access>read-only</access> <!--Способ доступа-->
</field>
<field>
...
</field>
</fields>
</register>
<register>
...
</register>
<registers>
</peripheral>
<peripheral>
...
</peripheral>
</pepherals>
Получается такая картина: файл разделён на блоки ограниченные тегами <peripheral> ... </peripheral>. В этих тегах описываются конкретные периферийные устройства. Далее идёт заголовок периферийного устройства, где указывается его базовый адрес в адресном пространстве МК, прерывания, если они есть, их именование в системе и номер вектора.
Далее тегами <register> ... </register> описываются все регистры, которые принадлежат данной периферии. Сколько регистров, столько и блоков. Каждый блок имеет также заголовок, в котором описывается имя регистра, смещение относительно базового адреса самого периферийного устройства, количество активных битов, значение при сбросе.
Теперь идут теги <field> ... </field> - в них идёт описание конкретных битов. Опять же имя, описание, смещение относительно адреса данного регистра, количество битов занимаемых полем и способ доступа: чтение, запись, чтение/запись и т. д.
Все данные структуры повторяются столько раз, сколько периферийных устройств присутствует в данном микроконтроллере.
Теперь о нюансах... Если несколько периферийных устройств имеют одинаковую структуру, каждое из них не описывается отдельно. Просто описывается одно, а другие описываются со ссылкой на предыдущее.
<peripheral derivedFrom="GPIOC"> <!--GPIOD--> <name>GPIOD</name> <baseAddress>0X40020C00</baseAddress> </peripheral>
Например GPIOC и GPIOD имеют одинаковую структуру, но разный базовый адрес. Описываем GPIOC, а у GPIOD ссылаемся на структуру GPIOC - <peripheral derivedFrom="GPIOC">, и указываем только новый базовый адрес - <baseAddress>0X40020C00</baseAddress>. Главное, чтобы периферия, на которую ссылаемся, была описана раньше.
Вот в принципе и всё, выкладываю набор проектов и файлов: STM32Lib. Здесь у нас каталог для предыдущих статей, но немного видоизменённый, добавились SVD-файлы для контроллеров, на которые мне нужно было срочно их сделать. Все каталоги CMSIS из проектов я перенёс сюда для уменьшения размера проектов. Позже я расскажу подробнее, что именно изменилось.









