|
Причины зависания и их поиск |
|
|
|
Dec 3 2007, 10:39
|
Местный
  
Группа: Участник
Сообщений: 256
Регистрация: 6-03-05
Из: Екатеринбург
Пользователь №: 3 112

|
В общем такая проблема: есть устройство, которое периодически отказвает в работе - зависает. Более подробно: mcu - Atmega128 управляет двумя устройствами по шине SPI, плюс одно на шине TWI, плюс на усарт повешен преобразователь в интерфейса rs485, через который и идёт связь с внешним миром. По внешним светодиодикам зависон выглядит так, как будто после перезагрузки по какой-то причине (по вотчдогу или пропаданию питания) контроллер начинает по новой инициализироваться и на каком-то этапе входит в вечный цикл, который обычно должен выполнятся очень быстро. После снятия напряжения питания и его восстановления зависон исчезает (на некоторое время). Привожу часть кода инициализации, с возможно проблемными местами (пояснения ниже): Код /******************************************************************************/ /* avr-gcc v 4.1.2 */ #include <avr/io.h>
#define BIT(b) (1 << b)
void spi_transmit (unsigned char c) { asm ("wdr"); SPDR = c; while (!(SPSR & BIT(SPIF))); } void spi_str_transmit (const unsigned char * str, unsigned char size, unsigned char no) { static const unsigned char cs_bit [] = {BIT(PB4), BIT(PB6)}; PORTB &= ~cs_bit [no]; for (;size--;) spi_transmit (*str++); PORTB |= cs_bit [no]; } /******************************************************************************/ void twi_transmit (unsigned char data, unsigned char flags, const unsigned char stat) { asm ("wdr"); TWDR = data; TWCR = flags; while (!(TWCR & BIT (TWINT))); }
void send_twi_addr (const char a) { twi_transmit (a, BIT(TWINT) | BIT(TWEN), 0x18); }
void send_twi_byte (const char b) { twi_transmit (b, BIT(TWINT) | BIT(TWEN), 0x28); } unsigned char read_twi_byte (void) { twi_transmit (0xFF, BIT(TWEA) | BIT(TWINT) | BIT(TWEN), 0x50); return TWDR; } void twi_start (void) { twi_transmit (0xFF, BIT(TWSTA) | BIT(TWINT) | BIT(TWEN), TWI_START); } void twi_stop (void) { TWCR = BIT (TWSTO) | BIT (TWINT) | BIT (TWEN); TWCR = BIT (TWSTO) | BIT (TWINT); }
/******************************************************************************/
void init (void) { DDRF |= BIT(PF4) | BIT(PF5) | BIT(PF6) | BIT(PF7); /* all leds */ PORTF |= BIT(PF4) | BIT(PF5) | BIT(PF6) | BIT(PF7); /* on */ asm ("wdr");
WDTCR = BIT(WDCE) | BIT(WDE); WDTCR = BIT(WDP2) | BIT(WDP1) | BIT(WDP0); /* watchdog timeout ~ 2 sec */ WDTCR = BIT(WDE);
DDRE = BIT (0x03); /* w/r rs485 driver ctrl. output enable */
DDRA |= BIT(PA3); /* debug led */ PORTA |= BIT(PA3); /* off */ PORTD |= BIT(PD3); /* internal pullup resistor */
PORTB = BIT(PB7) | BIT(PB6) | BIT(PB5) | BIT(PB0) | BIT(PB4); DDRB = BIT(PB7) | BIT(PB6) | BIT(PB5) | BIT(PB4) | BIT(PB2) | BIT(PB1) | BIT(PB0); while (!(PIND & BIT(PD3))); /* wait pwr signal */ SPCR = BIT(SPE) | BIT(MSTR) | (SPR0); /* init SPI (250 kHz) */
/* Two wire interface initialization */ TWSR = 0; /* <- setting prescaler */ TWBR = 0; /* F_CPU / 16; Bit rate = 250 kHz */
EIMSK = BIT(INT7) | BIT(INT6) | BIT(INT3); /* Extrnal intr. 7, 6, 3 */ EICRB = BIT(ISC71) | BIT(ISC61); /* Falling edge sens. */ EICRA = BIT(ISC31); /* Falling edge sens. */
PORTE = ~BIT(0x03); /* w/r rs485 driver read enable */
UCSR0B = BIT(RXCIE0) | BIT(TXCIE0) | BIT(RXEN0) | BIT(TXEN0); /* enable intr/ on recv/send byte usart0 */ UCSR0C = BIT(UCSZ01) | BIT(UCSZ00) | BIT(UPM01) | BIT(UPM00); /* async, even parity, 2 stop bit 8 bit usart0 */ init_r (0); /* spi_str_transmit */ init_r (1); /* spi_str_transmit */ reset_tm (); /* r/w twi */ init_s (); /* r/w twi */ init_m (); /* eeprom_read -> UBRR0H, UBRR0L; */ clear_list (); /* r/w twi */ asm ("sei"); PORTF &= ~(BIT(PF4) | BIT(PF5) | BIT(PF6) | BIT(PF7)); /* leds off */ } void loop (void) { for (;;) { /* ... */ } } int main (void) { init (); loop (); return 0; } Самое подозрительное в отношение зависания место - ожидание установки единицы на PD3: while (!(PIND & BIT(PD3))); /* wait pwr signal */. В реальном устройстве этот пин соединён через резистор 1к с шиной питания и вроде всегда должна там быть единица. Другие места, где возможно организуется вечный цикл - в функциях twi_transmit и spi_transmit. В связи с этим возникли такие вопросы : 1. Может ли линия порта ввода-вывода (и вообще порты ввода - вывода) входит в такое состояние, что уровни с неё не читаются корректно (то есть единица не воспринимается как единица)? 2. Могут ли так зависать внутринние устройства TWI - SPI, что чтение их статусных регистров всегда возвращает одно и тоже ? 3. Самое трудное - воспроизвести эту проблему не в условиях эксплуатации, а на месте, где её можно решить. Одно из устройств сейчас гоняю всяко - на мороз его выставляю, помехи возле него создаю, влажность повышенную - всё нипочём, - всегда бы так работало. Какие ещё дестабилизирующие средства можно применить ?
|
|
|
|
3 страниц
1 2 3 >
|
 |
