C Software SPI

Dieses Thema im Forum "Software" wurde erstellt von Janiiix3, 16. März 2018.

  1. Janiiix3

    Janiiix3 Aktives Mitglied

    Registriert seit:
    28. September 2013
    Beiträge:
    1.208
    Zustimmungen:
    7
    Punkte für Erfolge:
    38
    Sprachen:
    C
    Naaabend,



    CodeBox C und C++
    uint8_t spiSoftRead( uint8_t byte )
    {
       uint8_t n = 0;
       uint8_t ret = 0;
       uint8_t tmp = byte;
    
       for( ; n < 8 ; n++ )
       {
          //SCK KOMMT NOCH!
           ret>>=1;       
           ret |= PINA & 1<<PA3; // Wenn Bit gesetzt dann speichern
           tmp<<=1;       
       }
    
       return ret;
    }
    


    Versuche gerade via. SPI ein paar Bits einzulesen. Erstmal geht es nur um das speichern der eingebenden Daten.
    Ich würde gerne eine "if Abfrage" umgehen und es so wie im Kodebeispiel zu sehen ist realisieren. Geht das überhaupt?
     
  2. Dirk

    Dirk Administrator
    Mitarbeiter

    Registriert seit:
    28. Januar 2007
    Beiträge:
    4.172
    Zustimmungen:
    117
    Punkte für Erfolge:
    63
    Sprachen:
    C, Assembler, Pascal, C++, PHP, Java
    Hi Jan,

    ich weiß nun nicht, warum du "if" nicht verwenden möchtest :hmmmm: ...

    Dein Code funktioniert so nicht, da bereits nach 4 mal rechts shiften von "ret" die ersten Bits verloren gehen.
    Das ganze ist auch abhängig von der Pin-Position, in deinem Fall PA3.
    Bei PA7 würde es funktionieren, aber ob das so sinnvoll ist.
     
  3. Janiiix3

    Janiiix3 Aktives Mitglied

    Registriert seit:
    28. September 2013
    Beiträge:
    1.208
    Zustimmungen:
    7
    Punkte für Erfolge:
    38
    Sprachen:
    C
    Wollte es mal anders probieren. Wenn ich das ganze um die aktuelle Bit Position nach rechts verschiebe, sollte das doch klappen?
    Wenn Ich jetzt z.B (1<<5) abfragen möchte und dann (1<<5) >> 5 verschiebe, sollte das doch funktionieren?



    CodeBox C und C++
    result |= PINA & 1<<5 >> 5;
    result<<=1;
    
     
  4. Dirk

    Dirk Administrator
    Mitarbeiter

    Registriert seit:
    28. Januar 2007
    Beiträge:
    4.172
    Zustimmungen:
    117
    Punkte für Erfolge:
    63
    Sprachen:
    C, Assembler, Pascal, C++, PHP, Java
    Ja, ich denke schon, wenn du das Ergebnis der & Operation shiftest. Die & Operation würde ich noch Klammern.

    Ansonsten uberlege mal, was der Compiler hiermit macht
    (1<<5) >> 5

    Allerdings muss der Mikrocontroller ja einige Male shiften. Das ist ein bisschen wie, wenn du neben der Fahrertür deines Autos stehst, läufst um das Auto rum, steigst auf der Beifahrerseite ein und krabbelst zur Fahrerseite, weil du die if-Fahrertür nicht nutzen oder es einfach mal anders probieren möchtest ;):D Ok, sowas habe ich auch schon mal gemacht. Es gibt auch noch viel mehr Wege ;)
     
  5. Mikro23

    Mikro23 Mitglied

    Registriert seit:
    2. Januar 2017
    Beiträge:
    228
    Zustimmungen:
    18
    Punkte für Erfolge:
    18
    Sprachen:
    C, Assembler


    CodeBox C und C++
    result |= (PINA & PA3_bm) ? 1 : 0;
    result <<= 1;

    Ohne if :D
    ;)
    :p
     
  6. LotadaC

    LotadaC Sehr aktives Mitglied

    Registriert seit:
    22. Januar 2009
    Beiträge:
    2.913
    Zustimmungen:
    43
    Punkte für Erfolge:
    48
    Sprachen:
    BascomAVR, Assembler
    Hi Mikro,

    kannst Du das mal in Assembler (=Maschinencode) übersetzen (lassen)?
    Ich würde (in ASM) den Zustand des Eingangspins ins C-Flag übertragen (also C löschen, C in Abhängigkeit des Beins mit Hilfe von SBIC uns SEC setzen), und anschließend ins Result rollen.
    "PINA & PA3_bm" liest doch erst das Pinregister, und verANDet anschließend mit einer Konstante - was macht das "? 1 : 0" dahinter?
     
  7. Dirk

    Dirk Administrator
    Mitarbeiter

    Registriert seit:
    28. Januar 2007
    Beiträge:
    4.172
    Zustimmungen:
    117
    Punkte für Erfolge:
    63
    Sprachen:
    C, Assembler, Pascal, C++, PHP, Java
    :D Wo du recht hast, hast du recht.

    Andere Schreibweise für einen if-Block. Dies entspricht
    if (PINA & PA3_bm)
    result |= 1;
    else
    result |= 0; (entfällt)

    Mikro hat die if-Fahrertür umlackiert ;)
     
  8. Janiiix3

    Janiiix3 Aktives Mitglied

    Registriert seit:
    28. September 2013
    Beiträge:
    1.208
    Zustimmungen:
    7
    Punkte für Erfolge:
    38
    Sprachen:
    C
    Er würde erst nach links verschieben und dann das 5 te Bit setzen?.

    Das ist so als wenn Ich 5 x um das Haus renne bis Ich in die Eingangstüre gehe? Willst du mir das damit sagen? :D Also viel zu viel Aufwand?
     
  9. Mikro23

    Mikro23 Mitglied

    Registriert seit:
    2. Januar 2017
    Beiträge:
    228
    Zustimmungen:
    18
    Punkte für Erfolge:
    18
    Sprachen:
    C, Assembler
    Hi LotadaC,

    das ist, wie Dirk ganz richtig sagte, nur eine verkürzte Schreibweise für einen if-else-Block. ;)
    Der GCC übersetzt das so:

    CodeBox Assembler
           result |= (PINA & PA3_bm) ? 1 : 0;
    00000056  IN R24,0x19     In from I/O location
    00000057  BST R24,3       Bit store from register to T
    00000058  CLR R24         Clear Register
    00000059  BLD R24,0       Bit load from T to register
    0000005A  OR R28,R24      Logical OR
           result <<= 1;
    0000005B  LSL R28         Logical Shift Left
     
  10. LotadaC

    LotadaC Sehr aktives Mitglied

    Registriert seit:
    22. Januar 2009
    Beiträge:
    2.913
    Zustimmungen:
    43
    Punkte für Erfolge:
    48
    Sprachen:
    BascomAVR, Assembler
    Da nach einer Lösung ohne konditionalem Sprung gesucht werden soll (warum auch immer... mein Weg mit SBIC übers Carry rollen zählt ja auch dazu...), hier folgender Vorschlag:
    1. Pinregister lesen
    2. entsprechenden Pin ins T-Flag speichern
    3. Result schieben
    4. T in Result laden
    Mit dem Lesen und Schreiben von Result hat man hier drei I/O-Zugriffe, ein Logical Shift, und zwei T-Operationen. Außerdem werden so zwei Rechenregister benutzt.

    Edit: War ja quasi zeitgleich mit Deinem Beitrag - interessanterweise fast dasselbe...
    Wobei die IF-Abfrage rausoptimiert wurde - nicht schlecht.

    Trotzdem steig ich noch nicht so richtig durch, was konkret gemacht werden soll... Ich dachte, er will den Pin lesen, und in eine Variable reinschieben...
    Warum dann erst das gesicherte Bit ins gelöschte Register lesen, und danach verORren, und dann schieben?
     
    #10 LotadaC, 17. März 2018
    Zuletzt bearbeitet: 17. März 2018
  11. Janiiix3

    Janiiix3 Aktives Mitglied

    Registriert seit:
    28. September 2013
    Beiträge:
    1.208
    Zustimmungen:
    7
    Punkte für Erfolge:
    38
    Sprachen:
    C
    Ich wollte einfach mal eine andere Lösung suchen als mit "if" anscheind ist das aber nicht sinnvoll.
     
  12. Mikro23

    Mikro23 Mitglied

    Registriert seit:
    2. Januar 2017
    Beiträge:
    228
    Zustimmungen:
    18
    Punkte für Erfolge:
    18
    Sprachen:
    C, Assembler
    Die ausführliche Schreibweise
    Wird sogar noch kürzer übersetzt:

    CodeBox Assembler
           if (PINA & PA3_bm)
    00000056  SBIC 0x19,3       Skip if bit in I/O register cleared
               result |= 1;
    00000057  ORI R28,0x01      Logical OR with immediate
           result <<= 1;
    00000058  LSL R28           Logical Shift Left
     
  13. Mikro23

    Mikro23 Mitglied

    Registriert seit:
    2. Januar 2017
    Beiträge:
    228
    Zustimmungen:
    18
    Punkte für Erfolge:
    18
    Sprachen:
    C, Assembler
    Wie Du an meinem vorigen Beitrag siehst, führt die ausführliche Schreibweise zum kürzesten Code. ;)
     
  14. LotadaC

    LotadaC Sehr aktives Mitglied

    Registriert seit:
    22. Januar 2009
    Beiträge:
    2.913
    Zustimmungen:
    43
    Punkte für Erfolge:
    48
    Sprachen:
    BascomAVR, Assembler
    Das ist meinem Vorschlag mit SBIC ähnlich, aber müßte nicht eigentlich erst geschoben, und danach verORrt werden? So befindet sich das zuletzt eingeschobene Bit doch nicht mehr im LSB, sondern schon eins weiter...?

    also (Laden mal wieder weggelassen):
    1. Result schieben
    2. Bein mit SBIC "prüfen"
    3. 'ne "1" ins LSB von Result (ob mit ORI oder SUBI ist Jacke wie Hose)
    Aber SBIC ist eine konditionale Verzweigung - das will Jan ja aus irgendwelchen Gründen nicht...

    Edit: Schritt 3 mit INC - das verbiegt das Carry nicht. Dann brauchts auch keinen Bitzähler mehr. Vor dem Empfang 0x01 ins Result. Wenn beim Schieben das Carry kommt (bei Schritt 1), bist Du nach Schritt 3 fertig. Da 2 und 3 das Carry nicht antasten, kannst Du es auch nach 3 noch auswerten...

    @Mikro23 : mach mal C draus...
     
    #14 LotadaC, 17. März 2018
    Zuletzt bearbeitet: 17. März 2018
  15. Mikro23

    Mikro23 Mitglied

    Registriert seit:
    2. Januar 2017
    Beiträge:
    228
    Zustimmungen:
    18
    Punkte für Erfolge:
    18
    Sprachen:
    C, Assembler
    Das ist ein Relikt aus diesem Post:
    Wenn man das so schreibt, darf natürlich nach Empfang und verodern des letzten Bits nicht noch mal geschoben werden.
    Eleganter wäre, wie Du sagst, erst schieben und dann verodern.
     
  16. Janiiix3

    Janiiix3 Aktives Mitglied

    Registriert seit:
    28. September 2013
    Beiträge:
    1.208
    Zustimmungen:
    7
    Punkte für Erfolge:
    38
    Sprachen:
    C
    Also könnte ich die Spi Empfangsroutine so implementieren?


    CodeBox C und C++
    uint8_t spiSoftRead( uint8_t byte )
    {
       uint8_t n = 0;
       uint8_t ret = 0;
    
       /*
       *   Vorher Adresse des zu lesenden Kommandos senden..
       */
    
    
       for( n = 0 ; n < 8 ; n++ )
       {
           //CLK_HIGH
           ret |= (SPI_PORT & SPI_PIN) 1 : 0;
           ret<<=1;
           //CLK_LOW
       }
       
       return ret;
    }
    
     
  17. Mikro23

    Mikro23 Mitglied

    Registriert seit:
    2. Januar 2017
    Beiträge:
    228
    Zustimmungen:
    18
    Punkte für Erfolge:
    18
    Sprachen:
    C, Assembler
    Da ja 8 Bit empfangen werden, würde ich das in C so schreiben:
    (Es wird nicht das Ergebnis geschoben, sondern der Schleifenzähler ;))

    CodeBox C und C++
    for (uint8_t i = 1; i; i <<= 1)
       if (PINA & PA3_bm)
           result |= i;
    GCC macht das daraus:

    CodeBox Assembler
           for (uint8_t i = 1; i; i <<= 1)
    00000058  LDI R18,0x01       Load immediate
               if (PINA & (1<<PA3))
    00000059  SBIC 0x19,3        Skip if bit in I/O register cleared
                   result |= i;
    0000005A  OR R28,R18         Logical OR
    0000005B  LSL R18            Logical Shift Left
    0000005C  SBIW R24,0x01      Subtract immediate from word
    0000005D  BRNE PC-0x04       Branch if not equal
    
     
  18. Janiiix3

    Janiiix3 Aktives Mitglied

    Registriert seit:
    28. September 2013
    Beiträge:
    1.208
    Zustimmungen:
    7
    Punkte für Erfolge:
    38
    Sprachen:
    C
    Wann wird "i" unwahr? Wenn die Variable überläuft?
     
  19. Mikro23

    Mikro23 Mitglied

    Registriert seit:
    2. Januar 2017
    Beiträge:
    228
    Zustimmungen:
    18
    Punkte für Erfolge:
    18
    Sprachen:
    C, Assembler
    Wenn die "1" rausgeschoben worden ist, ist i = 0, d.h. unwahr.
    Wahr ist in C alles, was ungleich null ist.

    i sieht in diesem Fall also nacheinander so aus:
    ...i......// Schleifendurchlaufanzahl (entspricht Bitnr.)
    0x01 // 0
    0x02 // 1
    0x04 // 2
    0x08 // 3
    0x10 // 4
    0x20 // 5
    0x40 // 6
    0x80 // 7
    0x00 // hier wird die Schleife beendet
     
  20. LotadaC

    LotadaC Sehr aktives Mitglied

    Registriert seit:
    22. Januar 2009
    Beiträge:
    2.913
    Zustimmungen:
    43
    Punkte für Erfolge:
    48
    Sprachen:
    BascomAVR, Assembler
    Nein, wenn das Doppelregister R24:R25 null wird. An welcher Stelle dieses Register beladen wird, steht nicht im Code. In Zeile 8 wird von diesem Doppelregister (16Bit-Zahl) eine eins abgezogen, wenn das Ergebnis nicht null ist, wird in Zeile 9 zu Zeile 4 zurückgesprungen. Wenn das Ergebnis null war, wird Zeile 9 übersprungen. Wo dieser 24:25-Zähler initialisiert wird, steh nicht im vorliegendem Abschnitt...
    ???
    "i" scheint R18 zu sein, die Schleife scheint über R24:R25 zu laufen.
    "result" ist dann R28. Wären vier Register...

    Mein Vorschlag war:


    CodeBox Assembler
    einsprunglabel:
    LSL R28
    SBIC 0x19, 3
    INC R28
    BRCC einsprunglabel

    Result (R28) wird vor dem Start mit 0x01 beladen, nach achtmal schieben fällt die eins ins Carry, was sich in Zeile 5 auswirkt.
    Letztendlich willst Du aber nicht im Kreis springen sondern stattdessen auf die Clock-Flanken reagieren...
     
  • Über uns

    Unsere immer weiter wachsende Community beschäftigt sich mit Themenbereichen rund um Mikrocontroller- und Kleinstrechnersysteme. Neben den Themen Design von Schaltungen, Layout und Software, beschäftigen wir uns auch mit der herkömmlichen Elektrotechnik.

    Du bist noch kein Mitglied in unserer freundlichen Community? Werde Teil von uns und registriere dich in unserem Forum.
  • Coffee Time

    Unser makerconnect-Team arbeitet hart daran sicherzustellen, dass unser Forum permanent online und schnell erreichbar ist, unsere Forensoftware auf dem aktuellsten Stand ist und unser eigener makerconnekt-Server regelmäßig gewartet wird. Wir nehmen das Thema Datensicherung und Datenschutz sehr ernst und sind hier sehr aktiv, auch sorgen wir uns darum, dass alles Drumherum stimmt!

    Dir gefällt das Forum und die Arbeit unseres Teams und du möchtest es unterstützen? Unterstütze uns durch deine Premium-Mitgliedschaft, unser Team freut sich auch über eine Spende für die Kaffeekasse :-)
    Vielen Dank!
    Dein makerconnect-Team

    Spende uns! (Paypal)
  1. Diese Seite verwendet Cookies, um Inhalte zu personalisieren und die Seite optimal für dich anzupassen. Wenn du dich weiterhin auf dieser Seite aufhältst, akzeptierst du unseren Einsatz von Cookies.
    Information ausblenden