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

Помогите новичку со scatter-файлом

МК — MDR32F1QI. Необходимо в EEPROM особым образом подготовить две области:

  • Страница (0x1F000) для счетчика ресурсов. При разметке должна быть инициализирована единицами, что в принципе уже делает Erase Full Chip.
  • Страница (0x1E000) для хранения нескольких настроек. При разметке должна быть инициализирована нулями.

Счетчик ресурсов работает по принципу ежеминутного обнуления очередного бита выделенной страницы — для этого и необходимо ее инициализировать единицами.

Доступ к значениям настроек сейчас сделан так:

#define ADDR_SETTINGS 0x0001E000

int32_t  dat1_ __attribute__((at(ADDR_SETTINGS)));
int32_t  dat2_ __attribute__((at(ADDR_SETTINGS + 4)));
uint32_t dat3_ __attribute__((at(ADDR_SETTINGS + 8)));

// Переменые, хранящие эти значение в ходе работы программы.
int32_t  dat1;
int32_t  dat2;
uint32_t dat3;

// Считываение значений переменных из EEPROM при старте программы.
void read_settings()
{
    dat1 = dat1_;
    dat2 = dat2_;
    dat1 = dat3_;
}

// Запись измененных значений переменных в EEPROM
void update_settings()
{
    __disable_irq();

    EEPROM_ErasePage(ADDR_SETTINGS, EEPROM_Main_Bank_Select);

    EEPROM_ProgramWord(&dat1_, EEPROM_Main_Bank_Select, dat1);
    EEPROM_ProgramWord(&dat2_, EEPROM_Main_Bank_Select, dat2);
    EEPROM_ProgramWord(&dat3_, EEPROM_Main_Bank_Select, dat3);

    // Или записать можно и так, наверное:
    // EEPROM_ProgramWord(ADDR_SETTINGS, EEPROM_Main_Bank_Select, dat1);
    // EEPROM_ProgramWord(ADDR_SETTINGS + 4, EEPROM_Main_Bank_Select, dat2);
    // EEPROM_ProgramWord(ADDR_SETTINGS + 8, EEPROM_Main_Bank_Select, dat3);

    __enable_irq();
}

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

Вопрос в том, как в скаттере описать эти две страницы в EEPROM. Сразу скажу, что при перепрошивке МК нет необходимости сохранять старые настройки и наработку (подобная ситуация часто поднимается в обсуждениях) — нужно лишь их нужным образом инициализировать (нулями и единицами соответственно). Сейчас скаттер имеет такой вид:

; *************************************************************
; *** Scatter-Loading Description File generated by uVision ***
; *************************************************************

LR_IROM1 0x00000000 0x00020000  {    ; load region size_region
  ER_IROM1 0x00000000 0x00020000  {  ; load address = execution address
   *.o (RESET, +First)
   *(InRoot$$Sections)
   .ANY (+RO)
  }
  RW_IRAM1 0x20000000 0x00008000  {  ; RW data
   .ANY (+RW +ZI)
  }
  RW_IRAM2 0x20100000 0x00004000  {
    mdr32f9qx_eeprom.o
    RAMFunction.o (+RO)
   .ANY (+RW +ZI)
  }
}

Подскажите, как его изменить, чтобы указанные страницы при прошивке были инициализированы правильным образом?

А также интересует мнение, правильно ли я выбрал подход к доступу к настройкам. Они меняются крайне редко. А при первом запуске (после прошивки) должны вычитываться нулевые значения. При включении устройства EEPROM сразу переводится в программный режим.

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


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

просто из практики любая flash или eeprom память при стирании страницы заполняется битами-единичками, а не нулями. 0xFF.

Так что может стоит чуть пересмотреть алгоритм с целью избежать избыточного износа ячеек.

Можете проверить и почитать содержимое после стирания страницы.

Но это так, мысли вслух.

Изменено пользователем haker_fox
Убрал либо ошибочно написанное слово, либо косвенное оскорбление. Если необходимо, автору сообщения предлагаю написать правильно.

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


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

31 minutes ago, tathagata said:

А также интересует мнение, правильно ли я выбрал подход к доступу к настройкам. Они меняются крайне редко. А при первом запуске (после прошивки) должны вычитываться нулевые значения.

Организуйте настройки в виде структуры с magic в начале и CRC в конце. При несовпадении magic или некорректной CRC - установка значений по умолчанию.

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


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

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

А при первом запуске (после прошивки) должны вычитываться нулевые значения.

сделайте инверсию внутри процедур чтения и записи

