реклама на сайте
подробности

 
 
 
Reply to this topicStart new topic
> STM32F429 + SDRAM + Keil, Расположение переменных в памяти
MiklPolikov
сообщение Dec 3 2015, 14:53
Сообщение #1


Профессионал
*****

Группа: Свой
Сообщений: 1 942
Регистрация: 23-01-07
Из: Москва
Пользователь №: 24 702



Есть STM32F429 + SDRAM IS42S16400J-7TLI 64Мбит , проект в Keil.

Возникли вопросы:
1) Можно ли сделать так, что бы обращение к памяти было не через указатель на её адрес, а просто путем инициализации переменной ?
Т.е. что бы в коде декларировалась переменная char x[100000]; а уже компилятор сам размещал её по адресу внешней памяти ?
2) Нужно сообщить компилятору о наличие этой памяти, а для этого адрес и размер памяти нужно указать вот тут (картинка) в строке RAM1 ? И поставить галочку слева ?
А что означает галочка справа no init ?
3) Нужно ли заботится о том, что бы во внешней памяти размещались только большие массивы, а все часто используемые переменные были во внутренней ?
4) Какие ещё тонкости нужно учитывать ?

Заранее спасибо !
Эскизы прикрепленных изображений
Прикрепленное изображение
 


--------------------
Если у Вас не практического опыта в данной теме- не вступайте в дискуссию и не пишите никаких теоретических рассуждений! Заранее спасибо !
Go to the top of the page
 
+Quote Post
KnightIgor
сообщение Dec 3 2015, 17:11
Сообщение #2


Знающий
****

Группа: Участник
Сообщений: 625
Регистрация: 29-05-09
Из: Германия
Пользователь №: 49 725



Цитата(MiklPolikov @ Dec 3 2015, 15:53) *
Есть STM32F429 + SDRAM IS42S16400J-7TLI 64Мбит , проект в Keil.
Возникли вопросы:

Мне кажется, ультимативный подход - это размещение переменных для внешней RAM путем размещения их в определенной секции с последующим указанием в скрипте компоновщика (скаттере), что секция должна попасть во внешнюю RAM.

Четыре шага:
1. В опциях проекта, именно в том диалоге, что Вы привели в картинке, активировать либо IRAM2, либо RAM1, с указанием области адресов и размера.
2. Переменная для той RAM получит атрибут с именем секции:

char BlaBla[1000] __attribute__((section("EXTRAM")));

3. Скаттер, который генерируется по-умолчанию (имя проекта.SCT), дополнить (сразу за RW_IRAM1):

RW_IRAM2 <begin address> <size> {
*(EXTRAM)(+RW +ZI)
} ; если активирована IRAM2


или

RW_RAM1 <begin address> <size> {
*(EXTRAM)(+RW +ZI)
} ; если активирована RAM1


4. Переименовать скаттер файл и указать его явно в опциях проекта в секции компоновщика.
Go to the top of the page
 
+Quote Post
adnega
сообщение Dec 3 2015, 18:08
Сообщение #3


Гуру
******

Группа: Свой
Сообщений: 2 354
Регистрация: 14-05-07
Из: Ярославль, Россия
Пользователь №: 27 702



Цитата(KnightIgor @ Dec 3 2015, 20:11) *
Четыре шага:

При указании массива с атрибутом +ZI будет произведена его инициализация?
В какой момент производится инициализация? До main() в startup?
Внешняя память (интерфейс) настраивается после вызова main() и обращения к ней ранее не допустимы.

Что делать?:
1. Указать, что память не нуждается в инициализации и всю жизнь помнить об этом? Как это сделать?
2. Перенести инициализацию интерфейса внешней памяти вместе с тестированием в startup?
Нужно ли в нем заботится об инициализации областей data и bss или все случится на автомате?
А если это плюсы то, там, вроде, еще и конструкторы нужно инициализировать? Ничего не забыл?
Что делать если память не проходит тест? До инициализации памяти нужно еще много чего проиницализировать (RCC, GPIO).
Причем, такая инициализация использует переменные, которые тоже должны быть проинициализированы.
Или забыть о Си и шпарить без переменных на асме в startup?