Ответов
(1 - 34)
|
Dec 3 2007, 11:17
|

кекс
     
Группа: Свой
Сообщений: 3 825
Регистрация: 17-12-05
Из: Киев
Пользователь №: 12 326

|
Цитата(forever failure @ Dec 3 2007, 13:39)  Одно из устройств сейчас гоняю всяко - на мороз его выставляю, помехи возле него создаю, влажность повышенную - всё нипочём, - всегда бы так работало. Какие ещё дестабилизирующие средства можно применить ? Посылать поток данных такой же как в эксплуатации, т.к. здесь возможна программная ошибка. Где-то что-то переполняется, портит память, после чего прыгает в функцию инициализации с разрешенными прерываниями и алес... Если проблема воспроизводится в "поле", то было бы непохо в ваше изделие вставить возможность делать хотя бы частичный дамп памяти и регистров проца и периферии, например по прерыванию от WDT, и сохранять его в eeprom с возможностью вычитки после рестарта.. Кстати, если устройство подвисло, то почему не перезагрузилось по WDT? Цитата 2. Могут ли так зависать внутринние устройства TWI - SPI, что чтение их статусных регистров всегда возвращает одно и тоже ? Могут, если некоторые состояния намерено или случайно игнорируются драйвером. Цитата 1. Может ли линия порта ввода-вывода (и вообще порты ввода - вывода) входит в такое состояние, что уровни с неё не читаются корректно (то есть единица не воспринимается как единица)? нет.
|
|
|
|
|
Dec 3 2007, 13:32
|
Местный
  
Группа: Участник
Сообщений: 256
Регистрация: 6-03-05
Из: Екатеринбург
Пользователь №: 3 112

