Страница 1 из 1
Секция NoInit микроконтроллера STM32
Добавлено: Сб июл 02, 2016 16:38:29
Buffalo
Здравствуйте, разбираюсь с секцией NoInit микроконтроллера STM32. Как я понял, сначала эта секция с помощью программатора прошивается в некую область FLASH памяти микроконтроллера, а уже при подачи питания на микроконтроллер, эта область FLASH памяти копируется в SRAM. То есть секция NoInit эта секция ОЗУ, которая не инициализируется при старте или рестарте, и переменные живущие в этой области будут сохранять свои значения при сбросе. По крайней мере так понял я.
И вот тут у меня в голове возникает неутыка.
Представим ситуацию, есть переменная uint32_t counter, в которой находится значение 0, и есть микркоконтроллер , который стартовал и начал выполнять некие действия, работал микроконтроллер работал, изменял эту переменную и стал счетчик равным counter = 36558, и вдруг случилось ужасное, у микроконтроллера кратковременно пропало питание, произошел сброс. Получается, что во флеше у нас этот counter до сих пор равен нулю, так как мы его не изменяли, а ОЗУшка у нас сбросилась из-за потери питания. И counter начала увеличиваться с начала. Получается, что переменные не сохраняются, а сбрасываются. Никак не могу понять, где я туплю.
Соответственно вопрос, по какому механизму сохраняются переменные в ОЗУ, после сброса питания ?
Re: Секция NoInit микроконтроллера STM32
Добавлено: Вс июл 03, 2016 08:59:28
uk8amk
При отключении питания или входе в расширенные режимы сна содержимое ОЗУ теряется. Для сохранения важных данных можно использовать:
-резервную область часового модуля с батарейным питанием;
-внутреннюю EEPROM(в L серии);
-не занятые программой сектора Flash(ресурс сильно ограничен);
-внешнюю микросхему EEPROM;
-внешнюю микросхему FRAM(когда требуется высокая скорость) и т.д.
Re: Секция NoInit микроконтроллера STM32
Добавлено: Вс июл 03, 2016 17:49:34
Buffalo
uk8amk писал(а):При отключении питания или входе в расширенные режимы сна содержимое ОЗУ теряется. Для сохранения важных данных можно использовать:
-резервную область часового модуля с батарейным питанием;
-внутреннюю EEPROM(в L серии);
-не занятые программой сектора Flash(ресурс сильно ограничен);
-внешнюю микросхему EEPROM;
-внешнюю микросхему FRAM(когда требуется высокая скорость) и т.д.
Получается, что эта секция нужна для того, сохранить данные в не изменённом виде, например, если контроллер ушел в режим сна "Sleep", а потом проснулся. В то время как , если он уйдет в режим сна "Standby", то там все данные потеряются. Я Вас правильно понял ?
Re: Секция NoInit микроконтроллера STM32
Добавлено: Вс июл 03, 2016 18:15:02
Z_h_e
А можно какую-нибудь ссылочку на NoInit, чтобы почитать. Я первый раз об этом слышу, а с STM32 только одним типом пользовался. Там такого я не нашел.
Re: Секция NoInit микроконтроллера STM32
Добавлено: Вс июл 03, 2016 19:17:48
uk8amk
По всей видимости секция NOINIT потребуется когда часть данных сохраняется во внешней RAM/NVRAM и/или когда используется режим сна Standby. Тогда после выхода из Standby будет переход по вектору Reset и потрутся нужные данные. Noinit пропускает начальную инициализацию части памяти.
Использовать на деле не приходилось, поэтому всех тонкостей неизвестно.
Z_h_e писал(а):А можно какую-нибудь ссылочку на NoInit
http://www.keil.com/support/docs/3290.htm
Также встроенная справка 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.
Re: Секция NoInit микроконтроллера STM32
Добавлено: Пн июл 04, 2016 16:09:34
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) Создаем переменную
Код: Выделить всё
static uint32_t s_mySuperDuperCounter __attribute__ ((section (".backupSramSection")));
3) Юзаем в коде, именно так, как вы ожидали
Re: Секция NoInit микроконтроллера STM32
Добавлено: Пн июл 04, 2016 22:39:01
Buffalo
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) Создаем переменную
Код: Выделить всё
static uint32_t s_mySuperDuperCounter __attribute__ ((section (".backupSramSection")));
3) Юзаем в коде, именно так, как вы ожидали
Вы не могли бы выложить простой пример, что бы его в отладчике можно было погонять. Опять таки, если Вас это не затруднит, я только начал изучать STM32, поэтому если я, что-то сказал не так или прошу много, просьба не пинать, ибо еще много не осознаю. А вот, то что написали, что эту секцию вводят для ускорения запуска мк, за это отдельное спасибо, теперь по крайней мере понятно, для чего нужна эта секция.
Re: Секция NoInit микроконтроллера STM32
Добавлено: Вт июл 05, 2016 08:47:56
Shapa
Buffalo писал(а):я только начал изучать STM32, поэтому если я, что-то сказал не так или прошу много, просьба не пинать, ибо еще много не осознаю.
Лиха беда начала. Все когда-то начинали и наступали на кучу граблей по не зназнию, разве это то, чего стоит стыдиться?
Buffalo писал(а):Вы не могли бы выложить простой пример, что бы его в отладчике можно было погонять.
С удовольствием. Но учтите, это будет псевдо-код. Я предпочитаю GNU GCC (да и вообще проприретарщина - зло). Распишу 2 варианта, 1 - простой. 2 - правильный.
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;
}
Вариант 2: успростит размещение регистров в памяти (в коде т.к. размещать будет линкер)
1) в скрипте линкера создаем секцию
Код: Выделить всё
BACKUP (rw) : ORIGIN = 0x40006C00, LENGTH = 40 /* 40 - 20 регистров по 2 байта */
.backup (NOLOAD) : ALIGN(2)
{
_backup = .;
*(.backup .backup.*)
. = ALIGN(2) ;
_end_backup = .;
} > BACKUP
Код такой же, как в примере 1, только меняем
Код: Выделить всё
static uint16_t s_myNonVolatileVariable __attribute__((no_init)) __attribute__((at(0x40006C00)));
на
Код: Выделить всё
static uint16_t s_myNonVolatileVariable __attribute__((backup));
PS: возможны ошибки компиляции, т.к. не проверял, у меня Keil'я нет
Re: Секция NoInit микроконтроллера STM32
Добавлено: Чт июл 07, 2016 20:40:14
Buffalo
Shapa писал(а):Buffalo писал(а):я только начал изучать STM32, поэтому если я, что-то сказал не так или прошу много, просьба не пинать, ибо еще много не осознаю.
Лиха беда начала. Все когда-то начинали и наступали на кучу граблей по не зназнию, разве это то, чего стоит стыдиться?
Buffalo писал(а):Вы не могли бы выложить простой пример, что бы его в отладчике можно было погонять.
С удовольствием. Но учтите, это будет псевдо-код. Я предпочитаю GNU GCC (да и вообще проприретарщина - зло). Распишу 2 варианта, 1 - простой. 2 - правильный.
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;
}
Вариант 2: успростит размещение регистров в памяти (в коде т.к. размещать будет линкер)
1) в скрипте линкера создаем секцию
Код: Выделить всё
BACKUP (rw) : ORIGIN = 0x40006C00, LENGTH = 40 /* 40 - 20 регистров по 2 байта */
.backup (NOLOAD) : ALIGN(2)
{
_backup = .;
*(.backup .backup.*)
. = ALIGN(2) ;
_end_backup = .;
} > BACKUP
Код такой же, как в примере 1, только меняем
Код: Выделить всё
static uint16_t s_myNonVolatileVariable __attribute__((no_init)) __attribute__((at(0x40006C00)));
на
Код: Выделить всё
static uint16_t s_myNonVolatileVariable __attribute__((backup));
PS: возможны ошибки компиляции, т.к. не проверял, у меня Keil'я нет
У меня есть плата stm32vldiscovery. Там как раз стоит stm32f100rbt.
Подойдет ли батарейка типа CR2032 для backup питания ? Но я не могу понять как RTC связан с переменной s_myNonVolatileVariable и Reset'ом.