ARDUINO Диспетчер внешней SRAM для AVR (Mega2560, Mega128a, etc)

09.06.2019
57
5
8
#1
SRAM-512K schema.png

Первоначальная (оригинальная) схема доп. платы расширения внутренней SRAM микроконтроллеров на базе микросхемы HMM628512BLFP-5, емкостью 512 килобайт с временем доступа 50нс. На самом деле у значительного количества микросхем самых разных производителей статической памяти цоколевка SOP-32 корпусов имеет точно такую разводку ног и примерно те же самые тайминги. А, с учетом того что сюда вполне подходят и микросхемы памяти медленнее (3 такта ЦПУ микроконтроллера на цикл чтения/записи), то реальный выбор микросхем - "практически не ограничен" и их стоимость на момент покупки была в районе 40-60руб/корпус на АлиЭкспресс. Как итого, можно "придираться" к доп. параметрам, таким как "потребление в активном и пассивном режимах", возможность хранения с пониженным питанием, наличие встроенной батарейки для хранения при выключении .. и т.д. вплоть до поиска корпусов FRAM - ферритовой памяти, сохраняющей состояние длительно и вовсе без питания.
В общем - применимость весьма велика как и разнообразие поделок.

P.S. Изменения в схеме:
1. диод Д1, проводящий сигнал ALE на ногу CS чипа памяти - НЕ НУЖЕН и даже вреден. Его надо убрать, а входной сигнал EN подавать от дополнительной ножки микроконтроллера для "ручного" включения работы SRAM.
2. Подтягивать сигнал ALE к питанию - не надо!
3. На схему надо добавить резистор с базы на землю у Q1 не более 4.7к-9.1к, иначе он не закрывается полноценно.
4. Резистор R14 2.4к стоит уменьшить до 1к. В таком варианте, пауза для записи номера страницы получается около 45-90 тактов ЦПУ на 16Мгц. Чем меньше резистор с базы на землю - тем быстрее запирается этот транзистор. В целом некритично, поскольку это механизм переключения страниц..

Описание работы дистпетчера SRAM

1. Регистр-защелка U1 - строго согласно даташита занят демультиплексированием младшей части адреса ячейки А0-А7, в момент снятия сигнала ALE микроконтроллером. Ничем больше он не занимается и тут подходят только "быстродействующие" варианты типа 74HC573D или "быстрые" серии ACT, HCT и т.д.
Младшая часть адреса выведена на дополнительный интерфейс платы отдельно (см. средний прямоугольник).

2. Второй регистр (573D, U2) - регистр "страниц" ОЗУ. Хранит в младшей и старшей части текущие "номера страниц" от 0 до 15 и создает 2 "адресных пространства" по 256кб совместно с мультиплексором U3. Выбором подаваемой страницы на адресную шину ОЗУ управляет нога PortC бит6 (PC6, адресная линия А14) по входу S мультиплексора. Инвертированный транзистором сигнал адресной линии А15 (PC7) - принудительно переводит мультиплексор в третье состояние.
Поскольку его выходы подтянуты к питанию, это дает "фиксированный" адрес страницы на выходе, а именно последнюю №15.

Такое применение линий А14,А15, фактически разделяет адресное пространство микроконтроллера (64кб) на 3 окна:
"common window": А15==0, А14 - любое. Размер = 32кб. Расположение от 0 до 32кб.
"low window": А15=1, А14 = 0 - нижнее окно. На шину адреса ОЗУ выдается младшая тетрада регистра страниц. И из ОЗУ используется СВОЯ(!) половина памяти 256кб!
"high window": А15=1, А14=1 - верхнее окно. На шину адреса выдается старшая тетрада регистра страниц U2, и в ОЗУ используется вторая половина адресов, благодаря прохождению на адресную линию все того же сигнала А14!

3. Запись номеров страниц в регистр U2. Было замечено, что в даташите нигде(!) одновременно не используется 2 низких сигнала на линиях WR,RD! Этот факт и положен в основу записи номеров страниц ОЗУ в регистр с той же самой линии данных: При обоих низких сигналах диодно-транзисторной ИЛИ-НЕ схемой (D3,D4,Q1) разрешается прохождение шины данных в регистр и по снятию любого из них - происходит фиксация номеров страниц в регистре. Просто, дешево и сердито. :)
Управление записью номеров страниц в регистр производится библиотекой "вручную", при отключенном режиме "внешнего ОЗУ". При этом, чтобы не происходило дополнительной ложной записи в ОЗУ сигнал EN должен быть переведен также в закрытое состояние силами ПО.

Итого, имеем страничный диспетчер ОЗУ емкостью на 512килобайт, который предоставляет программам нижнее, общее и единое (не перепрограммируемое) окно в 32 килобайта, часть из которого занимает внутреннее ЗУ микроконтроллера. Кроме этого, предоставляется 2 окна по 16килобайт с возможностью "листания" страниц ОЗУ размером по 16кб, также НЕ пересекающихся между собой. Например страница №3 нижнего блока никак не доступна в расположении в верхнем окне адресного пространства ЦПУ. При статической линковке адресов это "аппаратно" исключает возможность "кривой адресации" из-за перемещения страницы ЗУ "чисто физически".

Ну вот. Нашел пока это..
 
Последнее редактирование:
09.06.2019
57
5
8
#2
Дополнительное применение не по прямому назначению.

Поскольку вся шина работы с ОЗУ выведена на разьем, то если держать сигнал EN=1 и не пользоваться ОЗУ, вручную, можно иметь:
а) дополнительно 8 бит (регистр U1) параллельного интерфейса управления чем-либо с записью в него данных ручным ногодрыгом по линии ALE;
Тут есть один недостаток: линии данных (portA) также будут пропускать через себя это "управление".
б) дополнительно иметь 4 линии из мультиплексора "переключаемых" вручную сигналом PC6 с младшей/старшей тетрады регистра страниц, запись в который как и выше производится низким уровнем на обоих линиях WR и RD. Можно чем-нибудь 4-х битно "моргать" переключая PC6 туда-сюда.
Недостаток - тот же. В момент записи в регистр страниц точно также используется регистр А микроконтроллера и его выводы.
:)
 