|
Переживать мне и нужно, иначе всё это будут прелести совместной отладки - один переводит стрелы на другого и т. д. А по поводу взрывов электролитов - там не та ситуация совсем. Каждый лишний вольт/миллиампер/милигенри/микрофарада - это просто криминал, потому недопустимо. Решение про 8-10 вольт, стабилитрон и тем более пару ватт не устаривает, как энергоёмкое и неискробезопасное.
Вообще хотелось бы увидеть здесь советы по воспроизведению проблемы, потому что причины могут быть разными, и вовсе не такими как предполагаются.
По поводу подозрительной строки - в данной строке ожидается готовность устройства, которое выставляет уровень 1. Сейчас оно отключено, потому нога просто через резистор подтянута к питанию. Опять таки, совсем не уверен, что исключение этой строки решит проблему - во первых и что делать, когда эта проверка будет нужна (а он обязательно понадобится) - во вторых.
|
|
|
|
|
Dec 3 2007, 13:49
|
Профессионал
    
Группа: Свой
Сообщений: 1 235
Регистрация: 14-05-05
Из: Санкт-Петербург
Пользователь №: 5 008

|
Цитата По поводу подозрительной строки - в данной строке ожидается готовность устройства, которое выставляет уровень 1. Сейчас оно отключено, потому нога просто через резистор подтянута к питанию. Опять таки, совсем не уверен, что исключение этой строки решит проблему - во первых и что делать, когда эта проверка будет нужна (а он обязательно понадобится) - во вторых. Я предлагаю это сделать для проверки, для локализации места зависания, если зависания после этого прекратятся, то вы будете знать, где копать. Кстати, щуп осциллографа - это емкость, может стоит добавить емкость между Pin3 и землей? И еще, зачем проверять состояние пина так рано? Я бы сперва провел инициализацию всей перефирии(SPI, TWI, UART), а уж потом стал проверять готовность какого то другого устройства, хотя у вас тут могут быть свои резоны...
--------------------
|
|
|
|
|
Dec 3 2007, 13:52
|
Местный
  
Группа: Свой
Сообщений: 234
Регистрация: 30-03-07
Из: Одесса
Пользователь №: 26 621

|
Цитата(forever failure @ Dec 3 2007, 16:06)  на TWI висит rtc+fram FM3130 может ли она так шину завесть, что её надо сбрасывать отключением питания ? По поводу WDT тоже не совсем понятно, похоже сброс всё таки есть, но он не помогает, так как есть что-то, что не сбрасывается сигналом, генерируемым вочдогом. Ещё один момент был - когда замерял все напряжения на зависшем устройстве - при касании щупа вольтметра этой ноги PD3 успройство ожило и пошло работать дальше, почему и возникло предположение про порты ввода-вывода. При условии, что слэйв на шине вследствии некоторых факторов не выставляет АСК, создаются предпосылки для надежного завмсания TWI модуля. Для надежной работы модуля лучше всего использовать асинхронную библиотеку из Атмеловской аппликухи, дополнив ее контролем ошибок. Зависон определяется по 0(наиболее типичная ситуация) в статус регистре. Зависон модуля снимается его полным отключением отключением(запретом) и последующей переинициализации модуля.
|
|
|
|
|
Dec 3 2007, 16:11
|
Местный
  
Группа: Участник
Сообщений: 256
Регистрация: 6-03-05
Из: Екатеринбург
Пользователь №: 3 112

|
Про емкость между пином и землёй - несколько раз возникала такая идея, попробую. Но, кстати, в одном из девайсов я соединил напрямую шину питания и пин (ну да, не самая лучшая идея), и всё равно ничего не изменилось. Версия про зависание шины TWI кажется наиболее правдоподобной и вероятной. Есть ещё несколько версий, так в частности, этой программе, как можно заметить неиспользуемые выводы контроллера оставлены висящими в воздухе, что, тоже может быть источником проблем.
Но в любом случае, ни одну из версий пока не удаётся проверить по причине непроявления проблемы на рабочем столе.
|
|
|
|
|
Dec 3 2007, 17:22
|

