Forum: Mikrocontroller und Digitale Elektronik Attiny804 (tinyAVR0) als I2C Slave gibt überhaupt keine Regung von sich


von DerElektronikbastler (Gast)


Lesenswert?

Hallo Leute!

Ich würde gerne einen ATtiny804 (tinyAVR0-Serie) als I2C Slave 
verwenden. Eine Application Note von Microchip konnte ich dazu nicht 
finden und sonst auch nicht so viel im Web, aber wenn man etwas gräbt 
findet man ein paar Codebeispiele (Links siehe unten). Entsprechend 
diesen habe ich mir einen minimalsten Code gebaut und einen Arduino ran 
gehangen der fleißig I2C sendet (verifiziert mit Oszi).

Allerdings passiert absolut überhaupt nix; keine Ausgabe via UART, dass 
die ISR aufgerufen wurde bzw. ich habe es auch schon mit Counter/LED 
innerhalb der ISR versucht. Aber es passiert gar nix.

Und so langsam habe ich keine Idee was noch falsch sein könnte, da sich 
alle Beispiele halbwegs einig sind. Habt Ihr eine Idee wo der Fehler 
liegen könnte?
1
#include <avr/io.h>
2
#include <util/delay.h>
3
#include <avr/interrupt.h>
4
5
extern void USART0_sendString(char *str, uint16_t len);
6
extern void USART0_init();
7
8
void twi_slave_begin(uint8_t address) {
9
  // Silicon bug?
10
  PORTB.OUTCLR = 0x03;  // PB0, PB1
11
    /*
12
        SDA ---> PB1
13
        SCL ---> PB0
14
    */
15
16
  TWI0.CTRLA = 0;                                        // Default timings
17
  TWI0.SADDR = address<<1;                             // Bottom bit is R/W bit
18
  // Enable address, data, and stop interrupts:
19
  TWI0.SCTRLA = TWI_APIEN_bm | TWI_DIEN_bm | TWI_PIEN_bm | TWI_ENABLE_bm;
20
21
  USART0_sendString("READY!\n", 7);
22
}
23
24
void TWI_HandleSlaveIRQ() {
25
  uint8_t action = 0;
26
  uint8_t clientStatus = TWI0.SSTATUS;
27
28
  if (clientStatus & TWI_APIF_bm) {  // Address/Stop Bit set
29
    if (clientStatus & TWI_AP_bm) {    // Address bit set
30
//...
31
    }
32
//...
33
  }
34
}
35
36
37
ISR(TWI0_TWIS_vect) {
38
  USART0_sendString("ISR\n", 4);
39
  // TWI_HandleSlaveIRQ();
40
}
41
42
43
int main() {
44
  _PROTECTED_WRITE(CLKCTRL.MCLKCTRLB, 1);         // set clock frequency to 10 MHz
45
    USART0_init();
46
    USART0_sendString("\n\n---Ready---\n", 14);
47
48
    twi_slave_begin(0x2a);
49
    
50
    sei();
51
52
    while(1) {
53
      _delay_ms(1);
54
    }
55
56
    return 0;
57
}

Links falls mal jemand hierüber stolpern sollte:
 - Beitrag "TWI Slave Code für ATtiny 2-series"
 - 
https://github.com/technoblogy/i2c-sd-card-module/blob/main/I2CSDCardModule.ino
 - 
https://github.com/SpenceKonde/DxCore/blob/master/megaavr/libraries/Wire/src/twi.c
 - 
https://github.com/SpenceKonde/megaTinyCore/tree/master/megaavr/libraries/Wire/src
 - 
https://github.com/wagiminator/ATtiny412-I2C-Rotary-Encoder/blob/main/software/I2C_RotaryEncoder.ino

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Angehängte Dateien:

Lesenswert?

DerElektronikbastler schrieb:
> // Silicon bug?
Woher kommt dieser Kommentar?

Bist du sicher, dass die Pins auf die TWI0-Einheit gemappt sind? 
Irgendwie werde ich aus dieser Tabelle nicht so recht schlau. Ist aber 
auch schon spät...

: Bearbeitet durch Moderator
von DerElektronikbastler (Gast)


Angehängte Dateien:

Lesenswert?

Lothar M. schrieb:
> DerElektronikbastler schrieb:
>> // Silicon bug?
> Woher kommt dieser Kommentar?

Der Kommentar kommt hier her: 
https://github.com/SpenceKonde/megaTinyCore/tree/master/megaavr/libraries/Wire#errata-warning

Da steht:
> All modern AVRs, since the release of the first tinyAVR 0/1-series, through the 
AVR DB-series, have always had a silicon bug relating to the TWI pins ...

Lothar M. schrieb:
> Bist du sicher, dass die Pins auf die TWI0-Einheit gemappt sind?
> Irgendwie werde ich aus dieser Tabelle nicht so recht schlau. Ist aber
> auch schon spät...

Aber dort steht doch (siehe Bild):
 - TWI0 SDA (9. Spalte) auf PB1, Pin 8
 - TWI0 SCL (9. Spalte) auf PB0, Pin 9

