ВходНаше всё Теги codebook 无线电组件 Поиск Опросы Закон Пятница
2 января
1563467 Топик полностью
POV (Вчера, 21:18 - 21:25, просмотров: 31) ответил POV на AT32 и им подобные - если я во флеш пишу, то прерывания в этот момент не будут работать?
Обратился вновь к этому. Судя по 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();
}