Местный
  
Группа: Свой
Сообщений: 479
Регистрация: 8-05-07
Из: г. Ставрополь. Северный Кавказ. Россия
Пользователь №: 27 606

|
Цитата(sensor_ua @ Dec 3 2007, 19:38)  Попробуй перед reset_tm (); /* r/w twi */ выдать twi_stop(); В код не вникал. Подавать команду стоп нельзя!!! Сбрасывают микросхемы висящие на i2c только многократной подачей команды старт. ЗЫ. Очень хорошее описание работы с шиной i2c, в пдф.
Сообщение отредактировал Т.Достоевский - Dec 3 2007, 17:34
|
|
|
|
|
Dec 3 2007, 20:56
|
Гуру
     
Группа: Свой
Сообщений: 2 712
Регистрация: 28-11-05
Из: Беларусь, Витебск, Строителей 18-4-220
Пользователь №: 11 521

|
Цитата(forever failure @ Dec 3 2007, 17:32)  Вообще хотелось бы увидеть здесь советы по воспроизведению проблемы, потому что причины могут быть разными, и вовсе не такими как предполагаются. Простите, но Вы не совсем правы. Именно питание вызывает сложные, трудновоспроизводимые и уникальные глюки. И к советам bodja74 надо отнестись со всей ответственностью. Я бы это сделал немедленно, правда предлагаю вам другой подход. 1. Поставить (на время проверки) отличный и мощный блок питания. Это необходимо сделать чтобы однозначно определится в чём проблема. В программной части или аппаратной. 2. По результатам испытаний проводить дальнейшее исследование. И ещё один момент из моей практики. WDT необходимо использовать тогда, когда к программной части нет претензий. Никаких сбоев и висов. Так как WDT предназначена для выхода из виса по аппаратным проблемам, но не по программным хомутам. По этому, в случае программного виса, вам сначало надо 1. Отключить WDT. 2. Локализовать место или выявить причину виса. 3. Продумать организацию WDT (а не бездумно воткнуть сброс в каждый цикл) 4. Включить WDT.
|
|
|
|
|
Dec 3 2007, 20:58
|
Профессионал
    
Группа: Свой
Сообщений: 1 266
Регистрация: 22-04-05
Из: Киев
Пользователь №: 4 387

