Размещение переменной по абсолютному адресу в памяти микроконтроллера




При помощи указателей

int  *var  =  (int*)0x20000500;
int main ()
{
  *var  =  0x44556677;
  //...
}

Объявление / определение: переменная var содержит адрес, по которому расположено значение типа int (в текущей реализации 4 байта). Может располагаться в любом месте до первого использования.

Инициализация присваиванием / присваивание: разыменовыванием указателя получаем доступ к значению переменной типа int, расположенной по адресу var. В Си нельзя исполнять код вне функций, поэтому присваивание должно располагаться в теле функции. Например: в main().

Ячейка памяти должна быть доступна для записи, а значит располагаться или в доступной области ОЗУ (статус rw - read-write), или быть доступным регистром периферийного устройста. Инициализировать подобным образом ячейку ПЗУ (статус ro - read-only) не получится, программа "свалится" в исключение.



При помощи атрибута at: __attribute__((at(address)))

uint32_t  var  __attribute__((at(0x08004000))) = 100500u;

Работает только с компилятором ARMCC от Keil. Не поддерживается GNU GCC и другими компиляторами. Компилятор ARM 6-й версии основан на компиляторе clang (llvm) и так же не поддерживает данный атрибут. Не рекомендуется использовать в настоящее время.

Данный метод размещает переменную var значением 100500 (беззнаковое целое) по адресу 0x0800'4000, и не требует изменения scatter-файла.



При помощи атрибута section: __attribute__((section("inf_section")))

uint32_t  var  __attribute__((section("inf_section"))) = 0x33445566u;

Работает с компилятором ARMCC от Keil, Clang (llvm), GNU GCC.

Данный метод размещает переменную var значением 0x33445566 (беззнаковое целое) в секции inf_section, адрес которой должен быть указан в scatter-файле.

Исходный scatter-файл, формируемый Keil по умолчанию:

; *************************************************************
; *** Scatter-Loading Description File generated by uVision ***
; *************************************************************

LR_IROM1 0x08000000 0x00010000  {    ; load region size_region
  ER_IROM1 0x08000000 0x00010000  {  ; load address = execution address
   *.o (RESET, +First)
   *(InRoot$$Sections)
   .ANY (+RO)
   .ANY (+XO)
  }
  RW_IRAM1 0x20000000 0x00005000  {  ; RW data
   .ANY (+RW +ZI)
  }
}

Микроконтроллер STM32F103C8T6 имеет 64 кБ flash-памяти: всего 64 страницы (нумерация страниц памяти: 0 ... 63) по 1 кБ (0x400 байт).

Страница памяти 63 (Page 63) имеет адреса начало/конец: 0x0800'FC00 ... 0x0800'FFFF. Если разместить секцию inf_section на последней странице, то scatter-файл будет таким:

; *************************************************************
; *** Scatter-Loading Description File generated by uVision ***
; *************************************************************

LR_IROM1 0x08000000 0x00010000  {    ; load region size_region
  ER_IROM1 0x08000000 0x0000FC00  {  ; load address = execution address
   *.o (RESET, +First)
   *(InRoot$$Sections)
   .ANY (+RO)
   .ANY (+XO)
  }
  ER_IROM2 0x0800FC00 FIXED  {  ; 
   *.o (inf_section)
  }
  RW_IRAM1 0x20000000 0x00005000  {  ; RW data
   .ANY (+RW +ZI)
  }
}

Уменьшили размер основного региона flash-памяти на размер страницы. Создали второй регион ER_IROM2 во flash-памяти вплотную за концом основного (root) региона. Использован атрибут FIXED для размещения региона ER_IROM2 по фиксированному адресу. Подключили к региону секцию inf_section из любого объектного файла.

Чтобы компоновщик не убрал при оптимизации во время сборки проекта созданную секцию, надо указать в командной строке --keep=''main.o(inf_section)''. Указывается в опциях проекта -> вкладка Linker -> поле Misc Controls.