Witam,
Tak więc mam hardware jak w temacie, i na dodatek podłączony eeprom at24c08 razem z rtc ds1388 na twi. Atmega ma kryształ 18.432MHz, rezystory na linii SDA i SCL to 10k każdy. Na dodatek, jest jeszcze procek stp16cp05, czyli kontroler LED z seryjnym podaniem danych (główna część pętli while()) i LEDy podłączone pod PORTD.7 i 4.
Oto część kodu:
a to jest funkcja read_time():
linia to unsigned char.
Problemy są dwa:
Jeden, w funkcji read_time(), podczas odbioru pierwszego bajtu ze slave'a, zwraca adres który wcześniej zapisałem do TWDR. Adres sprawdziłem i jest dobry. Dlaczego tak jest?
Dwa, gdy procek dochodzi do pętli while(), wykonuje ją całą, (wiem to, ponieważ diody zaświecają się z jakimiś danymi, które nie są 0xf0). I dalej nic nie idzie, ani SCL się nie zmienia, ani dane do driverów led się nie zmieniają, wszystko stoi.
Gdy ręcznie resetnę atmegę, to na diody wchodzą kolejne dane, przesuwając stare na bok, i wtedy znowu się zatrzymuje. Te nowe dane są już inne niż stare, ponieważ adres 0x01 w rtc to sekundy, które się zmieniły.
Tak więc zmieniłem read_time(), aby przeczytać dane z eepromu (który miał już kiedyś coś w sobie zapisanego). Ta sama sytuacja, czyta jeden bajt, potem się zatrzymuje i nic.
Jako że ja piszę w notepad++, kompiluje w avrgcc, i programuje w avrdude, to nie mam szansy na debugowanie. Tak więc w pewnych miejscach powklejałem
kod
który miga diodami.
Wynik był zaskakujący, otóż wyszło na to, że program się "zacina" w pętli while, w zaznaczonym miejscu w kodzie, w funkcji read_time().
Pytanie jest, dlaczego akurat przy drugim podejściu wysyłania START, a nie przy pierwszym czy jakimś innym? I dlaczego w ogóle się zacina...?
Proszę pomóżcie, nic mi nie przychodzi do głowy...
PS. Z I2C mam trochę doświadczenia, bo już się bawiłem na pcf8563, ale nigdy nie miałem takiego problemu.
Tak więc mam hardware jak w temacie, i na dodatek podłączony eeprom at24c08 razem z rtc ds1388 na twi. Atmega ma kryształ 18.432MHz, rezystory na linii SDA i SCL to 10k każdy. Na dodatek, jest jeszcze procek stp16cp05, czyli kontroler LED z seryjnym podaniem danych (główna część pętli while()) i LEDy podłączone pod PORTD.7 i 4.
Oto część kodu:
#include <avr/io.h>
#include <util/twi.h>
#define RTC_ADDR_R_0 0b11010001 //czytanie zmiennych
#define RTC_ADDR_W_0 0b11010000 //zmiana zmiennych
#define set_clk PORTB |= 0b10000000
#define clr_clk PORTB &= ~0b10000000
#define set_data PORTB |= 0b00100000
#define clr_data PORTB &= ~0b00100000
#define set_le PORTB |= 0b00001000
#define clr_le PORTB &= ~0b00001000
#define set_oe PORTB |= 0b00010000
#define clr_oe PORTB &= ~0b00010000
int main()
{
DDRA=0b11100000;
PORTA=0b00000000;
DDRB=0b10111000;
PORTB=0b00000000;
DDRC=0b00000000; //pc1 i pc0 to sda i scl
DDRD=0b10010000;
PORTD=0b10010000;
TWBR = 4;
TWSR = 0;
int i;
while(1)
{
PORTD=0;
if(!read_time()) {linia=0xf0;}
for(i=0;i<=7;++i)
{
clr_clk;
if(linia&(1<<i)) {set_data;} else {clr_data;}
set_clk;
}
set_le;
clr_le;
for(i=0;i<=1000;++i)
{}
}
}a to jest funkcja read_time():
char read_time (void) //zapisywanie czasu z rtc do zmiennych zwraca 1 jesli OK, 0 jesli blad
{
TWCR = (1<<TWSTA) | (1<<TWEN) | (1<<TWINT);
while (!(TWCR & (1<<TWINT)))
{} //Tutaj się zawiesza ********************
if ((TWSR & 0xF8) != TW_START)
{TWCR = (1<<TWSTO) | (1<<TWEN) | (1<<TWINT); return 0;}
TWDR = RTC_ADDR_W_0;
TWCR = (1<<TWEN) | (1<<TWINT);
while (!(TWCR & (1<<TWINT)))
{}
if ((TWSR & 0xF8) != TW_MT_SLA_ACK)
{TWCR = (1<<TWSTO) | (1<<TWEN) | (1<<TWINT); return 0;}
TWDR = 0x01;
TWCR = (1<<TWEN) | (1<<TWINT);
while (!(TWCR & (1<<TWINT)))
{}
if ((TWSR & 0xF8) != TW_MT_DATA_ACK)
{TWCR = (1<<TWSTO) | (1<<TWEN) | (1<<TWINT); return 0;}
TWCR = (1<<TWSTA) | (1<<TWEN) | (1<<TWINT);
while (!(TWCR & (1<<TWINT)))
{}
if ((TWSR & 0xF8) != TW_REP_START)
{TWCR = (1<<TWSTO) | (1<<TWEN) | (1<<TWINT); return 0;}
TWDR = RTC_ADDR_R_0;
TWCR = (1<<TWEN) | (1<<TWINT);
while (!(TWCR & (1<<TWINT)))
{}
if ((TWSR & 0xF8) != TW_MR_SLA_ACK)
{TWCR = (1<<TWSTO) | (1<<TWEN) | (1<<TWINT); return 0;}
//tutaj jest jeszcze odebrany adres slave, a chyba powinien juz byc bajt z adresu 1, nie? nie wiem dlaczego tak jest...
TWCR = (1<<TWEA) | (1<<TWEN) | (1<<TWINT);
while (!(TWCR & (1<<TWINT)))
{}
if ((TWSR & 0xF8) != TW_MR_DATA_ACK)
{TWCR = (1<<TWSTO) | (1<<TWEN) | (1<<TWINT); return 0;}
linia = TWDR;
TWCR = (1<<TWSTO) | (1<<TWEN) | (1<<TWINT);
return 1;
}linia to unsigned char.
Problemy są dwa:
Jeden, w funkcji read_time(), podczas odbioru pierwszego bajtu ze slave'a, zwraca adres który wcześniej zapisałem do TWDR. Adres sprawdziłem i jest dobry. Dlaczego tak jest?
Dwa, gdy procek dochodzi do pętli while(), wykonuje ją całą, (wiem to, ponieważ diody zaświecają się z jakimiś danymi, które nie są 0xf0). I dalej nic nie idzie, ani SCL się nie zmienia, ani dane do driverów led się nie zmieniają, wszystko stoi.
Gdy ręcznie resetnę atmegę, to na diody wchodzą kolejne dane, przesuwając stare na bok, i wtedy znowu się zatrzymuje. Te nowe dane są już inne niż stare, ponieważ adres 0x01 w rtc to sekundy, które się zmieniły.
Tak więc zmieniłem read_time(), aby przeczytać dane z eepromu (który miał już kiedyś coś w sobie zapisanego). Ta sama sytuacja, czyta jeden bajt, potem się zatrzymuje i nic.
Jako że ja piszę w notepad++, kompiluje w avrgcc, i programuje w avrdude, to nie mam szansy na debugowanie. Tak więc w pewnych miejscach powklejałem
kod
PORTD=0; PORTD=0b10010000;
który miga diodami.
Wynik był zaskakujący, otóż wyszło na to, że program się "zacina" w pętli while, w zaznaczonym miejscu w kodzie, w funkcji read_time().
Pytanie jest, dlaczego akurat przy drugim podejściu wysyłania START, a nie przy pierwszym czy jakimś innym? I dlaczego w ogóle się zacina...?
Proszę pomóżcie, nic mi nie przychodzi do głowy...
PS. Z I2C mam trochę doświadczenia, bo już się bawiłem na pcf8563, ale nigdy nie miałem takiego problemu.