Search code examples
cbeagleboneblackspilcd

Displaying the character on DIP203-6 LCD screen using beaglebone Black SPI


I am trying to write a character to my DIP203-6 LCD using the beagle bone black SPI. I have Initialised the LCD screen as the cursor blinks at the right position. The problem I am facing is in writing the character as in the data sheet the writing of character takes 10 bits but spi can take only 8 bits. The RS of the LCD needs to be made 1 according to the commands in the datasheet. I tend to get some garbage values.

In the int main() part, at the end you could see i am transferring the command using transfer function above the main

#include <stdint.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/types.h>
#include <linux/spi/spidev.h>

#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
static void transfer(int fd, uint16_t* tx, uint8_t cs);
void init_display(int fd);

static void pabort(const char *s)
{
    perror(s);
    abort();
}

static const char *device = "/dev/spidev2.1";
static uint8_t mode=3;
static uint8_t bits = 8;
static uint32_t speed = 40000;
static uint16_t delay;

  //initialization of display

void init_display(int fd)
{
        int ret;
        uint16_t tx[] = {
                0x0F8, 0x000, 0x0C0,
                0x0F8, 0x060, 0x000,
                0x0F8, 0x060, 0x0C0,
                0x0FC, 0x090, 0x000,
                0x0FC, 0x000, 0x020,
                0x0FE, 0x000, 0x000,
                0x0F8, 0x000, 0x0C0,
                0x0F8, 0x0F0, 0x000,
                0x0F8, 0x080, 0x000,

        };

        for (ret=0; ret<27; ret++)
        {
                transfer(fd,&tx[ret], 0);
                  usleep(2000);
        }
}
static void transfer(int fd, uint16_t* tx, uint8_t cs){
    int ret;
    uint16_t rx[ARRAY_SIZE(tx)] = {0, };
    struct spi_ioc_transfer tr = {
        .tx_buf = (unsigned long)tx,
        .rx_buf = 0,
        .len = 1,
        .delay_usecs = delay,
        .speed_hz = speed,
        .bits_per_word = bits,
        .cs_change=cs,
    };
    printf("%u", cs);

    ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
    if (ret < 1)
        pabort("can't send spi message");

//  for (ret = 0; ret < ARRAY_SIZE(tx); ret++) {
    //  if (!(ret % 6))
        puts("");
    //  printf("%.2X ", rx[ret]);
    }
//  puts("");


static void print_usage(const char *prog)
{
    printf("Usage: %s [-DsbdlHOLC3]\n", prog);
    puts("  -D --device   device to use (default /dev/spidev1.1)\n"
         "  -s --speed    max speed (Hz)\n"
         "  -d --delay    delay (usec)\n"
         "  -b --bpw      bits per word \n"
         "  -l --loop     loopback\n"
         "  -H --cpha     clock phase\n"
         "  -O --cpol     clock polarity\n"
         "  -L --lsb      least significant bit first\n"
         "  -C --cs-high  chip select active high\n"
         "  -3 --3wire    SI/SO signals shared\n");
    exit(1);
}

static void parse_opts(int argc, char *argv[])
{
    while (1) {
        static const struct option lopts[] = {
            { "device",  1, 0, 'D' },
            { "speed",   1, 0, 's' },
            { "delay",   1, 0, 'd' },
            { "bpw",     1, 0, 'b' },
            { "loop",    0, 0, 'l' },
            { "cpha",    0, 0, 'H' },
            { "cpol",    0, 0, 'O' },
            { "lsb",     0, 0, 'L' },
            { "cs-high", 0, 0, 'C' },
            { "3wire",   0, 0, '3' },
            { "no-cs",   0, 0, 'N' },
            { "ready",   0, 0, 'R' },
            { NULL, 0, 0, 0 },
        };
        int c;

        c = getopt_long(argc, argv, "D:s:d:b:lHOLC3NR", lopts, 
NULL);

        if (c == -1)
            break;

        switch (c) {
        case 'D':
            device = optarg;
            break;
        case 's':
            speed = atoi(optarg);
            break;
        case 'd':
            delay = atoi(optarg);
            break;
        case 'b':
            bits = atoi(optarg);
            break;
        case 'l':
            mode |= SPI_LOOP;
            break;
        case 'H':
            mode |= SPI_CPHA;
            break;
        case 'O':
            mode |= SPI_CPOL;
            break;
        case 'L':
            mode |= SPI_LSB_FIRST;
            break;
        case 'C':
            mode |= SPI_CS_HIGH;
            break;
        case '3':
            mode |= SPI_3WIRE;
            break;
        case 'N':
            mode |= SPI_NO_CS;
            break;
        case 'R':
            mode |= SPI_READY;
            break;
        default:
            print_usage(argv[0]);
            break;
        }
    }
}

int main(int argc, char *argv[])
{
    int ret = 0;
    int fd;

    parse_opts(argc, argv);

    fd = open(device, O_RDWR);
    if (fd < 0)
        pabort("can't open device");

    /*
     * spi mode
     */
    ret = ioctl(fd, SPI_IOC_WR_MODE, &mode);
    if (ret == -1)
        pabort("can't set spi mode");

    ret = ioctl(fd, SPI_IOC_RD_MODE, &mode);
    if (ret == -1)
        pabort("can't get spi mode");

    /*
     * bits per word
     */
    ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits);
    if (ret == -1)
        pabort("can't set bits per word");

    ret = ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits);
    if (ret == -1)
        pabort("can't get bits per word");

    /*
     * max speed hz
     */
    ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);
    if (ret == -1)
        pabort("can't set max speed hz");

    ret = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed);
    if (ret == -1)
        pabort("can't get max speed hz");

    printf("spi mode: %d\n", mode);
    printf("bits per word: %d\n", bits);
    printf("max speed: %d Hz (%d KHz)\n", speed, speed/1000);

    init_display(fd);
       usleep(20000);
    uint16_t hl[]={0X38,0X0E,0X06,0XF8,0X30,0x50,0x02};
    trnsfer(fd,hl,0);

    close(fd);

    return ret;
}

Solution

  • Your LCD module uses SSD1803 controller. According to the data sheet, you need to transfer 3 bytes for write operation.

    The first byte is a start byte composed of 5 bits of “1” followed by R/W, RS and end bit (“0”).

    Next 2 bytes are data bytes. Lower 4 bits of data followed by four “0”s. Then, upper 4 bits of data followed by four “0”s.

    • 1st byte: “1” “1” “1” “1” “1” R/W("0") RS("1") “0”
    • 2nd byte: D0 D1 D2 D3 “0” “0” “0” “0”
    • 3rd byte: D4 D5 D6 D7 “0” “0” “0” “0”

    The figure 7-11 in the data sheet illustrates this operation.

    enter image description here

    Also, looks like you are passing an array, but I think transfer function transfers only one byte because .len = 1;.

    struct spi_ioc_transfer tr = {
      .tx_buf = (unsigned long)tx,
      .rx_buf = 0,
      .len = 1, // <- HERE
      .delay_usecs = delay,
      .speed_hz = speed,
      .bits_per_word = bits,
      .cs_change=cs,
    };
    

    You want to transfer 3 bytes. You can modify the function and specify the length depending on the size of your array. Or, you can loop through your array and send one byte after another if you keep CS low between the transfers.