|
Проблемы с TWI, при работе с ADT75 |
|
|
|
Mar 23 2009, 13:46
|
Частый гость
 
Группа: Свой
Сообщений: 148
Регистрация: 26-05-05
Пользователь №: 5 416

|
Добрый день. Работаю с восьмой мегой и температурным датчиком ADT75. Написал собсвенные функции работы с TWI: Код unsigned char twi_get_last_status(void) { return (TWSR & (1 << TWS7|1 << TWS6|1 << TWS5|1 << TWS4|1 << TWS3)); } //--------------------------------------------------------------------------- unsigned char twi_Wait_TWINT(void) { register unsigned char i=0; //ожидаем TWIN==1 do { if(TWCR & (1<<TWINT)) return 0x01; //true } while(--i); return 0x00; //false } //--------------------------------------------------------------------------- void twi_init_asmaster(void) { TWBR = 0x20; TWSR = (0 << TWPS1|0 << TWPS0); TWCR |= (1 << TWEN|1 << TWEA); twi_start(); twi_write_address(0xff, 'r'); twi_start(); twi_stop(); } //--------------------------------------------------------------------------- unsigned char twi_start(void) //он же повстарт { TWCR = (1 << TWINT|1 << TWSTA|1 << TWEN); unsigned char twi_last_status = twi_get_last_status(); if(twi_Wait_TWINT() == 0x01) { if((twi_last_status == 0x08) || (twi_last_status == 0x10)) return 0x01; //true } else return 0x00; //false return 0; } //--------------------------------------------------------------------------- unsigned char twi_stop(void) { TWCR = (1 << TWINT|1 << TWSTO|1 << TWEN); register unsigned char i=0; do { if(PINC & 0x10) //смотрим, установилась ли в "1" линия SDA return 0x01; //true } while(--i); TWCR = (1 << TWINT|1 << TWSTO); return 0x00; //false } //--------------------------------------------------------------------------- unsigned char twi_write_byte(unsigned char data_byte) { TWDR = data_byte; TWCR = (1 << TWINT|1 << TWEN); if(twi_Wait_TWINT() == 0x01) { unsigned char twi_last_status = twi_get_last_status(); if((twi_last_status == 0x28) || (twi_last_status == 0x30)) return 0x01; //true else if(twi_get_last_status() == 0x38) return 0x00; //потеряли приоритет } else return 0x00; //false return 0; } //--------------------------------------------------------------------------- unsigned char twi_write_address(unsigned char address_byte, char read_write) { if(read_write == 'r') address_byte |= 0x01; else if(read_write == 'w') address_byte &= 0xFE; else return 0x00; TWDR = address_byte; TWCR = (1 << TWINT|1 << TWEN); if(twi_Wait_TWINT() == 0x01) { unsigned char twi_last_status = twi_get_last_status(); if(read_write == 'w') { if((twi_last_status == 0x18) || (twi_last_status == 0x20)) return 0x01; //true else if(twi_get_last_status() == 0x38) return 0x00; //потеряли приоритет } else if(read_write == 'r') { if((twi_last_status == 0x40) || (twi_last_status == 0x48)) { TWCR = (1 << TWINT|1 << TWEA|1 << TWEN); return 0x01; //true } else if(twi_get_last_status() == 0x38) return 0x00; //потеряли приоритет } } else return 0x00; //false return 0; } //--------------------------------------------------------------------------- unsigned char twi_read_byte(unsigned char *data, unsigned char ack_nack) //ack_nack == 1 - подтверждение { //ack_nack == 0 - неподтверждение if(twi_Wait_TWINT() == 0x01) { unsigned char twi_last_status = twi_get_last_status(); if((twi_last_status == 0x50) || (twi_last_status == 0x58)) { *data = TWDR; if(ack_nack == 1) TWCR = (1 << TWINT|1 << TWEA|1 << TWEN); if(ack_nack == 0) TWCR = (1 << TWINT|1 << TWEN); return 0x01; //true } } else return 0x00; return 0; } Соответсвенно для работы с температурной микросхемой использую вот такие функции: Код void ADT75_init(void) { twi_start(); twi_write_address(0x90, 'w'); twi_write_byte(0x01); twi_write_byte(0x20); twi_stop(); } //--------------------------------------------------------------------------- void ADT75_start(void) { twi_start(); twi_write_address(0x90, 'w'); twi_write_byte(0x04); twi_stop(); } //--------------------------------------------------------------------------- char ADT75_read(void) { unsigned char read_temp_h = 0; unsigned char read_temp_l = 0; twi_start(); twi_write_address(0x90,'w'); twi_write_byte(0x00); twi_stop(); twi_start(); twi_write_address(0x90, 'r'); twi_read_byte(&read_temp_h, 1); twi_read_byte(&read_temp_l, 0); twi_stop(); return (char)read_temp_h; } Но почему то всё время функция ADT75_read(); очень часто возвращает 0. Т.е. симптомы такие - работает всё около часа, потом всё время возвращается 0. Если выключить и снова включить прибор, то может часа три поработать, потом опять нули. Посмотрите пожалуйста свежим взглядом, а то я уже замылился... зы: если надо - соответсвующие порты настроены как высокоомные входы, линия подтягиваеться резюками 6,8к (пробовал разные)... Так же на шине присутсвсует микросхема памяти 24CO4N (вроде как), так она работает правильно всё время...
|
|
|
|
|
Mar 30 2009, 11:36
|

