Перейти к содержанию
    

Keil uVision. Выполнение кода из RAM

Приветствую!

Пишу сейчас загрузчик под STM32F0. Стирание и запись Flash - процессы весьма затратные по времени.
Сначала хотел перетащить в ОЗУ лишь таблицу векторов и сами обработчики прерываний, а также функции стирания/записи Flash.
Это чтобы события (прерывания) по тому же UART-у (это канал связи) не пропускать. Плюс события таймера и обслуживание другого канала связи.
В итоге решил весь код исполнять из ОЗУ: при старте FlashLoader (код из Flash) копирует рабочий код загрузчика из Flash в ОЗУ и передает ему управление.

Но попутно возник вопрос. В IAR, насколько я знаю, есть ключевое слово __ramfunc. Оно заставляет линковать функцию в ОЗУ. Ну ок.
Кроме того, как я понял, IAR следит, чтобы и вложенные вызовы других функций, а также обращение к константам производилось тоже из ОЗУ.
Т.е. константы, адресуемые через PC, должны быть расположены тоже в ОЗУ, а не во Flash. Так ли это? Если так, то что с косвенным доступом?
Например, функция, помеченная как исполняемая из ОЗУ, вызывает другую функцию, но не прямо, а через таблицу указателей на функции.

Так вот, если в IAR действительно прослеживается такое поведение, что насчет Keil? Он умеет такое или нет?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

2 hours ago, Arlleex said:

Сначала хотел перетащить в ОЗУ лишь таблицу векторов...

Так M0 же, вектора гвоздями прибиты. И зачем вообще все тащить в ОЗУ?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

2 часа назад, Arlleex сказал:

Кроме того, как я понял, IAR следит, чтобы и вложенные вызовы других функций, а также обращение к константам производилось тоже из ОЗУ.
Т.е. константы, адресуемые через PC, должны быть расположены тоже в ОЗУ, а не во Flash. Так ли это?

Так. Даже вроде где-то в документации это отражено.

Цитата

Если так, то что с косвенным доступом?
Например, функция, помеченная как исполняемая из ОЗУ, вызывает другую функцию, но не прямо, а через таблицу указателей на функции.

На счёт косвенных не знаю, не пробовал, но если, исходить из логики, думаю __ramfunc добавляет какое-то свойство к типу указателя на функцию и при разыименовании этого указателя не из __ramfunc, скорей всего компилятор должен матюгнуться.

Впрочем это нетрудно проверить.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

12 минут назад, aaarrr сказал:

Так M0 же, вектора гвоздями прибиты.

Так remap же.

2 часа назад, Arlleex сказал:

Например, функция, помеченная как исполняемая из ОЗУ, вызывает другую функцию, но не прямо, а через таблицу указателей на функции.

если сам указатель имеет специальный аттрибут по аналогии с кейлосвским __packed - то, теоретически, может. Если у указателя такого аттрибута нет - то нет и физической возможости у компилятора. Честно говоря сильно сомневаюсь в такой возможности.

Я бы зашел с другой стороны - пусть редактор связей (линкер) расположит в ОЗУ (подобно секции инициализированных переменных) вообще все сегменты кроме одного. В этом одном разместить тот самый начальный загрузчик, который будет копировать рабочий код в ОЗУ. Помнится, тут многие писали подобные загрузчики для атмеловских ARMов AT91RM9200, у которых код грузился из NAND во внешнее динамическое ОЗУ, в сети должны остаться примеры.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

3 минуты назад, Сергей Борщ сказал:

Я бы зашел с другой стороны - пусть редактор связей (линкер) расположит в ОЗУ (подобно секции инициализированных переменных) вообще все сегменты кроме одного. В этом одном разместить тот самый начальный загрузчик, который будет копировать рабочий код в ОЗУ.

У меня сейчас на XMC4700 примерно так и сделано.  :wink2:

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 час назад, aaarrr сказал:

Так M0 же, вектора гвоздями прибиты.

Сергей опередил, действительно можно (и, по-моему это единственный возможный вариант) сделать remap ОЗУ на 0x00000000.

1 час назад, aaarrr сказал:

И зачем вообще все тащить в ОЗУ?

А как иначе, чтобы не тормозить процессор на момент стирания и записи Flash?
МК (1) даже в режиме загрузчика должен взаимодействовать с рядом стоящим МК (2), иначе тот (2) подумает, что я (1) отвалился и будет сыпать ошибки.
Следовательно, МК (1), находясь в режиме загрузчика, не только обновляет прошивку по рабочему каналу связи, а еще как бы повторяет часть функционала рабочего ПО. Которое, собственно говоря, в том числе и взаимодействует с МК (2). Соответственно, очень трудно бродить по исходникам и думать, что размещать в ОЗУ, а что нет. Код то выполняется, алгоритм один, значит технически любая функция и любые константы могут быть выбраны (запрошены) из Flash. Это привело бы к торможению. Соответственно, придется копировать всю исполняемую программу в ОЗУ (включая константы) и передавать ей управление.
 

45 минут назад, Сергей Борщ сказал:

Я бы зашел с другой стороны - пусть редактор связей (линкер) расположит в ОЗУ (подобно секции инициализированных переменных) вообще все сегменты кроме одного. В этом одном разместить тот самый начальный загрузчик, который будет копировать рабочий код в ОЗУ...