09.06.2019
57
5
8
#3
C:
/**
* Extended Memory Sram (ems)
*
* !!! ВНИМАНИЕ: требует специального скрипта для линковщика с описанием секций RAM
*
* Тестовый код для управления внешней SRAM 512кбайт.
* Организация SRAM:
* PORTA -- AD0..7 совмещенная шина адреса/данных стробируется сигналом ALE
* регистры управления:
* XMCRA (0x0074):
*    7     6     5     4     3      2      1      0
*   SRE, SRL2, SRL1, SRL0, SRW11, SRW10, SRW01, SRW00
*
* SRE - разрешает работу интерфейса,
* SRL2:0 - граница нижнего/верхнего сегмента (адресного пространства {0,1:all upper, 2-7:0x4000..0xE000 upper},
* SRW1x - количество доп. тактов ожидания для верхнего сегмента,
* SRW0x - оно же для нижнего, если он есть.
*
* XMCRB (0x0075):
*     7          2     1     0
*   XMBK, ххх, XMM2, XMM1, XMM0
*
* XMBK - удекрживать данные на шине между тактами и адресом/данных (не переводить в Hz),
* XMMx - ширина шины адреса {0-all 16бит = 64k;1-PC7 не исп. 15бит 32k; 2-PC6 16k,..7-only 8 bit address без порта C)
*
* SRAM512kb имеет дополнительно:
* 1. Регистр номеров страниц: старшая тетрада - 0..15 верхнее окно 0xC000, младшая тетрада - 0..15 нижнее окно 0x8000
*    Запись в регистр страниц: вручную, через PORTA при !RD = !WR = 0, то есть номер проходит в регистр, если оба сигнала LOW
*      и защелкивается при записи HIGH в любой из пинов !RD, !WR или оба сразу.
*    Чтение регистра страниц - не предусмотрено.
*    Но из него есть комбинированный вывод 4 бит (0xF, старших или младших), в зависимости от PC7,PC6:00|01=>F, 10=>low, 11=>high;
*    то есть, младшие 32к адресов (PC7=0) выдают F, а старшие (PC7=1) в зависимости от PC6 младшую или старшую тетраду.
* 2. Регистр защелка сладшей части адреса. Используется интерфейсом самостоятельно, но можно использовать вручную при дополнительно,
*    при отключенном интерфейсе: PORTA записывается в регистр при ALE=1 и защелкивается в нем при ALE=0. Этот регистр имеет свои
*    отдельные выводы на шине расширения памяти, также как регистр страниц.
* 
* @author Arhat109
*/

// полезный, удобный макрос: собирает байт из младших полубайтов со сдвигами..
#define makeByte(h,l) (((((uint8_t)(h))<<4)&0xF0)|(((uint8_t)(l))&0x0F))

// определяем где и что находится у микроконтроллера (ATmega2560):
// 19 линий интерфейса внешней SRAM:
#define EMS_ALE         PG2
#define EMS_RD          PG1
#define EMS_WR          PG0
#define EMS_PORT_BUS    PORTG
#define EMS_DDR_BUS     DDRG
#define EMS_PORT_AD     PORTA
#define EMS_DDR_AD      DDRA
#define EMS_PORT_ADR    PORTC
#define EMS_DDR_ADR     DDRC

// последние адреса окон памяти и размеры окон:
// [0-8.5k[ - "own page"(internal SRAM); [8.5k-32k[ - "common page";
// [32k-48k[ - "low page"; [48k-64k[ - "high page".
#define EMS_OWN_END     (0x21FF)
#define EMS_COMMON_END  (0x7FFF)
#define EMS_LP_END      (0xBFFF)
#define EMS_HP_END      (0xFFFF)

#define SIZE_COMMONS (EMS_COMMON_END - EMS_OWN_END)
#define SIZE_LOWS    (EMS_LP_END - EMS_COMMON_END)
#define SIZE_HIGHS   (EMS_HP_END - EMS_LP_END)

// Доступные секции памяти (удобства для), см. спец. секции в расширении файла линковщика:
// На самом деле есть только 4 типа адресов (окон у процессора):
// внутренняя память, общий блок до 32кбайт и нижние/верхние окна для подключения страниц..
// Данные, обьявленные:
// а) без указания страницы - размещается во внутренеей памяти (секции .data, .bss, @see avr6.x):
// б) EMS_COMMON -- в общем блоке от конца internal до 32767-го байта включительно;
// в) EMS_LOW()  -- [0,15] -- размещение в "нижних" сегментах по 16кб с адреса 0x8000
// г) EMS_HIGH() -- [0,15] -- размещение в "верхних" сегментах по 16кб с адреса 0xC000
// Внимательно! последние страницы (15) - это тот же блок что и COMMON,
// но так можно иметь доступ к его младшим адресам, перекрытым внутренней памятью
//
#define EMS_COMMON        __attribute__((section(".cpage")))
#define EMS_LOW(pageNum)  __attribute__((section(".lpage" #pageNum)))
#define EMS_HIGH(pageNum) __attribute__((section(".hpage" #pageNum)))

uint8_t emsPages; // копия регистра страниц в нижней SRAM
uint8_t emsWaits; // количество тактов ожидания интерфейса @see emsOn(_ws);

/** 3t: установка служебных ног интерфейса "на выход" */
#define emsBusOut()      (EMS_DDR_BUS |= (1<<EMS_ALE)|(1<<EMS_RD)|(1<<EMS_WR))

/** 3t: разрешение записи в регистр страницы (интерфейс д.быть отключен!) */
#define emsPagesOpen()   (EMS_PORT_BUS &= ~((1<<EMS_WR)|(1<<EMS_RD)))

/** 3t: защелкивание в регистре страниц значения с шины AD (интерфейс д.быть отключен!) */
#define emsPagesLock()   (EMS_PORT_BUS |= ((1<<EMS_WR)|(1<<EMS_RD)))

/**
* ТОЛЬКО активация Extended Memory SRAM единым верхним куском без удержания шины
* + включение упр. сигналов на выход и заодно подтяжка к +5в
*
* @param uint8_t _ws -- wait states for interface
* @time 8t(const _ws)/7t(register _ws)
*/
#define emsOn(_ws)                            \
{                                             \
  emsWaits = (_ws);                           \
  XMCRA = (1 << SRE) | (((uint8_t)(_ws))<<2); \
  XMCRB = 0;                                  \
}
/**
* отключалка интерфейса extSRAM
* @time 1t
*/
#define emsOff() (XMCRA = 0)

