-         

Ergebnis 1 bis 8 von 8

Thema: PIC18F SPI über MSSP

  1. #1
    Erfahrener Benutzer Begeisterter Techniker Avatar von Torrentula
    Registriert seit
    10.10.2009
    Ort
    Procyon A
    Alter
    21
    Beiträge
    355

    PIC18F SPI über MSSP

    Anzeige

    Hallo PIC Experten!

    Im Moment bin ich dabei einen 74HC595 mit einem PIC18F2520 anzusteuern, genauer gesagt mit Hilfe des MSSP-Moduls. Ich möchte es im SPI Modus betreiben allerdings bekomme ich keinerlei Clock/Datensignal.

    Leider kann mir hier die wirklich tolle Seite von Sprut auch nicht weiterhelfen, deshalb hier mal mein code:

    Code:
    void spi_init(void){
    
        SSPSTATbits.SMP = 0; // Input data sampled at middle of data output time
        SSPSTATbits.CKE = 0; // Transmit occurs on transition from Idle to active clock state
    
        SSPCON1bits.CKP = 0; // Idle state for clock is a low level
    
        SSPCON1bits.SSPM3 = 0; // F_SPI = F_OSC / 4
        SSPCON1bits.SSPM2 = 0;
        SSPCON1bits.SSPM1 = 0;
        SSPCON1bits.SSPM0 = 0;
    
        // enable MSSP
        SSPCON1bits.SSPEN = 1;
    
        // set SDO (RC5) to output
        TRISCbits.RC5 = 0;
        // set SCK (RC3) to output
        TRISCbits.RC3 = 0;
        // set SS (RA5) to input
        //TRISAbits.RA5 = 1;
    }
    
    void spi_send(unsigned char data){
        // wait until the previous byte has been transmitted
        while( PIR1bits.SSPIF == 0 );
        PIR1bits.SSPIF = 0; // reset SSPIF bit
        SSPBUF = data; // write the data byte to be transmitted to SSPBUF
    }
    Der Teil in der init, bei dem Bits auf low gesetzt werden ist nur testweise und macht keinen Unterschied zu der init ohne diese Sequenz.

    Ich hoffe es gibt hier jemanden der einen möglicherweise simplen Fehler sieht
    MfG Torrentula

  2. #2
    Erfahrener Benutzer Roboter-Spezialist
    Registriert seit
    05.11.2007
    Ort
    Berlin
    Beiträge
    526
    Ich vermute :
    Nach einem Reset (Neustart des Prozessors) ist das Bit SSPIF gelöscht = 0.
    Das wird esvermutlich auch bleiben, solange Du noch nichts raus geschoben hast.
    Du must zumindest erstmal ein Byte rausschieben, damit dieses Bit gesetzt wird.
    Quasi den ganzen Vorgang erstmal starten mit einem Dummy Byte.
    Also direkt in SSPBUF was reinscheiben ohne Beachtung des SSPIF Flags.

  3. #3
    Erfahrener Benutzer Begeisterter Techniker Avatar von Torrentula
    Registriert seit
    10.10.2009
    Ort
    Procyon A
    Alter
    21
    Beiträge
    355
    Danke für den Input, das Problem war fast wie du sagst:
    Das SSBUF Register muss erst mit dem zu sendenden Byte geladen werden und dann muss man auf das SSPIF Bit warten.

    Ich habe das jetzt so gelöst:
    Code:
    void spi_send(unsigned char data){
        LATCbits.LATC2 = 0; // set CS low
        SSPBUF = data; // write the data byte to be transmitted to SSPBUF
        while(!PIR1bits.SSPIF); // wait for SSPIF bit to be set
        while(!SSPSTATbits.BF); // wait for BF bit to be set --> both bits set = transfer complete (-> double buffered)
        LATCbits.LATC2 = 1; // set CS high
    }
    Bei mir tut sich jetzt eine weitere Frage auf: Wenn ich nicht zusätzlich auf das BF Bit warte, geht CS viel zu früh (ca. ab der hälfte der Übertragung) wieder auf high. Laut Datenblatt wird das SSPIF Bit erst gesetzt, nachdem das Byte vollständig gesendet wurde. Meine Vermutung ist das das Double Buffering durch das SSPBUF Register etwas damit zu tun haben könnte.

    Mit der jetzigen Lösung bin ich allerdings auch nicht recht zufrieden, da CS relativ früh (8 takte vorher) auf high und auch relativ spät (auch ca. 8 takte) wieder auf high, was natürlich die Übertragungsgeschwindigkeit mindert.

    Hat jemand dazu noch eine Idee?
    MfG Torrentula

  4. #4
    Erfahrener Benutzer Roboter-Spezialist
    Registriert seit
    05.11.2007
    Ort
    Berlin
    Beiträge
    526
    Du must das SSPIF Bit auch wieder löschen, sonst ist deine erste while Schleife für die Katz, da das SSPIF-Bit ja noch von der letzen fertigen Übertragung gesetzt ist. Das ist auch der Grund warum dein CS gleich wieder hoch geht.
    Das gleichst Du jetzt quasi aus, indem Du auf das BF-Flag wartest.

    Also lösch mal erst das SSPIF Bit
    dann schreib den neuen Wert ins SSPBUF
    und dann warte auf das IF Bit

    Das BF-Bit ist für deine Anwenung, nur rausschieben, eigentlich irrelevant.

    Das Double Buffering hat damit nichts zu tun.
    Denn das ist nur beim Empfang aktiv. Beim Senden jedoch nicht.

    Ich hoffe, ich liege nicht völlig falsch, hab das auch noch nicht programmiert.

  5. #5
    Erfahrener Benutzer Begeisterter Techniker Avatar von Torrentula
    Registriert seit
    10.10.2009
    Ort
    Procyon A
    Alter
    21
    Beiträge
    355
    Der folgende code funktioniert leider auch nicht zufriedenstellend, egal ob ich das SSPIF bit vor dem laden von SSPBUF oder nach dem setzen von SSPIF wieder lösche, die CS Leitung ist jetzt gut doppelt so lange low wie sie sein sollte.

    Code:
    void spi_send(unsigned char data){
        LATCbits.LATC2 = 0; // set CS low
        SSPBUF = data; // write the data byte to be transmitted to SSPBUF
        while(!PIR1bits.SSPIF); // wait for SSPIF bit to be set
        PIR1bits.SSPIF = 0; // reset SSPIF bit
        LATCbits.LATC2 = 1; // set CS high
    }
    MfG Torrentula

  6. #6
    Erfahrener Benutzer Roboter-Spezialist
    Registriert seit
    05.11.2007
    Ort
    Berlin
    Beiträge
    526
    Nun müssen wir mal über die Zeiten reden.
    Wieviele Bytes schiebst Du denn raus pro Sekunde, bzw. was hast Du für eine Clockrequenz ?
    und wie lang ist denn dein CS-Signal auf Low.
    Wenn das sooooo Zeitkritisch bei Dir ist, solltest Du Dir mal den Assemblercode ansehen, den der Compiler gemacht hat.
    Im Zweifelsfalle kannst Du mit Assembler noch die eine oder andere Nano/Mikro-sekunde rausholen.
    Kann ich mir kaum vorstellen, dass deine Anwenung dies erfordert.
    Was hast Du denn dran an dem74595 ???

  7. #7
    Erfahrener Benutzer Begeisterter Techniker Avatar von Torrentula
    Registriert seit
    10.10.2009
    Ort
    Procyon A
    Alter
    21
    Beiträge
    355
    Also im Moment sende ich einfach 0xAA (10101010) alle 100ms bei einer clock Frequenz von 8MHz (ein 7,81MHz), an den uC Leitungen hängt bei den Messungen jetzt nichts dran (es funktioniert ja auch mit dem 595). Die CS-Leitung ist 2.52µs low und das Byte wird in 1µs übertragen.
    Besonders zeitkritisch ist es jetzt nicht, allerdings wundert mich es schon ein wenig.
    Die SPI Frequenz ist jetzt gleich der Frequenz der CPU, möglicherweise dauert das setzen des Ausgangsbits für CS einfach ein paar Taktzyklen und bei geringerer SPI Frequenz ist der Effekt dann nicht so gravierend.

    Ich möchte im Endeffekt das Display einer Binäruhr multiplexen (also so um die 24 LEDs).
    MfG Torrentula

  8. #8
    Erfahrener Benutzer Roboter-Spezialist
    Registriert seit
    05.11.2007
    Ort
    Berlin
    Beiträge
    526
    Na da mach Dir mal über die paar Takzyklen keine Sorgen, das ist völlig okay und spielt nicht annähernd eine Rolle bei deiner Anwendung.
    Und richtig, der PIC braucht ja für die Befehle entsprechend Zeit.
    Das würde in Assembler ungefär so aussehen.

    Code:
      movf    data,W        ; Daten ins W Register laden
      bcf     LATC,0        ; Chip Select Low
      movwf   SSPBUF        ; Daten ins Schieberegister
      bcf     PIR1,SSPIF    ; Interrupt Flag löschen
    wait:
      btfss   PIR1,SSPIF    ; scip, wenn SSPIF Bit gesetzt ist
      goto    wait          ; ansonsten weiter warten
      bsf     LATC,0        ; Chip Select wieder High
    Was dein Compiler draus macht weis ich ja nicht. Aber den erzeugten Assembler Code kannst Du Dir sicher auch irgendwie ansehen.
    Dann schaust Du in das Instruction Set von dem PIC und dort sind die Taktzyklen pro Befehl zu finden und kannst, wenns Dich interessiert, exakt ausrechnen wie lange er also braucht für den erzeugten Code.

    Also selbst wenn er 10 Mikro Sekunden brauchen würde um ein Byte rauszuschicken, braucht er für 3 Bytes (24 LEDs) grad mal 30 Mikrosekunden. Du könntest also theoretisch rund 3333 mal pro Sekunde komplett neue Daten zu deinen LEDs schicken. Ich denke da brauchst Du Dir wirklich keinen Kopf drüber machen. Geniess das Wochenende udn programmier einfach weiter

    -------------------------------------------------
    Instruction Set : Seite 270 im Datenblatt. Tabelle TABLE 24-2
    Geändert von Siro (07.09.2012 um 20:34 Uhr)

Ähnliche Themen

  1. PIC18F Entwicklungsboard
    Von Torrentula im Forum Suche bestimmtes Bauteil bzw. Empfehlung
    Antworten: 0
    Letzter Beitrag: 09.08.2012, 17:03
  2. PIC18F 32Mhz für Servomotor PWM 50Hz ?
    Von Alan-Lee Perkins im Forum PIC Controller
    Antworten: 1
    Letzter Beitrag: 31.07.2012, 12:07
  3. PIC18F - SDCC-Problem
    Von galdo im Forum PIC Controller
    Antworten: 0
    Letzter Beitrag: 24.03.2007, 11:50
  4. PIC18F mit PICKit2
    Von NF im Forum PIC Controller
    Antworten: 6
    Letzter Beitrag: 07.06.2006, 22:10
  5. Wo PIC18F mit 3936 Ram bestellen??
    Von Pitt1986 im Forum PIC Controller
    Antworten: 3
    Letzter Beitrag: 05.01.2006, 18:58

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •