spidev in c



  • Hallo,

    ich experimentiere gerade auf dem RaspberryPi mit SPI...

    dazu habe ich folgende funktionieren Funktion (steuert ein DIP204 von Electronic Assembly an):

    static void lcd_send_byte(int fd,int command,char value)
    {
      #define COMMAND 0b00011111  // Command start byte (1f)
      #define WRITE_DATA 0b01011111   // Write Data start byte (5f)
    
      unsigned char cmd=0;
    
      if (command)
        cmd=COMMAND;
      else
        cmd=WRITE_DATA;
    
      char lowerdata=value & 0x0f;
      char upperdata=(value & 0xf0) >> 4;
      cmd=reversebits(cmd);
      lowerdata=reversebits(lowerdata);
      upperdata=reversebits(upperdata);
    
      char writecommand[3] = {cmd, lowerdata, upperdata, };
    
      struct spi_ioc_transfer message[1] = {0};  //setup spi transfer data structure
    
      message[0].tx_buf = (unsigned long)writecommand;  //send the write command an$
      message[0].rx_buf = (unsigned long)NULL;
      message[0].len = sizeof(writecommand);
      //message[0].cs_change = 0; //keep holding chip select state
      message[0].cs_change = 1;
       int ret = ioctl(fd, SPI_IOC_MESSAGE(1), &message);      //spi check if sent
       if (ret < 1)
          pabort("can't send spi message");
    
       usleep(5000);                              //wait 5ms for write command to c$
    }
    

    so jetzt dachte ich, ich kann gleich mehrere Bytes schicken (string):

    static void lcd_send_string(int fd,char *value)
    {
      #define COMMAND 0b00011111  // Command start byte (1f)
      #define WRITE_DATA 0b01011111   // Write Data start byte (5f)
    
      unsigned char cmd=WRITE_DATA;
    
      unsigned int l=strlen(value);
    
      char *writecommand=malloc(1+l*2);//1byte for command/write-flag + 2byte per s$
      cmd=reversebits(cmd); //LSB_FIRST (RPi does not support it)
    
      writecommand[0]=cmd;
      printf("len: %d (%d)\n",l,sizeof(writecommand*));
      int i;
      for (i=0;i<l;i++)
      {
        char v=value[i];
        printf("%c (%x)\n", v,v);
    
        char lowerdata=v & 0x0f;
        char upperdata=(v & 0xf0) >> 4;
        //reversing bits (LSB_FIRST not supported by RPi)
        lowerdata=reversebits(lowerdata);
        upperdata=reversebits(upperdata);
    
        writecommand[1+i*2]=lowerdata;
        writecommand[2+i*2]=upperdata;
      }
      struct spi_ioc_transfer message[1] = {0};  //setup spi transfer data structure
    
      message[0].tx_buf = (unsigned long)writecommand;  //send the write command
      message[0].rx_buf = (unsigned long)NULL;
      message[0].len = sizeof(writecommand);
      //message[0].cs_change = 0;                     //keep holding chip select st$
      message[0].cs_change = 1;                     //chip select needs to be relea$
    free(writecommand);
       int ret = ioctl(fd, SPI_IOC_MESSAGE(1), &message);      //spi check if sent
       if (ret < 1)
          pabort("can't send spi message");
    
       usleep(5000);                              //wait 5ms for write command to c$
    
    }
    

    kompiliert super und beim Ausführen kommt kein Fehler....der Text wird aber auch nicht auf dem Display angezeigt. Kann natürlich sein, dass ich trotzdem vor jedem Datenbyte-Paar noch mal das Startbyte senden muss (Datenblatt: www.lcd-module.de/eng/pdf/zubehoer/ks0073.pdf).
    auf seite 52 des Datenblattes gibt es eine Ansicht für den "Continuous Write Mode" mit einer "Wait"-Zeit...nur wie realisiert man sowas (einfach ein 0-Byte)?
    Deswegen wollte ich mal fragen, ob ich das prinzipiell vom Code her richtig habe (gerade wegen der dynamischen Speicherzuweisung). bevor ich da weiter im Dunkeln stochere

    Gruß Frank



  • struct spi_ioc_transfer message[1] = {0};  // unsinniges Array
    
      message[0].tx_buf = (unsigned long)writecommand;
      message[0].rx_buf = (unsigned long)NULL;
      message[0].len = sizeof(writecommand);
      //message[0].cs_change = 0;                    
      message[0].cs_change = 1;                    
    free(writecommand);  // UB weil tx_buf hier jetzt auf undefinierten Speicher zeigt
       int ret = ioctl(fd, SPI_IOC_MESSAGE(1), &message); // UB wegen Adresse auf struct-Array statt Adresse auf struct
    

    Bist du dir sicher, dass das ganze Reverse-Zeugs wirklich notwenig ist und nichts kaputt macht?

    Ohne den Rpi jetzt wirklich zu kennen:

    static void lcd_send_string(int fd,char *value)
    {
     #define COMMAND 0b00011111  // Command start byte (1f)
     #define WRITE_DATA 0b01011111   // Write Data start byte (5f)
    
      unsigned int len=strlen(value);
    
      char rxdummy[128]="",*writecommand=calloc(1,2+len+1);
    
      writecommand[0]=WRITE_DATA;
      strcpy(writecommand+2,value);
    
      struct spi_ioc_transfer message = {
        .tx_buf = (unsigned long)writecommand,
        .rx_buf = (unsigned long)rxdummy,
        .len = 2+len,
        .cs_change = 1,
        ...  // hier sollte doch noch was kommen?!
      };
    
      int ret = ioctl(fd, SPI_IOC_MESSAGE(1), &message);
      free(writecommand); // erst NACH Verwendung von message das free!
    
      if (ret < 1)
         pabort("can't send spi message");
    
      usleep(5000);  
    }
    


  • Danke für deine Nachricht.

    Das Reverse-Zeug muss ich machen, da das Display LSB_FIRST erfordert, welches der Pi nicht unterstützt...

    Was meinst du mit "UB"?

    mit dem Free gebe ich dir absolut Recht...

    das mit dem vorinitialisierten message-Array habe ich aus einem Beispiel-Code, wo noch die Indizes 1 und 2 gefüllt wurden...

    was sollte noch in dem Message-Array drin sein?


Log in to reply