|
Цитата Подавать команду стоп нельзя!!! Нельзя сразу после START (в приведенной Вами доке почему-то STOP непосредственно после START позволителен - Fig. 16). Но соглашусь, что в данном случае нельзя, потому как неизвестно что же было перед этим. Сброс логики шины согласно спецификации действительно делается подачей S и/или Sr. Но в спецификации шины примеров как на Fig. 14(a) и Fig. 14(  что-то не находится. Просветите, плз, а то чего-то не попадалось таких наворотов. Максимум чего приходилось испорльзовать - в описании сброса AT24. 1. Clock up to 9 cycles. 2. Look for SDA high in each cycle while SCL is high. 3. Create a start condition.
--------------------
aka Vit
|
|
|
|
|
Dec 3 2007, 22:48
|

Местный
  
Группа: Свой
Сообщений: 479
Регистрация: 8-05-07
Из: г. Ставрополь. Северный Кавказ. Россия
Пользователь №: 27 606

|
Цитата(sensor_ua @ Dec 3 2007, 23:58)  ...Просветите, плз, а то чего-то не попадалось таких наворотов. Максимум чего приходилось испорльзовать - в описании сброса AT24... Не совсем понял вопроса, проясните. ИМХО. Рис 14а наверное что-бы слейв гарантированно отпустил таки этот SDA, и что-бы не проверять линию SDA в мастере. Некорректное начало/завершение обмена i2c системах ограничения доступа бывает очень часто. Сделал контроллер ключей с проверкой напряжения питания, оказалось что ВСЕ! кто ставил его на замки защёлки вернули с жалобами на сигнал просадки питания. (Просадка ниже 7 вольт дольше 250 милисекунд!!!!) forever failure Попробуйте отключать модули по очереди, и смотреть. А ещё лучше, задейтвовать какой нибудь свободный светодиодик или порт. И включать его по очереди после каждого модуля. То-есть: Включить светодиод ини модуля 1 ВЫлючить светодиод .... протестил, переставить на модуль 2 итд. А ещё красивее WDT переставить на генерацию прерывания, и выводить к какой-нибудь порт, адрес возврата. Наверняка есть цельный порт только на выход, и с него тестером можно считать.
Сообщение отредактировал Т.Достоевский - Dec 3 2007, 22:56
|
|
|
|
|
Dec 4 2007, 04:23
|
Профессионал
    
Группа: Свой
Сообщений: 1 266
Регистрация: 22-04-05
Из: Киев
Пользователь №: 4 387

|
Цитата Не совсем понял вопроса, проясните. В спецификации на шину (смотрю v2.1) не нашёл способов сброса шины соответствующих указанным на рис 14a и 14b (br24l16.pdf). Кроме того там указано, что нельзя давать "пустое" сообщение - оно illegal format, но не нашёл чего случится страшного при этом. Зато в доке от Rohm есть на рис 16 разрисовка такого случая и описано, мол чего-то таки будет работать. Непонятно это филипс недорасписал (или я криво читал) или у ребят из Rohm фантазия развитая или чего не договаривают. Откуда по 14 проклокиваний перед стартами?
--------------------
aka Vit
|
|
|
|
|
Dec 4 2007, 11:32
|
Местный
  
Группа: Свой
Сообщений: 234
Регистрация: 30-03-07
Из: Одесса
Пользователь №: 26 621

|
Цитата(forever failure @ Dec 4 2007, 10:43)  Ещё такая деталь: стартап тайм, определённое фьюзами равно 65 мсек. Если WDT включен и работает при каком-то вечном зависоне это можно видеть как периодическое притухание индикаторных светодиодов с периодом таймаута вочдога (65 мс каждые 2 сек). Совершенно точно помню, что в эксплуатации при зависании этого не было, т. е. выглядело так, как будто WDT не срабатывал. Все вроде честно. Прога на цикле ожидания флага от ТВАЯ, как и положено виснет, собака сбрасывает проц, после чего прога опять, как и положено виснет. Отлаживать софт с собакой - плохая практика. Отключите собаку и вычисляйте места зависонов конкретно. Хотя они ясны и так.
|
|
|
|
|
Dec 4 2007, 12:25
|
Местный
  
Группа: Участник
Сообщений: 256
Регистрация: 6-03-05
Из: Екатеринбург
Пользователь №: 3 112

|
Что бы что-то попробовать, нужно, чтоб ситуация хотябы иногда повторялась. Рекомендаций уже было дано достаточно много, но чтоб их проверить, нужно как-то вызвать зависающую ситуацию. Сейчас, у меня никак не получается вызвать такое.
Это на текущий момент проблема более основная, чем исправление причины зависания.
К тем устройствам, которые сейчас остались на месте эксплуатаци тоже сейчас нет возможности как-то добраться, в общем они где-то там, до куда сейчас не дойти не доехать, не вызвонить через проводки.
Поэтому заменив что-то в коде или исправив в источнике питания или ещё что-то сделав, я сейчас так и не узнаю - устранена причина или нет - на рабочем столе оно и так работает во всех позах без каких либо исправлений.
|
|
|
|
|
Dec 4 2007, 13:09
|
Местный
  
Группа: Участник
Сообщений: 256
Регистрация: 6-03-05
Из: Екатеринбург
Пользователь №: 3 112

|
Цитата(sensor_ua @ Dec 4 2007, 17:42)  Нужно аж симитировать сброс проца во время работы по TWI Было и такое. зависает до первого срабатывания WDT, то есть на две сек, а дальше норамльно работает.
|
|
|
|
|
Dec 4 2007, 20:13
|

Местный
  
Группа: Свой
Сообщений: 479
Регистрация: 8-05-07
Из: г. Ставрополь. Северный Кавказ. Россия
Пользователь №: 27 606

|
Цитата(sensor_ua @ Dec 4 2007, 07:23)  Непонятно это филипс недорасписал (или я криво читал) или у ребят из Rohm фантазия развитая или чего не договаривают. Откуда по 14 проклокиваний перед стартами? Как-то смутно i2c у Филипса описано. forever failure В некоторых мануалах на микросхемы 24c01 пишут, что микросхема начинает гарантированно работать через 0.15 (!!!) секунды. Пороверка наличия/работоспособности устройства, должна иметь выход по таймауту. Иначе как индицировать поломку?
|
|
|
|
|
Mar 2 2009, 06:05
|
Местный
  
Группа: Участник
Сообщений: 256
Регистрация: 6-03-05
Из: Екатеринбург
Пользователь №: 3 112

|
Чисто случайно нашёл сейчас свою тему, на какую следовало бы,в общем-то, отрапортовать : "Хэппи энд". Косяк нашёлся, дело было не в шине I2C, не в питании, и не в разводке платы. Проблема крылась в небольшом куске ассемблерного программного кода : CODE SIG_UART0_RECV: push r16 ; 2 in r16, IO_PORT(SREG) ; 1 push r17 ; 2 lds r17, LED_PORT ; 2 /* atmega128 */ ori r17, RECV_LED ; 1 sts LED_PORT, r17 ; 2 /* atmega128 */ push r30 ; 2 push r31 ; 2
in r31, IO_PORT(UDR0) ; 1 /* atmega128 */ in r17, IO_PORT(UCSR0A) ; 1 /* atmega128 */ andi r17, parity_error ; 1 lds r30, modbus_line_state ; 2 or r30, r17 ; 1 sts modbus_line_state, r30 ; 2 lds r16, modbus_line_timeout; 2 out IO_PORT(TCNT0), r16 ; 1 /* atmega128 */ in r17, IO_PORT(TIMSK) ; 1 /* atmega128 */ ori r17, BIT(TOIE0) ; 1 out IO_PORT(TIMSK), r17 ; 1 /* atmega128 */ in r17, IO_PORT(TIFR) ; 1 ori r17, BIT(TOV0) ; 1 out IO_PORT(TIFR), r17 ; 1 mov r17, r31 ; 1 lds r30, rxtx_buffer_ptr ; 2 lds r31, rxtx_buffer_ptr + 1; 2 st Z+, r17 ; 2 cpi r30, lo8(rxtx_buffer + RECV_MODBUS_BUFFER_SIZE) /* buffer size <= 256 bytes */ breq HERE + 8 ; 1 / 2 sts rxtx_buffer_ptr, r30 ; 2 sts rxtx_buffer_ptr + 1, r31; 2
pop r31 ; 2 pop r30 ; 2 pop r17 ; 2 out IO_PORT(SREG), r16 ; 1 pop r16 ; 2 reti Даже не очень опытный глаз тут сможет найти ошибку, которая в сочетании с другими дефектами программного кода (в частности сбросом собаки более, чем в одном месте приложения) с единичной вероятностью приводит к отказу устройства. Отсюда вывод (особенно всем тем, кто иногда заявляет "ИАР/ГЦЦ - глючит, атмел гонит брак"): мойте руки перед едой и не экономьте заварку. То есть, просто надо соблюдать простые элементарные правила - в частности чаще тестировать код, проверять в коде возвращаемые функциями значения. Но, хотя ни один из ответов по теме не мог бы решить проблему непосредственно, некоторые неспецифические рекомендации данные здесь, помогли в конечном итоге отловить этого жука. В частности, полезной оказалась рекомендация оставить сброс WDT только в одной точке приложения (и то, только после проверки некоторых условий), и помогла запись в EEPROM запись состояний регистра SREG при возникновении ошибки шины I2C и при возникновении других критических ошибок. Спасибо всем, кто ответил по этой теме.
|
|
|
|
2 чел. читают эту тему (гостей: 2, скрытых пользователей: 0)
Пользователей: 0
|
|
|