Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: МК после сброса по WatchDog
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > MSP430
ListenReality
Всем привет.

Проблема такая: Необходимо завести такую переменную, которая после сброса МК по WatchDog сохранит свое значение.

Пробовал через static. Но видимо я чего-то глубоко не понимаю. Если переменную не инициализировать, то в ней рандомное значение, которое нельзя никак изменить. (А писать static int i=0 глупо, т.к. оно каждый раз будет обнуляться).

Вообще возможно ли это? или МК после сброса по WatchDog затирает память?
mcheb
Компилятор по умолчанию при сбросе устанавливает указатель стека, обнуляет ОЗУ ( .bss область) и затем инициализирует переменные. Напишите свой ResetHandler. Я так пробовал
Код
//#pragma vector=RESET_VECTOR
//__interrupt void _reset_vector__(void)
//{
//    WDTCTL = WDTPW | WDTHOLD;   // Stop WDT
//    asm(" mov    #0x23fe,r1");// #0x23fe
//    asm("br #main");//main();
//}
//#pragma vector=UNMI_VECTOR          /* 0xFFFA User Non-maskable */
//__interrupt void _unmi_vector__(void)
//{
//    nop();
////   asm("reti");
//}
//#pragma vector=SYSNMI_VECTOR        /* 0xFFFC System Non-maskable */
//__interrupt void _sysnmi_vector__(void)
//{
//    nop();
////   asm("reti");
//}
//
k155la3
Цитата(ListenReality @ Jan 21 2016, 12:47) *
Всем привет.

Проблема такая: Необходимо завести такую переменную, которая после сброса МК по WatchDog сохранит свое значение.
. . .
Вообще возможно ли это? или МК после сброса по WatchDog затирает память?


В опциях проекта подключите файл линкера не по умолчанию, а с Вашими настройками.
(скопировать стандартный в каталог проекта)

В шапке лин-файла ( для MSP430F149 это файл lnk430F149.xcl )
есть такое:
Код
// segment     Restrictions    Usage
// -------     ------------    --------------------------
// DATA16_I    < 10000         Data16 initialized variables
// DATA16_Z    < 10000         Data16 zero initialized variables
// DATA16_N    < 10000         Data16 uninitialized variables
// DATA16_HEAP < 10000         Data16 heap used by malloc and free
// DATA20_I                    Data20 initialized variables
// DATA20_Z                    Data20 zero initialized variables
// DATA20_N                    Data20 uninitialized variables
// DATA20_HEAP                 Data20 heap used by malloc and free
// CSTACK      < 10000         Runtime stack


обратите внимание на сегмент DATA16_N.
Если переменную разместить там, то она не дожна инициализироваться при пергрузке.

int my_data @ "MY_DATA_IN_SEG" = 123;
MY_DATA_IN_SEG - указать в списке для DATA16_N в lnk430F149.xcl
Я сам это не проверял, но кажется в этом направлении.

также префикс __no_init
__no_init volatile unsigned __READ char U0RXBUF @ 0x0076;
итд




ListenReality
mcheb, k155la3 Спасибо за ваши ответы.

Не вижу файла "lnk430F149.xcl" или подобного для моего МК.
Есть только "lnk_msp430f2012.cmd", но содержимое его не похоже на то, что писали вы.

Код
MEMORY
{
    SFR                     : origin = 0x0000, length = 0x0010
    PERIPHERALS_8BIT        : origin = 0x0010, length = 0x00F0
    PERIPHERALS_16BIT       : origin = 0x0100, length = 0x0100
    RAM                     : origin = 0x0200, length = 0x0080
    INFOA                   : origin = 0x10C0, length = 0x0040
    INFOB                   : origin = 0x1080, length = 0x0040
    INFOC                   : origin = 0x1040, length = 0x0040
    INFOD                   : origin = 0x1000, length = 0x0040
    FLASH                   : origin = 0xF800, length = 0x07E0
    INT00                   : origin = 0xFFE0, length = 0x0002
    INT01                   : origin = 0xFFE2, length = 0x0002
    INT02                   : origin = 0xFFE4, length = 0x0002
    INT03                   : origin = 0xFFE6, length = 0x0002
    INT04                   : origin = 0xFFE8, length = 0x0002
    INT05                   : origin = 0xFFEA, length = 0x0002
    INT06                   : origin = 0xFFEC, length = 0x0002
    INT07                   : origin = 0xFFEE, length = 0x0002
    INT08                   : origin = 0xFFF0, length = 0x0002
    INT09                   : origin = 0xFFF2, length = 0x0002
    INT10                   : origin = 0xFFF4, length = 0x0002
    INT11                   : origin = 0xFFF6, length = 0x0002
    INT12                   : origin = 0xFFF8, length = 0x0002
    INT13                   : origin = 0xFFFA, length = 0x0002
    INT14                   : origin = 0xFFFC, length = 0x0002
    RESET                   : origin = 0xFFFE, length = 0x0002
}