48 минут назад, tathagata сказал:

Сразу скажу, что при перепрошивке МК нет необходимости сохранять старые настройки и наработку (подобная ситуация часто поднимается в обсуждениях)

Вы "ресурс" прошивки считаете, да? Типа, "этот код уже достаточно поработал, заменим на другой"))

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


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

12 minutes ago, tgruzd said:

сделайте инверсию внутри процедур чтения и записи

И не подумаю даже 🙂

 

Настройки должны иметь CRC, этого достаточно в том числе и для установки начального состояния.

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


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

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

И не подумаю даже 🙂

извиняюсь, не то процитировал. Думал, что цитирую ТСа)

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


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

58 минут назад, krux сказал:

просто из практики любая flash или eeprom память при стирании страницы заполняется битами-единичками, а не нулями. 0xFF.

На этом и основан наш алгоритм подсчета ресурса — я же выше указывал. Эту страницу достаточно просто стереть (заполнить единицами), а потом "гасить" очередные единички, не стирая всю страницу (т. е. без перезаписи). Так что в этом наши с вами подходы схожи.

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


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

1 hour ago, krux said:

просто из практики любая flash или eeprom память при стирании страницы заполняется битами-единичками, а не нулями. 0xFF.

К слову, не всегда так. Среди STM32 серии L есть экземпляры, у которых при стирании память FLASH заполняется нулями.

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


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

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

Организуйте настройки в виде структуры с magic в начале и CRC в конце. При несовпадении magic или некорректной CRC - установка значений по умолчанию.

Для хранения настроек как раз и не рассматривается необходимости использования контрольной суммы — полагаемся на корректную работу флеша) Вопрос в том, как правильно в скаттере прописать эти две области по заданным адресам, одна из которых (вся страница) будет инициализирована нулями, а вторая (тоже размером в страницу) — единичками. Со второй понятно, что полное стирание памяти перед прошивкой заполняет не инициализируемые другим способом ячейки памяти единицами. Кстати, порядок страниц принципиальной роли не играет (можно 0x1F000 — для счетчика, а 0x1E000 — для настроек, а можно и наоборот).

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

Вы "ресурс" прошивки считаете, да? Типа, "этот код уже достаточно поработал, заменим на другой"))

Этот момент обсуждается. Разумеется, что правильно было бы отделить мух от котлет. Но тогда придется работать двумя скаттерами (один  — для первоначальной прошивки с инициализацией областей хранения данных, а другой — для дальнейших возможных перепрошивок (с сохранением этих самых значений). Я правильно понял?

Сейчас интересно хоть какое-то решение.

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


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

13 minutes ago, tathagata said:

полагаемся на корректную работу флеша

Святая наивность.

 

15 minutes ago, tathagata said:

Но тогда придется работать двумя скаттерами

Да хоть 23-мя.

Сами стирайте, если значения неправильные.

Некоторые умные мысли есть тут

https://www.st.com/resource/en/application_note/an4894-eeprom-emulation-techniques-and-software-for-stm32-microcontrollers-stmicroelectronics.pdf

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


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

4 часа назад, tathagata сказал:

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

Идеологически правильнее:

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

Именно что - не только CRC подсчитать, но и допустимость значения каждого элемента структуры и допустимость их комбинаций. Также неплохо бы внутри структуры сохранять номер версии структуры. Чтобы потом, когда вдруг потребуется изменить формат структуры, и потом перешивать прошивку поверх старой, не было проблем.

4 часа назад, krux сказал:

любая flash или eeprom память при стирании страницы заполняется битами-единичками, а не нулями. 0xFF.

Подозреваю, что Вы не ознакомились со всеми существующими в мире моделями flash-памяти для столь категоричного заявления.

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

Для хранения настроек как раз и не рассматривается необходимости использования контрольной суммы — полагаемся на корректную работу флеша)

Тогда готовьтесь в будущем получать люлей по полной программе. :punish: От "счастливых" пользоватей.

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


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

Что скажете о таком варианте?

scatter.sct

LR_IROM1 0x00000000 0x0001E000  {    ; load region size_region
  ER_IROM1 0x00000000 0x0001E000  {  ; load address = execution address
   *.o (RESET, +First)
   *(InRoot$$Sections)
   .ANY (+RO)
  }
  RW_IRAM1 0x20000000 0x00008000  {  ; RW data
   .ANY (+RW +ZI)
  }
  RW_IRAM2 0x20100000 0x00004000  {
    mdr32f9qx_eeprom.o
    RAMFunction.o (+RO)
   .ANY (+RW +ZI)
  }
}
LR_IROM2 0x0001E000 0x00002000  {     ; отключаем LR_IROM2, если перепрошивка не должна затрагивать данные
    ER_IROM2 0x0001E000 0x00002000  { ; начало страницы инициализируется переменными из файла, остальное  0xFF
    data_init.o (+RO)
  }
}

