Форум программистов, компьютерный форум, киберфорум
Наши страницы
Микроконтроллеры Atmega AVR
Войти
Регистрация
Восстановить пароль
 
Рейтинг 4.80/5: Рейтинг темы: голосов - 5, средняя оценка - 4.80
Arhat109
0 / 0 / 0
Регистрация: 18.06.2018
Сообщений: 14
#1

Внешняя SRAM 512кбайт. Как обучить линкер оверлейным сегментам данных?

18.06.2018, 18:06. Просмотров 837. Ответов 13
Метки нет (Все метки)

Ни разу не общался со сценариями линкера. Есть такая задача:

Развел и изготовил плату расширения SRAM на 512кбайт для ATmega2560 и аналогичных камней, имеющих интерфейс расширения памяти. Память не блоками по 64кб (блуждающее решение в Сети), а сегментированная и распределена следующим образом:

0x0000 - 0x2200 -- встроенная SRAM меги (8200байт). Автоматически перекрывает доступ к внешней SRAM по этим адресам;
0x2200 - 0x7FFF -- общая страница внешней SRAM (32к - 8200). Не переключается, видна постоянно;
0x8000 - 0xBFFF -- "нижнее" страничное окно, к которому можно подключить 15 сегментов по 16 килобайт (суммарно 240кб);
0xC000 - 0xFFFF -- "верхнее" страничное окно, к которому можно подключить ещё 15 сегментов по 16кб (+240кб);

В итоге хочется видеть всё это барахло в программе с правильным распределением адресов компилятором и линкером.

Из того что уже нарыл:
1. Указать в коде программы к какому сегменту данных привязана та или иная переменная/массив можно типа так:

C
1
uint8_t buffer[16000] __atribute__((section(.data))); // не инициализированный массив, разместится в секции .bss, но тут переопределен на секцию .data
и ещё, скрипт линкера "по умолчанию" подгружает в секцию все "прочие" названия по правилу *(.bss*), что вроде как позволяет "настрогать" прямо в коде "свои" секции и указывать их примерно так:

C
1
uint8_t buffer[16000] __atribute__((section(.bss_lpage2))); // не инициализированный массив, размещаем в секции .bss_lpage2
, однако сама секция .bss - "не резиновая" и просто так этого не позволит.

2. Получается что надо писать свой скрипт линкеру, где можно указать эту раскладку адресов выше на требуемые куски памяти, типа так:

MEMORY
{
INTERNAL_RAM [rwa!x] : ORIGIN = 0x800200, LENGTH = 8000;
COMMON_RAM [rwa!x] : ORIGIN = 0x802200, LENGTH = 32768-8200;
LOW_WINDOW [rw!x] : ORIGIN = 0x808000, LENGTH = 16K;
UPPER_WINDOW [rw!x] : ORIGIN = 0x80C000, LENGTH = 16K;
}

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

REGION_ALIAS(lowPage0, LOW_WINDOW);
..
REGION_ALIAS(upperPage14, UPPER_WINDOW);

и уже потом определять секции типа так:

SECTIONS {
.bss_lpage0 : { *(.bss_lpage0) } > lowPage0
...
.bss_upage14 : { *(.bss_upage14) } > upperPage14
}

После этого уже можно будет привязывать данные к требуемым сегментам в программах через __atribute__((section(...)))


2. Есть функция, которая переключает доступную страницу в окнах. Можно ли как-то её "всучить" компилятору и/или линковщику, чтобы он мог сам листать страницы в окнах, в случаях появления в коде соответствующих переменных из той или иной страницы ОЗУ?

Ну или подскажите куда копать по сценариям к линковщику..
Спасибо заранее.

Добавлено через 18 минут
Поясню второй вопрос:
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// компилятору всучена такая функция переключения страниц:
void xmem_lowPage(uint8_t lowNum);
 
// в коде имеем типа такой массив,
// размещаемый первым во втором сегменте расширенного ОЗУ:
uint8_t  buffer[4096]  __attribute__((section(.lpage2)));
 
