Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Как скомпилировать сишный код в RAM?
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > ARM, 32bit
AndyDev
Подскажите плиз, как под Keil'ом скомпилировать сишный код в RAM?
На сколько я понимаю, если такое возможно, то код из ROM должен при старте каким-то загрузчиком быть перенесен в RAM.

Зачем это нужно? Очень просто - из ОЗУ код выполняется гораздо быстрее, чем из медленной Flash. И чем выше тактовая частота, тем эта разность заметнее.
Allregia
Цитата(AndyDev @ Nov 23 2012, 19:28) *
Подскажите плиз, как под Keil'ом скомпилировать сишный код в RAM? На сколько я понимаю, если такое возможно, то код из ROM должен при старте каким-то загрузчиком быть перенесен в RAM. Зачем это нужно?


В Кейле - вынести эти функции в отдельный файл, и в опциях для этого файла указать размещение в ОЗУ.
В IAR вроде можно просто перед функцией написать __ramfunction или как-то так.

Цитата
Очень просто - из ОЗУ код выполняется гораздо быстрее, чем из медленной Flash. И чем выше тактовая частота, тем эта разность заметнее.

Не всегда. Например для STM32F407 -"Z", это практически ничего не дает.
Spider
Раз уж такая тема пошла. подскажите, а возможно загрузить в память самостоятельную прошивку и полностью перейти на нее?
Сергей Борщ
QUOTE (Alexey Belyaev @ Nov 24 2012, 08:06) *
а возможно загрузить в память самостоятельную прошивку и полностью перейти на нее?
Да, возможно. Как это сделать именно в Кейле - не знаю.
haker_fox
QUOTE (AndyDev @ Nov 24 2012, 02:28) *
Подскажите плиз, как под Keil'ом скомпилировать сишный код в RAM?

Да. Настройки линкера - Ваша цель rolleyes.gif

QUOTE (Alexey Belyaev @ Nov 24 2012, 15:06) *
Раз уж такая тема пошла. подскажите, а возможно загрузить в память самостоятельную прошивку и полностью перейти на нее?

Да. У меня так работает мой загрузчик. При старте МК получает ip от DHCP сервера (можно и статический), и представляется FTP сервером. Затем, я "захожу" туда Total Commander'ом и "заливаю" бинарник. Чтобы сообщить загрузчику, что код можно исполнять, нужно "дозалить" файл с именем done. Полуив его, загрузчик проверяет, загружен ли до этого файл *.bin, и если да, то передает ему управление. Если нет - в моем случае ничего не делает. Ждет)
AndyDev
Подскажите тогда заодно, как в Кейле передаются параметеры в функцию, написанную на асме? Через стек, регистры? Какие регистры можно в этой функции использовать? Где вообще почитать инфу о соглашении на счет регистров в подобном случае?

Цитата(Allregia @ Nov 24 2012, 01:52) *
В Кейле - вынести эти функции в отдельный файл, и в опциях для этого файла указать размещение в ОЗУ.
В IAR вроде можно просто перед функцией написать __ramfunction или как-то так.


Не всегда. Например для STM32F407 -"Z", это практически ничего не дает.


Что-то я не нашел, где устанавливается размещение ОЗУ для файла.

У меня NXP1114, у него флешка слабенькая, на 50Мгц много тормозов дает.
SyncLair
Цитата(haker_fox @ Nov 24 2012, 12:56) *
Да. Настройки линкера - Ваша цель rolleyes.gif


Да. У меня так работает мой загрузчик. При старте МК получает ip от DHCP сервера (можно и статический), и представляется FTP сервером. Затем, я "захожу" туда Total Commander'ом и "заливаю" бинарник. Чтобы сообщить загрузчику, что код можно исполнять, нужно "дозалить" файл с именем done. Полуив его, загрузчик проверяет, загружен ли до этого файл *.bin, и если да, то передает ему управление. Если нет - в моем случае ничего не делает. Ждет)