/**
* Настройка БЕЗ включения интерфейса для setup() или раньше
*
* @param uint8_t _ws -- wait states for interface
* @time 6t
*/
#define emsSetup()    \
{                     \
  EMS_DDR_AD = 0xFF;  \
  EMS_DDR_ADR = 0xFF; \
  emsBusOut();        \
}

/**
* =================== Макросы сохранения номера страницы в глобал: ================ //
* @param uint8_t lp,hp,p
* @time 7t для emsStoreLow(),emsStoreHigh()
* @time 2t для emsStorePages()
*/
#define emsStoreLow(lp)      (emsPages=(emsPages&0xF0) | ((uint8_t)(lp)&0x0F))
#define emsStoreHigh(hp)     (emsPages=((uint8_t)(lp)&0xF0) | (emsPages&0x0F))
#define emsStorePages(p)     (emsPages=(uint8_t)(p))

/**
* =========================== Установка И запись страниц: ======================== //
* Пишем номера страниц блоков low, high в регистр страниц вручную, отключая extSRAM
*
* @time 31t (1.9375usec)
*/
void emsWritePages(void)
{
  cli();
  emsOff();                         //  1t, отключаем интерфейс extSRAM
  EMS_DDR_AD    = 0xFF;             //  1t, порт А (A/D) "на выход"
  emsPagesOpen();                   //  3t, оба сигнала !RD,!WR в LOW
  EMS_PORT_AD   = emsPages;         //  1t, номера страниц в A/D
  __asm__ __volatile__ ("nop" :::); //  1t, ждем 1 такт (62.5нсек)
  emsPagesLock();                   //  3t, оба сигнала !RD,!WR в HIGH
  EMS_DDR_AD    = 0;                //  1t, освобождаем порта А
  emsOn(emsWaits);                  // 10t, включаем интерфейс, восстанавливая тайминги
  sei();                            // 1t+1t+4t+4t (cli+sei+ret+call)
}

/**
* Запись в регистр страниц номер low page [0..15]
*
* @param uint8_t lowPage
* @time 38t
*/
#define emsWriteLow(lowPage) \
{                            \
  emsStoreLow(lowPage);      \
  emsWritePages();           \
}

/**
* Запись в регистр страниц номер high page [0..15]
*
* @param uint8_t highPage
* @time 38t
*/
#define emsWriteHigh(highPage) \
{                              \
  emsStoreHigh(highPage);      \
  emsWritePages();             \
}

/**
* Проверяет заданный буфер на совпадение с шаблоном,
* в случае расхождения вызывает callback().
* Прерывает работу, если callback() возвращает не 0.
*
* @param void (*)callback(uint16_t _addr, uint8_t _pattern, uint8_t _readed)
* @return count summary errors
*/
uint16_t emsMemtest(
  uint8_t * _buffer,  // буфер поиска расхождения
  uint16_t  _size,    // размер буфера
  uint8_t   _pattern, // искомый образец
  uint8_t (*callback)(uint8_t *_addr, uint8_t _pattern, uint8_t _readed) // нашел тут это!
){
  uint16_t res = 0;

  do{
    uint8_t tmp = *_buffer;

    if( tmp != _pattern ){
      res++;
      if( callback(_buffer, _pattern, tmp) ) return res;
    }
    _buffer++;
  }while( --_size > 0 );

  return res;
}

Тут первый кусок тестового скетча (единомоментно не лезет в 1 пост). Собственно библиотека примитивов для работы с внешним ОЗУ по схеме первого поста. Можно обрамить условной компиляцией, указанием что это код "из С" и использовать как обычную библиотеку.

В комментарии добавлены вырезки из даташита - справочно, дабы "не забыть самому" что где и куда. :)
 
Последнее редактирование:
09.06.2019
57
5
8
#4
C:
// =========================== ТЕСТ РУЧНОГО УПРАВЛЕНИЯ: ======================== //

/**
* в loop():
* Функция медленной и ручной побитной установки значений на шинах для
* проверки светодиодами работоспосоности пайки и платы в целом..
* щелкает сигналом ALE для проверки записи в регистр защелки адреса.
* Также можно проверить работу мультиплексора адреса от PC6,7
*/
void manualTest()
{
  for(uint8_t bit=0; bit<=7; bit++){
    EMS_PORT_BUS |= (1<<EMS_ALE);  // разрешаем запись
    emsPagesOpen();                // открываем регистр страниц на запись
    EMS_PORT_AD = (1<<bit);        // младшая часть адреса в защелку
    EMS_PORT_BUS &= ~(1<<EMS_ALE); // защелкиваем младшую часть адреса (шина AD)
    delay(500);                    // на посмотреть..
    emsPagesLock();                // защелкиваем и в регистр страниц тоже
    EMS_PORT_ADR = (1<<bit);       // старшая часть адреса отдельно
    delay(500);
  }
}
/**
* Имитация записи/четния SRAM вручную
*/
void manualTest2()
{
  EMS_PORT_ADR = 0; // старшая часть адреса тут не нужна

  for(uint8_t bit=0; bit<=7; bit++){
    EMS_PORT_AD = (1<<bit);        // младшая часть адреса (bit) в защелку
    EMS_PORT_BUS |= (1<<EMS_ALE);  // разрешаем запись адреса
    delay(500);                    // на посмотреть..
    EMS_PORT_BUS &= ~(1<<EMS_ALE); // защелкиваем младшую часть адреса (шина AD)

    EMS_PORT_AD = ~(1<<bit);       // данные на шину (кроме bit)
    EMS_PORT_BUS &= ~(1<<EMS_WR);  // запись
    delay(500);
    EMS_PORT_BUS |= (1<<EMS_WR);   // типа записали

    EMS_PORT_AD = 0;               // гасим все после записи
    delay(1000);

    EMS_PORT_AD = (1<<bit);        // младшая часть адреса снова в защелку
    EMS_PORT_BUS |= (1<<EMS_ALE);  // разрешаем запись адреса
    delay(500);                    // на посмотреть..
    EMS_PORT_BUS &= ~(1<<EMS_ALE); // защелкиваем младшую часть адреса (шина AD)

    EMS_DDR_AD = 0;                // шина AD на ввод
    EMS_PORT_BUS &= ~(1<<EMS_RD);  // чтение
    delay(500);
    EMS_PORT_BUS |= (1<<EMS_RD);   // типа прочли

    EMS_DDR_AD = 0xFF;             // шина AD на вывод
    EMS_PORT_AD = 0;               // гасим все после чтения
    delay(1500);
  }
}

