Partage
  • Partager sur Facebook
  • Partager sur Twitter

PIC et I2C

    31 octobre 2012 à 11:55:35

    Bonjour,

    Je travaille sur la communication I2C entre un mini-ordinateur (Raspberry-Pi) et un PIC16F887.

    Pour l'instant le RaspberryPi ne me sert qu'à envoyer les ordres i2c.
    Et le PIC commande une matrice à Led.

    Le Programme du PIC est décomposé de la manière suivante:
    -programme principal qui ne sert qu'à l'initialisation (après il n'est plus utilisé).
    -interruption timer qui gère l'affichage de la matrice à Led.
    -interruption i2c

    Mon soucis vient du fait que quand j'essaie d'envoyer un message au PIC (10 octets), il n'arrive pas entiérement et la quantité octets reçus est aléatoire.
    Je pense savoir d'où viens mon soucis: les actions effectuées durant l'interruption timer sont trop longues. Le pic est en train de recevoir des données, soudain interruption timer, il effectue les instructions, mais pendant ce temps le prochain octet est prèt à être envoyer, mais le registre est déjà plein. de ce fait le RaspberryPi coupe la communication.

    Je cherche des solutions pour résoudre mon soucis et actuellement j'en vois deux:

    La première est d'utiliser un quartz de 20Mhz (actuellemnt j'utilise l'horloge interne 8MHz). De cette manière je puis espérer que l'ensemble des instructions se ferra plus rapidement. Le soucis est que j'utilise avec mon timer la période la plus grande que je puis avec ma fréquence d'horloge. Ce qui entraine le fait que ma fréquence d'interruption sera doublé et j'ai peur que finalement je me retrouve au point de départ.

    La seconde est de passer le mécanisme d'affichage dans le programme principal. Ici le problème sera résolu facilement, mais mon soucis vient de ce que je prévois de faire dans mon projet: remplacer l'affichage par un système d'asservissement pour moteur. Je préférerais que mon programme reste dans l'interruption pour être sûr que la mise à jour de la vitesse du moteur se fasse à intervalles réguliers.

    Il ne doit pas y avoir trente-six milles solutions. Mais n'ayant pas un niveau fort avancé en électronique et micro-controleur, je sollicite vos avis sur à la fois la nature de mon problème et les solutions possibles.

    merci

    • Partager sur Facebook
    • Partager sur Twitter
      31 octobre 2012 à 14:59:35

      Salut,
      est-ce que tu peux nous dire si tu utilises le MSSP(page 191 de la doc) présent dans ton PIC ou bien si tu utilise une communication I2C software (que tu aurais fait à la main) ?

      Pourrais-t-on également avoir un schéma de ce que tu as fais ? As-tu bien mis les résistances de pull-up sur SCL et SDA?

      Je pense que dans un premier temps tu devrais essayer de recevoir des trames dans ta boucle principale et voir si les trames envoyées par le Raspberry corresponde bien aux trames reçues dans le PIC (si t'as un débugger, ça serait le top).

      Après, si on suit ce que dit la doc, si ton PIC est en "Slave Mode", quand il reçois de la data, le bit d'"acknowledge" est automatiquement généré et le buffer se remplit avec la data reçue (registre "SSPBUF"). Tu as également un "Interrupt Flag"(SSPIF) qui se met à 1 lorsque ce buffer est rempli et qui va te générer une interruption, ce qui pourrait être utile (plutôt que d'utiliser les timers).

      Serait-il possible de voir ton code également ? (Surtout pour voir les bits de configurations).

      Pour ma part, je ne pense pas que ça soit utile d'ajouter un quartz.
      • Partager sur Facebook
      • Partager sur Twitter
        31 octobre 2012 à 18:12:13

        J'utilise bien le MSSP et quand je parle d'interruption i2c, il s'agit de l'interruption généré par le SSPIF. l'interruption timer ne me sert que pour changer l'affichage de ma matrice à led (chenillard qui change la colonne considéré + octet en ligne + persistance rétinienne = image)

        j'ai des résistances de pull-up: elles sont incluse dans un composant qui fait le lien entre le Raspberry et le pic. Le raspberry travaille en 3v3 et mon pic en 5v. Le composant en question est un Logic Level Converter de sparkfun et le schéma montre des résistances de 10k.

        Pour la nature des trames, je n'ai pas de doute dessus: Elles sont affichées sur la matrice à led et correspondent bien à ce que j'ai envoyé. La seule chose qui cloche est que je n'obtiens pas toutes les trames.

        Sinon, je me suis procuré un oscillo et j'ai vérifié mes trames. J'ai remarqué que je n'ai pas la totalité de mes trames. Par contre si je supprime l'interruption timer, tout mon message est visible sur l'oscillo (mais je n'ai plus l'affichage sur la matrice à led).

        Je n'ai pas pensé à utiliser le débugger, je verrais cela. Ce qui m'embéte est que si le raspberry attend trop longtemps et decide de stopper la communication (je ne me souviens pas d'argument de timeout sur le code du Raspberry), au final je n'aurais qu'un octet de ma trame. Mais cela reste un comportement à vérifié.

        Pour le code, je ne l'ai pas sous la main mais je le posterais. je peux dire que pour la partie I2C c'est un copier/coller du code que l'on retrouve sur le cour de bigonoff (mis à part la syntaxe de l'assembleur qui différe quelques peu).


        Edit:

        Voici le programme en entier, diviser en plusieurs parties pour qu'il soit plus digeste.

        l'en-tête:

        list p=16f887 ; list directive to define processor
        #include <p16f887.inc> ; processor specific variable definitions


        ; '__CONFIG' directive is used to embed configuration data within .asm file.
        ; The labels following the directive are located in the respective .inc file.
        ; See respective data sheet for additional information on configuration word.

        __CONFIG _CONFIG1, _LVP_OFF & _FCMEN_ON & _IESO_OFF & _BOR_OFF & _CPD_OFF & _CP_OFF & _MCLRE_ON & _PWRTE_ON & _WDT_OFF & _INTRC_OSC_NOCLKOUT
        __CONFIG _CONFIG2, _WRT_OFF & _BOR21V



        ;***** VARIABLE DEFINITIONS
        w_temp EQU 0x7D ; variable used for context saving
        status_temp EQU 0x7E ; variable used for context saving
        pclath_temp EQU 0x7F ; variable used for context saving

        p_chenillard EQU 0x20
        p_sequence EQU 0x21
        compteur_seq EQU 0x22
        sequence_actuelle EQU 0x23
        it_seq EQU 0x24
        it_seq2 EQU 0x25
        num_seq EQU 0x26

        p_sequence_i2c EQU 0x29

        bufin EQU 0x40
        bufout EQU 0x40
        ptrin EQU 0x2A
        ptrout EQU 0x2B
        flagi2c EQU 0x2C
        flagout EQU 0
        flaggen EQU 1

        ssptemp EQU 0x2E

        ;MS_PROG_EE_ADDR EQU 0x27
        ;LS_PROG_EE_ADDR EQU 0x28
        ;LOWPMBYTE EQU 0x29
        ;HIGHPMBYTE EQU 0x2A


        Le systeme de gestion des interruptions

        ORG 0x000 ; processor reset vector

        nop
        goto main ; go to beginning of program


        ORG 0x004 ; interrupt vector location

        movwf w_temp ; save off current W register contents
        movf STATUS,w ; move status register into W register
        movwf status_temp ; save off contents of STATUS register
        movf PCLATH,w ; move pclath register into w register
        movwf pclath_temp ; save off contents of PCLATH register

        ; isr code can go here or be located as a call subroutine elsewhere

        CLRWDT

        BTFSC PIR1,SSPIF
        call i2c
        BTFSC INTCON,T0IF
        call timer0


        ; BCF INTCON,T0IF
        ; BCF PIR1,SSPIF
        ;-------------------------------

        movf pclath_temp,w ; ret-(rieve copy of PCLATH register
        movwf PCLATH ; restore pre-isr PCLATH register contents
        movf status_temp,w ; retrieve copy of STATUS register
        movwf STATUS ; restore pre-isr STATUS register contents
        swapf w_temp,f
        swapf w_temp,w ; restore pre-isr W register contents
        retfie ; return from interrupt



        interruption timer

        ; timer0 interruption
        timer0
        ;eteindre les leds
        BANKSEL PORTD
        CLRF PORTD

        ;changer de colonne
        BANKSEL 0
        MOVFW p_chenillard ; pointer
        MOVWF FSR
        MOVFW INDF ; w = *pointer

        BANKSEL PORTA
        MOVWF PORTA

        ;changer les led allum�es
        MOVFW p_sequence ; pointer
        MOVWF FSR
        MOVFW INDF

        ;gerer le cas particulier de la derni�re colonne
        MOVWF sequence_actuelle
        MOVFW compteur_seq
        XORLW 0x01
        BTFSC STATUS,Z
        CALL colonne9

        BANKSEL PORTD
        MOVFW sequence_actuelle
        MOVWF PORTD

        INCF p_chenillard ; pointer++
        INCF p_sequence

        ;if(--compteur_seq !=0)return
        DECFSZ compteur_seq
        RETURN
        ;else initialise pointeur
        CALL initialise_pointeur


        MOVFW num_seq
        XORLW 0x02
        BTFSC STATUS,Z
        CALL choix_sequence1

        MOVFW num_seq
        XORLW 0x01
        BTFSC STATUS,Z
        CALL choix_sequence2

        DECFSZ it_seq
        RETURN

        DECFSZ it_seq2
        RETURN

        MOVLW 0x10
        MOVWF it_seq2

        DECFSZ num_seq
        RETURN

        MOVLW 0x02
        MOVWF num_seq

        RETURN

        colonne9
        BCF sequence_actuelle, 6
        RETURN

        initialise_pointeur
        BANKSEL 0
        MOVLW 0x30
        MOVWF p_chenillard
        MOVLW 0x09
        MOVWF compteur_seq
        RETURN

        choix_sequence1
        MOVLW 0x40
        MOVWF p_sequence
        RETURN

        choix_sequence2
        MOVLW 0x40 ;0x50 //-------------- test avec une seule s�quence
        MOVWF p_sequence
        RETURN


        interruption i2C

        ;*****************************************************************************
        ;-----------------------------------------------------------------------------
        ; Gestion de l�interruption en mode esclave.
        ; cas 1 : r�ception de l�adresse en mode �criture
        ; cas 2 : r�ception d�une donn�e
        ; cas 3 : r�ception de l�adresse en mode lecture
        ; cas 4 : envoi d�une donn�e en mode lecture
        ; cas 5 : r�ception du NOACK de fin de lecture
        ; erreur : tout autre cas est incorrect, on provoque le reset du PIC par
        ; d�bordement du watchdog (� vous de traiter de fa�on appropri�e)
        ;-----------------------------------------------------------------------------

        ; conserver les bits utiles
        ; --------------------------
        BANKSEL SSPSTAT ; passer en banque 1
        movf SSPSTAT,w ; charger valeur SSPSTAT
        andlw B'00101101' ; garder D_A, S, R_W, et BF
        bcf STATUS,RP0 ; repasser en banque 0
        movwf ssptemp ; sauvegarder dans variable temporaire

        ; cas 1 : r�ception adresse �criture
        ; ----------------------------------
        xorlw B'00001001' ; buffer plein, contient une adresse
        btfss STATUS,Z ; condition r�alis�e ?
        goto intssp2 ; non, examiner cas 2

        movlw bufin ; charger adresse du buffer de r�ception
        movwf ptrin ; le prochain octet sera le premier du buffer in
        bcf flagi2c,flaggen ; par d�faut, pas une commande g�n�rale
        movf SSPBUF,w ; efface BF, teste l�adresse
        btfsc STATUS,Z ; adresse g�n�rale re�ue ?
        bsf flagi2c,flaggen ; oui, positionner le flag
        return ; fin du traitement


        ; cas 2 : r�ception d�une donn�e
        ; -------------------------------
        intssp2

        movf ssptemp,w ; charger bits utiles de SSPSTAT
        xorlw B'00101001' ; buffer plein, contient une donn�e
        andlw B'11110111' ; �liminer le bit S (stop-condition d�j� re�u)
        btfss STATUS,Z ; condition r�alis�e ?
        goto intssp3 ; non, examiner cas 3
        movf ptrin,w ; charger pointeur d�entr�e
        movwf FSR ; dans pointeur d�adresse
        movf SSPBUF,w ; charger donn�e re�ue
        movwf INDF ; la placer dans le buffer d�entr�e
        incf ptrin,f ; incr�menter le pointeur d�entr�e
        return ; fin du traitement

        ; cas 3 : �mission de la premi�re donn�e
        ; ---------------------------------------
        intssp3

        movf ssptemp,w ; charger bits utiles de SSPSTAT
        xorlw B'00001100' ; demande d�envoi, on vient de recevoir l�adresse
        btfss STATUS,Z ; condition r�alis�e ?
        goto intssp4 ; non, examiner cas 4

        movlw bufout+1 ; charger adresse du buffer d��mission + 1
        movwf ptrout ; le prochain octet sera le second du buffer out
        movf bufout,w ; charger le premier octet du buffer d��mission
        movwf SSPBUF ; dans le buffer I2C
        bsf SSPCON,CKP ; met fin � la pause, permet le transfert
        return ; fin du traitement

        ; cas 4 : �mission d�une donn�e quelconque
        ; ----------------------------------------
        intssp4
        movf ssptemp,w ; charger bits utiles de SSPSTAT
        xorlw B'00101100' ; demande d�envoi qui suit un autre envoi
        btfss STATUS,Z ; condition r�alis�e ?
        goto intssp5 ; non, examiner cas 5

        movf ptrout,w ; charger pointeur buffer de sortie
        movwf FSR ; dans pointeur d�adresse
        movf INDF,w ; charger octet � envoyer
        movwf SSPBUF ; le mettre dans le buffer de sortie
        bsf SSPCON,CKP ; lib�re l�horloge, permet le transfert
        incf ptrout,f ; incr�menter pointeur de sortie
        return ; fin du traitement

        ; cas 5 : r�ception du NOACK
        ; ---------------------------
        intssp5


        movf ssptemp,w ; charger bits utiles de SSPSTAT
        xorlw B'00101000' ; NOCAK re�u
        ; btfss STATUS,Z ; condition r�alis�e ?
        ; goto $ ; non, reset PIC par d�bordement watchdog
        bsf flagi2c,flagout ; signaler fin de lecture
        return ; et retour


        programme principal (initialisation matrice led)

        main
        ;initialisation des port
        BANKSEL PORTA
        CLRF PORTA

        BANKSEL ANSEL
        CLRF ANSEL

        BANKSEL TRISA
        CLRF TRISA

        BANKSEL PORTA
        MOVLW 0xFF
        MOVWF PORTA

        BANKSEL TRISD
        MOVLW 0x00
        MOVWF TRISD

        BANKSEL PORTD
        MOVLW 0xFF
        MOVWF PORTD


        CALL initialise_sequence
        CALL initialise_pointeur
        CALL choix_sequence1

        MOVLW 0x10
        MOVWF it_seq2
        MOVLW 0x02
        MOVWF num_seq


        programme principal (initialisation i2c)

        ;------------------------------
        ; configure i2c
        BANKSEL SSPADD ; passer en banque 1
        movlw 0x30 ; charger valeur adresse (bits 7 � 1)
        movwf SSPADD ; dans registre d�adresse
        clrf SSPSTAT ; slew rate ON, compatible I2C
        movlw B'10000000' ; appel g�n�ral en service (facultatif)
        movwf SSPCON2 ; dans registre SSPCON2
        bcf STATUS,RP0 ; repasser banque 0
        movlw B'00110110' ; MSSP en service, mode I2C 7 esclave 7 bits, SCL OK
        movwf SSPCON ; dans registre de contr�le


        programme principal (initialisation timer0)

        ;------------------------------
        ; configuration of timer0 interuption
        BANKSEL TMR0
        CLRF TMR0
        CLRWDT

        ;timer0 interanl clock, prescale 1/256
        BANKSEL OPTION_REG
        MOVLW b'10000111'
        MOVWF OPTION_REG

        ;valeur
        BANKSEL INTCON
        MOVLW b'11100000'
        MOVWF INTCON

        endmain
        goto endmain


        fonctions pour l'initalisation de la matrice.

        initialise_sequence
        ;sequence pour portA
        MOVLW b'01111111'
        MOVWF 0x30
        MOVLW b'10111111'
        MOVWF 0x31
        MOVLW b'11011111'
        MOVWF 0x32
        MOVLW b'11101111'
        MOVWF 0x33
        MOVLW b'11110111'
        MOVWF 0x34
        MOVLW b'11111011'
        MOVWF 0x35
        MOVLW b'11111101'
        MOVWF 0x36
        MOVLW b'11111110'
        MOVWF 0x37
        MOVLW b'11111111'
        MOVWF 0x38

        ;sequence pour portD (1)
        MOVLW b'11100001'
        MOVWF 0x40
        MOVLW b'11100001'
        MOVWF 0x41
        MOVLW b'11100001'
        MOVWF 0x42
        MOVLW b'11100001'
        MOVWF 0x43
        MOVLW b'11100001'
        MOVWF 0x44
        MOVLW b'11100001'
        MOVWF 0x45
        MOVLW b'11100001'
        MOVWF 0x46
        MOVLW b'11100001'
        MOVWF 0x47
        MOVLW b'11100001'
        MOVWF 0x48

        ;sequence pour portD (2)
        MOVLW b'11100101'
        MOVWF 0x50
        MOVLW b'11101100'
        MOVWF 0x51
        MOVLW b'11111010'
        MOVWF 0x52
        MOVLW b'11100001'
        MOVWF 0x53
        MOVLW b'11110010'
        MOVWF 0x54
        MOVLW b'11100110'
        MOVWF 0x55
        MOVLW b'11110011'
        MOVWF 0x56
        MOVLW b'11101111'
        MOVWF 0x57
        MOVLW b'11100001'
        MOVWF 0x58

        RETURN

        END

        • Partager sur Facebook
        • Partager sur Twitter
          5 novembre 2012 à 14:59:38

          Si tu n'as pas de fast interrupt sur 16F, la meilleur solution est de lever un flag sur ton IT timer et de faire du pooling dessus dans ta tache de fond pour faire toute ta gestion de la matrice en tache de fond. Ca veut dire que le reste de ta tâche de fond ne doit pas garder la main trop longtemps (plus tu fais de choses en tâches de fond, plus ca fera de latence sur la mise à jour de la matrice). Par contre, quand tu ajouteras ton moteur, tu pourras changer la consigne directement dans l'IT.

          Après, si tu veux un truc plus complexe, il faudra songer à prendre un micro avec une archi un peut plus riche (un 18F par exemple), parce que sans solution matérielle et seulement 128 octets de RAM, on ne peut pas faire des miracles.
          • Partager sur Facebook
          • Partager sur Twitter
          64kB de mémoire, c'est tout ce dont j'ai besoin

          PIC et I2C

          × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
          × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
          • Editeur
          • Markdown