From 02e96847167415e89758127cddc4045676106110 Mon Sep 17 00:00:00 2001 From: Cyprien Laplace Date: Sat, 24 Jun 2017 16:47:22 -0400 Subject: [PATCH] oled: add support for SPI ssd130x displays For I2C displays, the bus_type needs to be added: + .bus_type = SSD130x_BUS_I2C, .address = DISPLAY_ADDR, .bus_num = I2C0, To use a SPI display: 1/ add the SSP include: #include "drivers/ssp.h" 2/ add the SPI pins to the init table: /* SPI : Display */ { LPC_SSP0_SCLK_PIO_0_14, LPC_IO_DIGITAL }, { LPC_SSP0_MISO_PIO_0_16, LPC_IO_DIGITAL }, { LPC_SSP0_MOSI_PIO_0_17, LPC_IO_DIGITAL }, 3/ update the oled_display conf: .bus_type = SSD130x_BUS_SPI, .bus_num = SSP_BUS_0, .gpio_dc = LPC_GPIO_0_0, .gpio_cs = LPC_GPIO_1_0, .gpio_rst = LPC_GPIO_0_31, 4/ initialize the SPI bus: ssp_master_on(SSP_BUS_0, LPC_SSP_FRAME_SPI, 8, 8*1000*1000); --- drivers/ssp.c | 5 +- extdrv/ssd130x_oled_driver.c | 144 +++++++++++++++++---------- include/extdrv/ssd130x_oled_driver.h | 11 +- 3 files changed, 107 insertions(+), 53 deletions(-) diff --git a/drivers/ssp.c b/drivers/ssp.c index 353d75e..4e83d32 100644 --- a/drivers/ssp.c +++ b/drivers/ssp.c @@ -189,8 +189,9 @@ static int spi_transfer_bytes(struct lpc_ssp* ssp, uint8_t* data_out, uint8_t* d /* Read some of the replies, but stop if there's still data to send and the fifo * is running short */ - while ((ssp->status & LPC_SSP_ST_RX_NOT_EMPTY) && - !((count < size) && (ssp->raw_int_status & LPC_SSP_INTR_TX_HALF_EMPTY))) { + while ((ssp->status & LPC_SSP_ST_RX_FULL) || + ((ssp->status & LPC_SSP_ST_RX_NOT_EMPTY) && + !((count < size) && (ssp->raw_int_status & LPC_SSP_INTR_TX_HALF_EMPTY)))) { /* Read the data (mandatory) */ data_read = (uint8_t)ssp->data; if (data_in != NULL) { diff --git a/extdrv/ssd130x_oled_driver.c b/extdrv/ssd130x_oled_driver.c index 772d251..1fca0c7 100644 --- a/extdrv/ssd130x_oled_driver.c +++ b/extdrv/ssd130x_oled_driver.c @@ -31,6 +31,7 @@ #include "lib/string.h" #include "drivers/gpio.h" #include "drivers/i2c.h" +#include "drivers/ssp.h" #include "extdrv/ssd130x_oled_driver.h" @@ -89,26 +90,40 @@ #define CMD_BUF_SIZE 24 int ssd130x_send_command(struct oled_display* conf, uint8_t cmd, uint8_t* data, uint8_t len) { - char cmd_buf[CMD_BUF_SIZE] = { conf->address, SSD130x_NEXT_BYTE_CMD, cmd, }; - int ret = 0; - - if (len > (CMD_BUF_SIZE - 3)) { - return -EINVAL; - } + int i; - if (len != 0) { - int i = 0; + if (conf->bus_type == SSD130x_BUS_SPI) { + gpio_clear(conf->gpio_dc); + gpio_clear(conf->gpio_cs); + spi_transfer_single_frame(conf->bus_num, cmd); for (i = 0; i < len; i++) { - cmd_buf[ 3 + (2 * i) ] = SSD130x_NEXT_BYTE_CMD; - cmd_buf[ 4 + (2 * i) ] = data[i]; + spi_transfer_single_frame(conf->bus_num, data[i]); } - } - do { - ret = i2c_write(conf->bus_num, cmd_buf, (3 + (len * 2)), NULL); - } while (ret == -EAGAIN); - if (ret != (3 + (len * 2))) { - conf->probe_ok = 0; - return ret; + gpio_set(conf->gpio_cs); + } else if (conf->bus_type == SSD130x_BUS_I2C) { + char cmd_buf[CMD_BUF_SIZE] = { conf->address, SSD130x_NEXT_BYTE_CMD, cmd, }; + int ret; + + if (2 * len > (CMD_BUF_SIZE - 3)) { + return -EINVAL; + } + + if (len != 0) { + for (i = 0; i < len; i++) { + cmd_buf[ 3 + (2 * i) ] = SSD130x_NEXT_BYTE_CMD; + cmd_buf[ 4 + (2 * i) ] = data[i]; + } + } + + do { + ret = i2c_write(conf->bus_num, cmd_buf, (3 + (len * 2)), NULL); + } while (ret == -EAGAIN); + if (ret != (3 + (len * 2))) { + conf->probe_ok = 0; + return ret; + } + } else { + return -EPROTO; } return 0; } @@ -267,13 +282,24 @@ int ssd130x_display_on(struct oled_display* conf) conf->fullscreen = 0; + if (conf->bus_type == SSD130x_BUS_SPI) { + config_gpio(&conf->gpio_cs, 0, GPIO_DIR_OUT, 1); + config_gpio(&conf->gpio_dc, 0, GPIO_DIR_OUT, 1); + + config_gpio(&conf->gpio_rst, 0, GPIO_DIR_OUT, 0); + usleep(5); /* at least 3us */ + gpio_set(conf->gpio_rst); + msleep(1); + } + /* Display OFF */ ret = ssd130x_display_power(conf, SSD130x_DISP_OFF); /* 0xAE */ if (ret != 0) { return ret; } + if (conf->charge_pump == SSD130x_INTERNAL_PUMP) { - val = SSD130x_CMD_CHARGE_INTERN; + val = SSD130x_CMD_CHARGE_INTERN; /* 0x14 */ ssd130x_send_command(conf, SSD130x_CMD_CHARGE_PUMP, &val, 1); /* 0x8D */ } @@ -321,40 +347,52 @@ int ssd130x_display_on(struct oled_display* conf) int ssd130x_send_data(struct oled_display* conf, uint8_t* start, uint16_t len) { - int (*write)(uint8_t, const void *, size_t, const void*); - int ret = 0; + int ret; + + if (conf->bus_type == SSD130x_BUS_SPI) { + gpio_set(conf->gpio_dc); + gpio_clear(conf->gpio_cs); + ret = spi_transfer_multiple_frames(conf->bus_num, start, NULL, len, 8); + gpio_set(conf->gpio_cs); + if (ret != len) { + return ret; + } + } else if (conf->bus_type == SSD130x_BUS_I2C) { + int (*write)(uint8_t, const void *, size_t, const void*); - /* Check that start and satrt + len are within buffer */ + /* Check that start and satrt + len are within buffer */ - /* Copy previous two bytes to storage area (gddram[0] and gddram[1]) */ - conf->gddram[0] = *(start - 2); - conf->gddram[1] = *(start - 1); + /* Copy previous two bytes to storage area (gddram[0] and gddram[1]) */ + conf->gddram[0] = *(start - 2); + conf->gddram[1] = *(start - 1); - /* Setup I2C transfer */ - *(start - 2) = conf->address; - *(start - 1) = SSD130x_DATA_ONLY; + /* Setup I2C transfer */ + *(start - 2) = conf->address; + *(start - 1) = SSD130x_DATA_ONLY; - /* Send data on I2C bus */ - write = conf->async ? i2c_write_async : i2c_write; - do { - ret = write(conf->bus_num, (start - 2), (2 + len), NULL); - } while (ret == -EAGAIN); + /* Send data on I2C bus */ + write = conf->async ? i2c_write_async : i2c_write; + do { + ret = write(conf->bus_num, (start - 2), (2 + len), NULL); + } while (ret == -EAGAIN); - /* Restore gddram data */ - *(start - 2) = conf->gddram[0]; - *(start - 1) = conf->gddram[1]; + /* Restore gddram data */ + *(start - 2) = conf->gddram[0]; + *(start - 1) = conf->gddram[1]; - if (ret != (2 + len)) { - return ret; + if (ret != (2 + len)) { + return ret; + } + } else { + return -EPROTO; } - return len; + return 0; } /* Update what is really displayed */ int ssd130x_display_full_screen(struct oled_display* conf) { - int (*write)(uint8_t, const void *, size_t, const void*); - int ret = 0; + int ret; if (!conf->fullscreen) { ret = ssd130x_set_column_address(conf, 0, 127); @@ -368,16 +406,22 @@ int ssd130x_display_full_screen(struct oled_display* conf) conf->fullscreen = 1; } - /* Setup I2C transfer */ - *(conf->gddram + 2) = conf->address; - *(conf->gddram + 3) = SSD130x_DATA_ONLY; - - /* Send data on I2C bus */ - write = conf->async ? i2c_write_async : i2c_write; - do { - ret = write(conf->bus_num, conf->gddram + 2, 2 + GDDRAM_SIZE, NULL); - } while (ret == -EAGAIN); - + if (conf->bus_type == SSD130x_BUS_SPI) { + ret = ssd130x_send_data(conf, conf->gddram + 4, GDDRAM_SIZE); + } else if (conf->bus_type == SSD130x_BUS_I2C) { + /* Setup I2C transfer */ + *(conf->gddram + 2) = conf->address; + *(conf->gddram + 3) = SSD130x_DATA_ONLY; + + /* Send data on I2C bus */ + int (*write)(uint8_t, const void *, size_t, const void*); + write = conf->async ? i2c_write_async : i2c_write; + do { + ret = write(conf->bus_num, conf->gddram + 2, 2 + GDDRAM_SIZE, NULL); + } while (ret == -EAGAIN); + } else { + return -EPROTO; + } return ret; } diff --git a/include/extdrv/ssd130x_oled_driver.h b/include/extdrv/ssd130x_oled_driver.h index 83a972b..d4b0cec 100644 --- a/include/extdrv/ssd130x_oled_driver.h +++ b/include/extdrv/ssd130x_oled_driver.h @@ -25,13 +25,15 @@ #define EXTDRV_SSD130X_OLED_DRIVER_H #include "lib/stdint.h" +#include "drivers/gpio.h" /***************************************************************************** */ /* Oled Display */ struct oled_display { + uint8_t bus_type; /* I2C or SPI */ uint8_t address; /* 8 bits address */ - uint8_t bus_num; /* I2C bus number */ + uint8_t bus_num; /* I2C/SPI bus number */ uint8_t probe_ok; uint8_t charge_pump; uint8_t video_mode; @@ -42,6 +44,10 @@ struct oled_display { uint8_t display_offset; uint8_t* gddram; uint8_t async; + /* spi */ + struct pio gpio_dc; + struct pio gpio_cs; + struct pio gpio_rst; /* internal */ uint8_t fullscreen; }; @@ -66,6 +72,9 @@ enum ssd130x_defs { /* For display offset */ SSD130x_MOVE_TOP, SSD130x_MOVE_BOTTOM, + /* I2C or SPI */ + SSD130x_BUS_I2C, + SSD130x_BUS_SPI, }; -- 2.43.0