// ============================= Простейший тест: ========================== //
volatile uint8_t *adr;

void simpleTest(void)
{
  uint8_t tmp;

  Serial.println("Simple test started..");
  for( adr=(uint8_t*)(EMS_OWN_END+1); adr<=(uint8_t*)(EMS_OWN_END+10); adr++){
//  for( adr=(uint8_t*)(0x1000); adr<=(uint8_t*)(0x1000+10); adr++){
    *adr = 0xAA;
    tmp = *adr;
    if( tmp != 0xAA ){ Serial.println(tmp, DEC); }
    else             { Serial.println("ok");     }
  }
  Serial.println("Simple test ended");
  do{}while(1);
}

// =========================== ТЕСТОВЫЙ ПРИМЕР ТУТ: ======================== //

// объявляем 3 массива в разных окнах:

uint8_t commons[SIZE_COMMONS] EMS_COMMON;  // 24064 байт от внутренней SRAM в первых 32кбайтах
uint8_t lows[SIZE_LOWS]       EMS_LOW(0);  // 16кбайт от 32к до 48к
uint8_t highs[SIZE_HIGHS]     EMS_HIGH(0); // 16кбайт от 48к до 64к

uint8_t patterns[4] = {0xFF, 0x00, 0xAA, 0x55}; // образцы записи в память

/** собираем из обьявленных массивов пакет для тестирования */
#define MAX_PAGES 3
struct{
  uint8_t * address;
  uint16_t  size;
} pages[MAX_PAGES] = {{commons, SIZE_COMMONS}, {lows, SIZE_LOWS}, {highs, SIZE_HIGHS}};

/**
* callback() для вывода ошибки сохранения на монитор (и прервать работу)
*/
uint8_t testError(uint8_t *_addr, uint8_t _pattern, uint8_t _readed)
{
  Serial.println();
  Serial.print("ERROR at 0x"); Serial.print((uint16_t)_addr, HEX);
  Serial.print(", pattern="); Serial.print(_pattern, DEC);
  Serial.print(", readed="); Serial.print(_readed, DEC);
  return 0;
}

/**
* Собственно тест памяти:
* перебираем образцы, и страницы в пакете, заливаем страницу образцом
* и проверяем на совпадение с шаблоном
*/
void test(void){
  uint16_t errors;

  for(int8_t i=sizeof(patterns); i>=0; --i){
    for(int page=0; page<MAX_PAGES; page++){
      Serial.println();
      Serial.print("PAGE="); Serial.print(page, DEC);
      errors=0;
      memset(pages[page].address, patterns[i], pages[page].size);
      errors = emsMemtest(pages[page].address, pages[page].size, patterns[i], testError);
      if( errors != 0 ){
        Serial.print(" .. ERROR OCURED=");
        Serial.println(errors, DEC);
      }else{
        Serial.println(" .. is OK)");
      }
    }
  }
}

// =========================== SETUP() ======================== //

void setup()
{
//  emsSetup();
  emsOn(0);
  Serial.begin(115200);
}

void loop()
{
//  manualTest();
//  manualTest2();
  simpleTest();
//  test();
}
Собственно тестовая часть...

Первые 2 "manual" теста - это контроль пропайки платы светодиодами. Полезно, если нет осцилографа под рукой. Подключаем к разъему светодиоды, прошиваем тест и .. смотрим как бегают битики по светодиодам. Для вылавливания разного рода не пропаев.

Третий simpleTest содержит запись 10 байт шаблона во внешнюю SRAM и контроль чтения. Там есть закомментированная строка заговолка цикла, которая делает то же самое но во встроенную память МК. Если что-то идет не так - на убедиться что сам по себе тест рабочий.

Последний тест проверяет заданные страницы памяти по заданному набору шаблонов полностью. Выводит в сериал только найденные ошибки, если они есть. Там можно задавать разные страницы, шаблоны и вообще использовать как образец работы с расширенной памятью в программах.

Максимально доступный непрерывный массив, может теоретически занимать всё свободное окно микроконтроллера, т.е. для Мега2560 это 56 килобайт. Вручную, листая страницы, можно обрабатывать хоть все 520кб (512 внешних + 8 внутренних). :)
 
Последнее редактирование:
09.06.2019
57
5
8
#5
Код:
/* Default linker script, for normal executables */
OUTPUT_FORMAT("elf32-avr","elf32-avr","elf32-avr")
OUTPUT_ARCH(avr:6)
MEMORY
{
  text       (rx)   : ORIGIN = 0, LENGTH = 1024K
  data       (rw!x) : ORIGIN = 0x800200, LENGTH = 8K
  wndCommon  (rw!x) : ORIGIN = 0x802200, LENGTH = 32K-0x2200
  wndLow     (rw!x) : ORIGIN = 0x808000, LENGTH = 16K
  wndHigh    (rw!x) : ORIGIN = 0x80C000, LENGTH = 16K
  eeprom     (rw!x) : ORIGIN = 0x810000, LENGTH = 64K
  fuse       (rw!x) : ORIGIN = 0x820000, LENGTH = 1K
  lock       (rw!x) : ORIGIN = 0x830000, LENGTH = 1K
  signature  (rw!x) : ORIGIN = 0x840000, LENGTH = 1K
}