Извините за оффтоп, вы сами ftp сервер писали или взяли где? я тоже хочу запустить FTP но нигде примеров не нашёл хоть с BSD не портируй ((
Allregia
Цитата(AndyDev @ Nov 24 2012, 12:38) *
Что-то я не нашел, где устанавливается размещение ОЗУ для файла.


Alt-F7 на файле в Project, или правую кнопку и там верхняя стройка меню - Options for file....

Далее на вкладке Properties, внизу есть Memory Assignment, и там можно отдельно для Code/Const, ZI Data, Other Data указать где им быть - в ROMx, RAMx, IRAMx.
SyncLair
Цитата(AndyDev @ Nov 24 2012, 14:38) *
Подскажите тогда заодно, как в Кейле передаются параметеры в функцию, написанную на асме? Через стек, регистры? Какие регистры можно в этой функции использовать? Где вообще почитать инфу о соглашении на счет регистров в подобном случае?


В кейле как и везде передаюстся согласно стандарту АРМ на вызовы процедур.
AASPC-- так вроде называется. Если коротко, то через регистры с нулевого по третий.

haker_fox
QUOTE (SyncLair @ Nov 24 2012, 20:07) *
Извините за оффтоп, вы сами ftp сервер писали или взяли где? я тоже хочу запустить FTP но нигде примеров не нашёл хоть с BSD не портируй ((

Нет, самому мне не под силу такое rolleyes.gif
Я использовал библиотеку RL-ARM. Буквально за вечер смастерил приложение.
А примеры на RL-ARM есть. Более менее позволяют разобраться. Документация у Кейла на мой взгляд - вполне rolleyes.gif
_Артём_
Цитата(AndyDev @ Nov 24 2012, 12:38) *
У меня NXP1114, у него флешка слабенькая, на 50Мгц много тормозов дает.

Какой выигрыш получится от переноса функций в ОЗУ? Есть такие данные?
AndyDev
Цитата(_Артём_ @ Nov 24 2012, 15:47) *
Какой выигрыш получится от переноса функций в ОЗУ? Есть такие данные?

Зависит от конкретного микроконтроллера.
Если, допустим, у вас от 20-30Мгц задержка на доступ во флеш 1, от 30 до 40 - 2, 40 до 50 - 3,
то на каждую считанную команду вместо одного такта будет тратиться 2, 3 и 4, соответственно. Сами прикиньте.
Сергей Борщ
QUOTE (AndyDev @ Nov 24 2012, 13:52) *
Сами прикиньте.
Шина к флешке у него, насколько помню, 32-битная, команды 16-битные, значит за один цикл чтения вынимаются 2 команды. На переходах это, конечно, не спасает, но код состоит не из одних переходов. Далеко не все команды исполняются за 1 такт, значит во время их исполнения достаточно времени для чтения следующей команды. Прикидка показывает, что не все так страшно. Поэтому вас и спрашивали о реальных данных.
AndyDev
Цитата(Сергей Борщ @ Nov 25 2012, 00:15) *
Прикидка показывает, что не все так страшно. Поэтому вас и спрашивали о реальных данных.

Замеряю - напишу.
AndyDev
Цитата(AndyDev @ Nov 25 2012, 15:34) *
Замеряю - напишу.

Перенес несколько критичных к скорости функций в ОЗУ, и вся программа стала работать примерно на 50-60% быстрее.
А сами критичные функции, как-то ДПФ и т.д. - ускорились почти в два раза.

Микроконтроллер LPC1114, тактовая частота 48МГц. Делитель тактовой частоты FlashClock = 3 (как и положено для скоростей от 40 до 50МГц).
Сергей Борщ
QUOTE (AndyDev @ Nov 26 2012, 15:55) *
А сами критичные функции, как-то ДПФ и т.д. - ускорились почти в два раза.
Спасибо, полезная информация.
_Артём_
Цитата(AndyDev @ Nov 26 2012, 15:55) *
Перенес несколько критичных к скорости функций в ОЗУ, и вся программа стала работать примерно на 50-60% быстрее.

Интересно, спасибо.

Цитата(AndyDev @ Nov 26 2012, 15:55) *
А сами критичные функции, как-то ДПФ и т.д. - ускорились почти в два раза.

Попробовал потестить тем что под руку попалось: 50 не 50 - видимо зависит от функций.
Получилось - 20770 циклов из flash и 16600 циклов из ОЗУ - быстрей на 25 %,
CM0 приблизился к CM3 из flash на той же функции. sm.gif
Если конечно чего не попутал, что тоже возможно на ночь глядя.
Тактовая на тестовом проекте была вроде 48, но это наверное не важно, если wait-стайтов 3?.

PS. На каких бы функциях потестить и чтобы со сборкой функций не париться - что есть такое неэкзотическое.

Цитата(AndyDev @ Nov 26 2012, 15:55) *
Делитель тактовой частоты FlashClock = 3 .

Про FlashClock DS ничего не знает. FLASHTIM=2?
Могут быть ещё настройки влияющие на скорость выполнения из флеш у lpc11xx?
AndyDev
Цитата(_Артём_ @ Nov 27 2012, 02:50) *
Про FlashClock DS ничего не знает. FLASHTIM=2?
Могут быть ещё настройки влияющие на скорость выполнения из флеш у lpc11xx?


Не знаю, что такое DS )
Думаю, что больше настроек нет.

Устанавливаю так:

Код
      LPC_FLASH->FLASHCFG = (LPC_FLASH->FLASHCFG & 0xFFFFFFFC) | 0x2;    // FlashClock = 3 (установить делитель
                                                        // тактовой частоты для FlashMemory равным 3,
                                                        // для частот тактирования 40..50МГц
                                                        // (по умолчанию при сбросе так же)

Вячик13
Как поместить при компилировании, допустим, подпрограмму в ОЗУ мне понятно. Но разъясните, пожалуйста, поподробнее, как при старте приложения туда записать тело подпрограммы, если у меня нет загрузки извне, а приложение уже находится в FLASH?
Сергей Борщ
QUOTE (Вячик13 @ Nov 29 2012, 08:16) *
как при старте приложения туда записать тело подпрограммы, если у меня нет загрузки извне, а приложение уже находится в FLASH?
Точно также, как в ОЗУ попадают начальные значения инициализированных переменных - образ этой области ОЗУ хранится во флеше и перед запуском main() копируется в ОЗУ стартап-кодом. Если ваши функции поместить в этот же сегмент, то они могут быть скопированы в этом же цикле. А может быть в вашей среде разработки это делается отдельным циклом, значит размещать надо в другой сегмент. Или вообще для этого есть ключевое слово и компилятор по нему все разместит куда надо сам. Не ленитесь, изучите документацию на ваш компилятор/линкер - там наверняка этот вопрос расписан и пример есть.
редактор
За это отвечает стартап файл. Изначально тело подпрограммы зашито в код где то в области констант наверно.
При загрузке МК стартап проводит инициализацию памяти, копирует константы, в том числе и код RAM-функций.
Как-то так.
Вячик13
Спасибо, понял.
AndyDev
Не совсем по теме, но в том же проекте.

Использую функцию memset() для очистки памяти.
Все работает, но при компиляции всегда выдает предупреждение:

TestMain.c(1295): warning: #223-D: function "memset" declared implicitly

Оно и понятно, т.к. в инклудах не указан файл с этой функцией.
Но какой файл надо указать - я не знаю. В стандартных типа stdio и stdlib ее нету.
-JonnS-
Цитата
В стандартных типа stdio и stdlib ее нету.

string.h
AndyDev
Цитата(-JonnS- @ Feb 12 2013, 22:51) *

Большое спасибо, помогло.

И еще, можно ли в сишном исходнике принудительно указать, чтобы какие-то данные тоже выравнивались на границу, скажем 4 байта (границу слова). Допустим, у меня есть массив из short (16 бит), который при компиляции будет размещен выровненным на границу 2-х байт. Но работая с ним из ассемблера, мне бы было удобно считывать сразу по несколько 16-битных переменных таким образом LDM R0!,{R1,R2}. Но для этого массив обязательно должен быть выровнен на границу слова (4 байта).
Lotor
Цитата(AndyDev @ Feb 13 2013, 13:18) *
Большое спасибо, помогло.

И еще, можно ли в сишном исходнике принудительно указать, чтобы какие-то данные тоже выравнивались на границу, скажем 4 байта (границу слова).

Можно. С помощью директив Вашего компилятора.
AndyDev
Цитата(Lotor @ Feb 13 2013, 13:42) *
Можно. С помощью директив Вашего компилятора.

У меня Keil. Какие у него директивы для этого?
Lotor
Цитата(AndyDev @ Feb 13 2013, 13:46) *
У меня Keil. Какие у него директивы для этого?

Как-то так:
Код
__align(8) char buffer[64];
AndyDev
Цитата(Lotor @ Feb 13 2013, 13:52) *
Как-то так:
Код
__align(8) char buffer[64];

Большое спасибо, очень помогло!
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.