Код - эта область адресов используется для доступа к памяти, хранящей исполняемые коды.
Внутреннее ОЗУ - по этим адресам доступна внутренняя оперативная память.
Внутренняя периферия - по этим адресам доступны регистры управления внутренней периферией контроллера.
Внешнее ОЗУ - эта область адресов используется для доступа к внешней оперативной памяти.
Внешняя периферия - эта область адресов используется для доступа к внешней периферии.
Системная область - по этим адресам доступно управление самим ядром.
"Псевдонимизируемая" область памяти - перевод на русский язык выражение aliasing area. Смысл тут в том, что в зависимости от выбранного способа загрузки (выбирается сочетанием уровней сигналов на ногах boot0, boot1) эта область адресов может быть назначена псевдонимом flash-памяти или служебной области памяти. Соответственно, обращение по этим адресам реально будет приводить к обращению во flash или в служебную область памяти.
Например, если сочетанием ног boot0, boot1 выбрана загрузка с flash, то "псевдонимизируемая" область назначается псевдонимом flash-памяти, в результате чего flash-память становится доступна сразу по двум диапазонам адресов - начиная с 0x00000000 и начиная с 0x08000000. То есть теперь чтение/запись по адресу 0x00000000 приведёт к чтению/записи по адресу 0x08000000 (начало flash-памяти), чтение/запись по адресу 0x00000004 - к чтению/записи по адресу 0x08000004 и так далее.
Адреса, предназначенные для внутреннего ОЗУ и адреса, предназначенные для внутренней периферии. В каждой из этих областей есть диапазоны адресов, которые обозначены как "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. Старшие биты записываемого слова, как я уже говорил, значения не имеют. Если мы, наоборот, считываем слово из области доступа к отдельным битам, то старшие биты всегда читаются нулями.
У предшествующих ЦПУ ARM7 и ARM9 битовые операции в статическом ОЗУ можно
было выполнять только с помощью инструкций AND и OR. Для этого необходимо
выполнить последовательность ЧТЕНИЕ - МОДИФИКАЦИЯ - ЗАПИСЬ. Однако
использование этого метода приводит к чрезмерному расходованию количества циклов
на выполнение установки и сброса отдельных бит и увеличению результирующего кода
программы.
Преодолеть данное ограничение можно, если предусмотреть отдельные инструкции
сброса и установки бит или интегрировать полнофункциональный процессор битовой
обработки, однако это приведет к увеличению размеров и сложности ЦПУ. Вместо этого,
способ, называемый bit banding, позволяет напрямую воздействовать на биты в памяти
из областей УВВ и статического ОЗУ, не используя при этом каких-либо специальных
инструкций. Битноадресуемые области карты памяти Cortex разделены на две части:
область хранения бит (в нее входят до 1 Мбайт физической памяти или регистров УВВ)
и область доступа к битам, которая занимает до 32 Мбайт карты памяти. Получить
доступ к каждому отдельному биту из области хранения бит можно по соответствующему
адресу слова из области доступа к битам. Таким образом, если выполнять запись по
адресу в области доступа к битам на самом деле мы будем воздействовать на значение
определенного бита в физической памяти.
В итоге, мы можем воздействовать на значение отдельных бит, не прибегая, при этом,
к использованию специальных инструкций и сохраняя результирующие размеры ядра
Cortex на минимально возможном уровне. Чтобы использовать этот метод на практике,
необходимо вычислить адрес слова в области доступа к битам, который соответствует
заданной ячейки памяти из области УВВ или статического ОЗУ. Выполняется это по
следующей формуле:
Адрес в области доступа к битам = Базовый адрес области доступа к
битам + Смещение адреса слова доступа к биту,
где Смещение адреса слова доступа к биту = Смещение в байтах по
отношению базовому адресу области хранения бит х 0x20 + номер бита х 4
На самом деле все обстоит гораздо проще, чем может показаться на первый взгляд.
Рассмотрим практический пример. Необходимо выполнить запись в выходной регистр
порта ввода-вывода (ПВВ) для установки или сброса отдельных линий ввода-вывода.
Физический адрес выходного регистра порта В - 0x40010C0C. Предположим, что нужно
устанавливать и сбрасывать бит 8 этого регистра. Воспользуемся приведенной выше
формулой:
Адрес слова = 0x40010C0C
Базовый адрес области хранения бит УВВ = 0x40000000
Базовый адрес области доступа к битам УВВ = 0x42000000
Смещение в байтах по отношению базовому адресу области хранения бит
= 0x40010C0C - 0x40000000 = 10C0C
Смещение адреса слова доступа к биту
= (0x10С0С x 0x20) +(8x4) = 0x2181A0
Адрес в области доступа к битам
= 0x42000000 + 0x2181A0 = 0x422181A0
Теперь мы можем создать указатель на этот адрес с помощью следующей Си-строки:
#define PortBbit8 (*((volatile unsigned long *) 0x422181A0 ))
После этого, этот указатель можно использовать для установки и сброса бит ПВВ:
PB8 = 1; //включаем светодиод
После компиляции будут сгенерированы следующие ассемблерные инструкции:
MOVS r0,#0x01
LDR r1,[pc,#104]
STR r0,[r1,#0x00]
Для отключения светодиода используем строку:
PB8 = 0; // отключаем светодиод
Ей соответствуют следующие ассемблерные инструкции:
MOVS r0,#0x00
LDR r1,[pc,#88]
STR r0,[r1,#0x00]
Таким образом, для установки или сброса бита необходимо выполнить три 16-битных
инструкции. Микроконтроллер STM32, работающий на частоте 72 МГц, выполнит их
за 80 нс. Альтернативно установку или сброс бита можно выполнить, если применить
логическую операцию "ИЛИ" или "И" ко всему слову из области хранения бит УВВ или
статического ОЗУ:
GPIOB->ODR |= 0x00000100; //Включение светодиода
LDR r0,[pc,#68]
ADDS r0,r0,#0x08
LDR r0,[r0,#0x00]
ORR r0,r0,#0x100
LDR r1,[pc,#64]
STR r0,[r1,#0xC0C]
GPIOB->ODR &=!0x00000100; //Отключение светодиода
LDR r0,[pc,#40]
ADDS r0,r0,#0x08
LDR r0,[r0,#0x00]
MOVS r0,#0x00
LDR r1,[pc,#40]
STR r0,[r1,#0xC0C]
Но в таком случае, одна операция установки/сброса потребует выполнения смеси 16- и 32 битных инструкций, которые займут минимум 14 байт и на той же тактовой частоте будут выполняться как минимум 180 нс. Таким образом, в программе, где используется установка сброс множества бит в регистрах УВВ, а также применяются семафоры и флаги в статическом ОЗУ, использование метода bit banding позволит существенно сэкономить, как размер кода программы, так и время его выполнения.
Адреса периферии STM32F1
AHB
0xA0000000 0xA0000FFF FSMC
0×50000000 0x5003FFFF USB OTG FS
0×40030000 0x4FFFFFFF reserv
0×40028000 0x40029FFF Ethernet
0×40023400 0x40027FFF reserv
0×40023000 0x400233FF CRC
0×40022000 0x400223FF flash-memory
0×40021400 0x40021FFF reserv
0×40021000 0x400213FF RCC
0×40020800 0x40020FFF reserv
0×40020400 0x400207FF DMA2
0×40020000 0x400203FF DMA1
0×40018400 0x4001FFF reserv
0×40018000 0x400183FF SDIO
APB2
0×40015800 0x40017FFF reserv
0×40015400 0x400157FF TIM11
0×40015000 0x400153FF TIM10
0x40014C00 0x40014FFF TIM9
0×40014000 0x40014BFF reserv
0x40013C00 0x40013FFF ADC3
0×40013800 0x40013BFF USART1
0×40013400 0x400137FF
TIM8
0×40013000 0x400133FF SPI1
0x40012C00 0x40012FFF TIM1
0×40012800 0x40012BFF ADC2
0×40012400 0x400127FF ADC1
0×40012000 0x400123FF GPIOG
0x40011C00 0x40011FFF GPIOF
0×40011800 0x40011BFF GPIOE
0×40011400 0x400117FF GPIOD
0×40011000 0x400113FF GPIOC
0x40010C00 0x40010FFF GPIOB
0×40010800 0x40010BFF GPIOA
0×40010400 0x400107FF EXTI
0×40010000 0x400103FF AFIO
APB1
0×40007800 0x4000FFFF reserv
0×40007400 0x400077FF DAC
0×40007000 0x400073FF PWR
0x40006C00 0x40006FFF BKP
0×40006800 0x40006BFF reserv
0×40006400 0x400067FF bxCAN1
0×40006800 0x40006BFF bxCAN2
0×40006000 0x400063FF 512 byte
(USB/CAN)
0x40005C00 0x40005FFF USB,
registers FS
0×40005800 0x40005BFF I2C2
0×40005400 0x400057FF I2C1
0×40005000 0x400053FF UART5
0x40004C00 0x40004FFF UART4
0×40004800 0x40004BFF USART3
0×40004400 0x400047FF USART2
0×40004000 0x400043FF reserv
0x40003C00 0x40003FFF SPI3/I2S
0×40003800 0x40003BFF SPI2/I2S
0×40003400 0x400037FF reserv
0×40003000 0x400033FF WDG
0x40002C00 0x40002FFF WWDG
0×40002800 0x40002BFF RTC
0×40002400 0x400027FF reserv
0×40002000 0x400023FF TIM14
0x40001C00 0x40001FFF TIM13
0×40001800 0x40001BFF TIM12
0×40001400 0x400017FF TIM7
0×40001000 0x400013FF TIM6
0x40000C00 0x40000FFF TIM5
0×40000800 0x40000BFF TIM4
0×40000400 0x400007FF TIM3
0×40000000 0x400003FF TIM2
Комментариев нет:
Отправить комментарий