und ich bin mir ziemlich sicher, dass das so passt (Verpolung auch 
geprüft).

von Volker B. (Firma: L-E-A) (vobs)


Lesenswert?

DerElektronikbastler schrieb:

> Allerdings passiert absolut überhaupt nix; keine Ausgabe via UART, dass
> die ISR aufgerufen wurde bzw. ich habe es auch schon mit Counter/LED
> innerhalb der ISR versucht. Aber es passiert gar nix.

>
1
> ISR(TWI0_TWIS_vect) {
2
>   USART0_sendString("ISR\n", 4);
3
>   // TWI_HandleSlaveIRQ();
4
> }
5
>

Bist Du Dir sicher, dass USART0_sendString() aus einem Interrupt heraus 
aufgerufen werden darf? Zeig' doch bitte den Code dieser Funktion.

Grüßle,
Volker

von beobachta (Gast)


Lesenswert?

DerElektronikbastler schrieb:
> Entsprechend
> diesen habe ich mir einen minimalsten Code gebaut und einen Arduino ran
> gehangen der fleißig I2C sendet (verifiziert mit Oszi).

Zunächst sehe ich da zwei "Probleme" versteckt. Zum einen ballert
der Master mit vermutlich hoher Datenrate auf den Bus was einen
Slave zur Verzweiflung bringen kann selbst wenn das Prinzip der
Datenübertragung funktioniert. Der Slave hat ja noch was anderes
zu tun aussser Bytes in Empfang zu nehmen. Zum anderen ist bei
TWI bzw. I2C ein Bus-Handshake vorgesehen (das ACK wir abgewartet)
das der Master in diesem Fall vermutlich nicht abwartet.

von DerElektronikbastler (Gast)


Lesenswert?

Volker B. schrieb:
> Bist Du Dir sicher, dass USART0_sendString() aus einem Interrupt heraus
> aufgerufen werden darf? Zeig' doch bitte den Code dieser Funktion.

Ja, ich bin sicher. Und zur Sicherheit habe ich es ja auch mit einem 
Port-Pin-Toggle versucht und einem Counter, um die Zeit in der ISR zu 
minimieren.

beobachta schrieb:
> Zunächst sehe ich da zwei "Probleme" versteckt. Zum einen ballert
> der Master mit vermutlich hoher Datenrate auf den Bus was einen
> Slave zur Verzweiflung bringen kann selbst wenn das Prinzip der
> Datenübertragung funktioniert. Der Slave hat ja noch was anderes
> zu tun aussser Bytes in Empfang zu nehmen. Zum anderen ist bei
> TWI bzw. I2C ein Bus-Handshake vorgesehen (das ACK wir abgewartet)
> das der Master in diesem Fall vermutlich nicht abwartet.

Das ist alles Richtig was Du schreibst aber mir ging es ja erstmal um 
überhaupt eine Reaktion der TWI Hardware, z.B. dass der Interrupt 
Handler aufgerufen wird. Darin bastelt man ja dann die Logik wie ich in 
TWI_HandleSlaveIRQ angedeutet habe. Aber das Problem ist ja, dass 
überhaupt nix passiert.

__Weißer Rauch!__

__TL;DR: es läuft!__

Ich habe nochmal drüber nachgedacht, ob es nicht einen Zusammenhang mit 
der von mir benutzten UART gibt weil die ja teilweise Pins teilen. Also 
habe ich versucht die alternativen Pins für die UART zu verwenden und 
das hat nicht geklappt weil die Symbole im C Code als nicht definiert 
markiert wurde und zu einem Compiler-Fehler geführt haben. Und da hatte 
ich es: ich hatte das falsche Board eingestellt (ATtiny826) und nach 
Änderung auf das Korrekte läuft es einwandfrei! Ich bekomme ganz viele 
"ISR"-Ausgaben auf der seriellen Konsole (was auch oben die zwei 
"Fragen" beantwortet - eine Reaktion kann ich erzeugen auch ohne ACK 
etc. Logik).

D.h. Ihr habt mich auf die Lösung gebracht - Dankeschön!

P.S.: Falls jemand - wie ich - irgendwie den Eindruck gewinnt, dass es 
nirgendwo Beispiele zu TWI-Slave gibt, dem kann ich nur 
https://github.com/SpenceKonde/megaTinyCore/tree/master/megaavr/libraries/Wire/src 
empfehlen, weil daran habe ich mich orientiert.

P.S.S.: Zu:

> ... Zum anderen ist bei
> TWI bzw. I2C ein Bus-Handshake vorgesehen (das ACK wir abgewartet)
> das der Master in diesem Fall vermutlich nicht abwartet.

Das klappt auch mit meiner "Brechstangenmethode", weil: initial setzt 
man ja via "TWI0.SADDR = address<<1;" die Adresse, d.h. die Hardware des 
AVR antwortet eigenständig und korrekt auf die "Anfragen" des Masters, 
weil dieser ja die Adresse des Slaves + R oder W auf den Bus legt. 
Lediglich weitere Kommunikation schlägt fehl. Aber das war ja erstmal 
auch nicht mein Ziel.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.