Короче, кто как делает?
Go to the top of the page
 
+Quote Post
aaarrr
сообщение Dec 3 2015, 19:08
Сообщение #4


Гуру
******

Группа: Свой
Сообщений: 10 213
Регистрация: 11-12-04
Пользователь №: 1 448



Цитата(adnega @ Dec 3 2015, 21:08) *
При указании массива с атрибутом +ZI будет произведена его инициализация?

ZI - это не атрибут переменной, а тип секции. Атрибут переменной - __attribute__((zero_init)),
при присвоении этого атрибута переменной, она будет помещена в секцию типа ZI.
Как ясно из названия, будет инициализирован нулями.

Цитата(adnega @ Dec 3 2015, 21:08) *
В какой момент производится инициализация? До main() в startup?

Уже после startup, внутри __main():
startup -> __main -> 'C' main()

Цитата(adnega @ Dec 3 2015, 21:08) *
1. Указать, что память не нуждается в инициализации и всю жизнь помнить об этом? Как это сделать?

В scatter-файле через атрибут секции UNINIT.

Цитата(adnega @ Dec 3 2015, 21:08) *
2. Перенести инициализацию интерфейса внешней памяти вместе с тестированием в startup?
Нужно ли в нем заботится об инициализации областей data и bss или все случится на автомате?
А если это плюсы то, там, вроде, еще и конструкторы нужно инициализировать? Ничего не забыл?
Что делать если память не проходит тест? До инициализации памяти нужно еще много чего проиницализировать (RCC, GPIO).
Причем, такая инициализация использует переменные, которые тоже должны быть проинициализированы.
Или забыть о Си и шпарить без переменных на асме в startup?

А смысл тестировать память? Внутреннюю тоже тестируете? Неисправная железка - это неисправная железка, ничего не поделаешь.

Инициализацию можно написать на 'C', не будут доступны для использования только глобальные инициализированные переменные.
Go to the top of the page
 
+Quote Post
MiklPolikov
сообщение Dec 3 2015, 19:20
Сообщение #5


Профессионал
*****

Группа: Свой
Сообщений: 1 942
Регистрация: 23-01-07
Из: Москва
Пользователь №: 24 702



Спасибо большое за ответы.
Я понял, что лучше ничего не говорить компилятору про внешнюю память, а большие переменные писать в неё через указатели с заданными вручную адресами. sm.gif


--------------------
Если у Вас не практического опыта в данной теме- не вступайте в дискуссию и не пишите никаких теоретических рассуждений! Заранее спасибо !
Go to the top of the page
 
+Quote Post
Tarbal
сообщение Dec 3 2015, 19:59
Сообщение #6


Профессионал
*****

Группа: Свой
Сообщений: 1 242
Регистрация: 21-05-10
Пользователь №: 57 439



Цитата(MiklPolikov @ Dec 3 2015, 23:20) *
Спасибо большое за ответы.
Я понял, что лучше ничего не говорить компилятору про внешнюю память, а большие переменные писать в неё через указатели с заданными вручную адресами. sm.gif


Так конечно проще, но лучше все-таки сделать как вам посоветовали. Так по правилам.
Go to the top of the page
 
+Quote Post
aaarrr
сообщение Dec 3 2015, 20:14
Сообщение #7


Гуру
******

Группа: Свой
Сообщений: 10 213
Регистрация: 11-12-04
Пользователь №: 1 448



Цитата(MiklPolikov @ Dec 3 2015, 22:20) *
Я понял, что лучше ничего не говорить компилятору про внешнюю память, а большие переменные писать в неё через указатели с заданными вручную адресами. sm.gif

Подход имеет право на жизнь, если вся внешняя память используется, например, для хранения пары массивов, задействованных в одном модуле программы.
Но даже в таком случае грех отбирать у линкера его хлеб.
Go to the top of the page
 