// ...
// если в коде присутствует что-то типа такого:
for(int i=0; i<4096; i++){
  buffer[i] = 0;
}
 
// , то компилятор мог оценить какой сегмент сейчас активен и
// при необходимости дополнить его так самостоятельно:
 
xmem_lowPage(2);
for(int i=0; i<4096; i++){
  buffer[i] = 0;
}
 
// правильно подключив страничку, где определен этот массив..
Добавлено через 14 минут
Похоже вопрос №2 из раздела "фантастика" .. а по скрипту линкеру - может кто-то помочь "так оно или нет"?

Добавлено через 1 час 50 минут
Народ какое "бурное обсуждение" на 42 с гаком тыщи участников ..,

что никто ни разу в жизни не работал с сегментированной оперативкой?!?
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
18.06.2018, 18:06
Ответы с готовыми решениями:

Хранение данных во внешнем ОЗУ (SRAM)
Уважаемые граждане и гости форума, прошу Вашего содействия. Имеется платка,...

Как обучить бота разгадывать капчи?
Ну я думаю вопрос вполне понятен: Как обучить Бота разгадывать капчи? Не...

Как обучить программатор PicPgm новому Hardware?
Интересует возможность программирования МК PIC через встроенный в плату...

Внешняя память PIC: как нарастить внутреннюю память данных?
Я только начал разбираться с ПИКами и пока не все понимаю. Мне нужно...

Внешняя память данных.
Требуется работать с внешней памятью (ROM). Не могу найти внятного описания...

13
Rius
Эксперт .NET
4954 / 3176 / 781
Регистрация: 25.05.2015
Сообщений: 9,745
Записей в блоге: 11
Завершенные тесты: 4
18.06.2018, 18:18 #2

Не по теме:

Цитата Сообщение от Arhat109 Посмотреть сообщение
Народ какое "бурное обсуждение" на 42 с гаком тыщи участников ..,
что никто ни разу в жизни не работал с сегментированной оперативкой?!?
42 с гаком тыщи - это всех, по всем темам;
из них онлайн электронщиков с опытом дай бог пару десятков наберётся;
из них с такими костылями чтоб ещё работали.... может один-два, если повезёт...



Добавлено через 5 минут
Вопрошаемое можно реализовать (по крайней мере по опыту работы с ARM проблем не вижу), но без автоматического переключения сегментов.
1
Arhat109
0 / 0 / 0
Регистрация: 18.06.2018
Сообщений: 14
18.06.2018, 19:33  [ТС] #3
Пасибки, хоть так обнадежили, буду пгобовать, получится - отпишусь.

Не по теме:
Цитата Сообщение от Rius Посмотреть сообщение
из них с такими костылями чтоб ещё работали.... может один-два, если повезёт...
Блин, ну ведь линковали программы под спектрум с 256килами оперативы при адресном пространстве в 64к! Было же время, работало .. как-то не верится что современные линковщики утеряли эти технологии.

0
Rius
18.06.2018, 19:50
  #4

Не по теме:

Цитата Сообщение от Arhat109 Посмотреть сообщение
Блин, ну ведь линковали программы под спектрум с 256килами оперативы при адресном пространстве в 64к!
Ну были. И вы можете собрать такие, да и уже собрали. Только не автоматическое переключение страниц средствами, реализуемыми стандартным компилятором...

0
Arhat109
0 / 0 / 0
Регистрация: 18.06.2018
Сообщений: 14
18.06.2018, 21:49  [ТС] #5
Да уже смирился, что не получится всучить компилятору код переключалки страниц .. да и как он будет помнить какая страница в каком окне, если к примеру это некая функция, со своим static массивом? Уже ясно, что переключать только ручками.. но:

Не имея опыта писания скриптов к линковщикам, мне просто хочется понять на правильном ли я пути? т.е. оно ТАК пишется или как-то иначе?
0
Rius
Эксперт .NET
4954 / 3176 / 781
Регистрация: 25.05.2015
Сообщений: 9,745
Записей в блоге: 11
Завершенные тесты: 4
19.06.2018, 06:22 #6
Лучший ответ Сообщение было отмечено Arhat109 как решение

