Module17: updated display drivers to new SPI subsystem

pull/292/head
Silvano Seva 2024-10-09 21:50:37 +02:00
rodzic 5e94d2fef6
commit 5cc38316ea
4 zmienionych plików z 162 dodań i 116 usunięć

Wyświetl plik

@ -26,9 +26,11 @@
#include <peripherals/gpio.h>
#include <interfaces/delays.h>
#include <hwconfig.h>
#include <SPI2.h>
#include <spi_stm32.h>
#include "SH110x_Mod17.h"
extern const struct spiDevice spi2;
void SH110x_init()
{
gpio_setPin(LCD_CS);
@ -39,37 +41,46 @@ void SH110x_init()
gpio_setPin(LCD_RST);
delayMs(50);
gpio_clearPin(LCD_CS);
static const uint8_t init[] =
{
0xAE, /* SH110X_DISPLAYOFF */
0xD5, /* SH110X_SETDISPLAYCLOCKDIV, 0x51 */
0x51,
0x81, /* SH110X_SETCONTRAST, 0x4F */
0x4F,
0xAD, /* SH110X_DCDC, 0x8A */
0x8A,
0xA1, /* SH110X_SEGREMAP */
0xC0, /* SH110X_COMSCANINC */
0xDC, /* SH110X_SETDISPSTARTLINE, 0x0 */
0x00,
0xD3, /* SH110X_SETDISPLAYOFFSET, 0x60 */
0x60,
0xD9, /* SH110X_SETPRECHARGE, 0x22 */
0x22,
0xDB, /* SH110X_SETVCOMDETECT, 0x35 */
0x35,
0xA8, /* SH110X_SETMULTIPLEX, 0x3F */
0x3F,
0xA4, /* SH110X_DISPLAYALLON_RESUME */
0xA6, /* SH110X_NORMALDISPLAY */
0xAF /* SH110x_DISPLAYON */
};
gpio_clearPin(LCD_CS);
gpio_clearPin(LCD_DC); /* DC low -> command mode */
spi2_sendRecv(0xAE); /* SH110X_DISPLAYOFF */
spi2_sendRecv(0xD5); /* SH110X_SETDISPLAYCLOCKDIV, 0x51 */
spi2_sendRecv(0x51);
spi2_sendRecv(0x81); /* SH110X_SETCONTRAST, 0x4F */
spi2_sendRecv(0x4F);
spi2_sendRecv(0xAD); /* SH110X_DCDC, 0x8A */
spi2_sendRecv(0x8A);
spi2_sendRecv(0xA1); /* SH110X_SEGREMAP */
spi2_sendRecv(0xC0); /* SH110X_COMSCANINC */
spi2_sendRecv(0xDC); /* SH110X_SETDISPSTARTLINE, 0x0 */
spi2_sendRecv(0x00);
spi2_sendRecv(0xD3); /* SH110X_SETDISPLAYOFFSET, 0x60 */
spi2_sendRecv(0x60);
spi2_sendRecv(0xD9); /* SH110X_SETPRECHARGE, 0x22 */
spi2_sendRecv(0x22);
spi2_sendRecv(0xDB); /* SH110X_SETVCOMDETECT, 0x35 */
spi2_sendRecv(0x35);
spi2_sendRecv(0xA8); /* SH110X_SETMULTIPLEX, 0x3F */
spi2_sendRecv(0x3F);
spi2_sendRecv(0xA4); /* SH110X_DISPLAYALLON_RESUME */
spi2_sendRecv(0xA6); /* SH110X_NORMALDISPLAY */
spi2_sendRecv(0xAF); /* SH110x_DISPLAYON */
spi_send(&spi2, init, sizeof(init));
gpio_setPin(LCD_CS);
}
void SH110x_terminate()
{
spi2_sendRecv(0xAE);
uint8_t dispOff = 0xAE;
gpio_clearPin(LCD_CS);
gpio_clearPin(LCD_DC); /* DC low -> command mode */
spi_send(&spi2, &dispOff, 1);
gpio_setPin(LCD_CS);
}
void SH110x_renderRows(uint8_t startRow, uint8_t endRow, void *fb)
@ -81,14 +92,17 @@ void SH110x_renderRows(uint8_t startRow, uint8_t endRow, void *fb)
{
for(uint8_t x = 0; x < CONFIG_SCREEN_WIDTH/8; x++)
{
uint8_t cmd[3];
cmd[0] = (y & 0x0F); /* Set Y position */
cmd[1] = (0x10 | ((y >> 4) & 0x07));
cmd[2] = (0xB0 | x); /* Set X position */
gpio_clearPin(LCD_DC); /* RS low -> command mode */
(void) spi2_sendRecv(y & 0x0F); /* Set Y position */
(void) spi2_sendRecv(0x10 | ((y >> 4) & 0x07));
(void) spi2_sendRecv(0xB0 | x); /* Set X position */
spi_send(&spi2, cmd, sizeof(cmd));
gpio_setPin(LCD_DC); /* RS high -> data mode */
size_t pos = x + y * (CONFIG_SCREEN_WIDTH/8);
spi2_sendRecv(frameBuffer[pos]);
spi_send(&spi2, &frameBuffer[pos], 1);
}
}
@ -102,11 +116,12 @@ void SH110x_render(void *fb)
void SH110x_setContrast(uint8_t contrast)
{
uint8_t cmd[2];
cmd[0] = 0x81; /* Set Electronic Volume */
cmd[0] = contrast; /* Controller contrast range is 0 - 63 */
gpio_clearPin(LCD_CS);
gpio_clearPin(LCD_DC); /* RS low -> command mode */
(void) spi2_sendRecv(0x81); /* Set Electronic Volume */
(void) spi2_sendRecv(contrast); /* Controller contrast range is 0 - 63 */
gpio_clearPin(LCD_DC); /* RS low -> command mode */
spi_send(&spi2, cmd, sizeof(cmd));
gpio_setPin(LCD_CS);
}

