Files
velometer/st7789.c
2026-09-10 14:35:16 +03:00

215 lines
5.1 KiB
C

/*
* Copyright (c) 2021 Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*
*/
#include <string.h>
#include "hardware/gpio.h"
#include "pico/stdlib.h"
#include "st7789.h"
static struct st7789_config st7789_cfg;
static uint16_t st7789_width;
static uint16_t st7789_height;
static bool st7789_data_mode = false;
void st7789_cmd(uint8_t cmd, const uint8_t *data, size_t len) {
if (st7789_cfg.gpio_cs > -1) {
spi_set_format(st7789_cfg.spi, 8, SPI_CPOL_0, SPI_CPHA_0, SPI_MSB_FIRST);
} else {
spi_set_format(st7789_cfg.spi, 8, SPI_CPOL_1, SPI_CPHA_1, SPI_MSB_FIRST);
}
st7789_data_mode = false;
sleep_us(1);
if (st7789_cfg.gpio_cs > -1) {
gpio_put(st7789_cfg.gpio_cs, 0);
}
gpio_put(st7789_cfg.gpio_dc, 0);
sleep_us(1);
spi_write_blocking(st7789_cfg.spi, &cmd, sizeof(cmd));
if (len) {
sleep_us(1);
gpio_put(st7789_cfg.gpio_dc, 1);
sleep_us(1);
spi_write_blocking(st7789_cfg.spi, data, len);
}
sleep_us(1);
if (st7789_cfg.gpio_cs > -1) {
gpio_put(st7789_cfg.gpio_cs, 1);
}
gpio_put(st7789_cfg.gpio_dc, 1);
sleep_us(1);
}
void st7789_caset(uint16_t xs, uint16_t xe) {
uint8_t data[] = {
xs >> 8,
xs & 0xff,
xe >> 8,
xe & 0xff,
};
// CASET (2Ah): Column Address Set
st7789_cmd(0x2a, data, sizeof(data));
}
void st7789_raset(uint16_t ys, uint16_t ye) {
uint8_t data[] = {
ys >> 8,
ys & 0xff,
ye >> 8,
ye & 0xff,
};
// RASET (2Bh): Row Address Set
st7789_cmd(0x2b, data, sizeof(data));
}
void st7789_init(const struct st7789_config *config, uint16_t width, uint16_t height) {
memcpy(&st7789_cfg, config, sizeof(st7789_cfg));
st7789_width = width;
st7789_height = height;
spi_init(st7789_cfg.spi, 125 * 1000 * 1000);
if (st7789_cfg.gpio_cs > -1) {
spi_set_format(st7789_cfg.spi, 8, SPI_CPOL_0, SPI_CPHA_0, SPI_MSB_FIRST);
} else {
spi_set_format(st7789_cfg.spi, 8, SPI_CPOL_1, SPI_CPHA_1, SPI_MSB_FIRST);
}
gpio_set_function(st7789_cfg.gpio_din, GPIO_FUNC_SPI);
gpio_set_function(st7789_cfg.gpio_clk, GPIO_FUNC_SPI);
if (st7789_cfg.gpio_cs > -1) {
gpio_init(st7789_cfg.gpio_cs);
}
gpio_init(st7789_cfg.gpio_dc);
gpio_init(st7789_cfg.gpio_rst);
gpio_init(st7789_cfg.gpio_bl);
if (st7789_cfg.gpio_cs > -1) {
gpio_set_dir(st7789_cfg.gpio_cs, GPIO_OUT);
}
gpio_set_dir(st7789_cfg.gpio_dc, GPIO_OUT);
gpio_set_dir(st7789_cfg.gpio_rst, GPIO_OUT);
gpio_set_dir(st7789_cfg.gpio_bl, GPIO_OUT);
if (st7789_cfg.gpio_cs > -1) {
gpio_put(st7789_cfg.gpio_cs, 1);
}
gpio_put(st7789_cfg.gpio_dc, 1);
gpio_put(st7789_cfg.gpio_rst, 1);
sleep_ms(100);
// SWRESET (01h): Software Reset
st7789_cmd(0x01, NULL, 0);
sleep_ms(150);
// SLPOUT (11h): Sleep Out
st7789_cmd(0x11, NULL, 0);
sleep_ms(50);
// COLMOD (3Ah): Interface Pixel Format
// - RGB interface color format = 65K of RGB interface
// - Control interface color format = 16bit/pixel
st7789_cmd(0x3a, (uint8_t[]){0x55}, 1);
sleep_ms(10);
// MADCTL (36h): Memory Data Access Control
// - Page Address Order = Top to Bottom
// - Column Address Order = Left to Right
// - Page/Column Order = Normal Mode
// - Line Address Order = LCD Refresh Top to Bottom
// - RGB/BGR Order = RGB
// - Display Data Latch Data Order = LCD Refresh Left to Right
st7789_cmd(0x36, (uint8_t[]){0xA0}, 1);
st7789_caset(0, width);
st7789_raset(0, height);
// INVON (21h): Display Inversion On
st7789_cmd(0x21, NULL, 0);
sleep_ms(10);
// NORON (13h): Normal Display Mode On
st7789_cmd(0x13, NULL, 0);
sleep_ms(10);
// DISPON (29h): Display On
st7789_cmd(0x29, NULL, 0);
sleep_ms(10);
st7789_fill(0x0000);
sleep_ms(50);
gpio_put(st7789_cfg.gpio_bl, 1);
}
void st7789_ramwr() {
sleep_us(1);
if (st7789_cfg.gpio_cs > -1) {
gpio_put(st7789_cfg.gpio_cs, 0);
}
gpio_put(st7789_cfg.gpio_dc, 0);
sleep_us(1);
// RAMWR (2Ch): Memory Write
uint8_t cmd = 0x2c;
spi_write_blocking(st7789_cfg.spi, &cmd, sizeof(cmd));
sleep_us(1);
if (st7789_cfg.gpio_cs > -1) {
gpio_put(st7789_cfg.gpio_cs, 0);
}
gpio_put(st7789_cfg.gpio_dc, 1);
sleep_us(1);
}
void st7789_write(const void *data, size_t len) {
if (!st7789_data_mode) {
st7789_ramwr();
if (st7789_cfg.gpio_cs > -1) {
spi_set_format(st7789_cfg.spi, 16, SPI_CPOL_0, SPI_CPHA_0, SPI_MSB_FIRST);
} else {
spi_set_format(st7789_cfg.spi, 16, SPI_CPOL_1, SPI_CPHA_1, SPI_MSB_FIRST);
}
st7789_data_mode = true;
}
spi_write16_blocking(st7789_cfg.spi, data, len / 2);
}
void st7789_put(uint16_t pixel) { st7789_write(&pixel, sizeof(pixel)); }
void st7789_fill(uint16_t pixel) {
int num_pixels = st7789_width * st7789_height;
st7789_set_cursor(0, 0);
for (int i = 0; i < num_pixels; i++) {
st7789_put(pixel);
}
}
void st7789_set_cursor(uint16_t x, uint16_t y) {
st7789_caset(x, st7789_width);
st7789_raset(y, st7789_height);
}
void st7789_vertical_scroll(uint16_t row) {
uint8_t data[] = {(row >> 8) & 0xff, row & 0x00ff};
// VSCSAD (37h): Vertical Scroll Start Address of RAM
st7789_cmd(0x37, data, sizeof(data));
}