Нечётный пользователь.
     
Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417

|
Цитата(UniBomb @ Mar 23 2009, 16:46)  Добрый день. Работаю с восьмой мегой и температурным датчиком ADT75. Написал собсвенные функции работы с TWI: Код //--------------------------------------------------------------------------- unsigned char twi_read_byte(unsigned char *data, unsigned char ack_nack) { ... if(ack_nack == 1) TWCR = (1 << TWINT|1 << TWEA|1 << TWEN); if(ack_nack == 0) TWCR = (1 << TWINT|1 << TWEN); ...
} Не стоит так делать. Две записи в управляющий регистр. Кто его знает, как оно там реально внутри отрабатывает, вдруг иногда с учётом тактирования TWI попадает на то, что после первой записи начинает отрабатывать чтение с ACK-ом, когда надо бы с NAK-ом и как при этом реагирует именно термодатчик. Он может выдать на SDA уровень 0 как бы от следующего байта и не даст сделать стоп. Лучше так Код if(ack_nack == 1) TWCR = (1 << TWINT|1 << TWEA|1 << TWEN); else TWCR = (1 << TWINT|1 << TWEN); или, что то же самое, так Код TWCR = (ack_nack == 1) ? (1 << TWINT|1 << TWEA|1 << TWEN) : (1 << TWINT|1 << TWEN); или, что в итоге то же самое, но несколько уменьшает шансы оптимизатора сделать пессимизацию Код uint8_t temp = (1 << TWINT|1 << TWEN); if(ack_nack == 1) temp |= (1 << TWEA); TWCR = temp; p.s. не знаю, кто такой ADT75, с провалявшимися 10 лет в столе LM75 нормально работает atmega168, не хуже, чем когда-то с ними же atmega8 работала.
--------------------
Ну, я пошёл… Если что – звоните…
|
|
|
|
|
Mar 30 2009, 12:09
|
Частый гость
 
Группа: Свой
Сообщений: 148
Регистрация: 26-05-05
Пользователь №: 5 416

|
sensor_ua, лучше бы ты меня идиотом назвал... Проверил, коды функций мало чем отличаются, все различия несущественны и заключаются в различном офрмлении. ReAl, насчёт того, чего делать не стоит - да, там опечатка, но ничего вопиющего в принципе нет. Принял к сведению. А насчёт работы - это с моими функциями работает? с теми, что в первом посте? Сделал программный TWI используя функции, взятые тута - тоже не работает. Думаю пока что именно.
|
|
|
|
|
Mar 30 2009, 13:23
|