Wyświetl plik

@ -27,8 +27,9 @@
#include <interfaces/display.h>
#include <interfaces/delays.h>
#include <hwconfig.h>
#include <SPI2.h>
#include <spi_stm32.h>
extern const struct spiDevice spi2;
/**
* \internal
@ -50,7 +51,7 @@ void SSD1306_renderRow(uint8_t row, uint8_t *frameBuffer)
out |= ((tmp >> (7-j)) & 0x01) << j;
}
spi2_sendRecv(out);
spi_send(&spi2, &out, 1);
}
}
@ -65,37 +66,41 @@ void SSD1306_init()
gpio_setPin(LCD_RST);
delayMs(50);
gpio_clearPin(LCD_CS);
static const uint8_t init[] =
{
0xAE, // SH110X_DISPLAYOFF
0xD5, // SH110X_SETDISPLAYCLOCKDIV, 0x51
0x51,
0x81, // SH110X_SETCONTRAST, 0x4F
0x4F,
0xAD, // SH110X_DCDC, 0x8A
0x8A,
0xA0, // SH110X_SEGREMAP
0xC0, // SH110X_COMSCANINC
0xDC, // SH110X_SETDISPSTARTLINE, 0x0
0x00,
0xD3, // SH110X_SETDISPLAYOFFSET, 0x60
0x60,
0xD9, // SH110X_SETPRECHARGE, 0x22
0x22,
0xDB, // SH110X_SETVCOMDETECT, 0x35
0x35,
0xA8, // SH110X_SETMULTIPLEX, 0x3F
0x3F,
0xA4, // SH110X_DISPLAYALLON_RESUME
0xA6, // SH110X_NORMALDISPLAY
0xAF // SH110x_DISPLAYON
};
gpio_clearPin(LCD_RS);// RS low -> command mode
spi2_sendRecv(0xAE); // SH110X_DISPLAYOFF,
spi2_sendRecv(0xd5); // SH110X_SETDISPLAYCLOCKDIV, 0x51,
spi2_sendRecv(0x51);
spi2_sendRecv(0x81); // SH110X_SETCONTRAST, 0x4F,
spi2_sendRecv(0x4F);
spi2_sendRecv(0xAD); // SH110X_DCDC, 0x8A,
spi2_sendRecv(0x8A);
spi2_sendRecv(0xA0); // SH110X_SEGREMAP,
spi2_sendRecv(0xC0); // SH110X_COMSCANINC,
spi2_sendRecv(0xDC); // SH110X_SETDISPSTARTLINE, 0x0,
spi2_sendRecv(0x00);
spi2_sendRecv(0xd3); // SH110X_SETDISPLAYOFFSET, 0x60,
spi2_sendRecv(0x60);
spi2_sendRecv(0xd9); // SH110X_SETPRECHARGE, 0x22,
spi2_sendRecv(0x22);
spi2_sendRecv(0xdb); // SH110X_SETVCOMDETECT, 0x35,
spi2_sendRecv(0x35);
spi2_sendRecv(0xa8); // SH110X_SETMULTIPLEX, 0x3F,
spi2_sendRecv(0x3f);
spi2_sendRecv(0xa4); // SH110X_DISPLAYALLON_RESUME,
spi2_sendRecv(0xa6); // SH110X_NORMALDISPLAY,
spi2_sendRecv(0xAF); // SH110x_DISPLAYON
gpio_clearPin(LCD_CS);
gpio_clearPin(LCD_DC);
spi_send(&spi2, init, sizeof(init));
gpio_setPin(LCD_CS);
}
void SSD1306_terminate()
{
spi2_terminate();
}
void SSD1306_renderRows(uint8_t startRow, uint8_t endRow, void *fb)
@ -104,10 +109,13 @@ void SSD1306_renderRows(uint8_t startRow, uint8_t endRow, void *fb)
for(uint8_t row = startRow; row <= endRow; row++)
{
uint8_t cmd[3];
cmd[0] = 0xB0 | row; /* Set Y position */
cmd[1] = 0x00; /* Set X position */
cmd[2] = 0x10;
gpio_clearPin(LCD_RS); /* RS low -> command mode */
(void) spi2_sendRecv(0xB0 | row); /* Set Y position */
(void) spi2_sendRecv(0x00); /* Set X position */
(void) spi2_sendRecv(0x10);
spi_send(&spi2, cmd, sizeof(cmd));
gpio_setPin(LCD_RS); /* RS high -> data mode */
SSD1306_renderRow(row, (uint8_t *) fb);
}
@ -122,11 +130,12 @@ void SSD1306_render(void *fb)
void SSD1306_setContrast(uint8_t contrast)
{
uint8_t cmd[2];
cmd[0] = 0x81; /* Set Electronic Volume */
cmd[0] = contrast; /* Controller contrast range is 0 - 63 */
gpio_clearPin(LCD_CS);
gpio_clearPin(LCD_RS); /* RS low -> command mode */
(void) spi2_sendRecv(0x81); /* Set Electronic Volume */
(void) spi2_sendRecv(contrast); /* Controller contrast range is 0 - 63 */
gpio_clearPin(LCD_DC); /* RS low -> command mode */
spi_send(&spi2, cmd, sizeof(cmd));
gpio_setPin(LCD_CS);
}

