Forum: Mikrocontroller und Digitale Elektronik atmega32p verbinden mit attiny85 über SPI - Richtige SCK Frequenz


von derjaeger (Gast)


Angehängte Dateien:

Lesenswert?

Hallo,

ich möchte einen atmega328p (Master) über hardware-spi mit einem 
attiny85 (Slave) verbinden zum Datenaustausch (Slave=>Master). In wie 
weit ist das ein Problem bei der Übertragung und beim Slave Select, dass 
der Master mit 16 MHz angetrieben (Quarz) und der attiny mit 8 MHz 
internen Oszillator?

Ich hab beim Master die einen Prescaler die Möglichkeit eine 
CLK-Frequenz einstellen von 2 ... 128. Was ist der Mindestprescaler, 
damit der Slave nicht überfordert wird? Bei 2 würde ja die Frequenz am 
CLK Eingang des Slaves der Prozessorfrequenz entsprechen, ist das schon 
zuviel für die Auswertung?

Angehängt ist ein Ausschnitt aus dem Attiny85 Datenblatt (Serial 
Programming Characteristics).

Im Gegensatz zu I2C muss ich zwischen den beiden Mikrocontrollern keine 
Widerstände anbringen oder? Das der CS-Pin/SS-Pin softwareseitig vom 
Master selbst gesteuert werden muss ist mir bewusst und das er als 
Ausgang gesetzt werden muss.

Die ganze Aufgabe hat für mich einen Lerncharakter, um SPI etwas näher 
zu kommen.

von Wolfgang (Gast)


Lesenswert?

derjaeger schrieb:
> Die ganze Aufgabe hat für mich einen Lerncharakter, um SPI etwas näher
> zu kommen.

Dann probiere es aus. Fange mit langsamem Takt an und dann steigere 
dich. Du merkst, wenn der Slave mit dem Takt nicht mehr mit kommt. Und 
vergiss nicht, dem Slave genügend Zeit zum Verarbeiten zuzugestehen.

von spess53 (Gast)


Lesenswert?

Hi

>Ich hab beim Master die einen Prescaler die Möglichkeit eine
>CLK-Frequenz einstellen von 2 ... 128. Was ist der Mindestprescaler,
>damit der Slave nicht überfordert wird?

Der SPI-Takt des Masters muss kleiner als 1/4 des Taktes des Slaves 
sein.

MfG Spess

von Arno (Gast)


Lesenswert?

derjaeger schrieb:
> ich möchte einen atmega328p (Master) über hardware-spi mit einem
> attiny85 (Slave) verbinden zum Datenaustausch (Slave=>Master). In wie
> weit ist das ein Problem bei der Übertragung und beim Slave Select, dass
> der Master mit 16 MHz angetrieben (Quarz) und der attiny mit 8 MHz
> internen Oszillator?

Das ist kein besonderes Problem, denn der ATMega328 kann den SPI-Takt ja 
entsprechend niedrig einstellen. Wie niedrig, das steht im Datenblatt 
des ATTiny85 unter

