Hallo, habe einen ATmega als SPI-master mit drei ATtinies als slaves. Der mega hat drei Ausgänge, die jeweils als Chip select für einen der slaves fungieren. Frage: Wie kann ich SW-mäßig dafür sorgen, dass der slave nicht sendet, wenn er nicht angesprochen ist? Mein aktueller Ansatz: Ich habe den DO (data out)-Pin als Input ohne Pullup konfiguriert (tristate) und ändere diese Einstellung zum Enablen auf "mit Pullup" (durch eine Interruptroutine (PCINT)), die durch eine fallende Flanke auf dem Chip-select-Eingang getriggert wird). Damit ich in den Nicht-Sende-Phasen in Ruhe das USIDR beschreiben kann, wäre es gut, wenn auch der CLK-Impuls nicht ankäme und erst durch den Interrupt aktiviert würde. Dazu ist auch der UCLK-Pin auf input ohne Pullup (tristate) gestellt und bekommt erst durch den o.gen. Interrupt den Pullup gesetzt. Dennoch scheinen die Clockpulse durchzukommen, denn das Geschriebene wird beim Abfragen der anderen slaves überschrieben (lauter Einsen). Gibt es einen besseren Ansatz, oder was muß ich in meinem Ansatz ändern, um zum Ziel zu gelangen? Danke für Eure Hilfe! Roman
:
Bearbeitet durch User
Würde in der Nicht-Aktiv Phase das Clock Source Select auf No Clock stellen:
1 | USICS1 USICS0 USICLK Clock Source 4-bit Counter Clock Source |
2 | 0 0 0 No Clock No Clock |
Zum Aktivieren dann wieder auf 1 0 0 oder 1 1 0 Zeitsparender wäre es wohl, den USI_OVF interrupt zu nutzen. Wenn der getriggert wird (d.h. 1 Byte übertragen wurde), dann je nach Select Eingang entweder verwerfen oder in einem Ringbuffer ablegen.
:
Bearbeitet durch User
Hi Helmut, danke für den Tipp, ich hab's probiert, aber leider empfange ich auch weiterhin bloß Einsen. Der Master redet mit noch zwei anderen slaves, bevor er wieder diesen hier anspricht. Habe mal meinen Code angehängt; ich beabsichtige, dass der Slave mittels "Zaehler" die Sendevorgänge zählt und eine sich ständig inkrementierende Zahl sendet... es kommt jedoch bei jedem Sendevorgang immer nur 255.
1 | /* |
2 | SS von SPI master an PB2 = INT0 = Pin 5 |
3 | */ |
4 | |
5 | #include <avr/io.h> |
6 | #include <avr/interrupt.h> |
7 | |
8 | uint8_t Zaehler =0; |
9 | |
10 | void SPI_aktivieren(void); |
11 | void SPI_deaktivieren(void); |
12 | void USI_init(void); |
13 | void Timer_16_Init(void); |
14 | |
15 | |
16 | int main(void) |
17 | { |
18 | USI_init(); |
19 | Timer_16_Init(); |
20 | SPI_deaktivieren(); |
21 | USIDR=0; |
22 | |
23 | while(1) |
24 | { |
25 | if(!(PINB & (1<<PINB2))) |
26 | // SS ist auf LOW => SPI aktivieren |
27 | { |
28 | SPI_aktivieren(); |
29 | Zaehler++; |
30 | while (!(USISR & (1 << USIOIF))) // erwarte Ende d. Übertragung |
31 | SPI_deaktivieren(); |
32 | USIDR = Zaehler; |
33 | } |
34 | } |
35 | return 0; |
36 | } |
37 | |
38 | |
39 | void SPI_aktivieren() |
40 | { |
41 | USICR |= (1 << USICS1); // clock to External, pos edge |
42 | DDRA |= (1 << DDA5); // DO als output |
43 | } |
44 | |
45 | |
46 | void SPI_deaktivieren() |
47 | { |
48 | USICR &= ~(1 << USICS1); // no clock |
49 | DDRA &= ~(1 << DDA5); // DO als input, Pullup bleibt aktiv => tristate |
50 | USISR = (1 << USIOIF); // S. 125: The flag will only be cleared if a one is written to the USIOIF bit. |
51 | } |
52 | |
53 | |
54 | void USI_init() |
55 | { |
56 | //S. 56: Pins sind hochohmig, wenn DDxn = 0 UND PORTxn = 0, also Input mit inaktivem Pullup. |
57 | //Ausgangszustand: SPI deaktiviert; (USCK durch (USICS1:0 = no clock) deaktiviert) |
58 | |
59 | //DI, USCK, DO input |
60 | DDRA &= ~(1 << DDA4) & ~(1 << DDA6) & ~(1 << DDA5); |
61 | |
62 | //pull ups für DI, USCK aktiv, für DO deaktiviert |
63 | PORTA |= (1 << PA4) | (1 << PA6); |
64 | PORTA &= ~(1 << PA5); |
65 | |
66 | USICR |= (1 << USIWM0); // set three wire mode (SPI) |
67 | USICR |= (1 << USICS1); // clock to External, pos edge |
68 | |
69 | //Clear overflow flag |
70 | USISR = (1 << USIOIF); // S. 125: The flag will only be cleared if a one is written to the USIOIF bit. |
71 | } |
72 | |
73 | |
74 | void Timer_16_Init() |
75 | { |
76 | TCCR1B |= ((1<<CS10)|(1<<CS11)); // CPU/64 , S.111 |
77 | } |
:
Bearbeitet durch User
Wenn nur ein Tiny angesprochen wird funktionierts? Würde das vom Master geschickte Byte prüfen (z.B. 0x69 zeigt bit-shifts) Sicherheitshalber das USISR = (1 << USIOIF) beim Aktivieren machen (4-bit Counter auf 0 und das Overflow flag clearen) Leider sind meine C Kenntnisse sehr gering, kann es sein, dass ohne ein ';' ständig SPI_deaktivieren aufgerufen wird?
1 | while (!(USISR & (1 << USIOIF))) ; <-- |
2 | SPI_deaktivieren(); |
:
Bearbeitet durch User
Leider sind meine C Kenntnisse sehr gering, kann es sein, dass ohne ein ';' ständig SPI_deaktivieren aufgerufen wird? while (!(USISR & (1 << USIOIF))) ; <-- SPI_deaktivieren(); Helmut!! Genau das war's! Meine C-"Kenntnisse" sind nicht nur gering, sondern rudimentär! Großen Dank! Roman
Ok, nun bekomme ich eine ständig sich erhöhende Zahl, aber sie wird nicht um eins erhöht, sondern um 2 :-) ! Irgendwie habe ich den Verdacht, dass die Änderung eines Konfigurationsbits dazu führt, dass ein CLK-Impuls ausgelöst wird, der dann die Bits des USIDR um 1 nach MSB schiebt. Es liegt offenbar nicht daran, dass die while-Schleife innerhalb eines Zyklus zwei Mal den Chip select low erkennt, das habe ich durch eine Bedingung abgeprüft. Deinen Tip, Helmut, habe ich auch umgesetzt, deshalb sieht die Aktivierungs-Routine nun so aus:
1 | void SPI_aktivieren() |
2 | { |
3 | DDRA |= (1 << DDA5); // DO als output |
4 | USICR |= (1 << USICS1); // clock to External, pos edge |
5 | USISR |= (1 << USIOIF); // S. 125: The flag will only be cleared if a one is written to the USIOIF bit. |
6 | USIDR = Zaehler; |
7 | } |
:
Bearbeitet durch User
Hatte ein ähnliches Problem, der Master hat den Tiny verstanden aber umgekehrt war es immer um ein Bit geshiftet: Master schickt 0x03, Tiny liest 0x07. Sowas könnte auch der Grund für die +2 sein. Würde mal feste Werte in Zaehler nehmen, z.B 0b 1001 0111 und 0100 1010 Falls der Master nicht beide Werte richtig liest: Auf dem Mega CPOL und CPHA ändern, ich verwende auf dem tiny "External, positive edge" und auf dem Mega SPI Mode 3. Es kann aber auch nur Zufall sein, dass das so geht. Zur Fehlereingrenzung hilft auch, anfangs mit kleiner Frequenz (fosc/128) zu arbeiten. NB: In SPI_aktivieren statt USISR |= (1 << USIOIF) besser USISR = (1 << USIOIF), das setzt auch den 4-bit Counterwert auf 0.
:
Bearbeitet durch User
Danke Helmut, werd ich mal probieren. Ich hatte auf dem tiny zwischenzeitlich schon neg. edge versucht, dann kamen um eins inkrementierte Werte, aber beginnend mit 128. Irgendein Bitshift ist da drin, werde mir das timing-Diagramm nochmal zu Gemüte führen.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.