Нечётный пользователь.
     
Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417

|
Цитата(UniBomb @ Mar 30 2009, 15:09)  А насчёт работы - это с моими функциями работает? с теми, что в первом посте? Ну оно дет не помню сколко назад работало - три термодатчика на atmega8. У меня I2C и master и slave (сейчас на atmega168 кроме 24c256, ds1307 и LM75 ещё горсть atmega48 висит) сделаны в прерываниях на базе, как это ни смешно, апнот AVR311 и AVR315, если правильно помню. С мелкими непринципиальными коррекциями (что-то упростил, так как мне мультимастер не нужен, что-то просто по форме изменил). Цитата(UniBomb @ Mar 30 2009, 15:09)  Сделал программный TWI используя функции, взятые тута - тоже не работает. Думаю пока что именно. Ну не знаю, я те исходники тоже не смотрел. Может и помеха какая сбивает тот ADT75, поставь проверку по таймауту и сброс шины импульсами на SCK до поднятия SDA с последующим формированием STOP (вот этого я до сих пор в этой своей "настольной" системе не сделал  , не зависала шина ещё, пусть пока так потренируется).
--------------------
Ну, я пошёл… Если что – звоните…
|
|
|
|
|
Mar 30 2009, 22:04
|
Профессионал
    
Группа: Свой
Сообщений: 1 266
Регистрация: 22-04-05
Из: Киев
Пользователь №: 4 387

|
Цитата все различия несущественны функция i2c_start_wait (от Fleury) - там Код while ( 1 ) { // send START condition TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);
// wait until transmission completed while(!(TWCR & (1<<TWINT)));
// check value of TWI Status Register. Mask prescaler bits. twst = TW_STATUS & 0xF8;
if ( (twst != TW_START) && (twst != TW_REP_START)) continue; .... } обратите внимание на continueи это чисто формально, не разбираясь в работе TWI.
--------------------
aka Vit
|
|
|
|
|
Apr 2 2009, 16:13
|

Частый гость
 
Группа: Свой
Сообщений: 158
Регистрация: 15-10-07
Из: Й-Ола
Пользователь №: 31 376

|
Цитата(UniBomb @ Mar 23 2009, 17:46)  ... линия подтягиваеться резюками 6,8к (пробовал разные)... я еще кондеры вешаю 30-100 пикф к земле
|
|
|
|
|
Apr 3 2009, 04:52
|
Профессионал
    
Группа: Свой
Сообщений: 1 266
Регистрация: 22-04-05
Из: Киев
Пользователь №: 4 387