[quote 
http://www.atmel.com/images/atmel-2586-avr-8-bit-microcontroller-attiny25-attiny45-attiny85_datasheet.pdf]
15.3.6 Clock speed considerations
Maximum frequency for SCL and SCK is f_CK / 2
[/quote]

> Ich hab beim Master die einen Prescaler die Möglichkeit eine
> CLK-Frequenz einstellen von 2 ... 128. Was ist der Mindestprescaler,
> damit der Slave nicht überfordert wird? Bei 2 würde ja die Frequenz am
> CLK Eingang des Slaves der Prozessorfrequenz entsprechen, ist das schon
> zuviel für die Auswertung?

...also ist f_CLK = f_CK zu viel. Und auf 4MHz würde ich mich auch nicht 
verlassen, denn so präzise ist der interne RC-Oszillator nicht.

> Angehängt ist ein Ausschnitt aus dem Attiny85 Datenblatt (Serial
> Programming Characteristics).

...was allerdings nicht die "normale" SPI-Schnittstelle beschreibt, 
sondern die Programmierschnittstelle. Die "normale" SPI-Schnittstelle 
ist beim ATTiny85 nicht vorhanden und muss vom USI im Three-Wire-Mode 
nachgebildet werden.

Zum Lernen sicherlich nicht ganz ideal, einfacher wären zwei ATMega328 
zu verbinden. Andererseits kannst du damit gleich ausprobieren, wie man 
eine SPI-Schnittstelle noch so bauen kann, wenn man keine vollständige 
Hardware dafür hat.

MfG, Arno

von derjaeger (Gast)


Lesenswert?

>Zum Lernen sicherlich nicht ganz ideal, einfacher wären zwei ATMega328
>zu verbinden.

Ich gebe zu, ich habe eigentlich erwartet das beide Controller 
Hardware-SPI hätten (war so angegeben - Marketing halt), aber beim 
attiny ist aus berechtigten Gründen nur eine abgespeckte Version zu 
finden, ist aber nicht schlimm. Die Ansteuerung find ich halb so wild, 
der tiny soll ja nur Slave sein. Ein zweiten atmega328 hab ich aber auch 
rumliegen, ich finds aber zwischen zwei Serien interessanter.


Nach meinem Verständnis über SPI passiert beim Slave gar nichts, solang 
kein Takt ankommt. D.h. selbst wenn ich etwas ins 
Slave-SPI-Datenregister lege, "verrottet" es im Register solange bis der 
Master sich per Takt meldet, richtig?

Dann würd ich direkt beim Initialisieren schon was in den Sendepuffer 
reinlegen und nur noch daraufwarten (sleep) bis der Master mit dem Takt 
kommt.

Sowie ich es verstanden habe wird der Interrupt "USI Overflow" 
ausgelöst, wenn das Byte vom Master komplett abgeholt wurde.

Könnte ich fürs erste auf eine SS-Ansteuerung bei einem Slave verzichten 
und immer nur auf den "USI Overflow" Interrupt warten, um ständig den 
Sendepuffer nachzufüllen? Erscheint mir am einfachsten zu realisieren 
beim Tiny.

von derjaeger (Gast)


Lesenswert?

Ist eine Implementierung denkbar für den SS-Pin beim Slave, dass bei 
einem HIGH auf dem SS-Pin der SCK-Pin des Slaves als AUSGANG geschaltet 
ist (damit nicht das falsche Senderegister ausgelesen wird) und erst 
wenn der jeweilige SS-Pin auf LOW ist, wird zügig der Slave-SCK-Pin als 
Eingang geschaltet.

Oder aktiviert/deaktiviert man einfach immer zwischen den SS-Flanken das 
gesamte SPI-Modul?

von Peter D. (peda)


Lesenswert?

derjaeger schrieb:
> Könnte ich fürs erste auf eine SS-Ansteuerung bei einem Slave verzichten

Das machen auch einige und wundern sich dann, wenn die Übertragung 
unzuverlässig ist und aus dem Ruder läuft.
Es reicht dazu der kleinste Störimpuls. Oder der Master beginnt früher, 
als der Slave bereit ist. Oder der Slave ist früher bereit und nimmt 
einfach nen Puls auf dem noch floatenden SCK-Pin als Takt.

Das Slave-SPI ist auf den AVRs eh kritisch (Timing), da muß man nicht 
noch weitere Probleme hinzufügen.

Für MC-MC Kommunikation ist das I2C erheblich besser geeignet, da der 
Slave mit Clock-Stretching dem Master Bescheid gibt, wann er das nächste 
Byte senden darf. Es gibt also keine Timingprobleme oder verlorene 
Daten.

: Bearbeitet durch User
von derjaeger (Gast)


Lesenswert?

Hallo,

ich hab ein merkwüdiges Verhalten bei meinem tiny85-Slave.

Ich will das der tiny an den Master senden soll erst NACH dem 
erfolgreichen SS-Pin (=LOW). Damit meine ich das Beschreiben des 
Sendepuffers mit dem Byte. Das Erkennen des Slave-Selects erfolgt per 
PCINT.


Master-Seite:
1
spi_init(); //enable, clock
2
while(TASTER nicht gedrueckt);
3
slave_select();
4
delay(1s);
5
6
//...dummybyte senden...
7
[code]
8
9
Slave-Seite:
10
11
[code]
12
spi_init();
13
(1) sendepuffer=Daten (<== klappt)
14
while(slaveflag = high);
15
(2) sendepuffer=Daten (1<== klappt nicht)

Problem:
(1) wird ausgefuehrt, (2) wird immer "ignoriert". Wenn ich (2) direkt in 
die PCINT Interruptroutine packe, wird es auch ausgeführt:
1
if(POSITIVE FLANKE)
2
{
3
//nichts machen
4
}
5
else
6
{
7
 sendepuffer=Daten
8
 slaveflag=low
9
}

Wo könnte der Unterschied zwischen (2) und der Interruptroutine liegen?

von S. Landolt (Gast)


Lesenswert?

slaveflag ohne volatile?

von derjaeger (Gast)


Lesenswert?

>slaveflag ohne volatile?

Das wars. Danke.

Jetzt funktioniert das Senden von einem Byte vom attiny85 zum 
attiny328p. Das Senden eines Puffers hat noch Synchronisationprobleme 
zwischen beiden Seiten, sodass die Daten nicht in der richtigen 
Reihenfolge ankommen.

Das Senden eines Bytes hat funktioniert mit folgenden SCK Werten:

Prescaler 8  (SCK=2 MHz)  (auch mit mehreren Bytes hintereinander)
Prescaler 16 (SCK=1 MHz)
Prescaler 64 (250 kHz)
Prescaler 128 (125 kHz)

von neuer PIC Freund (Gast)


Lesenswert?

1
while(slaveflag == high);

Hat da der compiler nicht gemeckert?

von derjaeger (Gast)


Lesenswert?

>Hat da der compiler nicht gemeckert?

Leider nicht. Nichtmal eine Warnung. Ich benutze avr-gcc und laut 
Eclipse ist 'W-all' eingeschaltet.

von derjaeger (Gast)


Lesenswert?

Der Optimierungslevel steht auf "Size optimized (-Os)"

von Wolfgang (Gast)


Lesenswert?

derjaeger schrieb:
> Jetzt funktioniert das Senden von einem Byte vom attiny85 zum
> attiny328p.

SPI tauscht immer Bytes zwischen Master und Slave aus und der Master 
gibt den Takt für den Austausch an. Der Slave kann überhaupt nicht 
selbständig über SPI senden. Was machst du da?

von derjaeger (Gast)


Lesenswert?

>Der Slave kann überhaupt nicht selbständig über SPI senden. Was machst du da?

Der Slave sendet nicht selbst, sondern wartet das sich der Master sein 
Byte über den Takt abholt. Dazu sendet der Master "dummy"-Bytes, die der 
Slave nicht interpretiert.

Der Satz war technisch nicht richtig und sollte die gewünschte Aufgabe 
beschreiben, das der Master nur Bytes empfangen will.

Noch eine Frage zu SPI: Ist es für die Synchronisation sinnvoll bzw. 
üblich, nach jedem empfangenen/gesendeten Byte das Slave Select für eine 
kurze Zeit wieder auf HIGH zu setzen?

Damit wüsste der Slave immer bei jeder fallenden Flanke, dass z.B. nach 
5 ms in seinem Slave-Sendepuffer etwas drin stehen muss, sonst ist er zu 
spät.

von S. Landolt (Gast)


Lesenswert?

Ich würde innerhalb einer Nachricht das Slave-select auf low lassen, die 
einzelnen Bytes der Nachricht im Slave per ISR, zugelassen über 
USICR.USIOIE, bereitstellen; natürlich muss der Master dann die maximale 
Interruptlatenz des Slave berücksichtigen.
  Ausprobiert habe ich das aber nicht, ich greife eher zu einem ATmega, 
bevor ich mit dem USI arbeite.

von derjaeger (Gast)


Lesenswert?

>Ich würde innerhalb einer Nachricht das Slave-select auf low lassen, die
>einzelnen Bytes der Nachricht im Slave per ISR

Das habe ich nicht hinbekommen, weil ich das Datenblatt vom attiny nicht 
gründlich gelesen hatte. Denn dieses "Byte gesendet" - Flag setzt sich 
selbst nicht zurück. Man muss es mit einer "1" im Flagregister selbst 
zurücksetzen:

"If USISIE bit in USICR and the Global Interrupt Enable Flag are set, an 
interrupt will be generated when this flag is
set. The flag will only be cleared by writing a logical one to the 
USISIF bit."

Schon tückisch sowas. Ich war naiv zuglauben, dass es ausreicht in der 
jeweiligen ISR den Code einfach auszuführen. Klappt aber jetzt!


Na wie dem auch sei, ich poste einfach mal meinen Code für die Nachwelt. 
Soooo schwer ist das USI auch nicht als SPI-Slave-Interface :-)

