i fucked up my repos

This commit is contained in:
2026-06-27 20:04:13 +02:00
commit 40dad2e4cd
4 changed files with 275 additions and 0 deletions

5
CMakeLists.txt Normal file
View File

@@ -0,0 +1,5 @@
idf_component_register(
SRCS "st7920.c"
INCLUDE_DIRS "."
REQUIRES esp_driver_spi esp_driver_gpio
)

9
README.md Normal file
View File

@@ -0,0 +1,9 @@
# ST7920 display driver
For esp-idf since there's no fucking driver for it appearently
Ngl a clanker wrote most of it, thx claude. I made it better, cleaner, more optimized (?) and more readable. The clanker got it to work but man the code was ass.
It's geared to work with my own gfx library, it exposes draw/clear pixel funcs. Nothing else, other than basic init functions and backlight.
### Todo
- idk add backlight pwm maybe? it does work fine rn

156
st7920.c Normal file
View File

@@ -0,0 +1,156 @@
#include "st7920.h"
#include <string.h>
#include "esp_log.h"
#include "driver/gpio.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "rom/ets_sys.h"
/* ST7920 display driver lib
* regretfully a clanker wrote most of this. first try too, good shit claude
* i did make make the code cleaner, less ass in geneneral and optimized it a bit */
static const char *TAG = "ST7920";
// ST7920 SPI protocol uses specific byte sequences
// Format: 11111ABC where ABC identifies sync, R/W, RS bits
#define ST7920_SYNC_CMD 0xF8 // 11111000 - Sync + Command
#define ST7920_SYNC_DATA 0xFA // 11111010 - Sync + Data
// Timing delays (in microseconds)
#define ST7920_DELAY_CMD 72
#define ST7920_DELAY_DATA 72
#define ST7920_DELAY_RESET 100000 // 100ms
static esp_err_t st7920_spi_send(const st7920_device_t *dev, const uint8_t sync_byte, const uint8_t data) {
spi_transaction_t trans = {
.flags = 0,
.length = 24, // 3 bytes = 24 bits
.tx_data = {sync_byte, data & 0xF0, (data << 4) & 0xF0},
.rx_buffer = NULL,
};
trans.flags = SPI_TRANS_USE_TXDATA;
const esp_err_t ret = spi_device_polling_transmit(dev->spi, &trans);
return ret;
}
esp_err_t st7920_send_cmd(const st7920_device_t *dev, const uint8_t cmd) {
const esp_err_t ret = st7920_spi_send(dev, ST7920_SYNC_CMD, cmd);
ets_delay_us(ST7920_DELAY_CMD);
return ret;
}
esp_err_t st7920_send_data(const st7920_device_t *dev, const uint8_t data) {
const esp_err_t ret = st7920_spi_send(dev, ST7920_SYNC_DATA, data);
ets_delay_us(ST7920_DELAY_DATA);
return ret;
}
esp_err_t st7920_init(const st7920_config_t *config, st7920_device_t *device) {
memset(device, 0, sizeof(st7920_device_t)); // clears framebuffer too
device->pin_cs = config->pin_cs;
device->pin_bl = config->pin_bl;
// Configure CS pin
gpio_config_t io_conf = {
.pin_bit_mask = (1ULL << config->pin_cs),
.mode = GPIO_MODE_OUTPUT,
.pull_up_en = GPIO_PULLUP_ENABLE,
.pull_down_en = GPIO_PULLDOWN_DISABLE,
.intr_type = GPIO_INTR_DISABLE,
};
gpio_config(&io_conf);
gpio_set_level(config->pin_cs, 1);
// Configure BL pin if provided
if (config->pin_bl >= 0) {
io_conf.pin_bit_mask = (1ULL << config->pin_bl); // reuse part of ocnfig from CS pin
gpio_config(&io_conf);
st7920_set_backlight(device, 0);
}
// Configure SPI device
const spi_device_interface_config_t dev_cfg = {
.clock_speed_hz = config->spi_clock_speed_hz,
.mode = 3, // CPOL=1, CPHA=1 (required by ST7920)
.spics_io_num = -1, // We manage CS manually
.queue_size = 1,
.flags = SPI_DEVICE_NO_DUMMY,
};
const esp_err_t ret = spi_bus_add_device(config->spi_host, &dev_cfg, &device->spi);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Failed to add SPI device: %s", esp_err_to_name(ret));
return ret;
}
// start talking to the thing
vTaskDelay(pdMS_TO_TICKS(50)); // Wait after reset
st7920_send_cmd(device, ST7920_CMD_BASIC_FUNC);
vTaskDelay(pdMS_TO_TICKS(1));
st7920_send_cmd(device, ST7920_CMD_BASIC_FUNC);
ets_delay_us(100);
st7920_send_cmd(device, ST7920_CMD_CLEAR);
vTaskDelay(pdMS_TO_TICKS(10)); // Clear needs longer time
st7920_send_cmd(device, ST7920_CMD_ENTRY_MODE);
ets_delay_us(100);
st7920_send_cmd(device, ST7920_CMD_GRAPHIC_ON);
ets_delay_us(100);
st7920_send_cmd(device, ST7920_CMD_DISPLAY_ON);
ets_delay_us(100);
ESP_LOGI(TAG, "display init done");
return ESP_OK;
}
esp_err_t st7920_clear(st7920_device_t *dev) {
memset(dev->framebuffer, 0, sizeof(dev->framebuffer));
// Clear display RAM
st7920_send_cmd(dev, ST7920_CMD_BASIC_FUNC);
st7920_send_cmd(dev, ST7920_CMD_CLEAR);
vTaskDelay(pdMS_TO_TICKS(10));
st7920_send_cmd(dev, ST7920_CMD_GRAPHIC_ON);
return ESP_OK;
}
esp_err_t st7920_set_backlight(const st7920_device_t *dev, const bool backlight) {
return gpio_set_level(dev->pin_bl, backlight);
}
esp_err_t st7920_update_screen(const st7920_device_t *dev) {
// ST7920 is actually two 128x32 disps, we send row by row to each of them
for (uint8_t y = 0; y < 64; y++) {
const bool upper_half = y < 32;
st7920_send_cmd(dev, ST7920_CMD_SET_GRAPHIC_ADDR | (upper_half ? y : y - 32)); // adjust y pos if we're on 2nd screen
st7920_send_cmd(dev, ST7920_CMD_SET_GRAPHIC_ADDR | (upper_half ? 0x00 : 0x08)); // 2nd screen has a different addr
for (uint8_t x = 0; x < 16; x++)
st7920_send_data(dev, dev->framebuffer[y * 16 + x]);
}
return ESP_OK;
}
static void st7920_set_pixel_color(st7920_device_t *dev, const uint8_t x, const uint8_t y, const uint8_t color) {
if (x >= ST7920_WIDTH || y >= ST7920_HEIGHT)
return;
const uint16_t byte_index = (y * (ST7920_WIDTH / 8)) + (x / 8);
const uint8_t bit_index = 7 - (x % 8);
if (color)
dev->framebuffer[byte_index] |= (1 << bit_index);
else
dev->framebuffer[byte_index] &= ~(1 << bit_index);
}
void st7920_draw_pixel(void *dev, const uint8_t x, const uint8_t y) {
st7920_set_pixel_color(dev, x, y, 1);
}
void st7920_clear_pixel(void *dev, const uint8_t x, const uint8_t y) {
st7920_set_pixel_color(dev, x, y, 0);
}

