Daisy chain mit avr

Gast #4044674
Lesenswert?
• ▲
▼
Hallo,

ich möchte Daisy Chain mit mehreren AVRs machen. Aufbau wie hier 
http://www.mikrocontroller.net/articles/SPI_Daisychain

Der Master ist hier nicht das Problem. Den habe ich bereits mit 
Shiftregistern getestet.

SS low
alle Daten schicken
SS high


Nun ist aber die Frage, wie ich bei den Slaves am besten vorgehe. Jeder 
Slave soll 3 Byte erhalten.

Gibt es dazu einen kleinen Code für HardwareSPI`?
Gast #4044690
Lesenswert?
• ▲
▼
Mein c-Ansatz:
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3

4
#define SPI_DDR    DDRA
5
#define SPI_PORT  PORTA
6
#define SPI_SCK    PORTA4
7
#define SPI_MOSI  PORTA6
8
#define SPI_SS    PORTA7
9
#define SPI_MISO  PORTA5
10

11
uint8_t status;
12
volatile uint8_t data[3];
13
volatile uint8_t isr_flag;
14

15
uint8_t spi_slave_receive(void)
16
{
17
  while(!(SPSR & (1<<SPIF)));
18
  return SPDR;
19
}
20

21
int main(void)
22
{
23
  SPI_DDR |= (1<<SPI_MISO);
24
  SPCR = (1<<SPE) | (1<<SPIE); // Aktivierung SPI + Interupt
25
  status = SPSR;
26
  
27
  sei();
28
  
29
  while(1)
30
  {
31
    if(isr_flag && ((PINA & (1<<SPI_SS))))
32
    {
33
      isr_flag = 0;
34

35
// Werte übernehmen
36
    }
37
  }
38
}
Gast #4045059
Lesenswert?
• ▲
▼
So, habe einen kleine Teilerfolg. Nun kommen die Werte schon einmal 
richtig an. Stellt sich die Frage, wohin mit data[2] damit dieser am 
MISO wiederbereitsteht für den nächsten MOSI am folgenden AVR.

Werde gleich noch anstatt der Abfrage in der while Schleife einen 
Interrupt mit steigender Flankenerkennung einbauen. Der Attiny macht nur 
eine PWM für 3 Leds. Ansonsten ist er dauerhaft im Leerlauf.
1
volatile uint8_t data[3];
2
ISR(SPI_vect)
3
{
4
  data[2] = data[1];
5
  data[1] = data[0];
6
  data[0] = SPDR;
7
}
8

9
int main(void)
10
{
11
  while(1)
12
  {
13
    static uint8_t last_state = 0;
14
    uint8_t state = PINA & (1<<SPISPI_RCK);
15
    
16
    if(state && !last_state)
17
    {
18
      VAL_RED = 255-data[0];
19
      VAL_GREEN = 255-data[1];
20
      VAL_BLUE = 255-data[2];
21
    }
22
    last_state = state;
23
  }
Gast #4046514
Lesenswert?
• ▲
▼
Nochmal einen Nachtrag. Der Master funktioniert soweit korrekt. Sendet 
je angehängten Controller 3 Bytes.

Nur macht mir die ISR zu schaffen.

Wie läuft die ISR genau ab?

Sobald ein Byte empfangen ist?

Wenn ja, wie muss ich die ISR anpassen damit das ganze richtig 
weitergeleitet wird.
1
ISR(SPI_vect)
2
{
3
  data[3] = data[2]; // Ueber MISO an den nächsten MOSI.
4
  data[2] = data[1];
5
  data[1] = data[0];
6
  data[0] = SPDR;
7
}
#4046739
Lesenswert?
• ▲
▼
Sebastian schrieb:

> Wie läuft die ISR genau ab?
>
> Sobald ein Byte empfangen ist?

Genau.

> Wenn ja, wie muss ich die ISR anpassen damit das ganze richtig
> weitergeleitet wird.

Dein Problem ist ein ganz anderes.

Die SPI EInheit kann entweder Master oder Slave sein.
Natürlich könnte man die laufend umkonfigurieren. Aber ob das so schlau 
ist? Denn während die SPI Einheit als Master sendet, sollte sie ja als 
Slave eingangsseitig weiterhin auf Empfang bleiben.


Ich würde mir die Master Seite jedes Slaves in der Chain selbst 
ausprogrammieren. Ist ja keine Raketentechnik.
1
#define SEND_PORT        PORTB
2
#define SEND_DATA_PIN    PB6
3
#define SEND_DATA_CLOCK  PB7
4
#define SEND_SS          PB5
5

6
#define SEND_DELAY       5
7

8
void sendStart()
9
{
10
  SEND_PORT &= ~( 1 << SEND_SS );
11
}
12

13
void sendFinished()
14
{
15
  SEND_PORT |= ( 1 << SEND_SS );
16
}
17

18
void sendByte( uint8_t byte )
19
{
20
  uint8_t i;
21
  for( i = 0; i < 8; i++ )
22
  {
23
    if( byte & 0x80 )      // High Bit zuerst
24
      SEND_PORT |= ( 1 << SEND_DATA_PIN );
25
    else
26
      SEND_PORT &= ~( 1 << SEND_DATA_PIN );
27

28
    _delay_us( SEND_DELAY );   // Datenbit liegt an. Gib dem Empfänger ein
29
                               // bisschen Zeit.
30

31
    SEND_PORT |= ( 1 << SEND_CLOCK );
32
    _delay_us( SEND_DELAY );
33
    SEND_PORT &= ~( 1 << SEND_CLOCK );
34

35
    byte <<= 1;
36
  }
37
}

Damit hast du eine Software-SPI, mit der du Bytes an den nächsten Slave 
weiterschicken kannst (aber bitte nicht aus der ISR heraus).
#4046742
Lesenswert?
• ▲
▼
Karl Heinz schrieb:

> Die SPI EInheit kann entweder Master oder Slave sein.
> Natürlich könnte man die laufend umkonfigurieren. Aber ob das so schlau
> ist? Denn während die SPI Einheit als Master sendet, sollte sie ja als
> Slave eingangsseitig weiterhin auf Empfang bleiben.

Dazu kommt natürlich dann ja auch, dass du ja nur einen Satz an 
Hardware-SPI Pins hast. Aus Sicht eines deiner Slaves benötigst du aber 
2 'Anschlüsse'. Auf dem einen Satz von Leitungen kommen die Bytes vom 
jeweiligen Vorgänger in der Chain rein, auf dem anderen Satz von 
Leitungen gehen die Bytes an den jeweiligen Nachfolger raus.
#4046829
Lesenswert?
• ▲
▼
Sebastian schrieb:
> Nochmal einen Nachtrag. Der Master funktioniert soweit korrekt. Sendet
> je angehängten Controller 3 Bytes.
>
> Nur macht mir die ISR zu schaffen.
>
> Wie läuft die ISR genau ab?
>
> Sobald ein Byte empfangen ist?
>
> Wenn ja, wie muss ich die ISR anpassen damit das ganze richtig
> weitergeleitet wird.
>
>
1
> ISR(SPI_vect)
2
> {
3
>   data[3] = data[2]; // Ueber MISO an den nächsten MOSI.
4
>   data[2] = data[1];
5
>   data[1] = data[0];
6
>   data[0] = SPDR;
7
> }
8
>
etwa so:
    temp = data[2];
    data[2] = data[1];
    data[1] = data[0];
    data[0] = SPDR;
    SPDR = temp;

Das würde gehen, wenn der Master eine kleine Pause alle 8 Bits macht, 
damit der Slave die ISR ausführen kann.
#4046833
Lesenswert?
• ▲
▼
Das nächste Problem ist, wann weiß der Slave das alle Daten Übertragen 
sind.

Das SS-Signal wird zwar von de SPI-Einheit ausgewertet, aber die 
Software kommt da nicht ran.

Man brauch eine weitere Interrupt-Quelle die erkennt, dass das SS-Signal 
OFF geht (logisch HI). Entweder man legt das SS-Signal zusätzlich an 
einen INT-Eingang, oder man nimmt einen PIN-Change-Interrupt der die 
meisten TINYs und MEGAs an allen Pins haben.

EDIT:
Da es Zeitkritisch ist, SPDR zu früh wie möglich neu schreiben:
1
ISR(SPI_vect){
2
    uint8_t temp = SPDR;
3
    SPDR = data[2];
4
    data[2] = data[1];
5
    data[1] = data[0];
6
    data[0] = temp;
7
}
Gast #4047164
Lesenswert?
• ▲
▼
Hab den Thread durchgelesen, aber da wird in allen Richtungen spekuliert 
:(
Das senden ist bei mir kein Problem. Es werden 6 Bytes rausgesendet (hab 
dem ganzen mal ein paar µs Zeit gegegben.
1
void spi_master_transmit(uint8_t *buffer, uint8_t Datalenght )
2
{
3
  uint8_t Counter = 0;
4
  uint8_t data;
5
  PORTA &= ~(1<<PORTA7);
6
  _delay_us(50);
7
  // erten Wert senden
8
  SPDR = buffer[ Counter++ ];
9
  while( Counter < Datalenght )
10
  {
11
    _delay_us(50);
12
    data = buffer[ Counter ];
13
    while(!(SPSR & (1<<SPIF)));
14
    SPDR = data;
15
    Counter++;
16
  }
17
  while(!(SPSR & (1<<SPIF)));
18
  _delay_us(50);
19
  PORTA |= (1<<PORTA7);
20
}

Nur bekomme ich es nicht hin, dass wenn nun SS LOW ist, dass die Bytes 
durch alle Slaves geschoben werden.

Wenn ich 255, 255, 255, 0, 0, 255 als Bytes sende, soll es in Slaves 
sobald SS wieder HIGH ist, wie folgt aussehen.

Slave1
255, 255, 255
Slave2
0, 0, 255
#4047275
Lesenswert?
• ▲
▼
Habs es mal ein wenig zusammengefast, schien aber alles korrekt zu sein:
1
void spi_master_transmit(uint8_t* buffer, uint8_t size ) {
2
  uint8_t i;
3
  PORTA &= ~(1<<PORTA7); // SS to low
4
  for (i = 0; i++; i < size) {
5
    SPDR = buffer[i]; // Writing to the register initiates data transmission.
6
    while (!(SPSR & (1<<SPIF))); // waiting for SPI Interrupt Flag
7
    _delay_us(50);
8
  }
9
  PORTA |= (1<<PORTA7); //SS to Hi
10
}

Welchen AVR Controller verwendest du, im Masterbetrieb MUSS der SS-Pin 
als Output konfiguriert werden, auch wenn du einen anderen Pin benutzt 
um die Slaves zu selektieren.


Wie sieht dein Code jetzt in den Slaves aus?
Gast #4047289
Lesenswert?
• ▲
▼
Hallo Christian, ich habe einen Attiny841 genommen. SS ist dort auf PA7. 
Als Ausgang ist er im Master ebenfalls aktiv.


// Slave
1
ISR(SPI_vect)
2
{
3
  uint8_t tmp = SPDR;
4
  SPDR = data[2];
5
  data[2] = data[1];
6
  data[1] = data[0];
7
  data[0] = tmp;
8
}
9

10
ISR(INT0_vect) // SS von Master
11
{
12
  isr_flag_ss = 1;
13
}
14

15
void spi_slave_init(void)
16
{
17
  // Ausgang MISO
18
  DDRA |= (1<<DDRA5);
19
  // Aktivierung SPI + Interrupt
20
  SPCR = (1<<SPE) | (1<<SPIE);
21
}
22

23

24
int main(void)
25
{
26
/...
27
  DDRB &= ~(1<<PORTB1);
28
  PORTB |= (1<<PORTB1);
29

30
  // Interrupt bei steigender Flanke
31
  MCUCR |= (1<<ISC01) | (1<<ISC00);
32
  // Interrupt aktivieren
33
  GIMSK |= (1<<INT0);
34
//...
35
  while(1)
36
  {
37
    if(isr_flag_ss)
38
    {
39
      isr_flag_ss = 0;
40
      // Werte schreiben, wenn SS wieder HIGH ist
41
      // Wert1 = data[0];
42
      // Wert2 = data[1];
43
      // Wert3 = data[2];
44
    }
45
  }
46
}
#4047333
Lesenswert?
• ▲
▼
Schein an sich alles richtig zu sein.

Der Tiny kann die SPI-Leitungen wahlweise auf andere Pins Mappen:

Standard ist PA4 bis 7

A4 / A3 ist dein SCK
A5 / A0 ist dein SPI Output
A6 / A1 ist den SPI Input
A7 / A2 ist SS
und auf B1 ist ebenfalls das SS-Signal?

in deinen //.. versteckt sich hoffentlich das sei()


Welchen tackt haben die Controller und welche SPI Clock gibt der Master 
vor?

@Karl Heinz das sollte alles problemlos mit der Hardware-SPI gehen.
und jetzt hast du deinen Beitrag gelöscht
Gast #4047516
Lesenswert?
• ▲
▼
Christian K. schrieb:
> Schein an sich alles richtig zu sein.
>
> Der Tiny kann die SPI-Leitungen wahlweise auf andere Pins Mappen:
>
> Standard ist PA4 bis 7
>
> A4 / A3 ist dein SCK
> A5 / A0 ist dein SPI Output
> A6 / A1 ist den SPI Input
> A7 / A2 ist SS
> und auf B1 ist ebenfalls das SS-Signal?
>
> in deinen //.. versteckt sich hoffentlich das sei()
>
> Welchen tackt haben die Controller und welche SPI Clock gibt der Master
> vor?
>
> @Karl Heinz das sollte alles problemlos mit der Hardware-SPI gehen.
> und jetzt hast du deinen Beitrag gelöscht

Hallo Christian,

was möchtest du mit dem Remap mir erzählen? Dass ich die SPI 
Schnittstelle umlegen kann, ist mir bekannt, aber ich sehe da keinen 
nutzen drin.

Also auf B1 habe ich das SS-Signal gelegt und es mittels Interrupt 
abgefragt. SS ist ansonsten nirgends angeschlossen.

Die Master sendet mit FCK/16. Alle Tinys laufen mit den internen 8MHz.
#4047563
Lesenswert?
• ▲
▼
Sebastian schrieb:
> was möchtest du mit dem Remap mir erzählen? Dass ich die SPI
> Schnittstelle umlegen kann, ist mir bekannt, aber ich sehe da keinen
> nutzen drin.

Gut, hätte ja sein gekonnt das du das übersehen und die falschen Pins 
genommen hast.

> Also auf B1 habe ich das SS-Signal gelegt und es mittels Interrupt
> abgefragt. SS ist ansonsten nirgends angeschlossen.

Wie meinst du dass, SS geht nur an B1 oder zusätzlich zu B1 nirgendwo 
anders?

Die Hardware-SPI der Slaves brauch auf jeden Fall das SS-Signal, fest 
auf GND geht nicht, da sie im Gegensatz zu 0815 Schieberegistern 
Byte-orientiert arbeiten, und sonst nicht wissen wann das erste Bit los 
geht.
Einem 74x595 wäre das egal, da kann man es fest ah GND legen.

Ein externe PullUP von 10KOhm für das SS-Signal wäre optimal.
Gast #4047590
Lesenswert?
• ▲
▼
Die SPI Pins hatte sich soweit schon richtig. Brauch diese ja auch für 
das Programmieren. Bei den Alternative Port geht das nicht.
Ich werde dass mit SS noch einmal abändern.

Ich schaue gerade schon, ob es bei mir nicht sogar Sinn macht, dass 
ganze über USART in SPI Mode (synchron) zu machen. Da müsste ich doch 
dann 2 getrennte Hardware Systeme haben, die sich nicht in die Querre 
kommen. Ich muss halt nur darauf achten, dass ich das ganze so belegte, 
dass ich später noch Platz für 3 PWM (16 Bit-Timer) überhalte.

Antwort schreiben

Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt. Bitte hier nur auf die ursprüngliche Frage antworten, für neue Fragen einen neuen Beitrag erstellen.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.