======Типы памяти при работе с внешней шиной====== ===Адресное пространство в Cortex-M3 (МК 1986ВЕ9х)=== ^ Адреса ^ Назначение ^ Тип Памяти ^ XN ^ Описание ^ | 0x0000_0000 - 0x1FFF_FFFF | Code | Normal | - | Код программы и данные | | 0x2000_0000 - 0x3FFF_FFFF | SRAM | Normal | - | Данные и код программы | | 0x4000_0000 - 0x5FFF_FFFF | Peripheral | Device | XN | Периферия Milandr | | 0x6000_0000 - 0x9FFF_FFFF | Ext RAM | Normal | - | Внешнее ОЗУ | | 0xA000_0000 - 0xDFFF_FFFF | Ext Device | Device | XN | Внешние Устройства | | 0xE000_0000 - 0xE000_FFFF | Core Bus | Strongly Ordered | - | Периферия ядра - NVIC, SysTimer, регистры ядра | | 0xE001_0000 - 0xFFFF_FFFF | Reserved | Device | XN | Зарезервировано | **XN** - //Execute Never//, обращение за инструкциями для исполнения в данные области не возможен. Доступ к контроллеру внешней шины возможен через различные области адресного пространства. Эти области имеют разные //типы памяти//, которые могут быть изменены в блоке //MPU//. Всего типов памяти три: * Normal * Device * Strongly Ordered Обращение к внешней шине через эти области происходит с некоторыми нюансами. Предположим, что в коде есть подряд несколько записей во внешнюю память. Например, последовательность из статьи - [[prog:extbus:extbus_rr1_ve1|Работа с Flash памятью 1636РР1У по внешней шине 1986ВЕ91Т]]. // Стирание всей памяти FlashStatus EraseFullFLASH(void) { ... // Командная последовательность EraseFull HWEXTBUS(0x555) = 0xAAAAAAAA; HWEXTBUS(0x2AA) = 0x55555555; HWEXTBUS(0x555) = 0x80808080; HWEXTBUS(0x555) = 0xAAAAAAAA; HWEXTBUS(0x2AA) = 0x55555555; HWEXTBUS(0x555) = 0x10101010 ... } Каждое обращение на внешнюю шину занимает значительное количество тактов, ведь внешняя шина работает медленнее, чем ядро. Времена работы внешней шины задаются программно в регистрах и подстраиваются под скорость работы внешнего устройства. Процессор же, получив такую последовательность команд, должен либо остановиться пока не закончится текущая операция на шине (режим **Strongly Ordered**), либо записать обращения в некий внутренний буфер и продолжить выполнение прочих инструкций, не снижая общую производительность. Затем, команды из буфера (параллельно с работой ядра) будут выводиться на контроллер внешней шины - и здесь есть два варианта: - Если типа памяти **Normal**, то последовательность исполнения команд из буфера может быть изменена для повышения быстродействия. Не знаю, как происходит оптимизация исполнения в ядре на самом деле, но например, для снижения количества переключений сначала можно выполнить все чтения, а затем все записи. Ведь для переключения режима Read/Write необходимо дополнительное время на переключение сигналов шины nOE и WE, а так-же режима линий данных In/Out. Такой режим работы подходит, например, для чтения внешнего ОЗУ, где очередность выборки данных не имеет значения. - Если тип памяти **Device**, то последовательность команд сохраняется неизменной. Этот режим необходим там, где последовательность команд является важной. В данном коде выбор режима, в котором будет работать ядро, определяется старшими разрядами адреса при обращении в адресное пространство. // Макрос обращения к памяти #define HWREG(x) (*((volatile uint32_t *)(x))) // Макрос обращения к внешней шине #define EXTBUS_START_ADDR 0x60000000 // Normal или #define EXTBUS_START_ADDR 0xA0000000 // Device #define EXTBUS_ADDR(x) (EXTBUS_START_ADDR + ((x) << 2)) #define HWEXTBUS(x) HWREG(EXTBUS_ADDR(x)) Для управлением записью в 1636РР1У необходимо четко соблюдать последовательность команд, поэтому необходимо осуществлять обращения к внешней шине через регион с типом памяти //Device//. То-есть, адреса должны быть в диапазоне начинающимся с 0xA000_0000.