Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: WinAVR 200701..
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > AVR
defunct
Чип M168, компилирую с опцией -Os, с O0 использовать не могу т.к. hex получается больше 16k..
Девайс периодически перезагружается, MCUSR показывает Reset Source - 0 (прыжек на адрес 0), через ~1-8 часов работы..

В main при инициализации заполнил область стека тестовым паттерном 0xA5 после этого:
1. девайс начал иногда вместо ребута подвисать (через те же 1-8 часов работы), прерывания продолжают работать.. (WatchDog пока не включаю чтоб не мешал)
2. Заметил, что некая long переменная K, которую обновляю в основном цикле программы:
K = X; (где X long переменная равная xxxx, и X = (volatile long)Y; ) иногда принимает значение: 0xA5A5xxxx, когда ожидается 0x0000xxxx. (переменные X и Y - имеют правильные значения)

Промониторил стек после очередного ребута - за границу 256 байт - не выходит и не пересекается с другими структурами данных.
float, sprintf, printf в программе не применяю.

Собсно вопрос, может есть известные баги WinAVR 200701xx, которые бы могли это объяснить?
aesok
Цитата(defunct @ Apr 18 2007, 15:40) *
2. Заметил, что некая long переменная K, которую обновляю в основном цикле программы:
K = X; (где X long переменная равная xxxx, и X = (volatile long)Y; ) иногда принимает значение: 0xA5A5xxxx, когда ожидается 0x0000xxxx. (переменные X и Y - имеют правильные значения)


Приведите весь код где используються переменные K, X и Y

Анатолий.
defunct
Код
volatile U32 rtc_time;

struct
{
       U32  sys_time; // in seconds (from system reset)
       TRTC_REC rtc; // 6 переменных U8 (yy.mm.dd.hh.mm.ss)
       ...
} rtcContext;


struct
{
....
    U32 WhenToUpdateCounters;
....
} DeviceDesc;



static inline U8 ILock(void)
{
    U8 retval = SREG;
    cli();
    return retval;
}

static inline void IUnlock( U8 iStatus)
{
    SREG = iStatus;
}


void RTC_UpdateSysTime(void)
{
    U8 iStatus = ILock();
    rtcContext.sys_time = rtc_time;
    IUnlock( iStatus );
}

void RTC_ReloadContext(void)
{
    RTC_UpdateSysTime();
    if (GetRTC( &rtcContext.rtc ) != ACK )
    { // update rtc read-error counter
        if (DeviceDesc.stats.rtcErrors < 0xFFFF)
            DeviceDesc.stats.rtcErrors += 1;
    }
    else if ( (rtcContext.sys_time > DeviceDesc.WhenToUpdateCounters) &&
            ( (rtcContext.rtc.minutes == 0) || (rtcContext.rtc.minutes == 30) ) )
    {  
        // ТУТ НИЧЕГО БОЛЕЕ НЕ ДЕЛАЕТСЯ.. привожу как есть - только имитация работы
        DeviceDesc.WhenToUpdateCounters = rtcContext.sys_time + (60 * 30);; <-- DeviceDesc.WhenToUpdateCounter и есть переменная "K"
    }
}

/***********************************************
*                (1 Hz clock)                  *
***********************************************/
SIGNAL (INT0_vect)
{
    rtc_time += 1;  
    Set_Callback( &RTC_ReloadContext, 0, TASK_SINGLECALL );
}


rtc_time - переменная Y
rtcContext.sys_time - переменная X
DeviceDesc.WhenToUpdateCounters - переменная K

RTC_ReloadContext будет вызвана в основном цикле программы, и после выполнения - удалена из очереди.
aesok
Цитата(defunct @ Apr 18 2007, 16:47) *
RTC_ReloadContext будет вызвана в основном цикле программы, и после выполнения - удалена из очереди.


А очередь обладает свойством атомарности? Что будет если из очереди начинает удаляться функция, в этот момент происходит прерывание, в очередь добавляется новая функция, по окончании прерывания, заканчивает удаляться предыдущая функция?

Какой RTOS вы пользуетесь?


Анатолий.
defunct
Цитата(aesok @ Apr 18 2007, 16:15) *
А очередь обладает свойством атомарности? Что будет если из очереди начинает удаляться функция, в этот момент происходит прерывание, в очередь добавляется новая функция, по окончании прерывания, заканчивает удаляться предыдущая функция?

