Секция NoInit микроконтроллера STM32
Секция NoInit микроконтроллера STM32
Здравствуйте, разбираюсь с секцией NoInit микроконтроллера STM32. Как я понял, сначала эта секция с помощью программатора прошивается в некую область FLASH памяти микроконтроллера, а уже при подачи питания на микроконтроллер, эта область FLASH памяти копируется в SRAM. То есть секция NoInit эта секция ОЗУ, которая не инициализируется при старте или рестарте, и переменные живущие в этой области будут сохранять свои значения при сбросе. По крайней мере так понял я.
И вот тут у меня в голове возникает неутыка.
Представим ситуацию, есть переменная uint32_t counter, в которой находится значение 0, и есть микркоконтроллер , который стартовал и начал выполнять некие действия, работал микроконтроллер работал, изменял эту переменную и стал счетчик равным counter = 36558, и вдруг случилось ужасное, у микроконтроллера кратковременно пропало питание, произошел сброс. Получается, что во флеше у нас этот counter до сих пор равен нулю, так как мы его не изменяли, а ОЗУшка у нас сбросилась из-за потери питания. И counter начала увеличиваться с начала. Получается, что переменные не сохраняются, а сбрасываются. Никак не могу понять, где я туплю.
Соответственно вопрос, по какому механизму сохраняются переменные в ОЗУ, после сброса питания ?
И вот тут у меня в голове возникает неутыка.
Представим ситуацию, есть переменная uint32_t counter, в которой находится значение 0, и есть микркоконтроллер , который стартовал и начал выполнять некие действия, работал микроконтроллер работал, изменял эту переменную и стал счетчик равным counter = 36558, и вдруг случилось ужасное, у микроконтроллера кратковременно пропало питание, произошел сброс. Получается, что во флеше у нас этот counter до сих пор равен нулю, так как мы его не изменяли, а ОЗУшка у нас сбросилась из-за потери питания. И counter начала увеличиваться с начала. Получается, что переменные не сохраняются, а сбрасываются. Никак не могу понять, где я туплю.
Соответственно вопрос, по какому механизму сохраняются переменные в ОЗУ, после сброса питания ?
- Реклама
-
uk8amk
- Поставщик валерьянки для Кота
- Сообщения: 2222
- Зарегистрирован: Вт ноя 27, 2007 11:32:06
- Откуда: Tashkent
Re: Секция NoInit микроконтроллера STM32
При отключении питания или входе в расширенные режимы сна содержимое ОЗУ теряется. Для сохранения важных данных можно использовать:
-резервную область часового модуля с батарейным питанием;
-внутреннюю EEPROM(в L серии);
-не занятые программой сектора Flash(ресурс сильно ограничен);
-внешнюю микросхему EEPROM;
-внешнюю микросхему FRAM(когда требуется высокая скорость) и т.д.
-резервную область часового модуля с батарейным питанием;
-внутреннюю EEPROM(в L серии);
-не занятые программой сектора Flash(ресурс сильно ограничен);
-внешнюю микросхему EEPROM;
-внешнюю микросхему FRAM(когда требуется высокая скорость) и т.д.
Re: Секция NoInit микроконтроллера STM32
Получается, что эта секция нужна для того, сохранить данные в не изменённом виде, например, если контроллер ушел в режим сна "Sleep", а потом проснулся. В то время как , если он уйдет в режим сна "Standby", то там все данные потеряются. Я Вас правильно понял ?uk8amk писал(а):При отключении питания или входе в расширенные режимы сна содержимое ОЗУ теряется. Для сохранения важных данных можно использовать:
-резервную область часового модуля с батарейным питанием;
-внутреннюю EEPROM(в L серии);
-не занятые программой сектора Flash(ресурс сильно ограничен);
-внешнюю микросхему EEPROM;
-внешнюю микросхему FRAM(когда требуется высокая скорость) и т.д.
- Z_h_e
- Собутыльник Кота
- Сообщения: 2708
- Зарегистрирован: Сб май 14, 2011 21:16:04
- Откуда: г. Чайковский
Re: Секция NoInit микроконтроллера STM32
А можно какую-нибудь ссылочку на NoInit, чтобы почитать. Я первый раз об этом слышу, а с STM32 только одним типом пользовался. Там такого я не нашел.
-
uk8amk
- Поставщик валерьянки для Кота
- Сообщения: 2222
- Зарегистрирован: Вт ноя 27, 2007 11:32:06
- Откуда: Tashkent
Re: Секция NoInit микроконтроллера STM32
По всей видимости секция NOINIT потребуется когда часть данных сохраняется во внешней RAM/NVRAM и/или когда используется режим сна Standby. Тогда после выхода из Standby будет переход по вектору Reset и потрутся нужные данные. Noinit пропускает начальную инициализацию части памяти.
Использовать на деле не приходилось, поэтому всех тонкостей неизвестно.
Также встроенная справка KEIL:
Использовать на деле не приходилось, поэтому всех тонкостей неизвестно.
http://www.keil.com/support/docs/3290.htmZ_h_e писал(а):А можно какую-нибудь ссылочку на NoInit
Также встроенная справка KEIL:
Set Options for Target
Set target parameters in the dialog Options for Target - Target.
Open the dialog via the toolbar icon or the menu Project - Options for Target.
Read/Write Memory Areas
NoInit Specifies areas that should be excluded from zero initialization.
- Реклама
- Shapa
- Встал на лапы
- Сообщения: 127
- Зарегистрирован: Пт июн 20, 2008 09:38:05
- Откуда: Харьков
- Контактная информация:
Re: Секция NoInit микроконтроллера STM32
Господа, вы не оттуда пляшите. NoInit секция не есть "что-то специфичное для STM32 семества". Это обычная секция, здесь вам нужно поискать вообще, что есть секции линковки программы. В соответсвии со стандартом языка С, вся статитка (все глобальные объекты и ститические объекты) должны быть проинициализированны 0 (линкер разместит их в секции .bss). Но! Это обнуление происходит при выполнении стартап секции, что можен занять достаточно длитеьны промежуток времени. Потому, для ускорения запуска (актуально для embedded систем) нечто может быть размещено в .noinit секции. Т.е. не будет проинициализированно перед вашей точкой входа.
С практической точки зрения это значит что
распечатает рандомный мусор
и вам придется принудительно присваивать s_val = 0xDEADBEAF; в вашем коде, перед использованием
ОЗУ есть энергозависимая памаять и она потеряет своё состояние при потере питания.
Конкретный пример, как использовать .noinit в STM32:
о BackupSram слышали?:)
1) Добавляем в скрипт линкера секцию, что отображает эту память. обзываем её backupSramSection.
2) Создаем переменную
3) Юзаем в коде, именно так, как вы ожидали
С практической точки зрения это значит что
Код: Выделить всё
static int s_val __attribute__ ((section (".noinit"))) = 0xDEADBEAF; // вообще, тут будет ошибка
...
main() {
printf("%p", s_val);и вам придется принудительно присваивать s_val = 0xDEADBEAF; в вашем коде, перед использованием
Совершенно верно, при "сбросе". Но! Сброс и обесточивание - это две большие разницыне инициализируется при старте или рестарте, и переменные живущие в этой области будут сохранять свои значения при сбросе
ОЗУ есть энергозависимая памаять и она потеряет своё состояние при потере питания.
Конкретный пример, как использовать .noinit в STM32:
о BackupSram слышали?:)
1) Добавляем в скрипт линкера секцию, что отображает эту память. обзываем её backupSramSection.
2) Создаем переменную
Код: Выделить всё
static uint32_t s_mySuperDuperCounter __attribute__ ((section (".backupSramSection")));Re: Секция NoInit микроконтроллера STM32
Вы не могли бы выложить простой пример, что бы его в отладчике можно было погонять. Опять таки, если Вас это не затруднит, я только начал изучать STM32, поэтому если я, что-то сказал не так или прошу много, просьба не пинать, ибо еще много не осознаю. А вот, то что написали, что эту секцию вводят для ускорения запуска мк, за это отдельное спасибо, теперь по крайней мере понятно, для чего нужна эта секция.Shapa писал(а):Господа, вы не оттуда пляшите. NoInit секция не есть "что-то специфичное для STM32 семества". Это обычная секция, здесь вам нужно поискать вообще, что есть секции линковки программы. В соответсвии со стандартом языка С, вся статитка (все глобальные объекты и ститические объекты) должны быть проинициализированны 0 (линкер разместит их в секции .bss). Но! Это обнуление происходит при выполнении стартап секции, что можен занять достаточно длитеьны промежуток времени. Потому, для ускорения запуска (актуально для embedded систем) нечто может быть размещено в .noinit секции. Т.е. не будет проинициализированно перед вашей точкой входа.
С практической точки зрения это значит чтораспечатает рандомный мусорКод: Выделить всё
static int s_val __attribute__ ((section (".noinit"))) = 0xDEADBEAF; // вообще, тут будет ошибка ... main() { printf("%p", s_val);
и вам придется принудительно присваивать s_val = 0xDEADBEAF; в вашем коде, перед использованием
Совершенно верно, при "сбросе". Но! Сброс и обесточивание - это две большие разницыне инициализируется при старте или рестарте, и переменные живущие в этой области будут сохранять свои значения при сбросе
ОЗУ есть энергозависимая памаять и она потеряет своё состояние при потере питания.
Конкретный пример, как использовать .noinit в STM32:
о BackupSram слышали?:)
1) Добавляем в скрипт линкера секцию, что отображает эту память. обзываем её backupSramSection.
2) Создаем переменную3) Юзаем в коде, именно так, как вы ожидалиКод: Выделить всё
static uint32_t s_mySuperDuperCounter __attribute__ ((section (".backupSramSection")));
- Shapa
- Встал на лапы
- Сообщения: 127
- Зарегистрирован: Пт июн 20, 2008 09:38:05
- Откуда: Харьков
- Контактная информация:
Re: Секция NoInit микроконтроллера STM32
Лиха беда начала. Все когда-то начинали и наступали на кучу граблей по не зназнию, разве это то, чего стоит стыдиться?Buffalo писал(а):я только начал изучать STM32, поэтому если я, что-то сказал не так или прошу много, просьба не пинать, ибо еще много не осознаю.
С удовольствием. Но учтите, это будет псевдо-код. Я предпочитаю GNU GCC (да и вообще проприретарщина - зло). Распишу 2 варианта, 1 - простой. 2 - правильный.Buffalo писал(а):Вы не могли бы выложить простой пример, что бы его в отладчике можно было погонять.
Precondition:
1) У вас верно собрана схема backup питания. Т.е. подключена батарейка к МК
2) Разрешен rw доступ к backup регистрам (по идее надо врубить тактирование RTC, PWR, выполнить PWR_BackupAccessCmd(Enable) но лучше уточните)
Вариант 1 Stm32F100:
Код: Выделить всё
// uint16_t - т.к. у Stm32F100 sizeof(backupReg) == 2.
// Реальный адрес расчитан так: RTC_BASE + RegNo = 0x40006C00 + 0. реальные адреса для вашего камня смотрите начиная от BKP_WriteBackupRegister, там поймете
static uint16_t s_myNonVolatileVariable __attribute__((no_init)) __attribute__((at(0x40006C00))); // по идее в Keil'e заработает
int main (int argc, char *argv[]) {
YourBSPInit();
debugTrace("After reset s_myNonVolatileVariable is [%d]\n", s_myNonVolatileVariable);
while(1) {
if (someReason())
s_myNonVolatileVariable++;
}
return 0;
}
1) в скрипте линкера создаем секцию
Код: Выделить всё
BACKUP (rw) : ORIGIN = 0x40006C00, LENGTH = 40 /* 40 - 20 регистров по 2 байта */
.backup (NOLOAD) : ALIGN(2)
{
_backup = .;
*(.backup .backup.*)
. = ALIGN(2) ;
_end_backup = .;
} > BACKUP
Код: Выделить всё
static uint16_t s_myNonVolatileVariable __attribute__((no_init)) __attribute__((at(0x40006C00)));Код: Выделить всё
static uint16_t s_myNonVolatileVariable __attribute__((backup));Re: Секция NoInit микроконтроллера STM32
У меня есть плата stm32vldiscovery. Там как раз стоит stm32f100rbt.Shapa писал(а):Лиха беда начала. Все когда-то начинали и наступали на кучу граблей по не зназнию, разве это то, чего стоит стыдиться?Buffalo писал(а):я только начал изучать STM32, поэтому если я, что-то сказал не так или прошу много, просьба не пинать, ибо еще много не осознаю.
С удовольствием. Но учтите, это будет псевдо-код. Я предпочитаю GNU GCC (да и вообще проприретарщина - зло). Распишу 2 варианта, 1 - простой. 2 - правильный.Buffalo писал(а):Вы не могли бы выложить простой пример, что бы его в отладчике можно было погонять.
Precondition:
1) У вас верно собрана схема backup питания. Т.е. подключена батарейка к МК
2) Разрешен rw доступ к backup регистрам (по идее надо врубить тактирование RTC, PWR, выполнить PWR_BackupAccessCmd(Enable) но лучше уточните)
Вариант 1 Stm32F100:Вариант 2: успростит размещение регистров в памяти (в коде т.к. размещать будет линкер)Код: Выделить всё
// uint16_t - т.к. у Stm32F100 sizeof(backupReg) == 2. // Реальный адрес расчитан так: RTC_BASE + RegNo = 0x40006C00 + 0. реальные адреса для вашего камня смотрите начиная от BKP_WriteBackupRegister, там поймете static uint16_t s_myNonVolatileVariable __attribute__((no_init)) __attribute__((at(0x40006C00))); // по идее в Keil'e заработает int main (int argc, char *argv[]) { YourBSPInit(); debugTrace("After reset s_myNonVolatileVariable is [%d]\n", s_myNonVolatileVariable); while(1) { if (someReason()) s_myNonVolatileVariable++; } return 0; }
1) в скрипте линкера создаем секциюКод такой же, как в примере 1, только меняемКод: Выделить всё
BACKUP (rw) : ORIGIN = 0x40006C00, LENGTH = 40 /* 40 - 20 регистров по 2 байта */ .backup (NOLOAD) : ALIGN(2) { _backup = .; *(.backup .backup.*) . = ALIGN(2) ; _end_backup = .; } > BACKUPнаКод: Выделить всё
static uint16_t s_myNonVolatileVariable __attribute__((no_init)) __attribute__((at(0x40006C00)));PS: возможны ошибки компиляции, т.к. не проверял, у меня Keil'я нетКод: Выделить всё
static uint16_t s_myNonVolatileVariable __attribute__((backup));
Подойдет ли батарейка типа CR2032 для backup питания ? Но я не могу понять как RTC связан с переменной s_myNonVolatileVariable и Reset'ом.



