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