i fucked up my repos
This commit is contained in:
156
st7920.c
Normal file
156
st7920.c
Normal 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);
|
||||
}
|
||||
Reference in New Issue
Block a user