Секция NoInit микроконтроллера STM32

Кто любит RISC в жизни, заходим, не стесняемся.
Ответить
Buffalo
Открыл глаза
Сообщения: 68
Зарегистрирован: Вс ноя 13, 2011 15:09:58

Секция NoInit микроконтроллера STM32

Сообщение Buffalo »

Здравствуйте, разбираюсь с секцией NoInit микроконтроллера STM32. Как я понял, сначала эта секция с помощью программатора прошивается в некую область FLASH памяти микроконтроллера, а уже при подачи питания на микроконтроллер, эта область FLASH памяти копируется в SRAM. То есть секция NoInit эта секция ОЗУ, которая не инициализируется при старте или рестарте, и переменные живущие в этой области будут сохранять свои значения при сбросе. По крайней мере так понял я.

И вот тут у меня в голове возникает неутыка.

Представим ситуацию, есть переменная uint32_t counter, в которой находится значение 0, и есть микркоконтроллер , который стартовал и начал выполнять некие действия, работал микроконтроллер работал, изменял эту переменную и стал счетчик равным counter = 36558, и вдруг случилось ужасное, у микроконтроллера кратковременно пропало питание, произошел сброс. Получается, что во флеше у нас этот counter до сих пор равен нулю, так как мы его не изменяли, а ОЗУшка у нас сбросилась из-за потери питания. И counter начала увеличиваться с начала. Получается, что переменные не сохраняются, а сбрасываются. Никак не могу понять, где я туплю.

Соответственно вопрос, по какому механизму сохраняются переменные в ОЗУ, после сброса питания ?
Реклама
uk8amk
Поставщик валерьянки для Кота
Сообщения: 2222
Зарегистрирован: Вт ноя 27, 2007 11:32:06
Откуда: Tashkent

Re: Секция NoInit микроконтроллера STM32

Сообщение uk8amk »

При отключении питания или входе в расширенные режимы сна содержимое ОЗУ теряется. Для сохранения важных данных можно использовать:
-резервную область часового модуля с батарейным питанием;
-внутреннюю EEPROM(в L серии);
-не занятые программой сектора Flash(ресурс сильно ограничен);
-внешнюю микросхему EEPROM;
-внешнюю микросхему FRAM(когда требуется высокая скорость) и т.д.
Реклама
Buffalo
Открыл глаза
Сообщения: 68
Зарегистрирован: Вс ноя 13, 2011 15:09:58

Re: Секция NoInit микроконтроллера STM32

Сообщение Buffalo »

uk8amk писал(а):При отключении питания или входе в расширенные режимы сна содержимое ОЗУ теряется. Для сохранения важных данных можно использовать:
-резервную область часового модуля с батарейным питанием;
-внутреннюю EEPROM(в L серии);
-не занятые программой сектора Flash(ресурс сильно ограничен);
-внешнюю микросхему EEPROM;
-внешнюю микросхему FRAM(когда требуется высокая скорость) и т.д.
Получается, что эта секция нужна для того, сохранить данные в не изменённом виде, например, если контроллер ушел в режим сна "Sleep", а потом проснулся. В то время как , если он уйдет в режим сна "Standby", то там все данные потеряются. Я Вас правильно понял ?
Аватара пользователя
Z_h_e
Собутыльник Кота
Сообщения: 2708
Зарегистрирован: Сб май 14, 2011 21:16:04
Откуда: г. Чайковский

Re: Секция NoInit микроконтроллера STM32

Сообщение Z_h_e »

А можно какую-нибудь ссылочку на NoInit, чтобы почитать. Я первый раз об этом слышу, а с STM32 только одним типом пользовался. Там такого я не нашел.
Изображение
Добро всегда побеждает зло. Поэтому кто победил - тот и добрый.
Реклама
Эиком - электронные компоненты и радиодетали
uk8amk
Поставщик валерьянки для Кота
Сообщения: 2222
Зарегистрирован: Вт ноя 27, 2007 11:32:06
Откуда: Tashkent

Re: Секция NoInit микроконтроллера STM32

Сообщение 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.
Реклама
Аватара пользователя
Shapa
Встал на лапы
Сообщения: 127
Зарегистрирован: Пт июн 20, 2008 09:38:05
Откуда: Харьков
Контактная информация:

Re: Секция NoInit микроконтроллера 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) Создаем переменную

Код: Выделить всё

static uint32_t s_mySuperDuperCounter __attribute__ ((section (".backupSramSection")));
3) Юзаем в коде, именно так, как вы ожидали
Реклама
Buffalo
Открыл глаза
Сообщения: 68
Зарегистрирован: Вс ноя 13, 2011 15:09:58

Re: Секция NoInit микроконтроллера STM32

Сообщение 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, поэтому если я, что-то сказал не так или прошу много, просьба не пинать, ибо еще много не осознаю. А вот, то что написали, что эту секцию вводят для ускорения запуска мк, за это отдельное спасибо, теперь по крайней мере понятно, для чего нужна эта секция.
Аватара пользователя
Shapa
Встал на лапы
Сообщения: 127
Зарегистрирован: Пт июн 20, 2008 09:38:05
Откуда: Харьков
Контактная информация:

Re: Секция NoInit микроконтроллера STM32

Сообщение 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'я нет
Buffalo
Открыл глаза
Сообщения: 68
Зарегистрирован: Вс ноя 13, 2011 15:09:58

Re: Секция NoInit микроконтроллера STM32

Сообщение 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'ом.
Ответить

Вернуться в «ARM»