|
Причины зависания и их поиск |
|
|
|
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. Самое трудное - воспроизвести эту проблему не в условиях эксплуатации, а на месте, где её можно решить. Одно из устройств сейчас гоняю всяко - на мороз его выставляю, помехи возле него создаю, влажность повышенную - всё нипочём, - всегда бы так работало. Какие ещё дестабилизирующие средства можно применить ?
|
|
|
|
|
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 кажется наиболее правдоподобной и вероятной. Есть ещё несколько версий, так в частности, этой программе, как можно заметить неиспользуемые выводы контроллера оставлены висящими в воздухе, что, тоже может быть источником проблем.
Но в любом случае, ни одну из версий пока не удаётся проверить по причине непроявления проблемы на рабочем столе.
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|