Hallo,
derzeit benutze ich den TWI vom SAM4 über die ASF Funktionen. Anfangs
war es etwas holprig wie manche hier vielleicht wissen und zu guter
letzt laufen nun TWI0 und 1. Dachte ich zummindest :)
Slaves sind PCA9555PW als IO-Erweiterungen. Ich habe die Elektronik mal
länger laufen lassen. Es sollte nur eine LED am IO Extender getoggelt
werden im sekundentakt. Dazu lese ich jeweils den aktuellen Portzustand
(von Port 1 und Port 0). Toggle das entsprechende Bit der LED und
schreibe Port 1 und Port 0 wieder zurück. Das ganze funktioniert
eigentlich, nur nach etwa 15min bis 3Std habe ich es jetzt regelmäßig
erlebt, dass ich der TWI beim lesen der Ports aufhängt.
In der twi_master_read kommt er in der while(cnt>0) nicht weiter.
Der Master soll zwei Bytes lesen. Bereits nach dem ersten Byte gibt der
Master ein NACK und sendet STOP wobei die Funktion erst ein Byte
empfangen hat, welches auch noch im TWI_RHR liegt. Die Variable cnt ist
aber noch auf 1. Und gefühlte Tausendmal geht es auch ohne Probleme bis
genau dieses Problem auftritt. Hatte soetwas schonmal einer in der Form?
Ich weiß nicht so recht ob ich den PCA9555 verdächtigen soll oder die
ASF TWI Routine die "eigentlich" funktioniert.
Ein letztes Oszilloskopbild konnte ich auch bekommen. Habe die Infos mal
zusammgestellt und als Bild angehängt.
Der Aktuelle Staus der Variablen ist auch als Screen angehängt, sowie
die TWI-Register. An der Adresse 0x200036E0 steht 0xff (dieses Byte hat
er empfangen) und 0x200036E1 ist auf 0x00 (hat ermeiner Meinung nach
auch noch nicht gelesen, also irgendwas im Speicher).
Die twi_master_read() schaut so aus:
1 | uint32_t twi_master_read(Twi *p_twi, twi_packet_t *p_packet)
|
2 | {
|
3 | uint32_t status, cnt = p_packet->length;
|
4 | uint8_t *buffer = p_packet->buffer;
|
5 |
|
6 | /* Check argument */
|
7 | if (cnt == 0) {
|
8 | return TWI_INVALID_ARGUMENT;
|
9 | }
|
10 |
|
11 | /* Set read mode, slave address and 3 internal address byte lengths */
|
12 | p_twi->TWI_MMR = 0;
|
13 | p_twi->TWI_MMR = TWI_MMR_MREAD | TWI_MMR_DADR(p_packet->chip) |
|
14 | ((p_packet->addr_length << TWI_MMR_IADRSZ_Pos) &
|
15 | TWI_MMR_IADRSZ_Msk);
|
16 |
|
17 | /* Set internal address for remote chip */
|
18 | p_twi->TWI_IADR = 0;
|
19 | p_twi->TWI_IADR = twi_mk_addr(p_packet->addr, p_packet->addr_length);
|
20 |
|
21 | /* Send a START Condition */
|
22 | p_twi->TWI_CR = TWI_CR_START;
|
23 |
|
24 | while (cnt > 0) {
|
25 | //HIER hängt er (bei den 3 if Abfragen)
|
26 | status = p_twi->TWI_SR;
|
27 | if (status & TWI_SR_NACK) {
|
28 | return TWI_RECEIVE_NACK;
|
29 | }
|
30 |
|
31 | /* Last byte ? */
|
32 | if (cnt == 1) {
|
33 | p_twi->TWI_CR = TWI_CR_STOP;
|
34 | }
|
35 |
|
36 | if (!(status & TWI_SR_RXRDY)) {
|
37 | continue;
|
38 | }^
|
39 | *buffer++ = p_twi->TWI_RHR;
|
40 |
|
41 |
|
42 | cnt--;
|
43 | }
|
44 |
|
45 | while (!(p_twi->TWI_SR & TWI_SR_TXCOMP)) {
|
46 | }
|
47 |
|
48 | p_twi->TWI_SR;
|
49 |
|
50 | return TWI_SUCCESS;
|
51 | }
|
Habe schon die Taktrate von 50kHz bis 300kHz variiert und konnte keinen
Unterschied feststellen. Gefühlt hängt er schneller mit kleineren
Taktraten, als mit schnellen. Aber das ist nur so ein Gefühl.
Mit und ohne Debugger habe ich es auch probiert. Hängt sich in beiden
fällen auf.
PS: Erschreckt euch nicht bei dem Oszibild. Ich habe einmal "gezoomt"
und da steht mein Scope garnicht drauf. Darum ist SCL etwas spitz
geworden und geschwungen. Schaut live schön glatt und eckig aus.