Решение

Упрощённо так (на ARM)...

Регионы памяти:
Код
/* Specify the memory areas */
MEMORY
{
  RAM (xrw)      : ORIGIN = 0x20000000, LENGTH = 96K
  RAM2 (xrw)      : ORIGIN = 0x10000000, LENGTH = 32K
  FLASH (rx)      : ORIGIN = 0x8000000, LENGTH = 256K
}
Секция:
Код
  
  . = ALIGN(4);
  .mysection :
  {
    _smysection = .;
    *(.mysection)
    *(.mysection*)
    . = ALIGN(4);
    _emysection = .;
  } >RAM
Код:
C++
1
2
__attribute__ ((section(".mysection")))
uint8_t dataArray[1024];
Linker Command Language
The GNU linker
2
Arhat109
0 / 0 / 0
Регистрация: 18.06.2018
Сообщений: 14
19.06.2018, 09:39  [ТС] #7
Полез в исходники линкерных скриптов Ардуино за "образцом": hardware/tools/avr/avr/lib/ldscripts/ и внезапно обнаружил по нескольку копий скрипта для одной и той же версии архитектуры, в частности для avbr6 имеются:

avr6.x, avr6.xn, avr6.xbn, avr6.xr, avr6.xu

Кто-то может подсказать зачем такой "комплект" и какой из них в каких случаях используется? В настройках Ардуино ИДЕ - ничего про это нет, в строках которыми ИДЕ компилирует и собирает исходники - тоже никакой специальный выбор скрипта не указан. В описании на gcc - пока ничего не нашел, как он выбирает расширение для скрипта линкера по умолчанию...

Какой скрипт изменять?!?
0
Rius
Эксперт .NET
4954 / 3176 / 781
Регистрация: 25.05.2015
Сообщений: 9,745
Записей в блоге: 11
Завершенные тесты: 4
19.06.2018, 10:28 #8
Лучший ответ Сообщение было отмечено Arhat109 как решение

Решение

Изменять их не надо. Скопируйте себе и меняйте копию.

Why are there five different linker scripts?
From a comment in the source code:
Which one of the five linker script files is actually used depends on command line options given to ld.
  • A .x script file is the default script.
  • A .xr script is for linking without relocation (-r flag).
  • A .xu script is like .xr but *do* create constructors (-Ur flag).
  • A .xn script is for linking with -n flag (mix text and data on same page).
  • A .xbn script is for linking with -N flag (mix text and data on same page).
Добавлено через 1 минуту
Цитата Сообщение от Arhat109 Посмотреть сообщение
как он выбирает расширение для скрипта линкера по умолчанию...
Там файл явно указывается вроде.
1
Arhat109
0 / 0 / 0
Регистрация: 18.06.2018
Сообщений: 14
20.06.2018, 09:00  [ТС] #9
О, пасибки! (куда-то кнопка пропала) ..

Нет, Ардуино ИДЕ не указывает никакого скрипта, и я понимаю что линковщик avr-ld ищет типовой скрипт согласно указанной модели -mmcu, вот пример строки сборки из ИДЕ:

"/home/.../hardware/tools/avr/bin/avr-gcc" -Wall -Wextra -Os -Wl,--gc-sections -mmcu=atmega328p -o "/tmp/build8f6f47e5e1cc707751d4ea83951bb27b.tmp/sketch_jun05a.ino.elf" "/tmp/build8f6f47e5e1cc707751d4ea83951bb27b.tmp/sketch/sketch_jun05a.ino.cpp.o" "/tmp/build8f6f47e5e1cc707751d4ea83951bb27b.tmp/core/core.a" "-L/tmp/build8f6f47e5e1cc707751d4ea83951bb27b.tmp" -lm