SECTIONS
{
  /* Read-only sections, merged into text segment: */
  .hash          : { *(.hash)        }
  .dynsym        : { *(.dynsym)        }
  .dynstr        : { *(.dynstr)        }
  .gnu.version   : { *(.gnu.version)    }
  .gnu.version_d : { *(.gnu.version_d)    }
  .gnu.version_r : { *(.gnu.version_r)    }
  .rel.init      : { *(.rel.init)    }
  .rela.init     : { *(.rela.init)    }
  .rel.text      :
    {
      *(.rel.text)
      *(.rel.text.*)
      *(.rel.gnu.linkonce.t*)
    }
  .rela.text     :
    {
      *(.rela.text)
      *(.rela.text.*)
      *(.rela.gnu.linkonce.t*)
    }
  .rel.fini      : { *(.rel.fini)    }
  .rela.fini     : { *(.rela.fini)    }
  .rel.rodata    :
    {
      *(.rel.rodata)
      *(.rel.rodata.*)
      *(.rel.gnu.linkonce.r*)
    }
  .rela.rodata   :
    {
      *(.rela.rodata)
      *(.rela.rodata.*)
      *(.rela.gnu.linkonce.r*)
    }
  .rel.data      :
    {
      *(.rel.data)
      *(.rel.data.*)
      *(.rel.gnu.linkonce.d*)
    }
  .rela.data     :
    {
      *(.rela.data)
      *(.rela.data.*)
      *(.rela.gnu.linkonce.d*)
    }
  .rel.ctors     : { *(.rel.ctors)    }
  .rela.ctors    : { *(.rela.ctors)    }
  .rel.dtors     : { *(.rel.dtors)    }
  .rela.dtors    : { *(.rela.dtors)    }
  .rel.got       : { *(.rel.got)    }
  .rela.got      : { *(.rela.got)    }
  .rel.bss       : { *(.rel.bss)    }
  .rela.bss      : { *(.rela.bss)    }
  .rel.plt       : { *(.rel.plt)    }
  .rela.plt      : { *(.rela.plt)    }

  /* Internal text space or external memory.  */
  .text   :
  {
    *(.vectors)
    KEEP(*(.vectors))
    /* For data that needs to reside in the lower 64k of progmem.  */
     *(.progmem.gcc*)
    /* PR 13812: Placing the trampolines here gives a better chance
       that they will be in range of the code that uses them.  */
    . = ALIGN(2);
     __trampolines_start = . ;
    /* The jump trampolines for the 16-bit limited relocs will reside here.  */
    *(.trampolines)
    *(.trampolines*)
     __trampolines_end = . ;
     *(.progmem*)
    . = ALIGN(2);
    /* For future tablejump instruction arrays for 3 byte pc devices.
       We don't relax jump/call instructions within these sections.  */
    *(.jumptables)
    *(.jumptables*)
    /* For code that needs to reside in the lower 128k progmem.  */
    *(.lowtext)
    *(.lowtext*)
     __ctors_start = . ;
     *(.ctors)
     __ctors_end = . ;
     __dtors_start = . ;
     *(.dtors)
     __dtors_end = . ;
    KEEP(SORT(*)(.ctors))
    KEEP(SORT(*)(.dtors))
    /* From this point on, we don't bother about wether the insns are below or above the 16 bits boundary.  */
    *(.init0)  /* Start here after reset.  */
    KEEP (*(.init0))
    *(.init1)
    KEEP (*(.init1))
    *(.init2)  /* Clear __zero_reg__, set up stack pointer.  */
    KEEP (*(.init2))
    *(.init3)
    KEEP (*(.init3))
    *(.init4)  /* Initialize data and BSS.  */
    KEEP (*(.init4))
    *(.init5)
    KEEP (*(.init5))
    *(.init6)  /* C++ constructors.  */
    KEEP (*(.init6))
    *(.init7)
    KEEP (*(.init7))
    *(.init8)
    KEEP (*(.init8))
    *(.init9)  /* Call main().  */
    KEEP (*(.init9))
    *(.text)
    . = ALIGN(2);
     *(.text.*)
    . = ALIGN(2);
    *(.fini9)  /* _exit() starts here.  */
    KEEP (*(.fini9))
    *(.fini8)
    KEEP (*(.fini8))
    *(.fini7)
    KEEP (*(.fini7))
    *(.fini6)  /* C++ destructors.  */
    KEEP (*(.fini6))
    *(.fini5)
    KEEP (*(.fini5))
    *(.fini4)
    KEEP (*(.fini4))
    *(.fini3)
    KEEP (*(.fini3))
    *(.fini2)
    KEEP (*(.fini2))
    *(.fini1)
    KEEP (*(.fini1))
    *(.fini0)  /* Infinite loop after program termination.  */
    KEEP (*(.fini0))
     _etext = . ;
  }  > text

  .data :
  {
     PROVIDE (__data_start = .) ;
    /* --gc-sections will delete empty .data. This leads to wrong start
       addresses for subsequent sections because -Tdata= from the command
       line will have no effect, see PR13697.  Thus, keep .data  */
    KEEP (*(.data))
    *(.data*)
    *(.rodata)  /* We need to include .rodata here if gcc is used */
    *(.rodata*) /* with -fdata-sections.  */
    *(.gnu.linkonce.d*)
    . = ALIGN(2);
    _edata = . ;
    PROVIDE (__data_end = .) ;
  }  > data AT> text

  .bss   : AT (ADDR (.bss))
  {
     PROVIDE (__bss_start = .) ;
    *(.bss)
    *(.bss*)
    *(COMMON)
     PROVIDE (__bss_end = .) ;
  }  > data
   __data_load_start = LOADADDR(.data);
   __data_load_end = __data_load_start + SIZEOF(.data);

  /* Global data not cleared after reset.  */
  .noinit  :
  {
     PROVIDE (__noinit_start = .) ;
    *(.noinit*)
     PROVIDE (__noinit_end = .) ;
     _end = . ;
     PROVIDE (__heap_start = .) ;
  }  > data

  /* Window page segments for extSRAM as BSS only! not initialized, not loaded to elf! */
  .cpage ORIGIN(wndCommon) (NOLOAD) : { *(.cpage) } > wndCommon

  .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

  .eeprom  :
  {
    /* See .data above...  */
    KEEP(*(.eeprom*))
     __eeprom_end = . ;
  }  > eeprom
  .fuse  :
  {
    KEEP(*(.fuse))
    KEEP(*(.lfuse))
    KEEP(*(.hfuse))
    KEEP(*(.efuse))
  }  > fuse
  .lock  :
  {
    KEEP(*(.lock*))
  }  > lock
  .signature  :
  {
    KEEP(*(.signature*))
  }  > signature
  /* Stabs debugging sections.  */
  .stab 0 : { *(.stab) }
  .stabstr 0 : { *(.stabstr) }
  .stab.excl 0 : { *(.stab.excl) }
  .stab.exclstr 0 : { *(.stab.exclstr) }
  .stab.index 0 : { *(.stab.index) }
  .stab.indexstr 0 : { *(.stab.indexstr) }
  .comment 0 : { *(.comment) }
  .note.gnu.build-id : { *(.note.gnu.build-id) }
  /* DWARF debug sections.
     Symbols in the DWARF debugging sections are relative to the beginning
     of the section so we begin them at 0.  */
  /* DWARF 1 */
  .debug          0 : { *(.debug) }
  .line           0 : { *(.line) }
  /* GNU DWARF 1 extensions */
  .debug_srcinfo  0 : { *(.debug_srcinfo) }
  .debug_sfnames  0 : { *(.debug_sfnames) }
  /* DWARF 1.1 and DWARF 2 */
  .debug_aranges  0 : { *(.debug_aranges) }
  .debug_pubnames 0 : { *(.debug_pubnames) }
  /* DWARF 2 */
  .debug_info     0 : { *(.debug_info .gnu.linkonce.wi.*) }
  .debug_abbrev   0 : { *(.debug_abbrev) }
  .debug_line     0 : { *(.debug_line .debug_line.* .debug_line_end ) }
  .debug_frame    0 : { *(.debug_frame) }
  .debug_str      0 : { *(.debug_str) }
  .debug_loc      0 : { *(.debug_loc) }
  .debug_macinfo  0 : { *(.debug_macinfo) }
  /* SGI/MIPS DWARF 2 extensions */
  .debug_weaknames 0 : { *(.debug_weaknames) }
  .debug_funcnames 0 : { *(.debug_funcnames) }
  .debug_typenames 0 : { *(.debug_typenames) }
  .debug_varnames  0 : { *(.debug_varnames) }
  /* DWARF 3 */
  .debug_pubtypes 0 : { *(.debug_pubtypes) }
  .debug_ranges   0 : { *(.debug_ranges) }
  /* DWARF Extension.  */
  .debug_macro    0 : { *(.debug_macro) }
}

