Обратился вновь к этому. Судя по map, обработчики и таблица
векторов точно в ОЗУ. Из обработчиков не вызывается ничего из флеш
(к регистрам и озу только обращение). И всё же вызов обработчиков
блокируется во время записи во flash. Что я делаю не так? #define RAM_FUNC __attribute__((section(".text.ram_code"), long_call, noinline))// noinline — чтобы избежать inline в Flash-код скаттер файл
LR_IROM1 0x08000000 0x00100000 { ; Flash
ER_IROM1 0x08000000 0x00100000 { ; Flash (root region - должен быть первым)
*.o (RESET, +First)
*(InRoot$$Sections)
.ANY (+RO)
}
RW_IRAM1 0x20000000 0x00038000 { ; RAM
.ANY (+RW +ZI)
*(RAM_VECTOR_TABLE) ; Секция для таблицы векторов
}
; Execution region для кода в RAM
; Load address: автоматически в ER_IROM1 (Flash), Execution address: в RAM после RW_IRAM1
; Размещаем по адресу 0x20037000 (запас от конца RAM)
ER_RAM_CODE 0x20037000 0x00001000
{
*(.text.ram_code) ; Execution address в RAM
}
} далее
int main(void)
{
CopyRamCode();
CopyInterruptVectorsToRAM();
...
void CopyRamCode(void)
{
// Символы автоматически создаются scatter файлом ARM Compiler
extern uint32_t Image$$ER_RAM_CODE$$Base; // Начало RAM кода в RAM (execution address)
extern uint32_t Image$$ER_RAM_CODE$$Limit; // Конец RAM кода в RAM
extern uint32_t Load$$ER_RAM_CODE$$Base; // Начало RAM кода во Flash (load address)
uint32_t *src = (uint32_t*)&Load$$ER_RAM_CODE$$Base; // Load address (Flash)
uint32_t *dst = (uint32_t*)&Image$$ER_RAM_CODE$$Base; // Execution address (RAM)
uint32_t *end = (uint32_t*)&Image$$ER_RAM_CODE$$Limit; // Конец в RAM
// Проверяем валидность адресов
if (!src || !dst || !end)
{
return; // Символы не созданы линкером
}
// Проверяем, что есть что копировать
if (dst >= end)
{
return; // Нет кода для копирования
}
// Проверяем, что адреса в допустимых диапазонах
if ((uint32_t)src < 0x08000000 || (uint32_t)src >= 0x08100000)
{
return; // Load address не в Flash
}
if ((uint32_t)dst < 0x20000000 || (uint32_t)dst >= 0x20040000)
{
return; // Execution address не в RAM
}
// Копируем по словам
uint32_t count = (end - dst); // Количество uint32_t элементов
if (count > 0 && count < 0x1000) // Защита от переполнения (макс 4KB)
{
while (count--)
{
*dst++ = *src++;
} // Синхронизация кеша данных и инструкций
// Обеспечиваем, что код скопирован и готов к выполнению
__DSB();
__ISB();
}
}
void CopyInterruptVectorsToRAM(void)
{
extern uint32_t __Vectors[];
extern uint32_t __Vectors_End[];
extern uint32_t __Vectors_RAM[];
// Адреса обработчиков в RAM (execution address)
extern uint32_t Image$$ER_RAM_CODE$$Base;
extern uint32_t Image$$ER_RAM_CODE$$Limit;
// Адреса обработчиков во Flash (load address) - для вычисления смещения
extern uint32_t Load$$ER_RAM_CODE$$Base;
extern uint32_t Load$$ER_RAM_CODE$$Limit; // Адреса обработчиков в RAM (для прямой проверки)
extern void EXINT9_5_IRQHandler(void);
extern void EXINT15_10_IRQHandler(void);
extern void TMR3_GLOBAL_IRQHandler(void);
extern void TMR8_OVF_TMR13_IRQHandler(void);
extern void TMR1_OVF_TMR10_IRQHandler(void);
uint32_t *src = __Vectors;
uint32_t *dst = __Vectors_RAM;
uint32_t count = (__Vectors_End - __Vectors);
// Вычисляем смещение между Flash и RAM адресами
uint32_t flash_base = (uint32_t)&Load$$ER_RAM_CODE$$Base;
uint32_t flash_end = (uint32_t)&Load$$ER_RAM_CODE$$Limit;
uint32_t ram_base = (uint32_t)&Image$$ER_RAM_CODE$$Base;
uint32_t ram_end = (uint32_t)&Image$$ER_RAM_CODE$$Limit;
uint32_t offset = ram_base - flash_base;
// Адреса обработчиков в RAM (для прямой проверки)
uint32_t ram_exint9_5 = (uint32_t)EXINT9_5_IRQHandler;
uint32_t ram_exint15_10 = (uint32_t)EXINT15_10_IRQHandler;
uint32_t ram_tmr3 = (uint32_t)TMR3_GLOBAL_IRQHandler;
uint32_t ram_tmr8 = (uint32_t)TMR8_OVF_TMR13_IRQHandler;
uint32_t ram_tmr1 = (uint32_t)TMR1_OVF_TMR10_IRQHandler;
// Копируем таблицу векторов и обновляем указатели на обработчики в RAM
for (uint32_t i = 0; i < count; i++)
{ uint32_t vector = src[i];
// Проверяем, является ли это адресом одного из наших обработчиков
// 1. Проверяем диапазон Flash адресов (для обработчиков в секции .text.ram_code)
if (vector >= flash_base && vector < flash_end)
{
vector += offset; // Смещаем на разницу между RAM и Flash
}
// 2. Проверяем прямые адреса обработчиков в Flash и заменяем на RAM адреса
// Вычисляем возможные Flash адреса для каждого обработчика
else if (vector >= 0x08000000 && vector < 0x08100000)
{
// Проверяем каждый обработчик: если Flash адрес + offset = RAM адрес, обновляем
if ((vector + offset == ram_exint9_5) ||
(vector + offset == ram_exint15_10) ||
(vector + offset == ram_tmr3) ||
(vector + offset == ram_tmr8) ||
(vector + offset == ram_tmr1))
{
vector += offset;
} // Альтернативный способ: если адрес попадает в диапазон возможных Flash адресов
// и вычисленный RAM адрес попадает в диапазон RAM обработчиков, обновляем
else
{
uint32_t possible_ram = vector + offset;
if (possible_ram >= ram_base && possible_ram < ram_end)
{
// Это может быть наш обработчик, обновляем адрес
vector = possible_ram;
}
}
}
dst[i] = vector;
}
// Синхронизация перед обновлением VTOR
__DSB();
SCB->VTOR = (uint32_t)__Vectors_RAM;
__DSB();
__ISB();
}