По умолчанию код пользователя размещается в памяти FLASH. В этом случае такой код прозрачно для кода приложения подгружается в кэш и оттуда уже выполняется. В моменты копирования кода из FLASH в RAM кэша происходят задержки, появление которых прогнозировать невозможно.
В некоторых случаях необходимо обеспечить жесткий реалтайм, чтобы функция всегда работала строго определенное, заранее известное время (например код, который формирует задержки для потока данных RGB-светодиода [2]). Или нужно, чтобы функция всегда отрабатывала максимально быстро (например код обработчика прерывания, ISR). Для этого необходимо гарантировать, чтобы функция и любой вызываемый из неё код находились в RAM.
Некоторые системные функции, такие как код планировщика и API-функции RTOS, размещены в RAM. Размещение кода и данных в определенные места адресного пространства управляется файлом настройки линкера тулчейна GCC (файл с расширением *.ld или *.lds). Имена функций, которые должны быть размещены в RAM, должны быть упомянуты в соответствующей секции этого файла. Ниже приведен пример размещения в RAM микроконтроллера BK7231N пользовательской функции void myRAMfunc (uint8_t color).
void myRAMfunc (uin8_t color)
{
uint32_t duty;
bk_pwm_initlevl_set_high(PWM_CHANNEL);
GLOBAL_INT_DECLARATION();
GLOBAL_INT_DISABLE();
duty = (color & MASK_GREEN) ? 65 : 13;
pwm_set_duty_cycle(PWM_CHANNEL, duty);
pwm_unit_enable(PWM_CHANNEL);
rgbdelay(145);
...
pwm_unit_disable(PWM_CHANNEL);
GLOBAL_INT_RESTORE();
}
Ниже показан фрагмент файла линкера config/bk7231n_boot.lds, для функции myRAMfunc добавлена красная строчка:
/* Разделение памяти на области векторов и ОЗУ */
MEMORY
{
flash (rx) : ORIGIN = 0x00010000, LENGTH = 2M-68K
tcm (rw!x): ORIGIN = 0x003F0000, LENGTH = 60k
itcm (rwx): ORIGIN = 0x003FF000, LENGTH = 4k
ram (rw!x): ORIGIN = 0x00400100, LENGTH = 192k - 0x100
}
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
OUTPUT_ARCH(arm)
ENTRY(_vector_start);
_vector_start = ORIGIN(flash);
SECTIONS
{
/* Регион векторов прерывания */
. = ORIGIN(flash);
.vectors :
{
KEEP(*(*.vectors))
KEEP( *(*.rom1))
} > flash
/* Регион кода инструкций */
. = ORIGIN(itcm);
.itcm.code ALIGN(8) :
{
/* itcm 4KB code */
*(.text.intc_hdl_entry)
*(.text.intc_irq)
...
*(.text.rt_hw_interrupt_enable)
*(.text.rt_thread_self)
/**(.text.rt_schedule_remove_thread)*/
*(.text.rt_timer_stop)
/**(.text.rt_thread_resume)*/
*port_asm.o(.text .text.*)
*context_gcc.o(.text .text.*)
*(.text.myRAMfunc)
} > itcm AT>flash
_itcmcode_flash_begin = LOADADDR(.itcm.code);
_itcmcode_ram_begin = ADDR(.itcm.code);
_itcmcode_ram_end = _itcmcode_ram_begin + SIZEOF(.itcm.code);
...
[Ссылки]
1. bekencorp / bdk_rtt site:github.com. 2. WS2811: микросхема для управления трехцветным RGB-светодиодом. |