Сейчас, кстати, прорабатываю эту возможность. Так и задумывал сделать.
Хочу разместить начальный загрузчик во Flash. И чтобы он копировал код нужной части себя же (т.е. я хочу разработать единый бинарь в итоге).
Разбираюсь с Keil-овским scatterload, надо как-то сказать, чтобы он RAM делил между переменными для кода начального загрузчика и самим загрузчиком.
Как я понял, есть там ключевое слово OVERLAY. Буду копать в эту сторону.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

18 минут назад, Arlleex сказал:

Хочу разместить начальный загрузчик во Flash. И чтобы он копировал код нужной части себя же (т.е. я хочу разработать единый бинарь в итоге).

У меня весь загрузчик (загрузчик-прошивальщик) слинкован в ОЗУ. Целиком. А начальный загрузчик (просто загрузчик) - отдельно-скомпилированная программа, выполняющаяся из FLASH и просто копирующая загрузчик-прошивальщик в ОЗУ (со всеми проверками контрольных сумм и т.п.). Начальный загрузчик - чисто на ассемблере, простой цикл копирования с проверками. Он ещё предварительно выбирает один из двух экземпляров загрузчика-прошивальщика, который нужно копировать в ОЗУ (для возможности безопасного обновления загрузчика-прошивальщика).

__ramfunc в этом случае не нужен.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

13 минут назад, jcxz сказал:

У меня весь загрузчик (загрузчик-прошивальщик) слинкован в ОЗУ. Целиком. А начальный загрузчик (просто загрузчик) - отдельно-скомпилированная программа...

А, ну этот вариант довольно прост - его я тоже рассматриваю, но после того, какой я хочу запилить.
А хочу я одним бинарником - просто хранить несколько проектов не хочется, по крайней мере пока что:biggrin:
Вроде все должно быть достаточно просто. Слинковать функцию копирования и передачи управления во Flash.
А остальной код (код основного загрузчика) линковать в область ОЗУ. Сейчас буду экспериментировать.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 hour ago, Arlleex said:

МК (1) даже в режиме загрузчика должен взаимодействовать с рядом стоящим МК (2), иначе тот (2) подумает, что я (1) отвалился и будет сыпать ошибки.

А польза от этого взаимодействия есть, кроме подавления ошибок? Как-то немного натянуто выглядит, по правде говоря.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

47 минут назад, aaarrr сказал:

А польза от этого взаимодействия есть, кроме подавления ошибок? Как-то немного натянуто выглядит, по правде говоря.

Во многих прикладных областях есть требования по максимально-допустимому интервалу невыполнения какого-то функционала (если нужно например отслеживать некие события в реальном времени). Соответственно отсюда истекают и требования по максимально-допустимому времени старта устройства после вкл. питания и прочие подобные требования по максимально-допустимому времени неполно-функционального состояния.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

55 минут назад, aaarrr сказал:

А польза от этого взаимодействия есть, кроме подавления ошибок? Как-то немного натянуто выглядит, по правде говоря.

На этом МК еще управление кучкой дискретных выходов и контроль входов.
Есть определенный такт обменов, в течение которого МК обязан ответить.
Этот такт около 50мс, время стирания сектора - 30мс (типовое значение).
Поэтому я посчитал вполне разумным перетащить все это дело в ОЗУ.
Насколько страшно пропустить реальное считывание, продублировав старое состояние того же входа, я пока ответить не могу.
Но лучше заложить, что пропуски невозможны, и тогда не придется в будущем исправлять загрузчик, перешивая сотни девайсов:this:

P.S. Вопрос по теме.
А реально ли разместить RO-, XO-секции региона выполнения по адресу, не совпадающему с адресом региона загрузки? На картинке
image.png.c8d507a961a8b4c59b0e00fa5530f287.png

видно, что RO-секция (ну и XO тоже) исполняемого региона находится на том же месте, в котором она была в регионе загрузки.
А я хочу поведение, показанное на том же рисунке для RW-секции. Этим я хотел указать, что выполняемый образ лежит не там, куда его прошили физически.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

7 минут назад, Arlleex сказал:

А реально ли разместить RO-, XO-секции региона выполнения по адресу, не совпадающему с адресом региона загрузки? На картинке

Зависит от компилятора. На CCS я делал такое.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

16 минут назад, jcxz сказал:

Зависит от компилятора. На CCS я делал такое.

Понял, спасибо. Буду дальше разбираться.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

ИМХО, если хочется выполнять рабочий код из SRAM, то самое правильное будет:

- скомпилировать рабочую прошивку с тех адресов, где она штатно будет работать. Так и отлаживать проще.

- прошить её во Flash с некоторым смещением, чтобы вначале поместился начальный загрузчик.

- Написать начальный загрузчик, который копирует прошивку из flash в SRAM, делает remap и передаёт ей управление.

 

Можно, конечно, чтобы загрузчик был частью основной прошивки, но надо ли? Всё равно, при удалённом обновлении неубиваемый загрузчик лучше иметь.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
К сожалению, ваш контент содержит запрещённые слова. Пожалуйста, отредактируйте контент, чтобы удалить выделенные ниже слова.
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...