Master atmega:
1
void spi_master_init(void)
2
{
3
  DDRB |= (1<<PB2);//output
4
  PORTB |= (1<<PB2);//ss:high
5
  DDRB |= (1<<PB5);  //SCK: output
6
  DDRB |= (1<<PB3);   //MOSI:out
7
  DDRB &= ~(1<<PB4);   //MISO:in
8
  SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR0);
9
}
10
11
uint8_t spi_master_receive(void)
12
{
13
  uint8_t dummybyte = 0x77;
14
  uint8_t recvdbyte = 0x00;
15
16
  SPDR = dummybyte;
17
  while (!(SPSR & (1<<SPIF)));
18
19
  recvdbyte = SPDR;
20
  return recvdbyte;
21
}
22
23
int main(void)
24
{
25
  char buffer[100]={0};
26
  uint8_t i = 0;
27
////////////////
28
  spi_master_init();
29
  //===================================
30
  spi_start_spi();//select slave: SS low
31
  for(i=0;i<masterdata_cnt;i++)
32
  {
33
      _delay_ms(10);//give slave time to prepare
34
      buffer[i]=(char)spi_master_receive();
35
            //sends dummy bytes to generate CLK for slave
36
  }
37
  //===================================
38
  spi_stop_spi();//do not select slave: SS high

Slave tiny
1
void spi_slave_init_usi(void)
2
{
3
  DDRB &= ~(1<<PB0); //MOSI:input
4
  DDRB |= (1<<PB1); //MISO:output
5
  DDRB &= ~(1<<PB2); //SCK:input
6
  DDRB &= ~(1<<PB3); //SS:input
7
8
  // enable PCINT3
9
  PCMSK = (1<<PCINT3);
10
  GIFR = 0; //clear interrupt flag
11
  GIMSK = (1<<PCIE);
12
  sei();
13
14
  //enable SPI interface (three wiremode)
15
  USICR = (1<<USIWM0) | (1<<USICS1) | (1<<USIOIE);
16
}
17
18
ISR(PCINT0_vect)//Slave Select
19
{
20
  if( !((PINB) & (1<<PB3)) )
21
  {  // SLAVE SELECT: LOW
22
          if(count >= masterdata_cnt)
23
    {
24
      count = 0;
25
    }
26
    USIDR = masterdata[count];//first byte
27
    count++;
28
  }
29
}
30
31
ISR(USI_OVF_vect)//Synchronization
32
{
33
  USISR |= (1<<USIOIF); // DO NOT FORGET TO CLEAR IFG
34
35
  if(count >= masterdata_cnt)
36
  {
37
    count = 0;
38
  }
39
  USIDR = masterdata[count];
40
  count++;
41
}
42
43
int
44
main(void)
45
{
46
  _delay_ms(1000); // wait for SS pin of master is high 
47
  spi_slave_init_usi();
48
        while(1);
49
}

von derjaeger (Gast)


Lesenswert?

Nachtrag:
Hab den falschen Text aus dem Datenblatt kopiert (falsches Flag). Hier 
der richtige: "This flag is set (one) when the 4-bit counter overflows 
(i.e., at the transition from 15 to 0). If the USIOIE bit in
USICR and the Global Interrupt Enable Flag are set an interrupt will 
also be generated when the flag is set. The
flag will only be cleared if a one is written to the USIOIF bit."

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.