Wyświetl plik

@ -26,9 +26,11 @@
#include <peripherals/gpio.h>
#include <interfaces/delays.h>
#include <hwconfig.h>
#include <SPI2.h>
#include <spi_stm32.h>
#include "SSD1309_Mod17.h"
extern const struct spiDevice spi2;
void SSD1309_init()
{
gpio_setPin(LCD_CS);
@ -39,28 +41,36 @@ void SSD1309_init()
gpio_setPin(LCD_RST);
delayMs(50);
static const uint8_t init[] =
{
0xAE, // SSD1309_DISPLAYOFF,
0xD5, // Set display clock division
0xF0,
0xA8, // Set multiplex ratio, 1/64
0x3F,
0x81, // Set contrast control
0x32,
0xD9, // Set pre-charge period
0xF1,
0xDB, // Set VCOMH Deselect level
0x30,
0xAF
};
gpio_clearPin(LCD_CS);
gpio_clearPin(LCD_DC);// DC low -> command mode
spi2_sendRecv(0xAE); // SSD1309_DISPLAYOFF,
spi2_sendRecv(0xD5); // Set display clock division
spi2_sendRecv(0xF0);
spi2_sendRecv(0xA8); // Set multiplex ratio, 1/64
spi2_sendRecv(0x3F);
spi2_sendRecv(0x81); // Set contrast control
spi2_sendRecv(0x32);
spi2_sendRecv(0xD9); // Set pre-charge period
spi2_sendRecv(0xF1);
spi2_sendRecv(0xDB); // Set VCOMH Deselect level
spi2_sendRecv(0x30);
spi2_sendRecv(0xAF);
gpio_clearPin(LCD_DC);
spi_send(&spi2, init, sizeof(init));
gpio_setPin(LCD_CS);
}
void SSD1309_terminate()
{
spi2_sendRecv(0xAE);
uint8_t dispOff = 0xAE;
gpio_clearPin(LCD_CS);
gpio_clearPin(LCD_DC); /* DC low -> command mode */
spi_send(&spi2, &dispOff, 1);
gpio_setPin(LCD_CS);
}
void SSD1309_renderRows(uint8_t startRow, uint8_t endRow, void *fb)
@ -70,34 +80,38 @@ void SSD1309_renderRows(uint8_t startRow, uint8_t endRow, void *fb)
// Convert rows to pages
uint8_t startPage = startRow / 8;
uint8_t endPage = endRow / 8;
uint8_t cmd[3];
gpio_clearPin(LCD_DC);
spi2_sendRecv(0x20); // Set page addressing mode
spi2_sendRecv(0x02);
cmd[0] = 0x20; // Set page addressing mode
cmd[1] = 0x02;
spi_send(&spi2, cmd, 2);
uint8_t *framebuffer = (uint8_t *)fb;
for(uint8_t page = startPage; page < endPage; page++)
{
gpio_clearPin(LCD_DC);
spi2_sendRecv(0xB0 | page);
spi2_sendRecv(0x00);
spi2_sendRecv(0x10);
cmd[0] = 0xB0 | page;
cmd[1] = 0x00;
cmd[1] = 0x10;
spi_send(&spi2, cmd, 3);
gpio_setPin(LCD_DC); // DC high -> data mode
uint8_t topRow = page*8;
uint8_t topRow = page * 8;
for(uint8_t col = 0; col < CONFIG_SCREEN_WIDTH; col++)
{
uint8_t data = 0;
uint8_t bit_offset = col%8; // Bit offset in the fb for the column we are refreshing
uint8_t bit_offset = col % 8; // Bit offset in the fb for the column we are refreshing
// Gather the 8 rows of data
for(uint8_t row = 0; row < 8; row++)
{
uint8_t cell = framebuffer[((topRow+row)*CONFIG_SCREEN_WIDTH+col)/8];
data |= ((cell>>bit_offset)&0x01) << row;
size_t pos = ((topRow + row) * CONFIG_SCREEN_WIDTH + col) / 8;
uint8_t cell = framebuffer[pos];
data |= ((cell >> bit_offset) & 0x01) << row;
}
spi2_sendRecv(data);
spi_send(&spi2, &data, 1);
}
}
@ -106,14 +120,18 @@ void SSD1309_renderRows(uint8_t startRow, uint8_t endRow, void *fb)
void SSD1309_render(void *fb)
{
gpio_clearPin(LCD_CS);
static const uint8_t cmd[] =
{
0xB0,
0x20, // Set horizontal addressing mode
0x00,
0x00,
0x10
};
gpio_clearPin(LCD_CS);
gpio_clearPin(LCD_DC);
spi2_sendRecv(0xB0);
spi2_sendRecv(0x20); // Set horizontal addressing mode
spi2_sendRecv(0x00);
spi2_sendRecv(0x00);
spi2_sendRecv(0x10);
spi_send(&spi2, cmd, sizeof(cmd));
gpio_setPin(LCD_DC); // DC high -> data mode
uint8_t *framebuffer = (uint8_t *)fb;
@ -124,27 +142,30 @@ void SSD1309_render(void *fb)
for(uint8_t col = 0; col < CONFIG_SCREEN_WIDTH; col++)
{
uint8_t data = 0;
uint8_t bit_offset = col%8; // Bit offset in the fb for the column we are refreshing
uint8_t bit_offset = col % 8; // Bit offset in the fb for the column we are refreshing
// Gather the 8 rows of data
for(uint8_t subRow = 0; subRow < 8; subRow++)
{
uint8_t cell = framebuffer[((topRow+subRow)*CONFIG_SCREEN_WIDTH+col)/8];
data |= ((cell>>bit_offset)&0x01) << subRow;
size_t pos = ((topRow + subRow) * CONFIG_SCREEN_WIDTH + col) / 8;
uint8_t cell = framebuffer[pos];
data |= ((cell >> bit_offset) & 0x01) << subRow;
}
spi2_sendRecv(data);
spi_send(&spi2, &data, 1);
}
}
gpio_setPin(LCD_CS);
gpio_setPin(LCD_CS);
}
void SSD1309_setContrast(uint8_t contrast)
{
uint8_t cmd[2];
cmd[0] = 0x81; /* Set Electronic Volume */
cmd[0] = contrast; /* Controller contrast range is 0 - 63 */
gpio_clearPin(LCD_CS);
gpio_clearPin(LCD_DC); /* DC low -> command mode */
(void) spi2_sendRecv(0x81); /* Set Electronic Volume */
(void) spi2_sendRecv(contrast); /* Controller contrast range is 0 - 63 */
gpio_clearPin(LCD_DC); /* RS low -> command mode */
spi_send(&spi2, cmd, sizeof(cmd));
gpio_setPin(LCD_CS);
}

Wyświetl plik

@ -22,10 +22,11 @@
#include <peripherals/gpio.h>
#include <hwconfig.h>
#include <interfaces/platform.h>
#include <SPI2.h>
#include <spi_stm32.h>
#include "SH110x_Mod17.h"
#include "SSD1309_Mod17.h"
SPI_STM32_DEVICE_DEFINE(spi2, SPI2, NULL)
struct displayFuncs
{
@ -73,7 +74,7 @@ void display_init()
gpio_setMode(SPI2_SCK, ALTERNATE | ALTERNATE_FUNC(5));
gpio_setMode(SPI2_MOSI, ALTERNATE | ALTERNATE_FUNC(5));
gpio_setMode(SPI2_MISO, ALTERNATE | ALTERNATE_FUNC(5));
spi2_init();
spiStm32_init(&spi2, 1300000, 0);
/*
* Initialise GPIOs for LCD control
@ -88,7 +89,7 @@ void display_init()
void display_terminate()
{
display.terminate();
spi2_terminate();
spiStm32_terminate(&spi2);
}
void display_renderRows(uint8_t startRow, uint8_t endRow, void *fb)