Должна обладать. Запуск и удаление происходит так:
if (slot[i] != NULL)
{
U8 iStatus = ILock()
__func *temp = __slot[i];
__slot[i] = NULL;
IUnlock( iStatus );
temp();
}

Цитата
Какой RTOS вы пользуетесь?
В этом проекте я RTOS не использую.

Спасибо за ваш комент, помониторю на предмет ошибок очереди.

PS: А что насчет 0xA5A5xxxx, как это могло случиться в приведенном выше коде?
aesok
Цитата(defunct @ Apr 18 2007, 19:02) *
что насчет 0xA5A5xxxx, как это могло случиться в приведенном выше коде?


Пока нет мыслей.

Анатолий.
_artem_
Цитата(defunct @ Apr 18 2007, 14:40) *
2. Заметил, что некая long переменная K, которую обновляю в основном цикле программы:
K = X; (где X long переменная равная xxxx, и X = (volatile long)Y; ) иногда принимает значение: 0xA5A5xxxx, когда ожидается 0x0000xxxx. (переменные X и Y - имеют правильные значения)


Это может показывать что значение stack pointer каким то образом портится. Почему? Наверно переменная которая портится, располагается в стеке. Если значение SP каким то образом сместилось , при обрашении к стеку , переменные (изза того что они адресуются относительно SP) могут быть прочитаны из другой ячейки .
aesok
Цитата(_artem_ @ Apr 18 2007, 20:26) *
Это может показывать что значение stack pointer каким то образом портится. Почему? Наверно переменная которая портится, располагается в стеке. Если значение SP каким то образом сместилось , при обрашении к стеку , переменные (изза того что они адресуются относительно SP) могут быть прочитаны из другой ячейки .


Нет, в GCC нет адесации относительно указателя стека.

Анатолий.
_artem_
Цитата(aesok @ Apr 18 2007, 19:30) *
Нет, в GCC нет адесации относительно указателя стека.

Анатолий.


Тогда как же в gcc адресуются временные переменные живущие на время выполнения функции и обитаюшие в стеке?

Допустим из одной функции вызывается вторая. Временные переменные что первой функции обитают в стеке. Если стек во время выполнения вложенной функции запишется неправильное значение , то по возврату из вложенной функции когда основная функция будет считывать переменные - адрес памяти будет другим , может быть и то место , заполненное шахматным кодом для дебага.
aesok
Цитата(_artem_ @ Apr 18 2007, 20:39) *
Тогда как же в gcc адресуются временные переменные живущие на время выполнения функции и обитаюшие в стеке?

Это называется Frame Pointer, и он живет в регистре Y.

Анатолий.
_artem_
Цитата(aesok @ Apr 18 2007, 19:42) *
Это называется Frame Pointer, и он живет в регистре Y.

Анатолий.


Эт в смысле хард и софт тек в иар ? Не знал. Ну тогда по всей видимости портится этот регистр.
aesok
Цитата(_artem_ @ Apr 18 2007, 20:45) *
Эт в смысле хард и софт тек в иар ?


В avr-gcc один общий стек. Но для доступа к локальным переменным используеться регистр Y (FP).

Анатолий.
defunct
Уточню еще один момент. 0xA5A5xxxx проявляется не при первом обновлении переменной "K"... При первом - все в порядке.. Обращений к "K" в других местах программы - нет.

Конкретную проблему с этой переменной я устранил другим путем - поменял условие события, т.о. надобность в U32 переменной отпала. Ребуты продолжаются..
singlskv
Цитата(defunct @ Apr 18 2007, 21:19) *
Уточню еще один момент. 0xA5A5xxxx проявляется не при первом обновлении переменной "K"... При первом - все в порядке.. Обращений к "K" в других местах программы - нет.

Конкретную проблему с этой переменной я устранил другим путем - поменял условие события, т.о. надобность в U32 переменной отпала. Ребуты продолжаются..


А по-моему зря Вы убрали U32 переменную.
Как Вы теперь узнаете что прога близка к перезагрузке ?

Я бы в месте где идет работа с этой переменной поставил что-то типа
if (K==0xA5A5xxxx)
{
............ // здесь вывод SP, Y ну и всякой другой отладочной инфы
// куда-нибудь (если есть куда), ну или хотя бы в порт

while (1);
}
aesok
Цитата(defunct @ Apr 18 2007, 21:19) *
Конкретную проблему с этой переменной я устранил другим путем - поменял условие события, т.о. надобность в U32 переменной отпала. Ребуты продолжаются..