/****************************************************************************/
/* SPECIFY THE SECTIONS ALLOCATION INTO MEMORY                              */
/****************************************************************************/

SECTIONS
{
    .bss        : {} > RAM                  /* GLOBAL & STATIC VARS              */
    .data       : {} > RAM                  /* GLOBAL & STATIC VARS              */
    .sysmem     : {} > RAM                  /* DYNAMIC MEMORY ALLOCATION AREA    */
    .stack      : {} > RAM (HIGH)           /* SOFTWARE SYSTEM STACK             */

    .text       : {} > FLASH                /* CODE                              */
    .cinit      : {} > FLASH                /* INITIALIZATION TABLES             */
    .const      : {} > FLASH                /* CONSTANT DATA                     */
    .cio        : {} > RAM                  /* C I/O BUFFER                      */

    .pinit      : {} > FLASH                /* C++ CONSTRUCTOR TABLES            */
    .init_array : {} > FLASH                /* C++ CONSTRUCTOR TABLES            */
    .mspabi.exidx : {} > FLASH              /* C++ CONSTRUCTOR TABLES            */
    .mspabi.extab : {} > FLASH              /* C++ CONSTRUCTOR TABLES            */

    .infoA     : {} > INFOA              /* MSP430 INFO FLASH MEMORY SEGMENTS */
    .infoB     : {} > INFOB
    .infoC     : {} > INFOC
    .infoD     : {} > INFOD

    /* MSP430 INTERRUPT VECTORS          */
    .int00       : {}               > INT00
    .int01       : {}               > INT01
    PORT1        : { * ( .int02 ) } > INT02 type = VECT_INIT
    PORT2        : { * ( .int03 ) } > INT03 type = VECT_INIT
    USI          : { * ( .int04 ) } > INT04 type = VECT_INIT
    ADC10        : { * ( .int05 ) } > INT05 type = VECT_INIT
    .int06       : {}               > INT06
    .int07       : {}               > INT07
    TIMERA1      : { * ( .int08 ) } > INT08 type = VECT_INIT
    TIMERA0      : { * ( .int09 ) } > INT09 type = VECT_INIT
    WDT          : { * ( .int10 ) } > INT10 type = VECT_INIT
    .int11       : {}               > INT11
    .int12       : {}               > INT12
    .int13       : {}               > INT13
    NMI          : { * ( .int14 ) } > INT14 type = VECT_INIT
    .reset       : {}               > RESET  /* MSP430 RESET VECTOR         */
}
Obam
Так вы бы сразу указали, что не IARом пользуетесь.
ListenReality
Цитата(Obam @ Jan 22 2016, 14:56) *
Так вы бы сразу указали, что не IARом пользуетесь.


А можете подсказать как в CCS решить эту проблему ?
k155la3
Цитата(ListenReality @ Jan 22 2016, 12:35) *
А можете подсказать как в CCS решить эту проблему ?


ps - это не есть проблема sm.gif

В CCS не работал. Наверняка есть аналогичные ф-ии.
Почитайте раздел помощи, нечто вроде "pragma directive" для CCS
Там могут быть директивы - команды препроцессору компилятора, в каких сегментах
размещать данную переменную или модуль в целом.
Также - работа с абсолютными адресами.
(например, вектора прерываний всегда размещаются по указанным абс. адресам)
"Покурите" h-файлы CCS.
Dog Pawlowa
Цитата(ListenReality @ Jan 21 2016, 12:47) *
Но видимо я чего-то глубоко не понимаю. Если переменную не инициализировать, то в ней рандомное значение, которое нельзя никак изменить.

Вообще возможно ли это?

Возможно - что?
Кажется, вы каких-то чудес хотите - чтобы переменная не инициализировалась, но чтобы в ней не было рандомного значения.
"Горячий лед", "сухая вода" ?
jcxz
Цитата(k155la3 @ Jan 21 2016, 20:39) *
обратите внимание на сегмент DATA16_N.
Если переменную разместить там, то она не дожна инициализироваться при пергрузке.