Тут собственно добавлено описание "страниц" и то куда их надо маппировать линкеру. Ничего особенного тут нет.
 
09.06.2019
57
5
8
#6
Код:
##-- описание новых пунктов меню - в самое начало файла boards.txt:
menu.BOARD=board subtype
menu.clock=Clock cpu/board
menu.BOD=BOD
menu.LTO=Compiler LTO
menu.BOOT=BOOT options
##-- собственно сборка для всех "мег" совместимой серии:

##############################################################

megaAll.name=*** ATmega640/1280/1281/2560/2561 ***

###--- common settings for all boards and MCU ---###
megaAll.upload.tool=avrdude
megaAll.upload.speed=115200
megaAll.upload.protocol=wiring

megaAll.bootloader.tool=avrdude
megaAll.bootloader.unlock_bits=0x3F
megaAll.bootloader.lock_bits=0x0F

megaAll.build.core=arduino

##--- LTO submenu ---##
# Compiler link time optimization
megaAll.menu.LTO.Os=Disabled
megaAll.menu.LTO.Os.compiler.c.extra_flags=
megaAll.menu.LTO.Os.compiler.c.elf.extra_flags=
megaAll.menu.LTO.Os.lto_elf_flags=
megaAll.menu.LTO.Os.compiler.S.flags=-c -g -x assembler-with-cpp
megaAll.menu.LTO.Os.compiler.cpp.extra_flags=
megaAll.menu.LTO.Os.ltoarcmd=avr-ar

megaAll.menu.LTO.Os_flto=Enabled
megaAll.menu.LTO.Os_flto.compiler.c.extra_flags=-Wextra -flto
megaAll.menu.LTO.Os_flto.compiler.c.elf.extra_flags=-w -flto
megaAll.menu.LTO.Os_flto.lto_elf_flags=-w -flto
megaAll.menu.LTO.Os_flto.compiler.S.flags=-c -g -x assembler-with-cpp -flto
megaAll.menu.LTO.Os_flto.compiler.cpp.extra_flags=-Wextra -flto
megaAll.menu.LTO.Os_flto.ltoarcmd=avr-gcc-ar

##--- board selector submenu ---##
megaAll.menu.BOARD.arduino2560=Arduino Mega 2560 (common)
megaAll.menu.BOARD.arduino2560.upload.maximum_data_size=8192
megaAll.menu.BOARD.arduino2560.build.variant=mega
megaAll.menu.BOARD.arduino2560.build.board=AVR_MEGA2560

megaAll.menu.BOARD.megaADK=Arduino Mega ADK
megaAll.menu.BOARD.megaADK.upload.maximum_data_size=8192
megaAll.menu.BOARD.megaADK.build.variant=mega
megaAll.menu.BOARD.megaADK.build.board=AVR_ADK

megaAll.menu.BOARD.esram32=with ext.SRAM 32 kbytes
megaAll.menu.BOARD.esram32.upload.maximum_data_size=32256
megaAll.menu.BOARD.esram32.build.variant=mega
megaAll.menu.BOARD.esram32.build.board=AVR_MEGA2560
megaAll.menu.BOARD.esram32.compiler.c.elf.extra_flags= {lto_elf_flags} -Wl,--defsym=__heap_start=0x802200,--defsym=__heap_end=0x807fff

megaAll.menu.BOARD.esram64=with ext.SRAM 64 kbytes
megaAll.menu.BOARD.esram64.upload.maximum_data_size=65024
megaAll.menu.BOARD.esram64.build.variant=mega
megaAll.menu.BOARD.esram64.build.board=AVR_MEGA2560
megaAll.menu.BOARD.esram64.compiler.c.elf.extra_flags={lto_elf_flags} -Wl,--defsym=__heap_start=0x802200,--defsym=__heap_end=0x80ffff