При этом вызов с опцией --verbose выдает встроенный скрипт по умолчанию для архитектуры avr2, то есть воспользоваться им, при сборке под Мега2560 - ну никак не получится, а ведь как-то собирает! Остается сделать вывод что нагло пользуется опцией -mmcu

Ещё раз - пасибки.

Опция -Tскрипт у avr-ld похоже работает.

Добавлено через 22 часа 20 минут
Спасибо за помощь, тему можно закрывать, всё получилось.

Итого, что надо сделать для Ардуино ИДЕ (проверялось в версии 1.6.11, должно работать с версии 1.6.5 по идее):

1. Создаем свое описание такой платы в boards.txt, добавляя туда кроме прочих такую строчку по изменению скрипта компоновщика:
Bash
1
sram.menu.cpu.atmega2560.compiler.c.elf.extra_flags=-T{build.variant.path}/avr6.x -Wl,--defsym=__heap_start=0x802200,--defsym=__heap_end=0x807fff
,где sram - название платы, ".cpu.atmega2560" у меня просто выделены как пункты подменю, для расширения описания на остальные процы, имеющие этот интерфейс по аналогии с MegaCore проектом.
Заодно указываем символы для кучи malloc() смещая её ЗА стек во внутренней памяти и до конца "общей страницы в 32кб.

2. Создаем подкаталог в variants с названием этой платы, тут variants/sram и копируем в него arduino_pins.h из нужного места (тут из подкаталога variants/mega) И переносим в него скрипт линкера avr6.x, который дополняем позже так:

секция MEMORY:
Bash
1
2
3
  data       (rw!x) : ORIGIN = 0x800200, LENGTH = 32K-0x200
  wndLow     (rw!x) : ORIGIN = 0x808000, LENGTH = 16K
  wndHigh    (rw!x) : ORIGIN = 0x80C000, LENGTH = 16K
Тут заодно исправил размер секци .data уменьшив его до 32к - начало, то есть до конца общей страницы расширенной SRAM.

добавляем описание своих секций (добавлял после секции .noinit):
Bash
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
  /* Window page segments for extSRAM as BSS only! not initialized, not loaded to elf! */
  .lpage0  ORIGIN(wndLow) (NOLOAD) : { *(.lpage0)  } > wndLow
  .lpage1  ORIGIN(wndLow) (NOLOAD) : { *(.lpage1)  } > wndLow
  .lpage2  ORIGIN(wndLow) (NOLOAD) : { *(.lpage2)  } > wndLow
  .lpage3  ORIGIN(wndLow) (NOLOAD) : { *(.lpage3)  } > wndLow
  .lpage4  ORIGIN(wndLow) (NOLOAD) : { *(.lpage4)  } > wndLow
  .lpage5  ORIGIN(wndLow) (NOLOAD) : { *(.lpage5)  } > wndLow
  .lpage6  ORIGIN(wndLow) (NOLOAD) : { *(.lpage6)  } > wndLow
  .lpage7  ORIGIN(wndLow) (NOLOAD) : { *(.lpage7)  } > wndLow
  .lpage8  ORIGIN(wndLow) (NOLOAD) : { *(.lpage8)  } > wndLow
  .lpage9  ORIGIN(wndLow) (NOLOAD) : { *(.lpage9)  } > wndLow
  .lpage10 ORIGIN(wndLow) (NOLOAD) : { *(.lpage10) } > wndLow
  .lpage11 ORIGIN(wndLow) (NOLOAD) : { *(.lpage11) } > wndLow
  .lpage12 ORIGIN(wndLow) (NOLOAD) : { *(.lpage12) } > wndLow
  .lpage13 ORIGIN(wndLow) (NOLOAD) : { *(.lpage13) } > wndLow
  .lpage14 ORIGIN(wndLow) (NOLOAD) : { *(.lpage14) } > wndLow
  .lpage15 ORIGIN(wndLow) (NOLOAD) : { *(.lpage15) } > wndLow
 
  .hpage0  ORIGIN(wndHigh) (NOLOAD) : { *(.hpage0)  } > wndHigh
  .hpage1  ORIGIN(wndHigh) (NOLOAD) : { *(.hpage1)  } > wndHigh
  .hpage2  ORIGIN(wndHigh) (NOLOAD) : { *(.hpage2)  } > wndHigh
  .hpage3  ORIGIN(wndHigh) (NOLOAD) : { *(.hpage3)  } > wndHigh
  .hpage4  ORIGIN(wndHigh) (NOLOAD) : { *(.hpage4)  } > wndHigh
  .hpage5  ORIGIN(wndHigh) (NOLOAD) : { *(.hpage5)  } > wndHigh
  .hpage6  ORIGIN(wndHigh) (NOLOAD) : { *(.hpage6)  } > wndHigh
  .hpage7  ORIGIN(wndHigh) (NOLOAD) : { *(.hpage7)  } > wndHigh
  .hpage8  ORIGIN(wndHigh) (NOLOAD) : { *(.hpage8)  } > wndHigh
  .hpage9  ORIGIN(wndHigh) (NOLOAD) : { *(.hpage9)  } > wndHigh
  .hpage10 ORIGIN(wndHigh) (NOLOAD) : { *(.hpage10) } > wndHigh
  .hpage11 ORIGIN(wndHigh) (NOLOAD) : { *(.hpage11) } > wndHigh
  .hpage12 ORIGIN(wndHigh) (NOLOAD) : { *(.hpage12) } > wndHigh
  .hpage13 ORIGIN(wndHigh) (NOLOAD) : { *(.hpage13) } > wndHigh
  .hpage14 ORIGIN(wndHigh) (NOLOAD) : { *(.hpage14) } > wndHigh
  .hpage15 ORIGIN(wndHigh) (NOLOAD) : { *(.hpage15) } > wndHigh