+Quote Post
KnightIgor
сообщение Dec 4 2015, 09:07
Сообщение #8


Знающий
****

Группа: Участник
Сообщений: 625
Регистрация: 29-05-09
Из: Германия
Пользователь №: 49 725



Цитата(aaarrr @ Dec 3 2015, 21:14) *
Подход имеет право на жизнь

Более того, оба подхода сосуществуют, если размещать-таки переменные с помощью секции, указать запрет их инициализации (noinit), но потом, ссылаясь на них как на нормально объявленные переменные (об адресах позаботился компоновщик), проинициализировать, как желаемо, да и работать потом с ними проще... Как правильно замечено, зачем отбирать у компоновщика лопату и месить бетон самому, досыпая кучу #define и заботясь вручную о распределении памяти? При таком подходе чуть что забыл, все поехало, наехало, налезло и поломало. Потом пойдут вопросы "у меня спорадически портится кусок памяти, где искать".

Кстати, я смутно припоминаю, потому могу ошибаться, что в библиотеке в части инициализации внутри __main предусмотрены "виртуальные" (слабоопределенные) функции, которые можно переписать с целью предварительной инициализации аппаратуры доступа к внешней памяти. Где-то на странице arm или onarm было. А если это-таки плод моей фантазии, то можно либо дополнить system_"processor".c, где реализована функция SystemInit(), вызываемая из startup_"processor".s, либо модифицировать тот же startup_"processor".s как ниже:
Код
              
LDR     R0, =SystemInit
BLX     R0              
IMPORT ExtRAMInit
LDR     R0, =ExtRAMInit
BLX     R0              
LDR     R0, =__main
BX      R0

написав на С функцию ExtRAMInit().

Сообщение отредактировал KnightIgor - Dec 4 2015, 09:10
Go to the top of the page
 
+Quote Post
QuadMan
сообщение May 10 2017, 13:42
Сообщение #9


Частый гость
**

Группа: Свой
Сообщений: 92
Регистрация: 25-10-05
Пользователь №: 10 069



Подниму тему, никак не могу понять одну вещь.
Использую Keil, ARM Compiler V6.6.

Вот есть у меня внешняя периферия, которая начинается с адреса 0x50000000 к примеру.
Объявляю структуру
Код
volatile __attribute__((section(".ARM.__at_0x50000000"))) SystemRegs  REGS;

Программа загружается во внешнюю память по адресу 0x10000000 и оттуда работает

в scatter файле пишу
Код
LR_IROM1 0x10000000 0x0000C800  {   ; load region size_region
  ER_IROM1 0x10000000 0x0000C800  { ; load address = execution address
   *.o (RESET, +First)
   *(InRoot$$Sections)
   .ANY (+RO)
    *(.init_array) ; Section .init_array must be placed explicitly,
                   ; otherwise it is shared between two regions, and
                   ; the linker is unable to decide where to place it.  
  }

  RW_IRAM1 0x20000000 UNINIT 0x0008000  { ; RW data
   .ANY (+RW +ZI)
  }

  ER_PERIPHERAL 0x50000000 UNINIT 0x1000
  {
    *(.ARM.__at_0x50000000)
  }
}

Теперь после запуска отладчика, программа валится в MemoryMngFault, судя по всему при отработке функции _decompress системной библиотеки.
Если убрать секцию ER_PERIPHERAL из scatter файла, и в определении переменной REGS, все компилится и запускается нормально, но REGS, естественно, располагается во внутренней памяти.

Отсюда я делаю вывод, что при загрузке компилятор пытается проинициализировать переменную REGS во внешней памяти, хотя доступ к ней еще не настроен, поэтому и валится в HardFault.

Но, ведь я указал, что эта область UNINIT, зачем он вообще туда лезет? И как правильно это дело настроить? Через указатели не очень хочется.
Go to the top of the page
 
+Quote Post
aaarrr
сообщение May 10 2017, 20:23
Сообщение #10


Гуру
******