Это конечно всё правильно, только прочитайте внимательнее что именно пишет ТС. А пишет он, что неинициализированные переменные у него после указанного сброса принимают рандомные значения.
А теперь вопрос - какие именно секции линкер указывает как заполняемые рандомно при старте???
Я что-то не слышал о таком, чтобы стандартный стартап-код заполнял что-то рандомно. Обычно он обнуляет или не обнуляет (ну или максимум - заполняет неким шаблоном) секции.
Так что сначала копать надо в сторону выяснения - откуда берутся эти рандомные значения? Стартап-код генерить их не должен.
E.V.G.
В компиляторе IAR есть такая функция - int __low_level_init(void). Посмотрите, похоже, это ваш случай.
k155la3
Цитата(jcxz @ Jan 31 2016, 10:46) *
Это конечно всё правильно, только прочитайте внимательнее что именно пишет ТС. А пишет он, что неинициализированные переменные у него после указанного сброса принимают рандомные значения.
А теперь вопрос - какие именно секции линкер указывает как заполняемые рандомно при старте???
Я что-то не слышал о таком, чтобы стандартный стартап-код заполнял что-то рандомно. Обычно он обнуляет или не обнуляет (ну или максимум - заполняет неким шаблоном) секции.
Так что сначала копать надо в сторону выяснения - откуда берутся эти рандомные значения? Стартап-код генерить их не должен.


sm.gif нечто вроде RANDOM_INIT_SEGMENT
Случайное значение попадает в SRAM процессора только при холодном старте (и то не факт). И при выходе из какогонибудь LPM5.
Это значение может быть случайно-случайным или случайно-постоянным.
В общем, эта тема для меня еще недостаточно раскурена. Буду прикручивать к проекту работу WD - тогда разберемся.
(в RAM планирую сохранять данные причине сработки WDT и состоянии программы)
jcxz
Цитата(k155la3 @ Jan 31 2016, 18:24) *
Случайное значение попадает в SRAM процессора только при холодном старте (и то не факт). И при выходе из какогонибудь LPM5.

Это понятно. Но раз ТС пишет, что у него переменная принимает случайное значение, то советы перенести её в неинициализируемую секцию излишни - она и так уже там.
Ну только если она не находится в какой-то спец.секции рандомно инициализируемой. sm.gif
ListenReality
Цитата(Dog Pawlowa @ Jan 31 2016, 01:57) *
Возможно - что?
Кажется, вы каких-то чудес хотите - чтобы переменная не инициализировалась, но чтобы в ней не было рандомного значения.
"Горячий лед", "сухая вода" ?


Вы видимо не правильно поняли.
1) Включение МК по питанию(сигнал POR и PUC)
2) Сброс МК по WatchDog(только сигнал PUC). Программа начинает выполняться с начала, но есть бит, который указывает, что мы сбросились именно по WatchDog.
Код
if((IFG1&WDTIFG)==WDTIFG)//сбросились по собаке
{
IFG1&=~WDTIFG;//обнуляем флаг
countWatchDog++;
}


Поставлю вопрос тогда так. Где и как мне объявить переменную countWatchDog, чтобы:
1) Если включились по питанию, countWatchDog=0;
2) Если сброс по WatchDog, то countWatchDog++;

По сути нужно посчитать кол-во сбросов по WatchDog.

Пробовал:
Объявлял переменную за функцией main по-разному:
Код
int countWatchDog;
static int countWatchDog;

При этом main выглядит примерно так:
Код
int main(void)
{
/*настройка сторожевого таймера*/
WDTCTL =  WDTPW    // ключ защиты
             + WDTCNTCL // Обнуляем таймер
             + WDTSSEL;    // 0 - тактовый сигнал от SMCLK, 1 - ACLK
IE1 = WDTIE;// разрешаем прерывания от сторожевого таймера

BCSCTL3 = LFXT1S_2;//задаем для ACLK источник тактирования VLO

if((IFG1&WDTIFG)!=WDTIFG)//по питанию
{
  countWatchDog=0;
}
if((IFG1&WDTIFG)==WDTIFG)//сбросились по собаке
{
  IFG1&=~WDTIFG;//обнуляем флаг
  countWatchDog++;
}
}


