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
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.
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
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?
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:
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.
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.