data_init.c

const uint32_t data_array[3] __attribute__((used)) = {0x0, 0x0, 0x0};

data_init.h

#ifndef DATA_INIT_H
#define DATA_INIT_H
  
extern const uint32_t data_init[3];

#endif // DATA_INIT_H

 

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

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

Именно что - не только CRC подсчитать, но и допустимость значения каждого элемента структуры и допустимость их комбинаций. Также неплохо бы внутри структуры сохранять номер версии структуры. Чтобы потом, когда вдруг потребуется изменить формат структуры, и потом перешивать прошивку поверх старой, не было проблем.

Полностью согласен, что так идеологически правильнее. Кстати, это решило бы мою проблему с необходимостью инициализации нулями настроек при первой прошивке, поскольку 0xFFFFFF, считанные для всех переменных настроек не соответствовали бы CRC, так же равному 0xFFFFFF и тем самым запускали бы процесс принудительной инициализации значениями по-умолчанию (например, нулями в моем случае). Отличная мысль с CRC! Спасибо.

В таком случае мой скаттер мог бы иметь такой вид:

LR_IROM1 0x00000000 0x0001E000  {    ; load region size_region
  ER_IROM1 0x00000000 0x0001E000  {  ; load address = execution address
   *.o (RESET, +First)
   *(InRoot$$Sections)
   .ANY (+RO)
  }
  RW_IRAM1 0x20000000 0x00008000  {  ; RW data
   .ANY (+RW +ZI)
  }
  RW_IRAM2 0x20100000 0x00004000  {
    mdr32f9qx_eeprom.o
    RAMFunction.o (+RO)
   .ANY (+RW +ZI)
  }
}
LR_IROM2 0x0001E000 0x00002000  {     ; отключаем LR_IROM2, если перепрошивка не должна затрагивать данные
    ER_IROM2 0x0001E000 0x00002000  {
  }
}

Поправьте меня, если я неправ.

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


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

20 минут назад, tathagata сказал:

Полностью согласен, что так идеологически правильнее. Кстати, это решило бы мою проблему с необходимостью инициализации нулями настроек при первой прошивке, поскольку 0xFFFFFF, считанные для всех переменных настроек не соответствовали бы CRC, так же равному 0xFFFFFF и тем самым запускали бы процесс принудительной инициализации значениями по-умолчанию (например, нулями в моем случае). Отличная мысль с CRC! Спасибо.

Ведь необязательно защищать CRC весь объём записываемого конфига. Если у Вас в нём имеется какая-то часть, в которой модифицируются битики в описанном Вами порядке, то можете эту часть вынести за пределы области структуры конфига, защищаемой CRC. Защищайте CRC только ту часть конфига, которая не участвует в подсчёте ресурса.

Как-то подобно:

__packed struct {
  enum {VERSION = 1};
  __packed struct {
    u8 version;
    u16 key1;
    u8 key2
    u32 key3;
    ...
  } crcProtected;
  u32 crc;
  __packed struct {
    u32 counters[NNN];
    ...
  } resurs;
};

PS: __packed - это для IAR, для Keil заменить аналогом.

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


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

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

Ведь необязательно защищать CRC весь объём записываемого конфига. Если у Вас в нём имеется какая-то часть, в которой модифицируются битики в описанном Вами порядке, то можете эту часть вынести за пределы области структуры конфига, защищаемой CRC. Защищайте CRC только ту часть конфига, которая не участвует в подсчёте ресурса.

Да, именно так я себе это и представил: с помощью CRC защищаю данные настроек, а также использую этот hack для их первоначальной инициализации. А в странице с ресурсом наработки "гашу" биты, не используя контрольные суммы.

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


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

3 минуты назад, tathagata сказал:

Да, именно так я себе это и представил: с помощью CRC защищаю данные настроек, а также использую этот hack для их первоначальной инициализации. А в странице с ресурсом наработки "гашу" биты, не используя контрольные суммы.

Я говорю, что это "гашение" лучше делать в самой программе. Ведь она может определить факт своего первого старта по факту несовпадения CRC. И тогда никакой спец.скаттер для этого не понадобится.

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


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

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

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

Гость
Ответить в этой теме...

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

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

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

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

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

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