На 99% ошибка в вашей программе. Только не подумайте что я заявляю что GCC совершенно безглючный.

Чем отлаживаете? Поробуйте поставить брейк на переменной К, вернув ей тип long. Проверте работу с указателями, самая частая ошибка. Возможно гдето пропустили ILock()/ IUnlock(). Поодключайте в программе разные блоки.

Ищите!

Анатолий.
defunct
Цитата(aesok @ Apr 18 2007, 19:53) *
На 99% ошибка в вашей программе. Только не подумайте что я заявляю что GCC совершенно безглючный.

Это хорошо! А то компилятор менять совсем не хотелось.

Цитата
Чем отлаживаете? Поробуйте поставить брейк на переменной К, вернув ей тип long. Проверте работу с указателями, самая частая ошибка.

Dragon'ом

Цитата
Возможно гдето пропустили ILock()/ IUnlock(). Поодключайте в программе разные блоки.

Да да, я присмотрелся к коду представленному выше, и похоже там промах с ILock (не в том месте стоит).

Код
if (slot[i] != NULL)
{
   U8 iStatus = ILock()
   __func *temp = __slot[i];
   __slot[i] = NULL;
   IUnlock( iStatus );
   temp();
}


между проверкой на NULL и запретом прерываний slot мог обнулиться..
Написал так:

Код
U8 iStatus = ILock()
__func *temp = __slot[i];
__slot[i] = NULL;
IUnlock(iStatus);
if (temp != NULL)
    temp();


Оставлю на ночь с этим изменением, завтра отпишу рез-тат.
Большое спасибо за помощь cheers.gif


Цитата(singlskv @ Apr 18 2007, 19:52) *
А по-моему зря Вы убрали U32 переменную.
Как Вы теперь узнаете что прога близка к перезагрузке ?

Дык и раньше эти два события были мало взаимосвязаны. Т.е. программа могла продолжать работать с неверным K, а это для меня гораздо хуже чем перезагрузка..
singlskv
Цитата(defunct @ Apr 18 2007, 23:54) *
Дык и раньше эти два события были мало взаимосвязаны. Т.е. программа могла продолжать работать с неверным K, а это для меня гораздо хуже чем перезагрузка..

Ну наверное это все-таки как-то связанные события учитывая то что Вы заполнили перед этим
стек константой 0xA5, ну да ладно. не суть...

Лучше раскажите, удалось победить глюк, и если удалось то как победили и в чем он был ?
ilock ? или что-то другое
defunct
Да, проблема-таки была связана с ILock! С изменением приведенным выше девайс уже проработал 24 часа без ребутов.

Причина банальна - дребезг... Счетчик секунд который чуть-чуть опережал показание RTC это подтвердил.
Прерывание, которое должно происходить строго раз в секунду - иногда (очень редко) происходило едва ли не сразу после предыдущего. Если в момент запуска callback'а происходило повторное прерывание с повторной установкой этого же callback'a, то старый еще не запущенный но уже проверенный на NULL удалялся из очереди (у меня не допускается держать в очереди дубликаты событий) - ну а потом уже NULL() - и ребут....

Подправил расположение ILock и сместил время выполнения события на 20ms.
SetCallback( ..., 20, ...);
Теперь работает все как надо.

Еще раз спасибо всем кто принимал участие в обсуждении! cheers.gif
singlskv
Цитата(defunct @ Apr 19 2007, 23:40) *
Да, проблема-таки была связана с ILock! С изменением приведенным выше девайс уже проработал 24 часа без ребутов.

Причина банальна - дребезг... Счетчик секунд который чуть-чуть опережал показание RTC это подтвердил.
Прерывание, которое должно происходить строго раз в секунду - иногда (очень редко) происходило едва ли не сразу после предыдущего. Если в момент запуска callback'а происходило повторное прерывание с повторной установкой этого же callback'a, то старый еще не запущенный но уже проверенный на NULL удалялся из очереди (у меня не допускается держать в очереди дубликаты событий) - ну а потом уже NULL() - и ребут....

Подправил расположение ILock и сместил время выполнения события на 20ms.
SetCallback( ..., 20, ...);
Теперь работает все как надо.

