To co zamieściłem wcześniej to są funkcje obsługi warstwy TWI. Na tym trzeba zaimplementować obsługę konkretnych układów. Przykładowy kod zapisu bajtu do wybranego rejestru PCF8563. Do bufora wpisujesz adres rejestru i bajt danych, resztę załatwia funkcja zapisu bufora.
Kod:
#define PCF8563_ADDR 0xA2 //adres zegarka PCF8563
///////////////////////////////////////////////////////////////////////////////////////////////////
// RTC write register
void rtc_write_reg(u8 reg, u8 value)
{
u8 buffer[2]; //buffer
buffer[0]=reg; //adres rejestru
buffer[1]=value; //dane
twic_write_buf(PCF8563_ADDR, buffer, 2); //wysylanie bufora do RTC
}
Dziękuję.
A jak poradziłeś sobie z zapisem i odczytem c512? Zapis zrobiłem tak:
Kod:
void mem_write_reg(u16 reg, u8 value)
{
u8 buffer[3]; //buffer
buffer[0]=reg/256; //adres rejestru - starsza część
buffer[1]=reg%256; //adres rejestru - młodsza część
buffer[2]=value; //dane
twic_write_buf(mem_ADDR, buffer, 3); //wysylanie bufora do C512
}
Dobrze?
Z napisaniem procedury odczytu dla adresu 16 bitowego mam problem....
Edit:
Piszę i czytam C512. Praktycznie czytam od adresu '0' co jeden..
Problem podczas zapisu - adres rejestru działa wg wzoru:
adres rejestru=1+4*k gdzie k=0,1,2,3,4.. Taki 'myk' zapewnia zapisywanie do kolejnych komórek pamięci.
Nie wiem czego nie zrozumiałem, ale nie chcę budować żadnych 'protez' w programie. Jak to zrobić dobrze?
Witaj Staszku,
Nie za bardzo zrozumiałem z Twojego postu z czym masz problem - zapis, odczyt całego bufora ??
Na zapis do pamięci danych z bufora bez magicznych wzorów, które podałeś, można sobie np. tak poradzić:
Kod:
void mem_c512_write( uint16_t reg, uint8_t * bufor, uint8_t len )
{
uint8_t i = len - 1;
do {
bufor[i + 2] = bufor[ i ];
} while( i--);
bufor[0] = reg >> 8;
bufor[1] = reg & 0xff;
twic_write_buf(mem_ADDR, bufor, len + 2); //wysylanie bufora do C512
}
W tym przypadku bufor musi mieć co najmniej o 2 bajty większy rozmiar, niż ilość danych do zapisu. Na uwadze też mieć należy to, że zawartość bufora jest modyfikowana.
Nie określiłeś się co dokładnie chcesz zapisywać, odczytywać z/do pamięci. Jeżeli jakieś ustawienia, to może warto rozważyć użycie struktury, a w niej 2 pierwsze bajty zarezerwować dla adresu komórki w pamięci C512 ? Wtedy bez żadnych dodatkowych zabiegów wysyłamy taką strukturę przez i2c ? Rozwiązań jest tyle, ilu programistów...
Przy okazji taka mała sugesia. Staraj się bez potrzeby nie używać operacji dzielenia. Zwiększa to niepotrzebnie rozmiar kodu. Chyba, że ATxmega ma rozkazy sprzętowego dzielenia liczb 16 bitowych.
Przykład pisany "na kolanie".... więc.....
Interesująca propozycja - jutro rano wypróbuję.. i wywalę dzielenia...
Podsumowanie:
1. Zegar czytam (ustawiam za pomocą programu Husarka, potem napiszę setup)
2. Pamięć czytam i piszę z jednym problemem:
- czytam podając adres żądanego rejestru np. 0x0024
- do zapisu muszę użyć adresu wg wzoru: adres_rej=4*adres_rej+1 czyli 0x0091
i wtedy zapiszę pod realnym adresem 0x0024. Tego zupełnie nie rozumiem :-(...
Wszystkie procedury Adama i Pawła pracują bardzo dobrze...
BTW:
Ostatnio przeglądnąłem mnóstwo programów (starałem się ze zrozumieniem) i nasunęła mi się myśl. Otóż piszących programy można podzielić na 3 grupy:
1. Wyznawców ortodoksyjnie rozumianego prawa Murphy'ego "Jeśli coś może pójść źle, to na pewno pójdzie źle". W związku z tym mnóstwo komentarzy (bezcenne), pilnowanie rejestrów, zapalanie i gaszenie flag i etc. Takiego podejścia do tematu uczy szkoła asemblerowa...
2. Wyznawców odwróconego prawa Murphy'ego " Jeśli coś może pójść dobrze, to na pewno pójdzie dobrze". Nie ma komentarzy, flagi machają jak chcą ... do czasu ...
3. Całej reszty, która gdzieniegdzie machnie flagą, przynajmniej wiadomo gdzie autor miał kłopoty...
(13-12-2016 23:26)SP2GNB napisał(a): [ -> ]- czytam podając adres żądanego rejestru np. 0x0024
- do zapisu muszę użyć adresu wg wzoru: adres_rej=4*adres_rej+1 czyli 0x0091
i wtedy zapiszę pod realnym adresem 0x0024. Tego zupełnie nie rozumiem :-(...
Zaglądnąłem do PDF-a pamięci. Funkcja zapisu z przedstawionych tu przykładów zapisuje pod prawidłowym adresem.
Natomiast funkcję odczytu będzie trzeba zmodyfikować do tej pamięci.....
Strona 11 pdf-a. Mamy pokazany zapis do pamięci pojedynczej danej oraz całego "bufora". Jak widzisz, wysyłamy adres układu, 2 bajty adresu komórki pamięci, oraz dane. Między bajtami jest tylko sygnał ACK i na końcu STOP.
Odczyt już jest z lekka zakręcony.
mamy taką sekwencję::
START -> DEVICE_ADRESS(bit write)->ACK-->MSB_ADRES->ACK->LSB_ADRES->ACK->
START->DEVICE_ADRESS(bit read)->ACK->DATA1->NO_ACK->STOP
Zwróć uwagę na wyróżnioną sekwencję START. Występuje bez wcześniejszego STOP !!!
Te funkcje w przykładach chyba nie obsługują takiego odczytu. Nie przeglądałem ich...
Przy okazji, aby się upewnić, czy dane są zapisane pod właściwym adresem, zapisz do niej coś pod znany adres. Następnie w programatorze zewnętrznym odzytaj pamięć. Badzie wszystko wiadomo, gdzie leży błąd. W zapisie pod błędny adres, czy w funkcji odczytu....
PDF pamięci nic nie mówi o takim mechanizmie odczytu/zapisu:
adres_rej=4*adres_rej+1.
Nie posiadam aktualnie pamięci c512, oraz Xmegi, więc są to moje rozważania teoretyczne na chwilę obecną.
[
attachment=12047]
(14-12-2016 18:26)SQ8MVY napisał(a): [ -> ]Przy okazji, aby się upewnić, czy dane są zapisane pod właściwym adresem, zapisz do niej coś pod znany adres. Następnie w programatorze zewnętrznym odzytaj pamięć. Badzie wszystko wiadomo, gdzie leży błąd. W zapisie pod błędny adres, czy w funkcji odczytu....
Scalak SMD wlutowany na stałe :-( ...
Sprawdzam raz jeszcze...
EDIT:
Wyrzucam wzór z zapisu, traktuję zapis jako OK, grzebię w odczycie...
Rozumiem, że wszystkie sekwencje oprócz read generują automatycznie ACK. Sekwencja read wymaga NOACK ustawianego w CONTROLC..
Taka procedura odczytu dla 8 bitowego adresu rejestru działa bez zarzutu w czytaniu zegara....
Spróbuję zapisać zegar PCF...
Pisze i czytam PCF bez żadnych sztuczek...
Procedura czytania rejestru 16 bitowego wydaje się OK. Kość C512 padła?
A jakiej funkcji odczytu używasz ?
Tej od Adama:
Kod:
unsigned char twic_read_reg(unsigned char addr, unsigned char reg)
??
Jak tak, to ona musi być zmodyfikowana, bo adres komórki pamięci do odczytu jest wysyłany jako jeden bajt, natomiast dla c512 adres komórki pamięci jest 2-bajtowy.
Tak. Po zmodyfikowaniu:
Kod:
unsigned char mem_read_reg(unsigned char addr, uint16_t reg)
{
uint8_t data;
//nadaj adres slave + nr rejestru
TWIC_MASTER_ADDR = addr; //adres ukladu + WR, generuje START
while(!(TWIC_MASTER_STATUS & TWI_MASTER_WIF_bm)); //wait for WIF
twic_result = twic_test_result(); //wez status operacji
if (twic_result != TWI_ACK) return 0; //ACK idz dalej, inny zwracaj kod bledu
TWIC_MASTER_DATA = (reg & 0xFF00) >> 8; // /256 adres rejestru
while(!(TWIC_MASTER_STATUS & TWI_MASTER_WIF_bm)); //wait for WIF
twic_result = twic_test_result(); //wez status operacji
if (twic_result != TWI_ACK) return 0; //ACK idz dalej, inny zwracaj kod bledu
TWIC_MASTER_DATA = reg & 0x00FF; //adres rejestru
while(!(TWIC_MASTER_STATUS & TWI_MASTER_WIF_bm)); //wait for WIF
twic_result = twic_test_result(); //wez status operacji
if (twic_result != TWI_ACK) return 0; //ACK idz dalej, inny zwracaj kod bledu
TWIC_MASTER_ADDR = addr; //adres ukladu + WR, generuje START
while(!(TWIC_MASTER_STATUS & TWI_MASTER_WIF_bm)); //wait for WIF
twic_result = twic_test_result(); //wez status operacji
if (twic_result != TWI_ACK) return 0; //ACK idz dalej, inny zwracaj kod bledu
//nadaj adres do odczytu
TWIC_MASTER_ADDR = addr | 0x01; //adres ukladu I2C + RD
while(!(TWIC_MASTER_STATUS & TWI_MASTER_RIF_bm)); //czekaj na zakonczenie odbioru
data = TWIC_MASTER_DATA; //odczytany bajt
// send NACK and STOP
TWIC_MASTER_CTRLC = TWI_MASTER_ACKACT_bm|TWI_MASTER_CMD_STOP_gc;
// twic_result = TWI_OK; //poprawna operacja
return data;
}
Coraz bardziej podejrzewam 24C512 - nie mam, muszę zakupić...
Rozebrałem, na pamięci napis ATMLH440. Szukam info...
Nie podejrzewaj jeszcze pamięci !!!.
W tej Twojej Modyfikacji masz babola.
Wysyłasz 2 bajty adresu komórki pamięci - ok - tak powinno być.
A to co robisz w następnych liniach :
Kod:
TWIC_MASTER_ADDR = addr; //adres ukladu + WR, generuje START
while(!(TWIC_MASTER_STATUS & TWI_MASTER_WIF_bm)); //wait for WIF
twic_result = twic_test_result(); //wez status operacji
if (twic_result != TWI_ACK) return 0; //ACK idz dalej, inny zwracaj kod bledu
//nadaj adres do odczytu
TWIC_MASTER_ADDR = addr | 0x01; //adres ukladu I2C + RD
while(!(TWIC_MASTER_STATUS & TWI_MASTER_RIF_bm)); //czekaj na zakonczenie odbioru
data = TWIC_MASTER_DATA; //odczytany bajt
jest prawdopodobnie źle. Zobacz do noty producenta - strona 11
Po wysłaniu adresu komórki pamięci należy wygenerować START podając adres układu slave z ustawionym bitem READ ( addr |0x01 ).
U Ciebie - wysyłasz adres układu z bitem WRITE - generując START i następnie ponownie wysyłasz adres układu ale już z bitem READ - ponownie generując START
I tu się robi (tak mi się wydaje) zamieszanie obecnie...
I to było TO!
Święta racja Pawle, ślepnę na starość...
Będziesz w Gdyni to daj znać, przysługuje Ci rybka, frytki i browar...
Dziękuję...