Изучать архитектуру контроллеров stm32 мы начнём с их карты памяти. Зачем это надо? Ну, наверное, потому, что программа управления контроллером записана в памяти, данные, которыми мы оперируем, находятся в памяти, различные регистры контроллера также спроецированы на определённые адреса памяти. То есть чтобы работать с контроллером, нам просто необходимо знать что где расположено (по каким адресам) и как со всем этим обращаться. Как раз в этом нам поможет карта памяти.
Разработчики ядра Cortex-M3 реализовали для него жёстко распределённое 4-х гигабайтное адресное пространство, которое в общем виде выглядит следующим образом:
- Код — эта область адресов используется для доступа к памяти, хранящей исполняемые коды.
- Внутреннее ОЗУ — по этим адресам доступна внутренняя оперативная память.
- Внутренняя периферия — по этим адресам доступны регистры управления внутренней периферией контроллера.
- Внешнее ОЗУ — эта область адресов используется для доступа к внешней оперативной памяти.
- Внешняя периферия — эта область адресов используется для доступа к внешней периферии.
- Системная область — по этим адресам доступно управление самим ядром.
Ещё раз скажу, что описанное выше распределение памяти определяется ядром Cortex-M3, — это то, что получили для своих нужд разработчики контроллеров, решив отдать управление ими ядру Cortex-M3. Естественно, что в конкретных линейках контроллеров есть свои нюансы распределения памяти, например, какие-то области могут не использоваться, какие-то проецироваться одна на другую и так далее.
Карту памяти конкретного контроллера всегда можно найти в даташите на этот контроллер. А даташит, как я уже говорил, всегда можно найти на вкладке «Books» менеджера проектов.
В общем виде карта памяти контроллеров STM32 выглядит так, как на рисунке ниже.
Вцелом, тут практически всё понятно, прояснения пожалуй требуют только два момента.
Во-первых, у вас наверняка возникает вопрос, — Что это за «псевдонимизируемая» область памяти? Такое замысловатое название она получила потому, что я просто не знал как лучше перевести на русский язык выражение aliasing area. Смысл тут в том, что в зависимости от выбранного способа загрузки (выбирается сочетанием уровней сигналов на ногах boot0, boot1) эта область адресов может быть назначена псевдонимом flash-памяти или служебной области памяти. Соответственно, обращение по этим адресам реально будет приводить к обращению во flash или в служебную область памяти.
Например, если сочетанием ног boot0, boot1 выбрана загрузка с flash, то «псевдонимизируемая» область назначается псевдонимом flash-памяти, в результате чего flash-память становится доступна сразу по двум диапазонам адресов — начиная с 0x00000000 и начиная с 0x08000000. То есть теперь чтение/запись по адресу 0x00000000 приведёт к чтению/записи по адресу 0x08000000 (начало flash-памяти), чтение/запись по адресу 0x00000004 — к чтению/записи по адресу 0x08000004 и так далее.
Во-вторых, хотелось бы по-подробнее рассмотреть две области адресов, — адреса, предназначенные для внутреннего ОЗУ и адреса, предназначенные для внутренней периферии. Если вы ещё раз посмотрите на карту памяти контроллеров STM32, то увидите, что в каждой из этих областей есть диапазоны адресов, которые обозначены как «SRAM» и «регистры встроенной периферии контроллера», а есть диапазоны адресов, про которые сказано, что они «используются для доступа к отдельным битам» SRAM и регистров встроенной периферии, соответственно.
Это специальная фишка для удобства операций с отдельными битами, которая называется bit-band. По сути она является всё той же псевдонимизацией, только теперь псевдоним по другому адресу появляется не у байта или слова, а у каждого отдельного бита.
Зачем это надо? Традиционный способ изменить пару-тройку бит в байте, расположенном по определённому адресу, выглядит так: мы считываем нужный байт (слово / двойное слово) в какой-нибудь регистр, меняем нужные биты (например, с помощью логических операций), а потом результат записываем из регистра назад, по тому же адресу. Этот способ называется «чтение-модификация-запись».
В методе bit-band для каждого бита из области хранения данных есть псевдоним, обращаясь к которому можно сразу изменить нужный бит (операции «чтение-модификация-запись» контроллер сделает автоматически, без нашего участия).
Область адресов, по которым данные доступны традиционным образом называется bit-band region (в русскоязычной терминологии — область хранения бит). Именно такие области и подписаны на карте памяти как «SRAM» и «регистры встроенной периферии контроллера». Область адресов, в которой расположены псевдонимы отдельных бит из области хранения, называется bit-band alias (псевдонимы области хранения). Про такие области, на карте памяти написано, что они используются для доступа к отдельным битам.
Можно заметить, что область псевдонимов для доступа к отдельным битам в 32 раза больше области хранения бит. Это объясняется тем, что в области псевдонимов значащими являются
только младшие биты каждого 32-х битного слова (именно они и являются псевдонимами отдельного бита из области хранения). Почему именно так? Потому что контроллер-то у нас 32-х битный и оперировать мы всё равно будем 32-х битными словами, поэтому нужно, чтобы при изменении одного бита (а мы для этого будем писать в память целое 32-х битное слово) не затрагивались соседние биты.
Ну и самое интересное — каким образом вычислить адрес 32-х битного слова из области псевдонимов, младший бит которого является псевдонимом нужного нам бита из области хранения? Делается это по следующей формуле:
AAW = SAR + OWBR * 0x20 + BN * 4 , где
AAW (Address of Alias World) — адрес слова, содержащего псевдоним нужного бита
SAR (Start of Alias Region) — начальный адрес области доступа к отдельным битам
OWBR (Offset of World in Bit-band Region) — смещение слова из области хранения, содеращего нужный бит, относительно начала области хранения
BN (Bit Number) — номер бита
Например, нам нужно установить в единицу 3-й бит в слове по адресу 0x20000008. Этот бит находится в SRAM, то есть начальный адрес области доступа к отдельным битам (SAR) у нас будет равен 0x22000000. Смещение слова из области хранения, содержащего нужный бит, относительно начала области хранения (OWBR) будет равно 0x20000008 — 0x20000000 = 8. Номер бита (BN), как мы уже сказали, равен 3.
Вычисляем адрес слова, которое содержит псевдоним нужного нам бита: AAW = 0x22000000 + 8 * 0x20 + 3 * 4 = 2200010C. Вот и всё, теперь записав по этому адресу любое слово, содержащее в младшем бите единицу, мы фактически получим установку в единицу третьего бита в слове по адресу 0x20000008. Старшие биты записываемого слова, как я уже говорил, значения не имеют. Если мы, наоборот, считываем слово из области доступа к отдельным битам, то старшие биты всегда читаются нулями.
На сегодня всё. А дальше мы поговорим о том, как контроллер стартует, о режимах его работы, о регистрах… ну и ещё о чём-нибудь.
- Часть 1. Установка MDK, создание проекта, основы Keil uVision
- Часть 2. Команды и директивы ассемблера, структура и синтаксис программы. Первая программа для STM32
- Часть 3. Карта памяти контроллеров STM32, доступ к отдельным битам памяти
- Часть 4. Регистры, старт и режимы работы контроллеров STM32
- Часть 5. Как залить прошивку в контроллер
- Часть 6. Настройка системы тактирования
- Часть 7. Работа с портами ввода-вывода
- Часть 8. Процедуры на ассемблере для STM32
- Часть 9. Система прерываний
- Часть 10. CMSIS, использование стандартных библиотек и функций
- Часть 11. Подключение и использование драйверов из пакета StdPeriph
- Часть 12. Работа с модулями USART и UART.
- Часть 13. Работа с модулями ADC
- Часть 14. Использование DMA
- Часть 15. Таймеры. Глава 1 — Введение. Простейшие таймеры
- Часть 15. Таймеры. Глава 2 — Таймеры общего назначения TIM9 — TIM14
- Часть 15. Таймеры. Глава 3 — Таймеры общего назначения TIM2 — TIM5
- Часть 15. Таймеры. Глава 4 — Продвинутые таймеры TIM1, TIM8
- Часть 16. Создание устройства USB HID в Keil uVision при помощи библиотечного компонента USB
- Приложение 1. Набор инструкций THUMB-2 и особенности их использования
- Приложение 2. Таблица векторов прерываний для семейств STM32F101, STM32F102, STM32F103
- Приложение 3. Драйвера и функции библиотеки StdPeriph