Partage
  • Partager sur Facebook
  • Partager sur Twitter

[AVR] Protocol SPI

Sujet résolu
    10 décembre 2018 à 19:44:11

    Bonjour,

    Je souhaite utiliser un driver de leds (MBIXXXX) pour controller 16 leds via une puce ATmega128 (pas d'arduino autour).

    J'avais pensé faire un truc dans le genre :

    unsigned char leds0 = 0b01001100;
    unsigned char leds1 = 0b01010011;
    // Init et Transmit tirées de la doc
    SPI_MasterInit();
    while(1) {
      /* Mes pins LE et OE sont branchées à PE4 et PE5 
         je les mets en output */
      DDRE |= _BV (PE4);
      DDRE |= _BV (PE5);
      // Fonctions données dans la doc de la puce ATmega
      SPI_MasterTransmit(leds0);
      SPI_MasterTransmit(leds1);
    
      // Tire OE en haut
      PORTE |= _BV (PE5);
      // Tire LE en bas
      PORTE &= ~_BV (PE4);
    // delay ??? }

    Malheureusement, ça ne fonctionne pas, les bits ne sont pas transmis au led driver (je boucle infiniment en attendant que le buffer se vide). Qu'est ce que je fais de mal ? Avez vous de bons exemples d'utilisation  de SPI car je galère un peu à en trouver.

    Merci.

    -
    Edité par jdflm 10 décembre 2018 à 19:45:52

    • Partager sur Facebook
    • Partager sur Twitter
      11 décembre 2018 à 1:15:52

      Bonjour,

      Comme OE est active à l'état bas, si OE=1, les sorties sont désactivées, donc les LEDs sont fixes (probablement éteintes ?). 

      Tu peux faire la configuration des broches à l'extérieur de la boucle.

      La broche LE transfert le contenu des registres à décalage sur les sorties, sur un front descendant (d'après la datasheet d'un MBIXXXX pris au hasard), le reste du temps elle doit être maintenue à l'état bas, donc elle devrait être pulsé à la fin d'une écriture (si elle est à l'état haut pendant que la broche d'horloge change, d'autres fonctions sont activées).

      unsigned char leds0 = 0b01001100;
      unsigned char leds1 = 0b01010011;
      
      // Tire OE en haut, pour désactiver les sorties avant la 1ere écriture
      PORTE |= _BV (PE5);
      // Tire LE en bas
      PORTE &= ~_BV (PE4);
      
      /* Mes pins LE et OE sont branchées à PE4 et PE5
         je les mets en output */
      DDRE |= _BV (PE4);
      DDRE |= _BV (PE5);
      
      // Init et Transmit tirées de la doc
      SPI_MasterInit();
      while(1) {
        // Fonctions données dans la doc de la puce ATmega
        SPI_MasterTransmit(leds0);
        SPI_MasterTransmit(leds1);
      
        // Pulse LE pendant à 1 pendant au moins 20ns (l'atmega128 à un cycle d'horloge de 62ns au minimum donc delay n'est pas nécessaire)
        PORTE |= _BV(PE4);
        // Tire LE en bas et OE en bas
        PORTE &= ~_BV (PE4);
        PORTE &= ~_BV (PE5);
      }

      OE pourrait aussi être mis à 0, dès le début et retirer la dernière ligne de la boucle, mais si le registre du driver n'est pas à 0 à l'allumage, son contenu va être visible pendant une fraction de seconde (mais vu la fréquence de rafraîchissement ça ne serait probablement pas perceptible).

      • Partager sur Facebook
      • Partager sur Twitter
        11 décembre 2018 à 22:33:06

        C'est pas encore tout à fait ça mais en effet ça à l'air de mieux coller à ce que donne la doc. J'ai essayé de faire ça :

        unsigned char leds0 = 0b11111111;
        unsigned char leds1 = 0b00000000;
         
        // Tire OE en haut, pour désactiver les sorties avant la 1ere écriture
        PORTE |= _BV (PE5);
        // Tire LE en bas
        PORTE &= ~_BV (PE4);
         
        /* Mes pins LE et OE sont branchées à PE4 et PE5
           je les mets en output */
        DDRE |= _BV (PE4);
        DDRE |= _BV (PE5);
         
        // Init et Transmit tirées de la doc
        SPI_MasterInit();
        while(1) {
          // tire OE en haut
          PORTE |= _BV (PE5);
          _delay_ms (1);
          // Fonctions données dans la doc de la puce ATmega
          SPI_MasterTransmit(leds0);
          SPI_MasterTransmit(leds1);
         
          // Pulse LE pendant à 1 pendant au moins 20ns (l'atmega128 à un cycle d'horloge de 62ns au minimum donc delay n'est pas nécessaire)
          PORTE |= _BV(PE4);
          // Tire LE en bas et OE en bas
          PORTE &= ~_BV (PE4);
          PORTE &= ~_BV (PE5);
          unsigned char tmp = leds0;
          leds0 = leds1;
          leds1 = tmp;
        }

        Donc normalement là les 8 leds de chaque coté devraien s'allumer alternativement à chaque tour de boucle. Je ne vois pas du tout ce résultat, rien ne s'allume. Quand je ne mets pas de boucle autour du code, les bonnes leds s'allument en revance. Par contre j'ai l'impression que je dois brancher et débrancher mon installation plusieurs fois avant que ça fonctionne. Je ne sais pas si c'est un problème avec l'installation ou avec le buffer SPI qui n'est pas toujours flushé.

        Merci pour ta réponse en tous cas.

        • Partager sur Facebook
        • Partager sur Twitter
          12 décembre 2018 à 13:26:04

          Il n'y a pas de buffer SPI, puisque la fonction SPI_MasterTransmit de la doc attend que l'octet soit envoyé avant de rendre la main. Il n'y a que la broche LE qui contrôle l'envoie du buffer interne de la puce de driver (le registre à décalage), sur les sorties de ce même driver.

          Pourquoi remets tu OE à l'état haut dans la boucle ? Comme je l'ai écrit, ça sert à désactiver les LEDs, tu peux le mettre à 0 avant la boucle et ne plus y toucher après (à moins que tu veuilles éteindre les leds pour une raison ou une autre plus tard).

          Est-ce que ce ne serait pas mieux de mettre un délai plus grand entre chaque itération, 1ms (avec "_delay_ms (1);"), ce n'est pas assez pour être visible, et comme dans ton code actuel, le délai est juste après l'extinction des LEDs avec OE à 1, elles sont plus souvent éteintes qu'allumées.

          • Partager sur Facebook
          • Partager sur Twitter
            14 décembre 2018 à 15:58:06

            Je viens de m'appercevoir que le problème est un peu différent de ce que je pensais. Je ne rentre jamais la deuxième fois dans ma fonction SPI_MasterTransmit. Au premier appel il n'y a pas de soucis mais la deuxieme fois je ne rentre même pas dedans. Le code de SPI_MasterInit et SPI_MasterTanspmit :

            void SPI_MasterInit (void)
            {
              // Set these as output
              DDRB =
                (1 << DDB2) | // MOSI
                (1 << DDB1);  // SCK
            
              SPCR =
                (1<<SPE)  | // SPI enabled
                (1<<MSTR) | // Select master
                (1<<SPR0);  // Fosc / 16 clock speed
            }
            
            void SPI_MasterTransmit (unsigned char cData)
            {
              /* Start transmission */
              SPDR = cData;
              /* Wait for transmission complete */
              while(!(SPSR & (1<<SPIF)));
            }


            D'où cela peut-il venir ?

            -
            Edité par jdflm 14 décembre 2018 à 17:01:09

            • Partager sur Facebook
            • Partager sur Twitter
              14 décembre 2018 à 22:22:37

              Même si tu n'utilises pas la broche SS du SPI (PB0), il faut la définir en tant que sortie (peu importe sa valeur) ou au moins en entrée avec résistance de pull-up, parce que si elle est définie en tant qu'entrée et qu'elle passe à l'état bas, le bus SPI va interpréter ce changement comme la présence d'un autre maître sur le bus SPI et passer en mode esclave.

              C'est indiqué dans la doc dans la section "SS Pin functionality" juste après le code des 2 fonctions SPI_MasterInit et SPI_MasterTransmit.

              • Partager sur Facebook
              • Partager sur Twitter
                15 décembre 2018 à 10:03:34

                En effet c'était ça mon erreur. J'avais pourtant lu cette partie de la doc mais j'ai du mal la comprendre.

                Merci pour ton aide !

                EDIT : En la relisant elle est pourtant très claire...

                -
                Edité par jdflm 15 décembre 2018 à 10:05:22

                • Partager sur Facebook
                • Partager sur Twitter

                [AVR] Protocol SPI

                × 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