Еще раз спасибо всем кто принимал участие в обсуждении! cheers.gif

А стек при этом таки переполнялся или нет ?
прошу прощения за навязчивость, просто вопрос возникновения таких
ошибок меня сейчас очень интересует, точнее интересуют способы борьбы с такими ошибками...
вобщем вопрос в том как можно програмно конролировать выполнение собственной программы

типа статистику собираю, а Ваш случай интересный...
defunct
Цитата(singlskv @ Apr 19 2007, 21:54) *
А стек при этом таки переполнялся или нет ?

Стек не переполнялся это 100%, и объяснить появление 0xA5A5xxxx я не могу, кроме как предположить, что GCC при оптимизации держит константу 0, где-то в памяти, а при моем вмешательстве с заполнием стека паттерном "заполнило" и ее. (у меня там была довольно существенная прослойка "гуляющей" памяти - байт в 200 между стеком и переменными).

Сейчас я затрудняюсь сказать память портилась до перезагрузки или после.. Скорее всего после - тогда это многое объясняет, т.к инициализация проходила при разрешенных прерываниях.
singlskv
Цитата(defunct @ Apr 20 2007, 00:25) *
Стек не переполнялся это 100%, и объяснить появление 0xA5A5xxxx я не могу, кроме как предположить, что GCC при оптимизации держит константу 0, где-то в памяти, а при моем вмешательстве с заполнием стека паттерном "заполнило" и ее. (у меня там была довольно существенная прослойка "гуляющей" памяти - байт в 200 между стеком и переменными).

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

GCC держит константу 0 в регистре R1 кажись,
вроде бы были сообщения от userов что при определенных условиях там может оказатся не 0.
но это бабушка на двое сказала...

Вобщем если Вы пнете в меня своим hexом хотябы то мне будет очень интересно посмотреть
чего там протсходит, а если елфом то тады ваще очень интересно,
обесчаю перед прочтением Вашего кода его съесть...smile.gif
defunct
Цитата(singlskv @ Apr 19 2007, 22:58) *
GCC держит константу 0 в регистре R1 кажись,
вроде бы были сообщения от userов что при определенных условиях там может оказатся не 0.
но это бабушка на двое сказала...

При умножении! (mul/fmul используют R0/R1)
singlskv
Цитата(defunct @ Apr 20 2007, 01:03) *
При умножении! (mul/fmul используют R0, R1). А у меня там как раз и было умножение..

типа того, к сожалению точно не помню(не пользуюсь умножением/делением
на авр без особой нужды)

но если не етот глюк, то hex все таки пните...
если этот то тогда не надоsmile.gif
_artem_
Я бы блокировал прерывания прежде чем проверять очередь на наличие задачи, а не проверять результат после того как фунцкия выбрана из очереди, а дребезг подавлял бы до того как он сгенерирует событие. имхо.
Один вопрос - а Вы используете Ilock из прерывания ? Если нет то зачем статус регистр запоминать? Вроде бы Set_Callback для того чтобы запускать тасковые функции после прерывания.
defunct
Цитата(_artem_ @ Apr 20 2007, 00:32) *
Я бы блокировал прерывания прежде чем проверять очередь на наличие задачи, а не проверять результат после того как фунцкия выбрана из очереди

Резонно.

Цитата
, а дребезг подавлял бы до того как он сгенерирует событие. имхо.

Дребезг теперь сам-собой подавляется, из-за этих условий:
- два одинаковых события в очереди находиться не могут,
- время до запуска события - 20ms с момента попадания в очередь.
тобиш если приходит неожидаемое второе событие вызванное дребезгом - старое удалится - новое добавится, в очереди останется только одно такое событие.

Цитата
Один вопрос - а Вы используете Ilock из прерывания ? Если нет то зачем статус регистр запоминать? Вроде бы Set_Callback для того чтобы запускать тасковые функции после прерывания.

Некоторые функции, например запись в eeprom, могут выполняться как в обработчиках прерываний так и вне, в них требуется запрещать прерывания. ILock/Unlock у меня сделаны так чтобы не задумываться где я сейчас нахожусь. Думаю они себя оправдывают, 1 команда (in rr, sreg) не велика цена за универсальность.
Serjio
Еще можно добавить, что переменные, которые модифицируются в прерываниях положено объявлять как volatile - чтобы процессор правильно произвел оптимизацию обращения к этим переменным (не в регистры)
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.