Тут на каждое "окно" региона памяти по 16кб (начиная с 32кб и 48кб) заведено по 16 страниц (сколько их можно переключить на плате) и, для каждой из них, указано что они начинаются с адреса окна "принудительно". Иначе линкер "продолжает адресацию в программе, если указаны несколько массивов в соседних секциях. Так - работает верно.

Собственно и всё что надо.
Тестировал на этом коде, проверяя что выходит из под реассемблера avr-objdump:
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
int lowbuffer[10] = {1,2,3,4,5,6,7,8,9,0}; // section data
int buffer2[4000] __attribute__((section(".lpage2")));
int buffer4[4000] __attribute__((section(".lpage4")));
int buffer6[4000] __attribute__((section(".hpage6")));
 
volatile int tmp; // section bss
 
void setup()
{
}
 
void loop()
{
  for(int j=0; j<4000; j++){
      tmp = 55;                // volatile!
      buffer2[j] = tmp;
      buffer4[j] = tmp*2;
      tmp = buffer4[j];
      buffer6[j] = tmp;        // volatile!
  }
}
Все три массива скомпилялись "как надо", с нужных адресов своих окон.
0
Rius
20.06.2018, 09:12
  #10

Не по теме:

Arhat109, почему сразу не взять МК с 512КБ ОЗУ? Либо более простой МК, поддерживающий аппаратно такую внешнюю ОЗУ?..

0
Arhat109
0 / 0 / 0
Регистрация: 18.06.2018
Сообщений: 14
20.06.2018, 11:09  [ТС] #11
Ну ... сложный вопрос.
Наверное "исторически". (не холивара для, исключительно ИМХО. Обсуждать критику и возражения не буду, буду тупо жать кнопарь):

Атмеловские меги как 8-и битные управляющие микроконтроллеры - очень интересный продухт и наверное где-то даже лучший в своем классе. И мега2560 в этом плане - практически их "вершина", если не смотреть в сторону xmega.