megaAll.menu.BOARD.esram5=MYPK-xxx with ext.SRAM 512kbytes
megaAll.menu.BOARD.esram5.upload.maximum_data_size=32256
megaAll.menu.BOARD.esram5.build.variant=sram
megaAll.menu.BOARD.esram5.build.board=AVR_MEGA2560
megaAll.menu.BOARD.esram5.compiler.c.elf.extra_flags={lto_elf_flags} -T{build.variant.path}/avr6.x -Wl,--defsym=__heap_start=0x802200,--defsym=__heap_end=0x807fff

##--- CLOCK submenu ---##
# low fuse bits:
# bit7   -- CKDIV8 ==0 divider 1/8 is ON!
# bit6   -- CKOUT  ==0 CLKO is worked to output!
# bit5,4 -- SUT1,0: power on reset timing
# bit3,2,1,0 -- CKSEL3:0:
# -----------------------
# 0xF8..0xFF -- Low power external oscilator
# 0xF6..0xF7 -- Full swing external oscilator
# 0xF4..0xF5 -- Low frequency etxernal oscilator
# 0xF3       -- Internal 128kHz oscilator
# 0xF2       -- Calibrated internal oscilator (8Mhz)
# 0xF0       -- external clock no oscilator
#

megaAll.menu.clock.20ext=20 MHz external
megaAll.menu.clock.20ext.build.f_cpu=20000000L
megaAll.menu.clock.20ext.bootloader.low_fuses=0xf7

megaAll.menu.clock.18ext=18.432 MHz external
megaAll.menu.clock.18ext.build.f_cpu=18432000L
megaAll.menu.clock.18ext.bootloader.low_fuses=0xf7

megaAll.menu.clock.16ext=16 MHz external
megaAll.menu.clock.16ext.build.f_cpu=16000000L
megaAll.menu.clock.16ext.bootloader.low_fuses=0xf7

megaAll.menu.clock.12ext=12 MHz external
megaAll.menu.clock.12ext.build.f_cpu=12000000L
megaAll.menu.clock.12ext.bootloader.low_fuses=0xf7

megaAll.menu.clock.8ext=8 MHz external
megaAll.menu.clock.8ext.build.f_cpu=8000000L
megaAll.menu.clock.8ext.bootloader.low_fuses=0xf7

megaAll.menu.clock.int8=internal 8 MHz
megaAll.menu.clock.int8.build.f_cpu=8000000L
megaAll.menu.clock.int8.bootloader.low_fuses=0xE2

megaAll.menu.clock.int1M=internal 1 MHz
megaAll.menu.clock.int1M.build.f_cpu=1000000L
megaAll.menu.clock.int1M.bootloader.low_fuses=0x62

megaAll.menu.clock.128k=internal 128kHz
megaAll.menu.clock.128k.build.f_cpu=128000L
megaAll.menu.clock.128k.bootloader.low_fuses=0x62

##--- BOD Level submenu ---##
# extended fuse bits only this works:

megaAll.menu.BOD.dis=Disabled
megaAll.menu.BOD.dis.bootloader.extended_fuses=0xff
megaAll.menu.BOD.1v8=1.8v (4Mhz)
megaAll.menu.BOD.1v8.bootloader.extended_fuses=0xfe
megaAll.menu.BOD.2v7=2.7v (8Mhz)
megaAll.menu.BOD.2v7.bootloader.extended_fuses=0xfd
megaAll.menu.BOD.4v3=4.3v (16Mhz)
megaAll.menu.BOD.4v3.bootloader.extended_fuses=0xfc
#megaAll.bootloader.extended_fuses=0xfc

##--- BOOT submenu ---##
# High fuse bits this:
# bit7   -- OCDEN   -- ?!?
# bit6   -- JTAGEN  -- JTAG debugging is enable?
# bit5   -- SPIEN   -- SPI loading is enable?
# bit4   -- WDTON   -- watchdog is on always?
# bit3   -- EESAVE  -- protected EEPROM for erase?
# bit2,1 -- BOOTSZ  -- size for bootloader: 00-4096b, 01-2048b, 10-1024b, 11-512b
# bit0   -- BOOTRST -- from where reset start

# only SPI + bootsector=4096
megaAll.menu.BOOT.stk500v2=stk500v2
megaAll.menu.BOOT.stk500v2.bootloader.high_fuses=0xD8
megaAll.menu.BOOT.stk500v2.bootloader.file=stk500v2/stk500boot_v2_mega2560.hex

# optiboot in 1024 sector
megaAll.menu.BOOT.optiboot=Optiboot in 1024 bytes
megaAll.menu.BOOT.optiboot.bootloader.high_fuses=0xD6
megaAll.menu.BOOT.optiboot.bootloader.file=optiboot_flash_256kb/{build.mcu}/optiboot_flash_{build.mcu}_{upload.speed}_{build.f_cpu}.hex

##--- CPU submenu ---
megaAll.menu.cpu.atmega2560=ATmega2560
megaAll.menu.cpu.atmega2560.build.core=arduino
megaAll.menu.cpu.atmega2560.build.board=AVR_ATmega2560
megaAll.menu.cpu.atmega2560.build.mcu=atmega2560
megaAll.menu.BOOT.stk500v2.menu.cpu.atmega2560.upload.maximum_size=258048
megaAll.menu.BOOT.optiboot.menu.cpu.atmega2560.upload.maximum_size=261120

# special for 1280 arduino loader
megaAll.menu.cpu.atmega1280=ATmega1280
megaAll.menu.cpu.atmega1280.BOARD.mega2560.build.board=AVR_MEGA
megaAll.menu.BOOT.1280spec.menu.cpu.atmega1280=mega1280 arduino bootloader
megaAll.menu.BOOT.1280spec.menu.cpu.atmega1280.bootloader.high_fuses=0xDA
megaAll.menu.BOOT.1280spec.menu.cpu.atmega1280.bootloader.file=atmega/ATmegaBOOT_168_atmega1280.hex
megaAll.menu.BOOT.1280spec.menu.cpu.atmega1280.upload.speed=57600
megaAll.menu.BOOT.1280spec.menu.cpu.atmega1280.maximum_size=126976
megaAll.menu.BOOT.stk500v2.menu.cpu.atmega1280.maximum_size=126976
megaAll.menu.BOOT.optiboot.menu.cpu.atmega1280.maximum_size=130048
megaAll.menu.cpu.atmega1280.build.mcu=atmega1280