Группа: Свой
Сообщений: 10 213
Регистрация: 11-12-04
Пользователь №: 1 448



Цитата(QuadMan @ May 10 2017, 16:42) *
Но, ведь я указал, что эта область UNINIT, зачем он вообще туда лезет?

UNINIT, но не ZI, например.

Цитата(QuadMan @ May 10 2017, 16:42) *
И как правильно это дело настроить? Через указатели не очень хочется.

Если речь идет о периферии, то правильно будет как раз через указатели.
Go to the top of the page
 
+Quote Post
QuadMan
сообщение May 11 2017, 12:15
Сообщение #11


Частый гость
**

Группа: Свой
Сообщений: 92
Регистрация: 25-10-05
Пользователь №: 10 069



Цитата(aaarrr @ May 10 2017, 23:23) *
UNINIT, но не ZI, например.


Если речь идет о периферии, то правильно будет как раз через указатели.

Ok, периферию я переделал на указатели, не сложно.

Но у меня есть еще большой массив данных, который я храню во внешней памяти.

Атрибут zero_init в компиляторе версии 6.6 не распознается, хотя это, похоже, именно то, что нужно.
sad.gif((


Go to the top of the page
 
+Quote Post
jcxz
сообщение May 12 2017, 06:34
Сообщение #12


Гуру
******

Группа: Свой
Сообщений: 3 684
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713



Цитата(QuadMan @ May 11 2017, 14:15) *
Но у меня есть еще большой массив данных, который я храню во внешней памяти.
Атрибут zero_init в компиляторе версии 6.6 не распознается, хотя это, похоже, именно то, что нужно.
sad.gif((

Я не знаю Кейла, но например в IAR, чтобы переменная не обнулялась си-стартап-кодом, недостаточно ей указать атрибут __no_init. Надо ещё её поместить в соответствующую (отдельную от .bss) секцию и указать компоновщику в его файле конфигурации не инициализировать эту секцию:
в *.cpp: static __no_init int info @ ".eraw";
в *.icf: do not initialize {section .eraw};
Возможно, что в Кейле аналогично.
Я много раз использовал в проектах внешнюю память, размещал в ней и переменные (инициализированные и нет) и код и без каких-то проблем. Точно так же как во внутренней ОЗУ. Правда всё под IAR и CCS.
Go to the top of the page
 
+Quote Post
yanvasiij
сообщение May 14 2017, 18:47
Сообщение #13


Местный
***

Группа: Свой
Сообщений: 321
Регистрация: 23-12-11
Из: Уфа
Пользователь №: 69 041



Цитата(jcxz @ May 12 2017, 11:34) *
Я не знаю Кейла, но например в IAR, чтобы переменная не обнулялась си-стартап-кодом, недостаточно ей указать атрибут __no_init. Надо ещё её поместить в соответствующую (отдельную от .bss) секцию и указать компоновщику в его файле конфигурации не инициализировать эту секцию:


В keil тоже самое, но там файл линковщика называется scatter-файлом подробнее о нем можно почитать например ТУТ, по синтаксису очень похож и на IAR и на gcc. Чтобы начать его редактировать нужно перейти в указанном ТС окне во вкладку Linker, там убрать галочку Use memory layot from target dialog, после этого станет активной строчка Scatter file, слева от этой строчки нажимаете на кнопку edit и открывается Scatter-файл на редактирование. Там вы можете объявлять секции внутри внешней ОЗУ и размещать в ней, что хотите, даже bss целых файлов. Например, есть у вас внешняя SDRAM по адресу 0x80000000 размером скажем 0x00010000 байт, и вы хотите разместить в ней всю оперативную память из файла blalbacode.cpp, тогда в scatter нужно добавить:

Код
  RW_SDRAM1 0x80000000 0x00010000  {; RW data
   blablacode.o (+RW +ZI)
  }
Go to the top of the page
 
+Quote Post

Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 17th October 2017 - 16:56
Рейтинг@Mail.ru


Страница сгенерированна за 0.01321 секунд с 7
ELECTRONIX ©2004-2016