Хочется посмотреть что можно интересного реализовать при избытке памяти, ну и таки допилить а-ля "Лего-кирпич" (для обучения детишек) из неё. Правда пока оно идет с "переменным успехом" уже наверное год .. каждый месяц появляется новое понимание "как" можно сделать "ишо лучше" .. вот, сейчас, находясь где-то на финишной прямой, понял что плату можно было развести "ещё красивше" .. переделывать? снова?
0
Rius
20.06.2018, 11:18
  #12

Не по теме:

Цитата Сообщение от Arhat109 Посмотреть сообщение
вот, сейчас, находясь где-то на финишной прямой, понял что плату можно было развести "ещё красивше" .. переделывать? снова?
Конечно!) Потому что вот этот процесс может быть бесконечным:
Цитата Сообщение от Arhat109 Посмотреть сообщение
каждый месяц появляется новое понимание "как" можно сделать "ишо лучше"
:)

Совершенство достигнуто не тогда, когда нечего добавить, а когда нечего убрать.

0
Arhat109
0 / 0 / 0
Регистрация: 18.06.2018
Сообщений: 14
20.06.2018, 11:39  [ТС] #13
Пополню тему, вдруг кому приспичит повторять это. Описание принципиальной схемы шилда, svg-файлы для ЛУТ, раскладка деталек, а также сами платы на базе mega128a mega2560, какое-то обсуждение есть тут: {del-ссылки на сторонние форумы запрещены}

Добавлено через 15 минут
P.S. Так вот и находится "чего убрать" ..
0
Arhat109
0 / 0 / 0
Регистрация: 18.06.2018
Сообщений: 14
21.06.2018, 08:32  [ТС] #14
Раз запрещены ссылки, дублирую тут, на случай если кто захочет поиметь себе полноценную плату микроконтроллера с расширенной памятью для обучательных целей (переплевываем EV3 блок):

1. Плата микроконтроллера МУРК-2560 ( Мега - Учебный, с Расширителем Контроллер на базе ATmega2560). Архив содержит: схему электрическую + svg-файлы для самостоятельного изготовления плат F-CU - зеркально, + слой F-SILK размещения деталек.
Это "второй релиз платы" со стабилизатором питания на базе RT8289 - с токами по шине питания до 5А. Методом ЛУТ изготавливал опытную плату первой версии (AMS1117-5.0). БП оказался слабоват для подключения больше 1 серводвигателя.
Фотки опытной платы вложил тоже.

2. Плата расширенной памяти. Подключается с обратной стороны платы МУРК к разьему расширения памяти (тот что не запаян на фото опытной платы). Есть только схема + разводка под ЛУТ, саму плату не паял, только начал. Делал опытный вариант, но он меня не устроил..

На все есть gerber-файлы из kicad и по 10шт плат (всего 30: МУРК-128а, МУРК-2560 и SRAM512k) получил от китайцев за смешные 12 долларов.

Не по теме:

В общем, пока наши "производители" не смогут работать также аккуратно, быстро и четко по ценнику (а не пришлите нам письмо - скажем цену .. в 8700руб - было "самое дешевое предложение на этот комплект плат!) - никакого "импортозамещения" ждать не стоит..

0
Миниатюры
Внешняя SRAM 512кбайт. Как обучить линкер оверлейным сегментам данных?   Внешняя SRAM 512кбайт. Как обучить линкер оверлейным сегментам данных?   Внешняя SRAM 512кбайт. Как обучить линкер оверлейным сегментам данных?  

Вложения
Тип файла: zip MYPK-2560-v2.zip (154.3 Кб, 0 просмотров)
Тип файла: zip SRAM512k.zip (76.8 Кб, 0 просмотров)
21.06.2018, 08:32
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
21.06.2018, 08:32

Линкер и компиллятор
только не смейтесь, не умею толком работать с данными инструментами. среда...

Ругается линкер
Что-то приключилось с компилятором, всегда когда нормально уже напишу...

Ошибка ,линкер еррор
Всем привет. Делаю прогу (инст), почти доделал, выскакивает ошибка Unresolved...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
14
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2018, vBulletin Solutions, Inc.
Рейтинг@Mail.ru