При этом в случае, когда "int countWatchDog;" переменная всегда = 0
В случае, когда "static int countWatchDog;" переменная всегда равна 0х261. И в отладчике, после прохождения строчки "countWatchDog=0;" - значение переменной не меняется.
jcxz
Цитата(ListenReality @ Feb 2 2016, 08:43) *
При этом в случае, когда "int countWatchDog;" переменная всегда = 0
Так и должно быть.
Цитата(ListenReality @ Feb 2 2016, 08:43) *
В случае, когда "static int countWatchDog;" переменная всегда равна 0х261. И в отладчике, после прохождения строчки "countWatchDog=0;" - значение переменной не меняется.
Вот это странно. Должна быть ==0.
А как Вы отладчиком подключаетесь? Он сброс на МК выставляет при подключении? Возможно, что он подключается на лету, без сброса, тогда переменная содержит значение, присвоенное её в ходе выполнения ПО.
И вообще контролировать надо не отладчиком, а без него. Например - вывести значение переменной в UART при старте.

Как правильно объявить переменную - Вам уже сказали. Как сделать это в Вашем компиляторе - не знаю, а в IAR например:
static __root __no_init int var @ ".myNoInitSection";
Потом в командном файле компоновщика говорите компоновать секцию .myNoInitSection в отдельный регион памяти, который не надо инитить нулями.

Цитата(ListenReality @ Jan 22 2016, 14:35) *
А можете подсказать как в CCS решить эту проблему ?

В CCS я делал так (это для ARM926 ядра), в файле .cmd:
Код
#define RAM_SDRAM_ARM_NC_RW_BEGIN  0xC0010000
#define RAM_SDRAM_ARM_NC_RW_LEN    0x000E0000

MEMORY
{
  PAGE 0: //!<RAM
  ...
  RAM_SDRAM_ARM_NC_RW (RWX): o = RAM_SDRAM_ARM_NC_RW_BEGIN l = RAM_SDRAM_ARM_NC_RW_LEN //!<read-write noncached SDRAM is accessible only ARM
}

SECTIONS
{
  ...
  .mmuTTable            > RAM_SDRAM_ARM_NC_RW, type = NOINIT
}

Это легко узнаётся из описания компоновщика CCS, если конечно хотя-бы попытаться его открыть и почитать...
ListenReality
Спасибо всем за помощь. Впредь буду детальнее читать Help blush.gif

На всякий случай оставлю пример. Программа считает количество WatchDog'ов
Код
#pragma NOINIT (x );
int x;
int main(void)
{
    /*настройка сторожевого таймера*/
        WDTCTL =  WDTPW    // ключ защиты
                //+ WDTNMI    // 0 - Вход аппаратного сброса, 1 - вход прервания
                 //+ WDTTMSEL    // 0 - режим сторожевого таймера, 1 - интервальный таймер
                 + WDTCNTCL // Обнуляем таймер
                 + WDTSSEL;    // 0 - тактовый сигнал от SMCLK, 1 - ACLK
                //+ WDTIS0;
                //+ WDTIS1;
        IE1 = WDTIE;// разрешаем прерывания от сторожевого таймера

        BCSCTL3 = LFXT1S_2;//задаем для ACLK источник тактирования VLO

        DCOCTL = CALDCO_1MHZ;
        BCSCTL1 = CALBC1_1MHZ;

          if((IFG1&WDTIFG)==WDTIFG)//сбросились по собаке
          {
              IFG1&=~WDTIFG;//обнуляем флаг
              x++;
          }
          else x=0;
}


d7d1cd
Цитата(ListenReality @ Jan 21 2016, 12:47) *
Проблема такая: Необходимо завести такую переменную, которая после сброса МК по WatchDog сохранит свое значение.
Вообще возможно ли это? или МК после сброса по WatchDog затирает память?

Меня тоже интересует сохраняются ли значения в RAM памяти после сброса сторожевым таймером именно в тот момент, когда уже произошел сброс и МК начал выполнять первую инструкцию, расположенную по адресу вектора сброса.
Baser
Цитата(d7d1cd @ Apr 24 2016, 10:08) *
Меня тоже интересует сохраняются ли значения в RAM памяти после сброса сторожевым таймером именно в тот момент, когда уже произошел сброс и МК начал выполнять первую инструкцию, расположенную по адресу вектора сброса.

Никакого вида сбросы не влияют на содержимое оперативной памяти. На ее содержимое влияет только напряжение питания.
Есть минимальное напряжение, когда ОЗУ еще сохраняется. Из мануала на MSP430F2xx :
Цитата
V(RAMh) RAM retention supply voltage (CPU halted) 1.6 V
This parameter defines the minimum supply voltage VCC when the data in RAM remains unchanged. No program execution should
happen during this supply voltage condition.

Если ОЗУ слетело, значит или питание пропадало, или процессор что-то туда записал согласно программе
d7d1cd
Baser, Спасибо за ответ. Он, кстати, был Вашим 1000 по счету. Так что с юбилеем!
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2024 Invision Power Services, Inc.