megaAll.menu.cpu.atmega640=ATmega640
megaAll.menu.cpu.atmega640.build.core=MegaCore
megaAll.menu.cpu.atmega640.build.variant=standard
megaAll.menu.cpu.atmega640.build.board=AVR_ATmega640
megaAll.menu.BOOT.stk500v2.menu.cpu.atmega640.upload.maximum_size=61440
megaAll.menu.BOOT.optiboot.menu.cpu.atmega640.upload.maximum_size=64512
megaAll.menu.cpu.atmega640.build.mcu=atmega640

megaAll.menu.cpu.atmega2561=ATmega2561
megaAll.menu.cpu.atmega2561.build.core=MegaCore
megaAll.menu.cpu.atmega2561.build.variant=standard
megaAll.menu.cpu.atmega2561.build.board=AVR_ATmega2561
megaAll.menu.BOOT.stk500v2.menu.cpu.atmega2561.upload.maximum_size=258048
megaAll.menu.BOOT.optiboot.menu.cpu.atmega2561.upload.maximum_size=261120
megaAll.menu.cpu.atmega2561.build.mcu=atmega2561

megaAll.menu.cpu.atmega1281=ATmega1281
megaAll.menu.cpu.atmega1281.build.core=MegaCore
megaAll.menu.cpu.atmega1281.build.variant=standard
megaAll.menu.cpu.atmega1281.build.board=AVR_ATmega1281
megaAll.menu.BOOT.stk500v2.menu.cpu.atmega1281.maximum_size=126976
megaAll.menu.BOOT.optiboot.menu.cpu.atmega1281.maximum_size=130048
megaAll.menu.cpu.atmega1281.build.mcu=atmega1281

Выкладываю кусками из-за невозможности разместить пост больше 10тыс. символов .. увы, клеить придется самостоятельно. :)
 
09.06.2019
57
5
8
#7
Доработка и/или дополнить Ардуино ИДЕ (тест в 1.8.5), чтобы удобно общаться с расширенной памятью:
!! Все дано для работающих под Линукс. Для винды изменения простые и очевидны, не вижу смысла специально оговаривать это !!

1. Добавление objdump (удобства для) в список шаблонов исполнения в platform.txt, тут под Линукс, под винду есть ссыль выше:

1а) добавляем опции для objdump. Файл <каталог с ИДЕ>/hardware/arduino/avr/platform.txt, секция "AVR compile variables"
Код:
compiler.objdump.cmd=avr-objdump.sh 
compiler.objdump.flags={compiler.path} {build.path}/{build.project_name}.elf {build.path}/{build.project_name}.lst
1б) К этому пункту не относится, но там же сразу в этой же секции убираем включение -flto "по умолчанию (оригинальные строки под комментом):
Код:
#compiler.c.flags=-c -g -Os {compiler.warning_flags} -std=gnu11 -ffunction-sections -fdata-sections -MMD -flto -fno-fat-lto-objects 
compiler.c.flags=-c -g -Os {compiler.warning_flags} -std=gnu11 -ffunction-sections -fdata-sections -MMD 
#compiler.c.elf.flags={compiler.warning_flags} -Os -g -flto -fuse-linker-plugin -Wl,--gc-sections 
compiler.c.elf.flags={compiler.warning_flags} -Os -Wl,--gc-sections 
#compiler.S.flags=-c -g -x assembler-with-cpp -flto -MMD 
compiler.S.flags=-c -g -x assembler-with-cpp 
#compiler.cpp.flags=-c -g -Os {compiler.warning_flags} -std=gnu++11 -fpermissive -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics -MMD -flto 
compiler.cpp.flags=-c -g -Os {compiler.warning_flags} -std=gnu++11 -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics -MMD
1в) В этом же файле, далее в секции AVR compile patterns добавляем хук вызова objdump после Create output files (.eep and .hex):
Код:
## POST objcopy: make objdump too: 
recipe.hooks.objcopy.postobjcopy.1.pattern="{compiler.path}{compiler.objdump.cmd}" {compiler.objdump.flags}
1г) В папке <каталог с ИДЕ>/hardware/tool/avr/bin создаем файл с названием avr-objdump.sh и содержимым:
Код:
#! /bin/sh 
$1avr-objdump -h -S $2 > $3
.. и если надо, меняем ему владельца и даем права на исполнение, типовыми chown,chmod ..

Собственно тут всё - после компиляции/заливки в папке /tmp/build_xxx/ можно будет обнаружить файлик с расширением *.lst - он и есть листинг всей сборки.

2. Доработка настроек ИДЕ для работы с этой и др. платами с расширенной памятью.

2а) если был пропущен п.1б, то тут ему самое место..

2б) В начало файла <каталог с ИДЕ>/hardware/arduino/avr/boards.txt , после menu.cpu=Processor вставляем описание платы, что дано выше..

2в) в папке <каталог с ИДЕ>/hardware/arduino/avr/variants создаем папку sram и копируем в ней файлик <каталог с ИДЕ>/hardware/arduino/avr/variants/mega/pins_arduino.h

2г) создаем там же (2в) файлик <каталог с ИДЕ>/hardware/arduino/avr/variants/sram/avr6.x с содержимым из поста выше

.. собственно, если ничего не забыл, то это всё. В ИДЕ появится опция выбора "*** ATmega640/1280/1281/2560/2561 ***" с расширенным меню и возможностью управлять выбором процессора из семейства, частотой камня, уровнем Bodlevel, включением опции LTO и типом платы: с памятью, без памяти и какой памятью..

P.S. В процессе эксплуатации было замечено что описание платы выше несколько неверно (не разбирался) и после выбора этих плат пропадает выбор остальных. Собственно нам остальные уже и не нужны, поэтому и не копал что напутал в системе меню.. кто знает - подправьте.
Ну или как решение - вынос настроек в плагин по аналогии с MegaCore проектом. Мне было лениво.. :)
 
09.06.2019
57
5
8
#8
MURK-SRAM512k.jpg

Ну и под занавес - фото готовой и рабочей платы. Таких сделано уже больше 20шт, сейчас дорабатывается 3-й релиз.. :)