|
Цитата совершенно непонятно как это делает мой код нерабочим Вы меня не поняли. Я не берусь судить рабочий Ваш код или нет - я обращаю внимание на то, что отличия есть. Ещё у Fleury в записи проверяется вроде бы (лень искать эту маску) нужные флаги вместе (главное, что "в один присест") Код if( twst != TW_MT_DATA_ACK) return 1; return 0; а у Вас в twi_write_address Код unsigned char twi_last_status = twi_get_last_status(); if(read_write == 'w') { if((twi_last_status == 0x18) || (twi_last_status == 0x20)) return 0x01; //true else if(twi_get_last_status() == 0x38) return 0x00; //потеряли приоритет } .... Проверка похожа, но, думаю, что не такая, ну и второе чтение регистра статуса - вроде бы у Fleury его нет. Аналогично с проверкой и вторым чтением регистра у Вас в twi_write_byte. Не знаю, что правильно, но думаю, что такие отличия существенны
--------------------
aka Vit
|
|
|
|
|
Apr 3 2009, 07:12
|
Частый гость
 
Группа: Свой
Сообщений: 148
Регистрация: 26-05-05
Пользователь №: 5 416

|
M_Andrey, я надеюсь не на шину, а к питанию? ensor_ua, ясно))) Вы немного неправильно делаете - над именно судить код, а не искать различия реализации алгоритма. Цитата(sensor_ua @ Apr 3 2009, 08:52)  Ещё у Fleury в записи проверяется вроде бы (лень искать эту маску) нужные флаги вместе (главное, что "в один присест") ... Проверка похожа, но, думаю, что не такая Нужные флаги тут проверить ну никак нельзя, т.к. нужно смотреть их совокупность (совокупное значение). Этот товарищ делает точно также за двумя исключеними - я пользуюсь числовым обозначением - он предопределёнными константами; он отсекает то что не надо одним махом - я же смотрю только то, что нужно. Критического тут ничего нет. Цитата(sensor_ua @ Apr 3 2009, 08:52)  ну и второе чтение регистра статуса - вроде бы у Fleury его нет. Проверяет он регистр статуса - без этого никак. С TWI можно работать двумя способами - либо через прерывания (в котором всё равно смотрится код статуса в регистре статуса), либо самому регистр статуса всё время мониторить. Вот как он это делает: Код twst = TW_STATUS & 0xF8; if( twst != TW_MT_DATA_ACK) return 1; где TW_STATUS - предопределённая константа, идущая в хедере вместе с компилятором : Код #define TW_STATUS_MASK (_BV(TWS7)|_BV(TWS6)|_BV(TWS5)|_BV(TWS4)|\ _BV(TWS3)) #define TW_STATUS (TWSR & TW_STATUS_MASK) Для наглядности (и просто по привычке) я этими макросами не пользуюсь и представляю всё в явном виде. Возврщаясь к проблеме скажу, что код, на который вы указали работает и у меня запустился. Температура читается и вроде даже без глюков. Но понять почему - я пока так и не смог  Так что спасибо за ссылку и за диалог. Вопрос вроде как снимается)))
|
|
|
|
|
Apr 3 2009, 08:15
|
Профессионал
    
Группа: Свой
Сообщений: 1 266
Регистрация: 22-04-05
Из: Киев
Пользователь №: 4 387

|
Цитата ясно))) Вы немного неправильно делаете извините, но это моё дело. А в моих замечаниях Вы, похоже, не поняли ничего. Цитата Проверяет он регистр статуса В том конкретном месте у Fleury в коде проверка статуса делается ОДИН раз и по ОДНОЙ маске, а у Вас проверка выполняется с ДРУГОЙ логикой - по наличию любого из конкретных СОСТОЯНИЙ - и, в добавок, с ДВОЙНЫМ чтением регистра статуса. Цитата TW_STATUS - предопределённая константа, идущая в хедере вместе с компилятором Это замечание отправьте в детский сад, плз. ЗЫ. Прошу не считать меня излишне резким
--------------------
aka Vit
|
|
|
|
|
Apr 6 2009, 08:05
|
Частый гость
 
Группа: Свой
Сообщений: 148
Регистрация: 26-05-05
Пользователь №: 5 416

|
Так, вопрос всё ещё актуальный... sensor_ua, прошу прощения за возможно-безосновательные претензии  В общем получается так - если написать маленькую программку, в которой просто сделать опрос температурной микросхемы, то всё работает. Код for(;;) { set_conG; for(int i = 0; i < 20; i++) _delay_loop_2(0xFFFF); ds1621_start(); clr_conG; for(int i = 0; i < 20; i++) _delay_loop_2(0xFFFF); temperature = ds1621_read(); } Причём как при использовании функций товарища Fleury. Температура считывается, передаётся по RS-485 и всё в общем пучком. Если те же самые функции запихнуть в основную программу, то происходит то, что я написал в третьем посте. Казалось бы виной тому остальные части большой программы, но я в ней уже всё вичистил. Функции для работы с TWI ни на кого не завязаны, порты нигде не меняюются и т.д. Аггрр....
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|