SPI-Kommunikationsproblem zwischen Master (HW-SPI) und Slave (USI)

    Diese Seite verwendet Cookies. Durch die Nutzung unserer Seite erklären Sie sich damit einverstanden, dass wir Cookies setzen. Weitere Informationen

    Aufgrund technischer Veränderungen ist der Mailverkehr innerhalb des Forums (Private Nachrichten) nur noch eingeschränkt möglich. Die Einschränkung ist notwendig, um zusätzliche Betriebskosten für das Forum zu vermeiden. Näheres zu den Hintergründen im Thread "Aktuelles zum Forum".Wir bitten um Verständnis.

    Hinweis kann nach Kenntnisnahme deaktiviert werden!

    • SPI-Kommunikationsproblem zwischen Master (HW-SPI) und Slave (USI)

      Hallo Community,


      seit Gestern beschäftige ich mich zum ersten mal einen SPI-Slave über USI zu programmieren/ konfigurieren. Leider ohne Erfolg, dabei ist der Programmcode beinahe komplett aus Beispiele herausgenommen worden (avrhelp.mcselec.com).

      verwendete Hardware:
      - ATmega1284p (Master)
      - ATtiny85 (Slave)

      welche wie im Anhang "SPI_blockschaltbild" angeschlossen ist.

      belegte Pins:
      ATmega1284p (Master) ATtiny85 (Slave)
      PB5 MOSI --> PB0 MOSI
      PB6 MISO --> PB1 MISO
      PB7 SCK --> PB2 SCK

      Da der ATtiny85 der einzige Busteilnehmer ist, wurde auf den Slave-Select verzichtet. Dieser muss bei USI sowieso über Software programmiert werden.

      Programmcode Master:

      ...

      BASCOM-Quellcode

      1. Config Spi = Hard , Interrupt = Off , Data_Order = Msb , Master = Yes , Polarity = Low , Phase = 0 , Clockrate = 128, NOSS = 1 'SPI-Mode 0, beim Slave berücksichtigt (s. Anh. "SPI_mode)
      2. SPDR = &B00000000 'Daten senden zu Slave
      3. Do
      4. Loop Until SPSR.7 = 1




      Programmcode Slave: (org. Beispielcode im Anhang "usi_beispielcode")


      BASCOM-Quellcode

      1. $regfile = "ATtiny85.DAT"
      2. $crystal = 8000000
      3. $hwstack = 32
      4. $swstack = 10
      5. $framesize = 30
      6. Dim B As Byte
      7. Dim Usi_data_ready As Bit
      8. Config Portb.1 = Output 'DO ---> MISO of ATXMEGA (PD6)
      9. Config Portb.2 = Output 'USCK ---> SCK of ATXMEGA (PD7)
      10. Set Portb.2 'enable Pullup
      11. Config Portb.0 = Input 'DI ---> MOSI of ATXMEGA (PD5)
      12. Set Portb.0 'enable Pullup
      13. 'Init USI as SPI Slave in USICR = USI Control Register
      14. Set Usicr.usiwm0 'Three-wire mode. Uses DO, DI, and USCK pins.
      15. Set Usicr.usics1 'Clock Source: External, positive edge ; External, both edges
      16. Set Usicr.usioie 'USI Counter Overflow Interrupt Enable
      17. On Usi_ovf Usi_overflow_int
      18. Enable Usi_ovf
      19. Enable Interrupts
      20. Do
      21. If Usi_data_ready = 1 Then
      22. Reset Usi_data_ready
      23. Usidr = &B00000000
      24. End If
      25. Loop
      26. End
      27. ' After eight clock pulses (i.e., 16 clock edges) the 4-Bit USI counter will generate an overflow interrupt
      28. ' A USI Overflow Int can also wakeup the Attiny from Idle mode if needed
      29. Usi_overflow_int:
      30. Set Usi_data_ready
      31. B = Usidr
      32. Usisr = &B01_000000 'Reset Overflow Flag and reset 4-Bit USI counter
      33. Return
      Alles anzeigen
      Dateien
    • Aslo eigentlich muss das so beim 85er:

      Config Portb.0 = Input 'mosi/di>>mosi m8
      Config Portb.2 = Input 'usck>>clk m8
      Set Usicr.usiwm0 'three wire mode do,di,usck
      Set Usicr.usics1 'clock source: external, both edges
      Set Usicr.usioie '?usi counter overflow enable

      warum konfigurierst du sck als Output?? Ist doch der Slave, der nimmt nur und gibt nischt...und warum den pullup einschalten?
      Zumindest läuft bei mir so der 84er wunderbar als slave, hab für deinen 85er nur die ports geändert.

      Tobias
    • @ Schraubbaer:

      habe dies aus einem Beispielcode, wie im Anhang zu sehen ist. Habe mich selbst gewundert wieso im Beispielcode der Takt als Ausgang konfiguriert ist.

      @ Michael:

      Sry, für den unvollständigen Programmcode. Habe den Beitrag versehentlich abgeschickt und eigentlich gedacht, dass ich gleich eine Antwort geschickt habe zu den unvollständigen Beitrag. Da mein Programmcode viel zu groß ist, poste ich nur den notwendigen Teil.

      Programmcode Master:


      BASCOM-Quellcode

      1. $regfile = "m1284pdef.dat"
      2. $crystal = 16000000
      3. $framesize = 64
      4. $hwstack = 80
      5. $swstack = 80
      6. Declare Sub Impulsgeber
      7. Ddrb = &B00011111 'Port B Ausgänge = 1
      8. Portb.1 = 1
      9. Portb.2 = 1
      10. Portb.3 = 1
      11. Portb.4 = 1
      12. Config Spi = Hard, Interrupt = Off, Data_Order = Msb, Master = Yes, Polarity = low, Phase = 0, Clockrate = 128, NOSS = 1
      13. Spiinit
      14. '************************************************
      15. main:
      16. ...
      17. imp_data_send = &B00000001
      18. Call Impulsgeber
      19. If imp_data_rec = &B00000010 then
      20. Call taste_enter
      21. End If
      22. ...
      23. goto main
      24. End
      25. '************************************************
      26. Sub Impulsgeber
      27. SPDR = imp_data_send 'daten senden
      28. Do
      29. Loop Until SPSR.7 = 1
      30. SPDR = imp_data_send 'daten senden
      31. Do
      32. Loop Until SPSR.7 = 1
      33. imp_data_rec = SPDR 'lese daten slave
      34. End Sub
      35. Programmcode Slave:
      36. $Regfile="attiny85.dat"
      37. $Crystal=4000000
      38. $hwstack=40
      39. $swstack=16
      40. $framesize=32
      41. Declare Sub taste_enter
      42. '-------------------------------------------------------------------------------
      43. 'Variablen ini
      44. Dim Usi_data_in As Byte
      45. Dim Usi_data_out As Byte
      46. Dim Usi_data_ready As Bit
      47. '-------------------------------------------------------------------------------
      48. 'MCU config ini
      49. Config Debounce = 20 '20ms Entprellung (default 25ms)
      50. Ddrb = &B00000110 'Port B: Eingänge = 0; Ausgänge = 1
      51. pORTB = &B00111101 'SS and SCK enable Pullup
      52. Config Portb.1 = Output 'DO ---> MISO of ATXMEGA (PD6)
      53. Config Portb.2 = Input 'USCK ---> SCK of ATXMEGA (PD7)
      54. Set Portb.2 'enable Pullup
      55. Config Portb.0 = Input 'DI ---> MOSI of ATXMEGA (PD5)
      56. Set Portb.0
      57. Set Usicr.usiwm0 'Three-wire mode. Uses DO, DI, and USCK pins.
      58. Set Usicr.usics0
      59. Set Usicr.usics1 'Clock Source: External, positive edge ; External, both edges
      60. Set Usicr.usioie 'USI Counter Overflow Interrupt Enable
      61. '-------------------------------------------------------------------------------
      62. 'Interrupt ini
      63. On Usi_ovf Usi_overflow_int
      64. Enable Usi_ovf
      65. Enable Interrupts
      66. '-------------------------------------------------------------------------------
      67. 'ini
      68. USIDR = Usi_data_out
      69. '------------------------------------------------------------------------------
      70. 'Hauptprogramm
      71. main:
      72. If PinB.4 = 0 then Call taste_enter
      73. If Usi_data_ready = 1 Then
      74. Reset Usi_data_ready
      75. USIDR = usi_data_out
      76. End If
      77. goto main
      78. End
      79. '*************************************************************************
      80. '*************************************************************************
      81. ' UNTERPROGAMME
      82. '*************************************************************************
      83. '*************************************************************************
      84. ' After eight clock pulses (i.e., 16 clock edges) the 4-Bit USI counter will generate an overflow interrupt
      85. ' A USI Overflow Int can also wakeup the Attiny from Idle mode if needed
      86. Usi_overflow_int:
      87. Set Usi_data_ready
      88. Usi_data_in = USIDR
      89. Usisr = &B01_000000 'Reset Overflow Flag and reset 4-Bit USI counter
      90. Return
      91. Sub taste_enter
      92. If Usi_data_in = &B00000001 then
      93. Usi_data_out = &B00000010
      94. End If
      95. If Usi_data_in = &B00000010 then
      96. Usi_data_out = &B00000001
      97. End If
      98. End Sub
      Alles anzeigen
    • belegte Pins:
      ATmega1284p (Master) ATtiny85 (Slave)
      PB5 MOSI --> PB0 MOSI
      PB6 MISO --> PB1 MISO
      PB7 SCK --> PB2 SCK

      Das finde ich nicht korrekt, oder ich hab's falsch verstanden.
      Übersetze mal Mosi: master out, slave in
      Miso: master in, slave out
      so gesehen würde ich diese pins verdreht verbinden.
      Raum für Notizen

      -----------------------------------------------------------------------------------------------------

      -----------------------------------------------------------------------------------------------------
    • Mein Teil stammt aus meinem funktionierenden Programm zwischen einem M8 als Master und einem Tiny84 als Slave nur das ich die pins auf den T85 des Themenstarters umgeschrieben hab. Anschlüsse des M8 stehen ja hinten dran: nix mit überkreuz. Ich hab damals auch ewig rumprobiert bis das mal lief. All die Beispiele bringen einen nicht 100% zum Ziel. Und irgendwie hatten die Pullups auch Probleme gemacht, daher ohne. Weiss aber nichtmehr genau welche Probleme das waren. Müsste es nochmal mit probieren obs immer noch so ist. Geht in meinem Fall bisher auch ohne a_56_df238249

      Tobias
    • MaIv schrieb:

      Sry, für den unvollständigen Programmcode.
      Er ist leider immernoch nicht vollständig.

      Helfer laden sich den Code in ihre IDE und testen, simulieren oder schauen sich das einfach mal farbig an.
      Vieles sieht man dann schon, aber manche laden sich den Code auch auf ihren AVR und schauen mit dem Oszi oder anderen Tools nach. Deswegen ist es sinnvoll, compilierfähigen Code zu posten.

      Den Code kannst du auch prima in Codetags setzen, dann wird er auch im Forum einigermaßen lesbar. oben das Zeichen </>
    • @Schraubbaer
      habe in der Konfiguration die pullup`s weggelasse und den Takt als Eingang konfiguriert. Leider blieb das Resultat erfolglos.

      @Michael
      Hier ein vollständiger Mastercode. Bitte beim Slavecode beachten, dass ich nach Schraubbaer´s Hinweis im 2. Beitrag den Takt als Eingang konfiguriert habe.

      Quellcode

      1. $regfile = "m1284pdef.dat"
      2. $crystal = 16000000
      3. $framesize = 64
      4. $hwstack = 80
      5. $swstack = 80
      6. Declare Sub Impulsgeber
      7. Declare Sub taste_enter
      8. Declare Sub taste_return
      9. Dim page_select As Byte
      10. Dim imp_data_send As Byte
      11. Dim imp_data_rec As Byte
      12. Ddrb = &B00011111 'Port B Ausgänge = 1
      13. Portb.1 = 1
      14. Portb.2 = 1
      15. Portb.3 = 1
      16. Portb.4 = 1
      17. Config Spi = Hard, Interrupt = Off, Data_Order = Msb, Master = Yes, Polarity = low, Phase = 0, Clockrate = 128, NOSS = 1
      18. Spiinit
      19. '************************************************
      20. main:
      21. Select Case page_select
      22. Case 0:
      23. imp_data_send = &B00000001
      24. Call Impulsgeber
      25. If imp_data_rec = &B0000010 then
      26. Call taste_enter
      27. End If
      28. Case 1:
      29. imp_data_send = &B00000010
      30. Call Impulsgeber
      31. If imp_data_rec = &B00000001 then
      32. Call taste_return
      33. End If
      34. End Select
      35. goto main
      36. End
      37. '************************************************
      38. '-------------------------------------------------------------------------------
      39. ' Drehimpulsgeber
      40. Sub Impulsgeber
      41. SPDR = imp_data_send 'daten senden
      42. Do
      43. Loop Until SPSR.7 = 1
      44. SPDR = imp_data_send 'daten senden
      45. Do
      46. Loop Until SPSR.7 = 1
      47. imp_data_rec = SPDR 'lese daten slave
      48. End Sub
      49. '-------------------------------------------------------------------------------
      50. ' Taste Enter
      51. Sub taste_enter
      52. page_select = 1
      53. End Sub
      54. '-------------------------------------------------------------------------------
      55. ' Taste Return
      56. Sub taste_return
      57. page_select = 0
      58. End Sub
      Alles anzeigen
    • Ändere mal

      BASCOM-Quellcode

      1. main:
      2. Select Case page_select
      3. Case 0:
      4. imp_data_send = &B00000001
      5. Call Impulsgeber
      6. If imp_data_rec = &B0000010 then
      7. Call taste_enter
      8. End If
      9. Case 1:
      10. imp_data_send = &B00000010
      11. Call Impulsgeber
      12. If imp_data_rec = &B00000001 then
      13. Call taste_return
      14. End If
      15. End Select
      16. goto main
      17. End
      Alles anzeigen
      in

      BASCOM-Quellcode

      1. Do
      2. Select Case page_select
      3. Case 0:
      4. imp_data_send = &B00000001
      5. Call Impulsgeber
      6. If imp_data_rec = &B0000010 then
      7. Call taste_enter
      8. End If
      9. Case 1:
      10. imp_data_send = &B00000010
      11. Call Impulsgeber
      12. If imp_data_rec = &B00000001 then
      13. Call taste_return
      14. End If
      15. End Select
      16. Loop
      17. End
      Alles anzeigen
      Man sollte auf GOTO verzichten und eine Hautpschleife mit Do Loop End definieren.
      Eine Lösung habe ich nicht, aber mir gefällt Ihr Problem.
    • @djmsc
      auf GOTO zu verzichten hat leider keine Besserung erbracht.

      @Schraubbaer
      der Master sendet den Takt und die Information korrekt.

      Master Ausgangssignal:
      master_zu_slave.jpg

      Slave Ausgangssignal: (Bild im Stop-Modus aufgenommen, da kein definiertes Signal)
      slave_zu_master.jpg

      Habe auch eine kleine Routine programmiert, wenn Slave das Signal empfängt ein Ausgang auf high gehen soll. Hat leider ebenso nicht geklappt. Somit liest der ATtiny das Signal auch nicht korrekt ein. Synchronisieren tut der ATtiny auf 16 Takte mit seinem USI-Counter Register USISR. Kann es sein, dass der Slave falsch synchronisiert? Dieser zählt lediglich die Takte und wenn der Master schon ein Takt erzeugt bevor der Slave gebootet hat, könnte er doch möglicherweiße falsch zählen?
    • MaIv schrieb:

      könnte er doch möglicherweiße falsch zählen?
      richtig. Dafür ist das CS da. Es wird vor der Kommunikation auf Low gezogen, dann kann der Slave den Zähler resetten und den ersten Takt erwarten. Sollte der Master noch nicht bereit sein, dann sorgt ein Pullup dafür, dass der CS High bleibt und der Slave inaktiv. Das passiert z.B. beim Programmieren des AVRs.


      MaIv schrieb:

      Slave Ausgangssignal: (Bild im Stop-Modus aufgenommen, da kein definiertes Signal)
      das Signal sieht wirklich schlecht aus. Was meinst du mit Stop Modus?

      P.S.: Warum nimmst du nicht ein einfaches SPIMOVE?
    • @Michael
      Stop-Modus auf dem Oszilloskop -> Bild eingefroren (ansonsten auf positive oder negative Flanke getriggert)

      Neuer Kenntnisstand:
      Als ich das Datenregister (USIDR) beim Slave nicht beschrieben habe (beschreiben damit ich dem Master Daten zurück geben kann), entsprach MOSI und MISO dem selben Signal (wie es sich auch gehört). Allerdings möchte ich das Register beschreiben damit ich eine bidirektionale Kommunikation aufbauen kann.
    • @Michael
      Beide Controller sind mit GND verbunden. Der Takt kommt vom Master und mein Oszilloskop habe ich am Slave angeschlossen. Wie beschrieben entsprach das Eingangssignal vom Slave dem Ausgangssignal (MOSI -> MISO), als ich nicht mehr das Datenregister USIDR (beim Slave) beschrieben habe.

      Die Synchronisation muss ich noch in der Software realisieren, da ich nicht weiß ab wann der Slave die Takte zählt. Leider klappt es nicht dass der Slave dem Master die Daten schickt, wenn ich bei einem Counter-Interrupt die Daten im USIDR-Register einlesen und die zu versendete Daten im nächsten Schritt einlese.

      Quellcode

      1. Usi_overflow_int:
      2. Set Usi_data_ready
      3. Usi_data_in = USIDR
      4. USIDR = Usi_data_out
      5. Usisr = &B01_000000 'Reset Overflow Flag and reset 4-Bit USI counter
      6. Return


      Ein weiterer Versuch bei dem die Synchronisation egal wäre, habe ich ins USIDR-Register &HFF geschrieben. Das Ausgangssignal (Slave) hatte wie zuvor kein definierten Zustand.

      Quellcode

      1. Usi_overflow_int:
      2. Set Usi_data_ready
      3. Usi_data_in = USIDR
      4. USIDR = &B11111111
      5. Usisr = &B01_000000 'Reset Overflow Flag and reset 4-Bit USI counter
      6. Return

      Nachdem ich das USIDR-Register im Hauptprogramm permanent mit &HFF beschrieben habe, war das Ausgangssignal (Slave) durchgehend auf einem High-Pegel

      Quellcode

      1. main:
      2. USIDR = &B11111111
      3. If PinB.4 = 0 then Call taste_enter
      4. If Usi_data_ready = 1 Then
      5. Reset Usi_data_ready
      6. USIDR = usi_data_out
      7. End If
      8. goto main
      9. End
      Habe ich im Protokoll ein Denkfehler? Nach 16 Clock´s lädt der Slave seine empfangene Daten (Zeile 3) ins USIDR-Register und gibt die geladene Daten (Zeile 4) im USIDR-Register bei den nächsten 16 Clock´s dem Master über?
    • MaIv schrieb:

      Wie beschrieben entsprach das Eingangssignal vom Slave dem Ausgangssignal (MOSI -> MISO), als ich nicht mehr das Datenregister USIDR (beim Slave) beschrieben habe.
      MOSI gehört aber an MOSI und nicht an MISO, ein Schreibfehler?
      Ich würde mir ernsthaft Sorgen um das Signal auf dem Oszi machen und erstmal schauen, warum hier nur 2V anliegen.
      Macht dich denn das nicht stutzig?
      Wenn da Pegel gegeneinander arbeiten, kannst du am Protokoll rätseln, wie du willst, das wird nichts.
      Ich sag das jetzt zum dritten mal, aber irgendwie scheint das für dich kein Problem zu sein, deswegen frag ich ab jetzt da nicht mehr weiter, versprochen. Allerdings sehe ich auch keinen Sinn, da ohne eine Lösung an der Stelle weiterzumachen.
    • Willst du überhaupt Daten an den Master zurückschicken? Wenn nicht lass mal die Miso-miso Verbindung weg, die stört nur und es geht einwandfrei ohne. Wie gesagt, die Beschreibungen sind fast alle der schwer verständliche Auszug ausm Datenblatt.

      Vergiss es ,hab übersehen das du auch lesen willst. Ich würde sagen fang nochmal ganz neu an, schon allein das du beim Master die Ausgänge setzt ist ja an sich gegen das was die Config SPI hergibt, deine Ausgänge werden je mach master/slave mit SPI init gesetzt.

      Tobias

      Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von Schraubbaer ()

    • @Michael
      Sry, für die schlechte Ausdrucksweise. Physikalisch habe ich MOSI an MOSI und MISO an MISO angeschlossen. Ich wollte damit nur sagen, wenn ich das USDR-Register nicht beschreibe schickt der Slave ja die selben Daten zurück wie es empfangen hat. Somit habe schickt der Master ein Signal, welches er wieder selbst vom Slave zurück bekommt.

      Das Signal ist fortlaufend, und ändert sich ständig. Deshalb kann ich das Signal auf dem Oszilloskop nicht einfangen und es sieht so aus als wäre dort nur 2V. Ich hatte ja schon ein sauberes Signal wie im Absatz eins beschrieben.

      @Schraubbaer
      Ohne SS ist schon gegen das Protokoll =) Aber USI bietet es an, bzw. man muss diesen per Software programmieren wenn man diesen benötigt. Habe gedacht das andere entspricht den Protokoll? Wenn ich irgendwelche SPI-AD-Converter einsetze, haben diese doch auch eine bidirektionale Schnittstelle. Oder wie kann man sonst den Chip konfigurieren und die Spannung einlesen?

      @djmsc
      Habe keinen Programmer an der Schnittstelle, wenn ich die Schaltung teste.