[Programmation] Communication SPI
Répondre à la discussion
Affichage des résultats 1 à 19 sur 19

Communication SPI



  1. #1
    Billy 1816

    Communication SPI


    ------

    Bonjour a tous,
    J'essaye de faire communiquer deux PIC16F1828 entre eux grâce à la communication SPI et je rencontre des problèmes.

    Voici le code du master, sur Mblab X avec XC8:
    Code:
    #pragma config FOSC = INTOSC    // Oscillator Selection (INTOSC oscillator: I/O function on CLKIN pin)
    #pragma config WDTE = OFF       // Watchdog Timer Enable (WDT disabled)
    #pragma config PWRTE = OFF      // Power-up Timer Enable (PWRT disabled)
    #pragma config MCLRE = ON       // MCLR Pin Function Select (MCLR/VPP pin function is MCLR)
    #pragma config CP = OFF         // Flash Program Memory Code Protection (Program memory code protection is disabled)
    #pragma config CPD = OFF        // Data Memory Code Protection (Data memory code protection is disabled)
    #pragma config BOREN = OFF      // Brown-out Reset Enable (Brown-out Reset disabled)
    #pragma config CLKOUTEN = OFF   // Clock Out Enable (CLKOUT function is disabled. I/O or oscillator function on the CLKOUT pin)
    #pragma config IESO = OFF       // Internal/External Switchover (Internal/External Switchover mode is disabled)
    #pragma config FCMEN = OFF      // Fail-Safe Clock Monitor Enable (Fail-Safe Clock Monitor is disabled)
    
    // CONFIG2
    #pragma config WRT = OFF        // Flash Memory Self-Write Protection (Write protection off)
    #pragma config PLLEN = OFF      // PLL Enable (4x PLL disabled)
    #pragma config STVREN = ON      // Stack Overflow/Underflow Reset Enable (Stack Overflow or Underflow will cause a Reset)
    #pragma config BORV = LO        // Brown-out Reset Voltage Selection (Brown-out Reset Voltage (Vbor), low trip point selected.)
    #pragma config LVP = OFF        // Low-Voltage Programming Enable (High-voltage on MCLR/VPP must be used for programming)
    
    #include <stdio.h>
    #include <stdlib.h>
    #include "fonctions.h"
    #define _XTAL_FREQ 16000000
    
    
    int main(int argc, char** argv) {
        OSCCONbits.IRCF0 = 1;
        OSCCONbits.IRCF1 = 1;
        OSCCONbits.IRCF2 = 1;
        OSCCONbits.IRCF3 = 1;
        SPI_init();
        TRISAbits.TRISA5 = 0;
        while (1){
            __delay_ms(2000);
            SPI_write(101);
        }
        return (EXIT_SUCCESS);
    }
    
    //////////////////////////////// Et voici les fonctions :
    
    #include <xc.h>
    #include "fonctions.h"
    #define _XTAL_FREQ 16000000
    
    void SPI_init(){
        SSP1CON1bits.SSPM = 1; // selectionne le mode spi master avec fosc/16
        SSP1CON1bits.CKP = 0; // définit l'état inactif de l'horloge a 0
        SSP1STATbits.CKE = 0; // les données seront transmises au passage de l'horloge de l'état bas àl'état haut
        SSP1STATbits.SMP = 0; // les données sont échantillonnées (à la réception) à la moitié du temps de l'émission
        TRISCbits.TRISC6 = 0; // gère les I/O
        TRISCbits.TRISC7 = 0; 
        TRISBbits.TRISB6 = 0; 
        TRISBbits.TRISB4 = 1; 
        SSP1CON1bits.SSPEN = 1;
        RC6 = 1; // met la pin ss à l'état haut désactive la communication
    }
    
    void SPI_write(unsigned char data){
        RC6 = 1; // lance la communication
        SSP1BUF = data;
        while(!PIR1bits.SSP1IF){
            RA5 = 1; // led d'indication : elle clignote quand l'envoi a lieu
        }
        PIR1bits.SSP1IF = 0;
        RA5 = 0; 
        RC6 = 1; // finit la communication*/
        
    }
    Et le code du slave :
    Code:
    #pragma config FOSC = INTOSC    // Oscillator Selection (INTOSC oscillator: I/O function on CLKIN pin)
    #pragma config WDTE = OFF       // Watchdog Timer Enable (WDT disabled)
    #pragma config PWRTE = OFF      // Power-up Timer Enable (PWRT disabled)
    #pragma config MCLRE = ON       // MCLR Pin Function Select (MCLR/VPP pin function is MCLR)
    #pragma config CP = OFF         // Flash Program Memory Code Protection (Program memory code protection is disabled)
    #pragma config CPD = OFF        // Data Memory Code Protection (Data memory code protection is disabled)
    #pragma config BOREN = OFF      // Brown-out Reset Enable (Brown-out Reset disabled)
    #pragma config CLKOUTEN = OFF   // Clock Out Enable (CLKOUT function is disabled. I/O or oscillator function on the CLKOUT pin)
    #pragma config IESO = OFF       // Internal/External Switchover (Internal/External Switchover mode is disabled)
    #pragma config FCMEN = OFF      // Fail-Safe Clock Monitor Enable (Fail-Safe Clock Monitor is disabled)
    
    // CONFIG2
    #pragma config WRT = OFF        // Flash Memory Self-Write Protection (Write protection off)
    #pragma config PLLEN = OFF      // PLL Enable (4x PLL disabled)
    #pragma config STVREN = ON      // Stack Overflow/Underflow Reset Enable (Stack Overflow or Underflow will cause a Reset)
    #pragma config BORV = LO        // Brown-out Reset Voltage Selection (Brown-out Reset Voltage (Vbor), low trip point selected.)
    #pragma config LVP = OFF        // Low-Voltage Programming Enable (High-voltage on MCLR/VPP must be used for programming)
    
    #include <stdio.h>
    #include <stdlib.h>
    #include "fonctions.h"
    #define _XTAL_FREQ 16000000
    
    
    unsigned char data = 0;
    
    void main(void) {
        OSCCONbits.IRCF0 = 1;
        OSCCONbits.IRCF1 = 1;
        OSCCONbits.IRCF2 = 1;
        OSCCONbits.IRCF3 = 1;
        TRISBbits.TRISB7 = 0;
        SPI_init_slave(); // initialise le mssp1
        RB7 = 1;
        while (1){
            if (SPI_isready()){
                /*if(SPI_read() == 0){
                    RB7 = 1;
                }
                else{
                    RB7 = 0;
                }*/
                //RB7 = 1;
                data = SPI_read();
                SPI_write_slave(127);
                SPI_init_slave();
            }
            if (data != 0){
                RB7 = 1;
            }
            else if (data == 0){
                RB7 = 0;
            }
            
        }
        return;
    }
    /////////////////////////////et les fonctions :
    
    #include <xc.h>
    #include "fonctions.h"
    
    void SPI_init_slave(){
        SSP1CON1bits.SSPM = 0b0100; // selectionne le mode spi avec contôle par ss
        SSP1CON1bits.CKP = 0; // définit l'état inactif de l'horloge a 0
        SSP1STATbits.CKE = 0; // les données seront transmises au passage de l'horloge de l'état bas àl'état haut
        SSP1STATbits.SMP = 0; // les données sont échantillonnées (à la réception) à la moitié du temps de l'émission
        TRISCbits.TRISC6 = 1; // met la pin ss en entée
        TRISCbits.TRISC7 = 0; // met la pin SDO en sortie (serial data output pour ce module connecté à sdi du master)
        TRISBbits.TRISB6 = 1; // met la pin SCK en entrée
        TRISBbits.TRISB4 = 1; // met la pin SDI en entrée
        SSP1CON1bits.SSPEN = 1; // active la communication le module mssp
    }
    
    void SPI_write_slave(int data){
        SSP1BUF = data;
    }
    
    unsigned char SPI_read(void){
        unsigned char dat = SSP1BUF;
        return(dat);
    }
    
    unsigned SPI_isready(void){
        if(PIR1bits.SSP1IF){
            PIR1bits.SSP1IF = 0;
            return 1;
        }
        else{
            return 0;
        }
    }
    Donc avec ça j'ai une communication qui se lance bien toutes les deux secondes (une led sur SCK me le prouve), et qui s'exécute aussi sur la pin SDO du master, mais seulement quand la valeur rentrée dans SPI_write() est ronde. Par exemple, avec SPI_write(50), je vois que la communication sur SDO se fait bien en même temps que SCK, mais avec SPI_write(51) la pin SDO se met à un état plus ou moins haut, indéfiniment.

    De plus, le slave ne reçoit jamais autre chose que 0, alors que celui ci est synchronisé. (SSP1IF, le flag qui indique que les 8 bits ont bien été transmis, se met bien à 1 toute les deux secondes).

    Je ne sais donc pas ce qui échoue dans les fonctions de lecture et d'écriture et c'est pourquoi je sollicite votre aide.
    Merci d'avance

    -----

  2. #2
    invite03481543

    Re : Communication SPI

    Bonjour,

    as-tu mis un pull-up sur MISO (ton SDI)?
    Il est possible que tu en aies besoin également sur ton SDO (voir ta datasheet), tu peux mettre une 10K.
    Dernière modification par HULK28 ; 01/03/2020 à 13h24.

  3. #3
    Billy 1816

    Re : Communication SPI

    Merci de votre réponse
    Non, n'en avais pas placé. Correction faite, avec ou sans, le résultat reste le même

  4. #4
    sandrecarpe

    Re : Communication SPI

    Salut,
    Pas besoin de pull-up, ça devrait marcher sans
    Dans le code de l'esclave, ta fonction SPI_init_slave() ne devrait pas être appelé qu'un seule fois
    Dans l'initialisation de tes périphériques, tu devrais toujours effacer les flag correspondants avant d'activer ton péripérique

  5. A voir en vidéo sur Futura
  6. #5
    Billy 1816

    Re : Communication SPI

    Le SPI_init() dans la boucle est un oubli après un test, merci de l'avoir fait remarquer.
    J'ai modifié le code comme vous me l'avez conseillé mais ça ne résout malheureusement pas les problèmes.

  7. #6
    sandrecarpe

    Re : Communication SPI

    Je suppose que tu n'as pas d'oscillo pour voir si les données sortent bien. Pour t'aider à débugger, envoi une valeur fixe, et allume ta led seulement si tu reçois cette valeur.
    Essai de poller le bit SSP1STAT.BF à la place du flag d'interruption. Il passe à 1 lorsqu'une donnée a été reçue

    PS : Je viens de voir que microchip dit qu'une pull-up est peut-être nécessaire sur SS, suivant l'application

  8. #7
    Billy 1816

    Re : Communication SPI

    Non en effet, je n'ai pas d'oscillo mais j'avais déjà essayé d'envoyer une valeur fixe. Par contre, il ne me semble pas avoir utilisé le flag BF sur les deux pics en même temps. Je vais essayer ça

  9. #8
    Billy 1816

    Re : Communication SPI

    Bon j'ai testé de changer le flag, et je garde le même résultat. Cependant je remarque que la ligne SDO (ou MOSI) reste a son état haut uniquement quand le valeur rentrée dans SPI_init() est impaire. Cela veut dire que le programme s’exécute normalement (SCK fonctionne toute les deux sec), mais que la ligne SDO grade l'état du dernier bit transmis, lors de la première transmission. Ça me parait étrange mais je ne vois pas d'autre explication. Ce serait donc le module MSSP qui dysfonctionne ? Je ne pense pas que ce soit ce dernier car la pin RC6, qui est pilotée comme une I/O dans le programme est au même état que SDO. La fonction SPI_write() alors ? Je vous avoue que j'ai un peu de mal à comprendre.
    J'espère que vous aurez une idée

  10. #9
    sandrecarpe

    Re : Communication SPI

    Je viens de voir que tu n'effectues pas de lecture du registre sur ton maître. Ça peut expliquer ton problème.
    La lecture et l'écriture se fait en même temps sur le spi. Cependant, si la lecture n'est pas faite, le uc peut avoir un mécanisme de collision/erreur qui peut bloquer l'accès au registre. A voir ce que dit la doc

    Donc avec ton maître, tu vas écrire un octet, ce qui va permettre à l'esclave d'envoyer (simultanément) un octet, puis à la suite tu vas lire la réponse de l'esclave. Et c'est reparti pour un tour si nécessaire

  11. #10
    umfred

    Re : Communication SPI

    il y a une Errata Note sur ce pic concernant le MSSP en master (page 11) http://ww1.microchip.com/downloads/e.../80000510K.pdf
    Je ne suis pas sûr que ça rentre dans ton cas, mais on ne sait jamais.
    Il peut y avoir un détection de collision (WCOL=1) si le programme réagit trop rapidement.

  12. #11
    Billy 1816

    Re : Communication SPI

    Merci de ta réponse umfred, j'ai changé la valeur de CKE et la ligne SDO envoie bien les données a présent (testé avec une LED...). Le seul problème restant est que le slave reçoit toujours 0, mais je n'ai pas encore creusé sur ce sujet.

  13. #12
    Billy 1816

    Re : Communication SPI

    Je n'ai pas réussi a résoudre le problème du côté du slave (décidément...).
    Je sais que le problème vient de lui et non pas du master car, quand je connecte la pin SDI (MOSI) au 5v, la lecture du Buffer renvoie 0 et non pas le 255 attendu. Je sais aussi que cette lecture a bien lieu, toute les deux secondes, comme imposé par le master (LED sur RB7).
    Donc si tout fonctionne, je ne vois pas pourquoi le SSP1BUF est égal à 0...

    Je vous joint a nouveau le code du slave, car j'y ai apporté quelques modifications :

    Code:
    #pragma config FOSC = INTOSC    // Oscillator Selection (INTOSC oscillator: I/O function on CLKIN pin)
    #pragma config WDTE = OFF       // Watchdog Timer Enable (WDT disabled)
    #pragma config PWRTE = OFF      // Power-up Timer Enable (PWRT disabled)
    #pragma config MCLRE = ON       // MCLR Pin Function Select (MCLR/VPP pin function is MCLR)
    #pragma config CP = OFF         // Flash Program Memory Code Protection (Program memory code protection is disabled)
    #pragma config CPD = OFF        // Data Memory Code Protection (Data memory code protection is disabled)
    #pragma config BOREN = OFF      // Brown-out Reset Enable (Brown-out Reset disabled)
    #pragma config CLKOUTEN = OFF   // Clock Out Enable (CLKOUT function is disabled. I/O or oscillator function on the CLKOUT pin)
    #pragma config IESO = OFF       // Internal/External Switchover (Internal/External Switchover mode is disabled)
    #pragma config FCMEN = OFF      // Fail-Safe Clock Monitor Enable (Fail-Safe Clock Monitor is disabled)
    
    // CONFIG2
    #pragma config WRT = OFF        // Flash Memory Self-Write Protection (Write protection off)
    #pragma config PLLEN = OFF      // PLL Enable (4x PLL disabled)
    #pragma config STVREN = ON      // Stack Overflow/Underflow Reset Enable (Stack Overflow or Underflow will cause a Reset)
    #pragma config BORV = LO        // Brown-out Reset Voltage Selection (Brown-out Reset Voltage (Vbor), low trip point selected.)
    #pragma config LVP = OFF        // Low-Voltage Programming Enable (High-voltage on MCLR/VPP must be used for programming)
    
    #include <pic16f1828.h>
    #include "fonctions.h"
    #define _XTAL_FREQ 16000000
    
    
    unsigned char donees = 100;
    
    void main(void) {
    
        OSCCONbits.IRCF = 15;
        TRISBbits.TRISB7 = 0;
        SPI_init_slave();            // initialise le mssp1
        RB7 = 1;
        while (1){
    
            if (SPI_isready()){
                RB7 = 1;             // LED test
                donees = SPI_read();
                SPI_write_slave(120);
                RB7 = 0;
            }
            if (donees != 0){ 
                RB7 = 1;
            }
            else {
                RB7 = 0;
            }
            
        }
        return;
    }
    
    
    
    Et voici les fonctions :
    
    
    #include <xc.h>
    #include <pic16f1828.h>
    #include "fonctions.h"
    #define _XTAL_FREQ 16000000
    
    void SPI_init_slave(){
        SSP1CON1bits.SSPM = 4; // selectionne le mode spi avec contôle par ss
        SSP1CON1bits.CKP = 0; // définit l'état inactif de l'horloge a 0
        SSP1STATbits.CKE = 1; // les données seront transsmises au passage de l'horloge de l'état bas à l'état haut (inverse si =1)
        SSP1STATbits.SMP = 0; // les données sont échantillonnées (à la réception) à la moitié du temps de l'émission
        TRISCbits.TRISC6 = 1; // met la pin ss en entée
        TRISCbits.TRISC7 = 0; // met la pin SDO en sortie (serial data output pour ce module connecté à sdi du master)
        TRISBbits.TRISB6 = 1; // met la pin SCK en entrée
        TRISBbits.TRISB4 = 1; // met la pin SDI en entrée
        SSP1STATbits.BF = 0;
        SSP1CON1bits.SSPEN = 1; // active la communication le module mssp
    }
    
    void SPI_write_slave(unsigned char data){
        SSP1BUF = data;
    }
    
    unsigned char SPI_read(void){
        while(!SSP1STATbits.BF);
        unsigned char dat = SSP1BUF;
        return(dat);
    }
    
    _Bool SPI_isready(void){
        if(SSP1STATbits.BF){
            return 1;
        }
        else{
            return 0;
        }
    }
    J'espère que quelqu'un pourra m'aider.
    Bonne soirée

  14. #13
    umfred

    Re : Communication SPI

    le problème doit venir de ton maitre, il faut que /SS soit à 0 sur l'esclave pour que la réception soit valide (donc RC6=0 au début du SPI_Write())

  15. #14
    Billy 1816

    Re : Communication SPI

    Merci de votre réponse, mais je ne pense pas que ce soit cela. Le master met en effet la pin SS à 0 avant la communication, le code proposé en début de topic comportant une erreur. C'était donc tout à fait pertinent de votre part de me le faire remarquer

  16. #15
    Billy 1816

    Re : Communication SPI

    Je pense que le problème vient de la pin SDI du slave. J'ai lu ce sujet sur le forum Microchip, mais c'est en anglais et la personne utilise MPLAB Harmony (je ne sais pas vraiment ce que c'est). En tout cas j'ai pu lire dans les derniers messages que le problème, qui est similaire au mien, venait de la pin SDI...
    Dernière modification par Billy 1816 ; 11/03/2020 à 18h45.

  17. #16
    umfred

    Re : Communication SPI

    remplace donc le PIC par un autre pour vérifier

  18. #17
    Billy 1816

    Re : Communication SPI

    J'ai essayé mais je n'obtiens pas de résultat, je vais continuer de faire des recherches.

  19. #18
    Billy 1816

    Re : Communication SPI

    Je n'arrive toujours pas à résoudre le problème de lecture, que ce soit sur le slave ou sur le maître. Je sais que le problème vient de l'acquisition de la donnée dans le SSP1BUF, mais je n'ai pas réussi à trouver pourquoi.
    J’espère que quelqu'un a déjà eu une la même expérience que moi et saura me guider.

    Le sujet est assez complexe. Je comprendrai naturellement qu'il reste irrésolu.
    En tout cas, merci à tous pour vos réponses, qui ont déjà permis de corriger pas mal de choses.

  20. #19
    Billy 1816

    Re : Communication SPI

    Ça y est !!!!
    J'ai enfin trouvé le problème et je tiens à partager la solution pour les personnes qui en auraient besoin.

    Le problème venait bien de la pin SDI : C'est une pin analogique (AN10) et est configurée ainsi par défaut.
    Comme le dit la datasheet, la lecture en digital de la broche étatait donc impossible.

    La solution est donc de configurer la pin SDI en digital et tout fonctionne. (ANSELB = 0)

    C'est ce site qui m'a permis de trouver la source du problème.
    Vous m'aviez permis de résoudre les précédents. Merci encore

Discussions similaires

  1. Bus de communication
    Par steyf65 dans le forum Électronique
    Réponses: 11
    Dernier message: 15/05/2014, 15h19
  2. Power Line communication sur une ligne DC. Communication CAN
    Par invitee2723b34 dans le forum Électronique
    Réponses: 3
    Dernier message: 21/02/2012, 11h28
  3. BTS Communication
    Par invite83f4eae0 dans le forum Orientation après le BAC
    Réponses: 1
    Dernier message: 14/06/2010, 13h29
  4. ADN - et communication
    Par Uersaúra dans le forum Biologie
    Réponses: 12
    Dernier message: 31/07/2007, 10h34
  5. communication
    Par invite7f5e7850 dans le forum Technologies
    Réponses: 2
    Dernier message: 09/07/2006, 13h40
Découvrez nos comparatifs produits sur l'informatique et les technologies.