105
st7920.h Normal file
View File

@@ -0,0 +1,105 @@
#ifndef ST7920_H
#define ST7920_H
#include "esp_err.h"
#include "driver/spi_master.h"
// Display dimensions
#define ST7920_WIDTH 128
#define ST7920_HEIGHT 64
// SPI commands for ST7920
#define ST7920_CMD_BASIC_FUNC 0x30 // Basic instruction set
#define ST7920_CMD_EXTENDED_FUNC 0x34 // Extended instruction set
#define ST7920_CMD_DISPLAY_ON 0x0C // Display ON
#define ST7920_CMD_DISPLAY_OFF 0x08 // Display OFF
#define ST7920_CMD_CLEAR 0x01 // Clear display
#define ST7920_CMD_ENTRY_MODE 0x06 // Entry mode
#define ST7920_CMD_HOME 0x02 // Return home
#define ST7920_CMD_GRAPHIC_ON 0x36 // Extended + Graphic mode ON
#define ST7920_CMD_SET_GRAPHIC_ADDR 0x80 // Set GDRAM address
// Configuration structure
typedef struct {
spi_host_device_t spi_host;
int pin_cs;
int pin_bl;
int spi_clock_speed_hz;
} st7920_config_t;
// Handle for ST7920 device
typedef struct {
spi_device_handle_t spi;
int pin_cs;
int pin_bl;
uint8_t framebuffer[ST7920_WIDTH * ST7920_HEIGHT / 8];
} st7920_device_t;
/**
* @brief Initialize ST7920 display
*
* @param config Configuration structure
* @param out_dev Pointer to store device handle
* @return esp_err_t ESP_OK on success
*/
esp_err_t st7920_init(const st7920_config_t *config, st7920_device_t *device);
/**
* @brief Send command to ST7920
*
* @param dev Device handle
* @param cmd Command byte
* @return esp_err_t ESP_OK on success
*/
esp_err_t st7920_send_cmd(const st7920_device_t *dev, uint8_t cmd);
/**
* @brief Send data to ST7920
*
* @param dev Device handle
* @param data Data byte
* @return esp_err_t ESP_OK on success
*/
esp_err_t st7920_send_data(const st7920_device_t *dev, uint8_t data);
/**
* @brief Clear the display
*
* @param dev Device handle
* @return esp_err_t ESP_OK on success
*/
esp_err_t st7920_clear(st7920_device_t *dev);
/**
* @brief Set backlight on or off
*
* @param dev Device handle
* @param backlight Backlight enabled
*/
esp_err_t st7920_set_backlight(const st7920_device_t *dev, bool backlight);
/**
* @brief Update the entire display with framebuffer contents
*
* @param dev Device handle
* @return esp_err_t ESP_OK on success
*/
esp_err_t st7920_update_screen(const st7920_device_t *dev);
/**
* @brief Turn a pixel ON at given coordinates
* @param dev Device handle
* @param x x coordinate
* @param y y coordinate
*/
void st7920_draw_pixel(void *dev, uint8_t x, uint8_t y);
/**
* @brief Turn a pixel OFF at given coordinates
* @param dev Device handle
* @param x x coordinate
* @param y y coordinate
*/
void st7920_clear_pixel(void *dev, uint8_t x, uint8_t y);
#endif // ST7920_H