lcd-clock - initial commit

This commit is contained in:
Thomas Klaehn 2020-02-13 11:00:05 +00:00
commit 495f2861e7
17 changed files with 1482 additions and 0 deletions

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
bin/
obj/

144
Makefile Normal file
View File

@ -0,0 +1,144 @@
CROSS_COMPILE ?=
TARGET_FILE ?= test_c
CC = $(CROSS_COMPILE)gcc
CPP = $(CROSS_COMPILE)cpp
CHECK = cppcheck
LCOV = lcov
GENHTML = genhtml
SRC_DIR = src
OBJ_DIR = obj
BIN_DIR = bin
COVERAGE_DIR = coverage
UNIT_TEST_SRC_DIR = test/unit
UNIT_TEST_OBJ_DIR = $(OBJ_DIR)/$(UNIT_TEST_SRC_DIR)
PREFIX ?= /usr
BIN_INSTALL_DIR = $(PREFIX)/bin
INCLUDES := interface/
INCLUDES += include/
INCLUDES += include/$(ARCH)/
INCLUDES += $(PREFIX)/include/
INCLUDES += $(EXTRA_INC)
LIBS =
LD_FLAGS += $(addprefix -L,$(EXTRA_LIB_DIR))
ifneq "$(findstring $(MAKECMDGOALS), build_unit_test exec_unit_test coverage)" ""
INCLUDES += test/inc
C_FLAGS += --coverage
LD_FLAGS += --coverage
endif
C_FLAGS += -fpic
C_FLAGS += -O0 -g -Wall
CPP_FLAGS += $(addprefix -I, $(INCLUDES))
CHECK_FLAGS = $(addprefix -I,$(filter-out $(PREFIX)/include/,$(INCLUDES)))
CHECK_FLAGS += --enable=all --template=gcc --error-exitcode=1 --suppress=missingIncludeSystem --inline-suppr --force
C_SRCS = $(wildcard $(SRC_DIR)/*.c)
C_SRCS += $(wildcard $(SRC_DIR)/$(ARCH)/*.c)
C_OBJS = $(patsubst $(SRC_DIR)%,$(OBJ_DIR)%,$(patsubst %.c,%.o,$(C_SRCS)))
UNIT_TEST_SRCS = $(wildcard $(UNIT_TEST_SRC_DIR)/*.c) $(filter-out %main.c,$(CC_SRCS))
UNIT_TEST_OBJS = $(patsubst $(SRC_DIR)%,$(OBJ_DIR)%,$(patsubst $(UNIT_TEST_SRC_DIR)%,$(UNIT_TEST_OBJ_DIR)%,$(patsubst %.c,%.o,$(UNIT_TEST_SRCS))))
OBJS = $(C_OBJS)
UNIT_TEST_TARGET = $(BIN_DIR)/$(UNIT_TEST_SRC_DIR)/$(TARGET_FILE)
TARGET = $(BIN_DIR)/$(TARGET_FILE)
THIS_MAKEFILE := $(lastword $(MAKEFILE_LIST))
.PHONY: all install uninstall clean distclean debug
debug:
@echo $(C_SRCS)
@echo $(C_OBJS)
@echo $(ARCH)
@echo $(CPP_FLAGS)
all: $(TARGET)
install: all
install -d $(BIN_INSTALL_DIR)
install -m 0666 $(TARGET) $(BIN_INSTALL_DIR)
uninstall:
rm -f $(BIN_INSTALL_DIR)/$(TARGET_FILE)
clean:
rm -f $(TARGET)
rm -f $(OBJS) $(patsubst %.o,%.d,$(OBJS))
rm -f $(UNIT_TEST_OBJS) $(patsubst %.o,%.d,$(UNIT_TEST_OBJS)) $(UNIT_TEST_TARGET)
rm -f $(UNIT_TEST_OBJ_DIR)/*.gcda
rm -f $(UNIT_TEST_OBJ_DIR)/*.gcno
rm -f $(OBJ_DIR)/*.gcda $(OBJ_DIR)/*.gcno
rm -fr $(COVERAGE_DIR)
distclean:
rm -rf $(OBJ_DIR) $(BIN_DIR) $(COVERAGE_DIR)
.PHONY: coverage
coverage: _cov_genhtml
$(eval COVERAGE:=$(shell grep 'lines' .coverage.tmp | egrep -o '[0-9]+.[0-9]+%'))
@echo
@echo Line coverage: $(COVERAGE)
@echo
@rm -f .coverage.tmp
.PHONY: _cov_lcov
_cov_lcov: exec_unit_test
@rm -f $(UNIT_TEST_OBJ_DIR)/*.gcda
@rm -f $(UNIT_TEST_OBJ_DIR)/*.gcno
@mkdir -p $(COVERAGE_DIR)
$(LCOV) -c -d $(OBJ_DIR) -o $(COVERAGE_DIR)/coverage.info
.PHONY: _cov_genhtml
_cov_genhtml: _cov_lcov
$(GENHTML) -o $(COVERAGE_DIR)/html $(COVERAGE_DIR)/coverage.info > .coverage.tmp
.PHONY: unit_test
build_unit_test: $(UNIT_TEST_TARGET)
.PHONY: unit_test
exec_unit_test: $(UNIT_TEST_TARGET)
$(UNIT_TEST_TARGET)
.PHONY: check
check: $(CC_SRCS)
$(CHECK) $(CHECK_FLAGS) $(CC_SRCS)
$(UNIT_TEST_TARGET): $(UNIT_TEST_OBJS) $(THIS_MAKEFILE)
@mkdir -p $(BIN_DIR)/$(UNIT_TEST_SRC_DIR)
$(CC) $(CC_FLAGS) $(LD_FLAGS) $(UNIT_TEST_OBJS) -o $@
$(TARGET): $(OBJS) $(THIS_MAKEFILE)
@mkdir -p $(BIN_DIR)
$(CC) $(CC_FLAGS) $(LD_FLAGS) $(OBJS) $(addprefix -l,$(LIBS)) -o $@
.PRECIOUS: $(OBJ_DIR)/%.d
$(OBJ_DIR)/%.d: $(SRC_DIR)/%.c
@mkdir -p $(OBJ_DIR)/$(ARCH)
$(CPP) -MM -MF $@ -MP -MT $(patsubst %.d,%.o,$@) $(CPP_FLAGS) $(patsubst $(OBJ_DIR)/%.d,$(SRC_DIR)/%.c,$@)
.PRECIOUS: $(UNIT_TEST_OBJ_DIR)/%.d
$(UNIT_TEST_OBJ_DIR)/%.d: $(UNIT_TEST_SRC_DIR)/%.c
@mkdir -p $(UNIT_TEST_OBJ_DIR)
$(CPP) -MM -MF $@ -MP -MT $(patsubst %.d,%.o,$@) $(CPP_FLAGS) $(patsubst $(UNIT_TEST_OBJ_DIR)/%.d,$(UNIT_TEST_SRC_DIR)/%.c,$@)
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.c $(OBJ_DIR)/%.d
@mkdir -p $(OBJ_DIR)/$(ARCH)
$(CC) -c $(CPP_FLAGS) $(C_FLAGS) $< -o $@
$(UNIT_TEST_OBJ_DIR)/%.o: $(UNIT_TEST_SRC_DIR)/%.c $(UNIT_TEST_OBJ_DIR)/%.d
@mkdir -p $(UNIT_TEST_OBJ_DIR)
$(CC) -c $(CPP_FLAGS) $(C_FLAGS) $< -o $@
ifneq ($(MAKECMDGOALS),clean)
-include $(patsubst %.o,%.d,$(OBJS))
endif

168
include/posix/board.h Normal file
View File

@ -0,0 +1,168 @@
#ifndef __BOARD_H__
#define __BOARD_H__
#include "driver.h"
#include "posix/i2c.h"
#include "ssd1306.h"
#include "st7789.h"
#include "gpio.h"
#include "spi.h"
// Board file for the posix board
//// ST7789 LCD
// spi
static const char * const spi_dev_name = "/dev/spidev0.0";
static struct spi spi0 = {
.spi_device = spi_dev_name,
.mode = SPI_MODE_0,
.bits_per_word = 8,
.speed = 20000000,
};
static const struct driver spi0_drv = {
.fp = &spi_fp,
.dev = &spi0,
};
// data/command select gpio
static const struct gpio dc_select = {
.pin = 25,
};
static const struct driver dc_drv = {
.fp = &gpio_fp,
.dev = &dc_select,
};
// backlight gpio
static const struct gpio bl_select = {
.pin = 24,
};
static const struct driver bl_drv = {
.fp = &gpio_fp,
.dev = &bl_select,
};
// reset gpio
static const struct gpio rst_select = {
.pin = 27,
};
static const struct driver rst_drv = {
.fp = &gpio_fp,
.dev = &rst_select,
};
// lcd
static const struct st7789 lcd_dev = {
.spi = &spi0_drv,
.dc = &dc_drv,
.bl = &bl_drv,
.rst = &rst_drv,
.height = 240,
.width = 240,
};
static const struct driver lcd_drv = {
.fp = &st7789_fp,
.dev = &lcd_dev,
};
#if 0
// I2C driver
static const char * const i2c_dev_name = "/dev/i2c-1";
static struct i2c i2c_dev = {
.i2c_device = i2c_dev_name,
.slave_addr = 0x3c,
};
const char i2c_name[] = "i2c-1";
static const struct driver i2c_drv = {
.name = i2c_name,
.fp = &i2c_fp,
.dev = &i2c_dev,
};
// SSD 1306 driver
static char display_buffer[(SSD1306_LCDHEIGHT * SSD1306_LCDWIDTH / 8) + 1] = {
0x40,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x80, 0x80, 0xC0, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xF8, 0xE0, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80,
0x80, 0x80, 0x00, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0xFF,
0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00,
0x80, 0xFF, 0xFF, 0x80, 0x80, 0x00, 0x80, 0x80, 0x00, 0x80, 0x80, 0x80, 0x80, 0x00, 0x80, 0x80,
0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x8C, 0x8E, 0x84, 0x00, 0x00, 0x80, 0xF8,
0xF8, 0xF8, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xE0, 0xE0, 0xC0, 0x80,
0x00, 0xE0, 0xFC, 0xFE, 0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xC7, 0x01, 0x01,
0x01, 0x01, 0x83, 0xFF, 0xFF, 0x00, 0x00, 0x7C, 0xFE, 0xC7, 0x01, 0x01, 0x01, 0x01, 0x83, 0xFF,
0xFF, 0xFF, 0x00, 0x38, 0xFE, 0xC7, 0x83, 0x01, 0x01, 0x01, 0x83, 0xC7, 0xFF, 0xFF, 0x00, 0x00,
0x01, 0xFF, 0xFF, 0x01, 0x01, 0x00, 0xFF, 0xFF, 0x07, 0x01, 0x01, 0x01, 0x00, 0x00, 0x7F, 0xFF,
0x80, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x7F, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x01, 0xFF,
0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x03, 0x0F, 0x3F, 0x7F, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE7, 0xC7, 0xC7, 0x8F,
0x8F, 0x9F, 0xBF, 0xFF, 0xFF, 0xC3, 0xC0, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xFC, 0xFC,
0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xF8, 0xF8, 0xF0, 0xF0, 0xE0, 0xC0, 0x00, 0x01, 0x03, 0x03, 0x03,
0x03, 0x03, 0x01, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x03, 0x03, 0x03, 0x01, 0x01,
0x03, 0x01, 0x00, 0x00, 0x00, 0x01, 0x03, 0x03, 0x03, 0x03, 0x01, 0x01, 0x03, 0x03, 0x00, 0x00,
0x00, 0x03, 0x03, 0x00, 0x00, 0x00, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
0x03, 0x03, 0x03, 0x03, 0x03, 0x01, 0x00, 0x00, 0x00, 0x01, 0x03, 0x01, 0x00, 0x00, 0x00, 0x03,
0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x80, 0xC0, 0xE0, 0xF0, 0xF9, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x1F, 0x0F,
0x87, 0xC7, 0xF7, 0xFF, 0xFF, 0x1F, 0x1F, 0x3D, 0xFC, 0xF8, 0xF8, 0xF8, 0xF8, 0x7C, 0x7D, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x3F, 0x0F, 0x07, 0x00, 0x30, 0x30, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xFE, 0xFE, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xC0, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0xC0, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x7F, 0x3F, 0x1F,
0x0F, 0x07, 0x1F, 0x7F, 0xFF, 0xFF, 0xF8, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xF8, 0xE0,
0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFE, 0x00, 0x00,
0x00, 0xFC, 0xFE, 0xFC, 0x0C, 0x06, 0x06, 0x0E, 0xFC, 0xF8, 0x00, 0x00, 0xF0, 0xF8, 0x1C, 0x0E,
0x06, 0x06, 0x06, 0x0C, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFE, 0xFE, 0x00, 0x00, 0x00, 0x00, 0xFC,
0xFE, 0xFC, 0x00, 0x18, 0x3C, 0x7E, 0x66, 0xE6, 0xCE, 0x84, 0x00, 0x00, 0x06, 0xFF, 0xFF, 0x06,
0x06, 0xFC, 0xFE, 0xFC, 0x0C, 0x06, 0x06, 0x06, 0x00, 0x00, 0xFE, 0xFE, 0x00, 0x00, 0xC0, 0xF8,
0xFC, 0x4E, 0x46, 0x46, 0x46, 0x4E, 0x7C, 0x78, 0x40, 0x18, 0x3C, 0x76, 0xE6, 0xCE, 0xCC, 0x80,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x01, 0x07, 0x0F, 0x1F, 0x1F, 0x3F, 0x3F, 0x3F, 0x3F, 0x1F, 0x0F, 0x03,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x00, 0x00,
0x00, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x00, 0x00, 0x03, 0x07, 0x0E, 0x0C,
0x18, 0x18, 0x0C, 0x06, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x01, 0x0F, 0x0E, 0x0C, 0x18, 0x0C, 0x0F,
0x07, 0x01, 0x00, 0x04, 0x0E, 0x0C, 0x18, 0x0C, 0x0F, 0x07, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x00,
0x00, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x07,
0x07, 0x0C, 0x0C, 0x18, 0x1C, 0x0C, 0x06, 0x06, 0x00, 0x04, 0x0E, 0x0C, 0x18, 0x0C, 0x0F, 0x07,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
static const struct ssd1306 display_dev = {
.output_dev = &i2c_drv,
.output_buffer = &display_buffer[0],
.bitmap = &display_buffer[1],
.width = SSD1306_LCDWIDTH,
.heigth = SSD1306_LCDHEIGHT,
};
const char ssd1306_name[] = "ssd1306";
static const struct driver ssd1306_drv = {
.name = ssd1306_name,
.fp = &ssd1306_fp,
.dev = &display_dev,
};
#endif
#endif

29
include/posix/gpio.h Normal file
View File

@ -0,0 +1,29 @@
#ifndef __GPIO_H__
#define __GPIO_H__
#include <stdarg.h>
#include "driver.h"
#define IOCTL_CMD_SET_DIRECTION 0
int gpio_open(const struct driver *drv);
int gpio_close(const struct driver *drv);
int gpio_read(const struct driver *drv, char *buffer, unsigned int len);
int gpio_write(const struct driver *drv, const char *buffer, unsigned int len);
int gpio_ioctl(const struct driver *drv, unsigned int cmd, unsigned int argc, va_list args);
struct gpio {
int pin;
};
static const struct driver_fp gpio_fp = {
.open = gpio_open,
.close = gpio_close,
.read = gpio_read,
.write = gpio_write,
.ioctl = gpio_ioctl
};
#endif

25
include/posix/i2c.h Normal file
View File

@ -0,0 +1,25 @@
#ifndef __I2C_H__
#define __I2C_H__
#include "driver.h"
int i2c_open(const struct driver *drv);
int i2c_close(const struct driver *drv);
int i2c_read(const struct driver *drv, char *buffer, unsigned int len);
int i2c_write(const struct driver *drv, const char *buffer, unsigned int len);
struct i2c {
const char * i2c_device;
const uint8_t slave_addr;
int i2c_file;
};
static const struct driver_fp i2c_fp = {
.open = i2c_open,
.close = i2c_close,
.read = i2c_read,
.write = i2c_write,
};
#endif

37
include/posix/spi.h Normal file
View File

@ -0,0 +1,37 @@
#ifndef __SPI_H__
#define __SPI_H__
#include <stdarg.h>
#include <stdint.h>
#include <stdbool.h>
#include <linux/spi/spidev.h>
#include "driver.h"
int spi_open(const struct driver *drv);
int spi_close(const struct driver *drv);
int spi_read(const struct driver *drv, char *buffer, unsigned int len);
int spi_write(const struct driver *drv, const char *buffer, unsigned int len);
int spi_ioctl(const struct driver *drv, unsigned int cmd, unsigned int argc, va_list args);
struct spi {
const char * spi_device;
uint8_t mode;
uint8_t bits_per_word;
uint32_t speed;
int spi_file;
bool is_open;
};
static const struct driver_fp spi_fp = {
.open = spi_open,
.close = spi_close,
.read = spi_read,
.write = spi_write,
.ioctl = spi_ioctl,
};
#endif

37
include/ssd1306.h Normal file
View File

@ -0,0 +1,37 @@
#ifndef __SSD1306_H__
#define __SSD1306_H__
#include <stdarg.h>
#include "driver.h"
#define SSD1306_LCDWIDTH 128
#define SSD1306_LCDHEIGHT 64
#define IOCTL_CMD_CLS 0
#define IOCTL_CMD_REFRESH 1
#define IOCTL_CMD_DRAW_PIXEL 2
#define IOCTL_CMD_DRAW_LINE 3
#define IOCTL_CMD_DRAW_CIRCLE 4
int ssd1306_open(const struct driver *drv);
int ssd1306_close(const struct driver *drv);
int ssd1306_ioctl(const struct driver *drv, unsigned int cmd, unsigned int argc, va_list args);
struct ssd1306 {
const struct driver *output_dev;
char *output_buffer;
char *bitmap;
uint32_t width;
uint32_t heigth;
};
static const struct driver_fp ssd1306_fp = {
.open = ssd1306_open,
.close = ssd1306_close,
.read = NULL,
.write = NULL,
.ioctl = ssd1306_ioctl,
};
#endif

32
include/st7789.h Normal file
View File

@ -0,0 +1,32 @@
#ifndef __ST7789_H__
#define __ST7789_H__
#include <stdarg.h>
#include "driver.h"
#define IOCTL_CMD_DRAW_IMAGE 0
int st7789_open(const struct driver *drv);
int st7789_close(const struct driver *drv);
int st7789_write(const struct driver *drv, const char *buffer, unsigned int len);
struct st7789 {
const struct driver *spi;
const struct driver *dc;
const struct driver *bl;
const struct driver *rst;
unsigned int height;
unsigned int width;
};
static const struct driver_fp st7789_fp = {
.open = st7789_open,
.close = st7789_close,
.read = NULL,
.write = st7789_write,
.ioctl = NULL,
};
#endif

34
interface/driver.h Normal file
View File

@ -0,0 +1,34 @@
#ifndef __DRIVER_H__
#define __DRIVER_H__
#include <stdarg.h>
struct driver;
typedef int (*fp_open_t)(const struct driver *);
typedef int (*fp_close_t)(const struct driver *);
typedef int (*fp_read_t)(const struct driver *, char *, unsigned int);
typedef int (*fp_write_t)(const struct driver *, const char *, unsigned int);
typedef int (*fp_ioctl_t)(const struct driver *, unsigned int, unsigned int argc, va_list);
struct driver_fp {
fp_open_t open;
fp_close_t close;
fp_read_t read;
fp_write_t write;
fp_ioctl_t ioctl;
};
struct driver {
const char *name;
const struct driver_fp *fp;
const void *dev;
};
int drv_open(const struct driver *drv);
int drv_close(const struct driver *drv);
int drv_read(const struct driver *drv, char *buffer, unsigned int length);
int drv_write(const struct driver *drv, const char *buffer, unsigned int length);
int drv_ioctl(const struct driver *drv, unsigned int cmd, unsigned int argc, ...);
#endif

6
src/clock_face.h Normal file

File diff suppressed because one or more lines are too long

67
src/driver.c Normal file
View File

@ -0,0 +1,67 @@
#include <stdlib.h>
#include <assert.h>
#include "driver.h"
int drv_open(const struct driver *drv)
{
int res = -1;
assert(drv != NULL);
if(drv->fp->open) {
res = drv->fp->open(drv);
}
return res;
}
int drv_close(const struct driver *drv)
{
int res = -1;
assert(drv != NULL);
if(drv->fp->close) {
res = drv->fp->close(drv);
}
return res;
}
int drv_read(const struct driver *drv, char *buffer, unsigned int length)
{
int res = -1;
assert(drv != NULL);
if(drv->fp->read) {
res = drv->fp->read(drv, buffer, length);
}
return res;
}
int drv_write(const struct driver *drv, const char *buffer, unsigned int length)
{
int res = -1;
assert(drv != NULL);
if(drv->fp->write) {
res = drv->fp->write(drv, buffer, length);
}
return res;
}
int drv_ioctl(const struct driver *drv, unsigned int cmd, unsigned int argc, ...)
{
int res = -1;
assert(drv != NULL);
if(drv->fp->ioctl) {
va_list args;
va_start(args, argc);
res = drv->fp->ioctl(drv, cmd, argc, args);
va_end(args);
}
return res;
}

26
src/main.c Normal file
View File

@ -0,0 +1,26 @@
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <stdio.h>
#include "board.h"
#include "driver.h"
#include "clock_face.h"
uint16_t image[240 * 240];
int main(void)
{
drv_open(&lcd_drv);
for (uint16_t i = 0; i < 240 * 240; i++) {
image[i] = 0xffff;
}
drv_write(&lcd_drv, (const char *)image, 240 * 240);
sleep(5);
drv_write(&lcd_drv, (const char *)clock_face, 240 * 240);
sleep(5);
drv_close(&lcd_drv);
return 0;
}

168
src/posix/gpio.c Normal file
View File

@ -0,0 +1,168 @@
#include <assert.h>
#include <fcntl.h>
#include <stddef.h>
#include <stdio.h>
#include <unistd.h>
#include "gpio.h"
#define BUF_SIZE 3
#define DIRECTION_MAX 35
#define VALUE_MAX 30
static int gpio_export(int pin);
static int gpio_unexport(int pin);
static int gpio_set_direction(int pin, int dir);
int gpio_open(const struct driver *drv)
{
int res;
assert(NULL != drv);
struct gpio *this = (struct gpio *)(drv->dev);
res = gpio_unexport(this->pin);
res = gpio_export(this->pin);
usleep(100000); /* Wait until sysfs is exported. */
return res;
}
int gpio_close(const struct driver *drv)
{
int res;
assert(NULL != drv);
struct gpio *this = (struct gpio *)(drv->dev);
res = gpio_unexport(this->pin);
return res;
}
int gpio_read(const struct driver *drv, char *buffer, unsigned int len)
{
assert(NULL != drv);
char path[VALUE_MAX];
int fd;
struct gpio *this = (struct gpio *)(drv->dev);
snprintf(path, VALUE_MAX, "/sys/class/gpio/gpio%d/value", this->pin);
fd = open(path, O_RDONLY);
if(-1 == fd) {
return -1;
}
if(-1 == read(fd, buffer, len)) {
return -1;
}
close(fd);
return 0;
}
int gpio_write(const struct driver *drv, const char *buffer, unsigned int len)
{
assert(NULL != drv);
char path[VALUE_MAX];
int fd;
struct gpio *this = (struct gpio *)(drv->dev);
snprintf(path, VALUE_MAX, "/sys/class/gpio/gpio%d/value", this->pin);
fd = open(path, O_WRONLY);
if(-1 == fd) {
return -1;
}
int res;
if((res = write(fd, buffer, len)) != 1) {
return -1;
}
close(fd);
return 0;
}
int gpio_ioctl(const struct driver *drv, unsigned int cmd, unsigned int argc, va_list args)
{
assert(drv != 0);
int res = 0, dir;
struct gpio *this = (struct gpio *)(drv->dev);
switch(cmd) {
case IOCTL_CMD_SET_DIRECTION:
if(argc != 1) {
res = -1;
break;
}
dir = va_arg(args, int);
res = gpio_set_direction(this->pin, dir);
break;
}
return res;
}
static int gpio_export(int pin)
{
char buffer[BUF_SIZE];
ssize_t bytes_written;
int fd;
fd = open("/sys/class/gpio/export", O_WRONLY);
if(-1 == fd) {
return -1;
}
bytes_written = snprintf(buffer, BUF_SIZE, "%d", pin);
write(fd, buffer, bytes_written);
close(fd);
return 0;
}
static int gpio_unexport(int pin)
{
char buffer[BUF_SIZE];
ssize_t bytes_written;
int fd;
fd = open("/sys/class/gpio/unexport", O_WRONLY);
if(-1 == fd) {
return -1;
}
bytes_written = snprintf(buffer, BUF_SIZE, "%d", pin);
write(fd, buffer, bytes_written);
close(fd);
return 0;
}
static int gpio_set_direction(int pin, int dir)
{
static const char directions_str[] = "in\0out";
char path[DIRECTION_MAX];
int fd;
snprintf(path, DIRECTION_MAX, "/sys/class/gpio/gpio%d/direction", pin);
fd = open(path, O_WRONLY);
if(-1 == fd) {
return -1;
}
if(-1 == write(fd, &directions_str[0 == dir ? 0 : 3], 0 == dir ? 2 : 3)) {
return -1;
}
close(fd);
return 0;
}

67
src/posix/i2c.c Normal file
View File

@ -0,0 +1,67 @@
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/i2c-dev.h>
#include "posix/i2c.h"
int i2c_open(const struct driver *drv)
{
assert(drv != NULL);
struct i2c *i2c = (struct i2c *)(drv->dev);
if((i2c->i2c_file = open(i2c->i2c_device, O_RDWR)) < 0) {
fprintf(stderr, "Failed to open the i2c bus\r\n");
return -1;
}
if(ioctl(i2c->i2c_file, I2C_SLAVE, i2c->slave_addr) < 0) {
fprintf(stderr, "Failed to acquire bus access and/or talk to slave.\r\n");
return -2;
}
return 0;
}
int i2c_close(const struct driver *drv)
{
assert(drv != NULL);
struct i2c *i2c = (struct i2c *)(drv->dev);
close(i2c->i2c_file);
return 0;
}
int i2c_read(const struct driver *drv, char *buffer, unsigned int len)
{
assert(drv != NULL);
struct i2c *i2c = (struct i2c *)(drv->dev);
if(read(i2c->i2c_file, buffer, len) != len) {
fprintf(stderr, "Failed to read from the i2c bus.\r\n");
return -1;
}
return len;
}
int i2c_write(const struct driver *drv, const char *buffer, unsigned int len)
{
assert(drv != NULL);
struct i2c *i2c = (struct i2c *)(drv->dev);
if(write(i2c->i2c_file, buffer, len) != len) {
fprintf(stderr, "Failed to write to the i2c bus.\r\n");
return -1;
}
return len;
}

120
src/posix/spi.c Normal file
View File

@ -0,0 +1,120 @@
#include <assert.h>
#include <fcntl.h>
#include <stddef.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include "spi.h"
int spi_open(const struct driver *drv)
{
assert(drv != NULL);
int res;
struct spi *this = (struct spi *)(drv->dev);
// open spi dev
this->spi_file = open(this->spi_device, O_RDWR);
if(this->spi_file < 0) {
return this->spi_file;
}
// set spi mode
res = ioctl(this->spi_file, SPI_IOC_WR_MODE, &(this->mode));
if(res < 0) {
close(this->spi_file);
return res;
}
res = ioctl(this->spi_file, SPI_IOC_RD_MODE, &(this->mode));
if(res < 0) {
close(this->spi_file);
return res;
}
// set word length
res = ioctl(this->spi_file, SPI_IOC_WR_BITS_PER_WORD, &(this->bits_per_word));
if(res < 0) {
close(this->spi_file);
return res;
}
res = ioctl(this->spi_file, SPI_IOC_RD_BITS_PER_WORD, &(this->bits_per_word));
if(res < 0) {
close(this->spi_file);
return res;
}
// set max speed
res = ioctl(this->spi_file, SPI_IOC_WR_MAX_SPEED_HZ, &(this->speed));
if(res < 0) {
close(this->spi_file);
return res;
}
res = ioctl(this->spi_file, SPI_IOC_RD_MAX_SPEED_HZ, &(this->speed));
if(res < 0) {
close(this->spi_file);
return res;
}
this->is_open = true;
return res;
}
int spi_close(const struct driver *drv)
{
assert(drv != NULL);
int res = -1;
struct spi *this = (struct spi *)(drv->dev);
if(this->is_open == true) {
close(this->spi_file);
this->is_open = false;
res = 0;
}
return res;
}
int spi_read(const struct driver *drv, char *buffer, unsigned int len)
{
assert(drv != NULL);
struct spi *this = (struct spi *)(drv->dev);
struct spi_ioc_transfer tr = {
.tx_buf = (unsigned long)0,
.rx_buf = (unsigned long)buffer,
.delay_usecs = 0,
.speed_hz = this->speed,
.bits_per_word = this->bits_per_word,
.len = len,
};
int res = ioctl(this->spi_file, SPI_IOC_MESSAGE(1), &tr);
return res;
}
int spi_write(const struct driver *drv, const char *buffer, unsigned int len)
{
assert(drv != NULL);
struct spi *this = (struct spi *)(drv->dev);
struct spi_ioc_transfer tr = {
.tx_buf = (unsigned long)buffer,
.rx_buf = (unsigned long)0,
.len = len,
.delay_usecs = 0,
.speed_hz = this->speed,
.bits_per_word = this->bits_per_word,
};
int res = ioctl(this->spi_file, SPI_IOC_MESSAGE(1), &tr);
return res;
}
int spi_ioctl(const struct driver *drv, unsigned int cmd, unsigned int argc, va_list args)
{
assert(drv != NULL);
return 0;
}

249
src/ssd1306.c Normal file
View File

@ -0,0 +1,249 @@
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include "ssd1306.h"
static void ssd1306_display(const struct driver *drv);
static void ssd1306_cls(const struct driver *drv);
static void ssd1306_dot(const struct driver *drv, uint32_t x, uint32_t y);
static void ssd1306_line(const struct driver *drv, int16_t x0, int16_t y0, int16_t x1, int16_t y1);
static void ssd1306_circle(const struct driver *drv, int16_t x0, int16_t y0, int16_t radius);
static void ssd1306_on(const struct driver *drv);
static void ssd1306_off(const struct driver *drv);
static void ssd1306_cmd(const struct driver *drv, uint8_t c);
static void ssd1306_reset_cursor(const struct driver *drv);
int ssd1306_open(const struct driver *drv)
{
assert(drv != NULL);
struct ssd1306 *this = (struct ssd1306 *)(drv->dev);
drv_open(this->output_dev);
ssd1306_off(drv);
ssd1306_cmd(drv, 0xa8); // Set Multiplex Ratio
ssd1306_cmd(drv, 0x3f); // Value
ssd1306_cmd(drv, 0xd3); // Set Display offset
ssd1306_cmd(drv, 0x00); // no vertical shift
ssd1306_cmd(drv, 0x40); // set display start line
ssd1306_cmd(drv, 0xa1); // set segment re-map
ssd1306_cmd(drv, 0xc8);
ssd1306_cmd(drv, 0xda);
ssd1306_cmd(drv, 0x12);
ssd1306_cmd(drv, 0xa4);
ssd1306_cmd(drv, 0xa6);
ssd1306_cmd(drv, 0xd5);
ssd1306_cmd(drv, 0x80);
ssd1306_cmd(drv, 0x8d);
ssd1306_cmd(drv, 0x14);
ssd1306_cmd(drv, 0x20);
ssd1306_cmd(drv, 0x20);
ssd1306_on(drv);
ssd1306_reset_cursor(drv);
return 0;
}
int ssd1306_close(const struct driver *drv)
{
assert(drv != 0);
struct ssd1306 *this = (struct ssd1306 *)(drv->dev);
ssd1306_off(drv);
drv_close(this->output_dev);
return 0;
}
int ssd1306_ioctl(const struct driver *drv, unsigned int cmd, unsigned int argc, va_list args)
{
assert(drv != 0);
int res = 0;
unsigned int xy[4];
switch(cmd) {
case IOCTL_CMD_CLS:
ssd1306_cls(drv);
break;
case IOCTL_CMD_REFRESH:
ssd1306_display(drv);
break;
case IOCTL_CMD_DRAW_PIXEL:
if(argc != 2) {
res = -1;
break;
}
for(unsigned int i = 0; i < argc; i++) {
xy[i] = va_arg(args, unsigned int);
}
ssd1306_dot(drv, xy[0], xy[1]);
break;
case IOCTL_CMD_DRAW_LINE:
if(argc != 4) {
res = -1;
break;
}
for(unsigned int i = 0; i < argc; i++) {
xy[i] = va_arg(args, unsigned int);
}
ssd1306_line(drv, xy[0], xy[1], xy[2], xy[3]);
break;
case IOCTL_CMD_DRAW_CIRCLE:
if(argc != 3) {
res = -1;
break;
}
for(unsigned int i = 0; i < argc; i++) {
xy[i] = va_arg(args, unsigned int);
}
ssd1306_circle(drv, xy[0], xy[1], xy[2]);
break;
}
return res;
}
static void ssd1306_cmd(const struct driver *drv, uint8_t c)
{
assert(drv != NULL);
struct ssd1306 *this = (struct ssd1306 *)(drv->dev);
char control[] = {0x00, c}; // Co = 0, D/C = 0
drv_write(this->output_dev, control, sizeof(control));
}
static void ssd1306_off(const struct driver *drv)
{
assert(drv != NULL);
ssd1306_cmd(drv, 0xae); // display off
}
static void ssd1306_on(const struct driver *drv)
{
assert(drv != NULL);
ssd1306_cmd(drv, 0xaf); // display on
}
static void ssd1306_reset_cursor(const struct driver *drv)
{
assert(drv != NULL);
ssd1306_cmd(drv, 0x21); // # set column address
ssd1306_cmd(drv, 0x00); // # set start address
ssd1306_cmd(drv, 0x7F); // # set end address (127 max)
ssd1306_cmd(drv, 0x22); // # set page address
ssd1306_cmd(drv, 0x00); // # set start address
ssd1306_cmd(drv, 0x07); // # set end address (7 max)
}
static void ssd1306_cls(const struct driver *drv)
{
assert(drv != NULL);
struct ssd1306 *this = (struct ssd1306 *)(drv->dev);
memset(this->bitmap, 0x00, (SSD1306_LCDWIDTH * SSD1306_LCDHEIGHT / 8));
}
static void ssd1306_display(const struct driver *drv)
{
assert(drv != NULL);
struct ssd1306 *this = (struct ssd1306 *)(drv->dev);
drv_write(this->output_dev, this->output_buffer, (SSD1306_LCDWIDTH * SSD1306_LCDHEIGHT / 8) + 1);
}
static void ssd1306_dot(const struct driver *drv, uint32_t x, uint32_t y)
{
assert(drv != NULL);
struct ssd1306 *this = (struct ssd1306 *)(drv->dev);
this->bitmap[x + (y / 8) * SSD1306_LCDWIDTH] |= (1 << (y & 7));
}
#ifndef _swap_int16_t
#define _swap_int16_t(a, b) { int16_t t = a; a = b; b = t; }
#endif
static void ssd1306_line(const struct driver *drv, int16_t x0, int16_t y0, int16_t x1, int16_t y1)
{
assert(drv != NULL);
int16_t steep = abs(y1 - y0) > abs(x1 - x0);
if(steep) {
_swap_int16_t(x0, y0);
_swap_int16_t(x1, y1);
}
if(x0 > x1) {
_swap_int16_t(x0, x1);
_swap_int16_t(y0, y1);
}
int16_t dx, dy;
dx = x1 - x0;
dy = abs(y1 - y0);
int16_t err = dx / 2;
int16_t ystep;
if(y0 < y1) {
ystep = 1;
} else {
ystep = -1;
}
for(; x0 <= x1; x0++) {
if(steep) {
ssd1306_dot(drv, y0, x0);
} else {
ssd1306_dot(drv, x0, y0);
}
err -= dy;
if (err < 0) {
y0 += ystep;
err += dx;
}
}
}
static void ssd1306_circle(const struct driver *drv, int16_t x0, int16_t y0, int16_t radius)
{
assert(drv != NULL);
int16_t x = 0, y = radius;
int16_t dp = 1 - radius;
do {
if (dp < 0) {
dp = dp + (x++) * 2 + 3;
} else {
dp = dp + (x++) * 2 - (y--) * 2 + 5;
}
ssd1306_dot(drv, x0 + x, y0 + y); //For the 8 octants
ssd1306_dot(drv, x0 - x, y0 + y);
ssd1306_dot(drv, x0 + x, y0 - y);
ssd1306_dot(drv, x0 - x, y0 - y);
ssd1306_dot(drv, x0 + y, y0 + x);
ssd1306_dot(drv, x0 - y, y0 + x);
ssd1306_dot(drv, x0 + y, y0 - x);
ssd1306_dot(drv, x0 - y, y0 - x);
} while (x < y);
ssd1306_dot(drv, x0 + radius, y0);
ssd1306_dot(drv, x0, y0 + radius);
ssd1306_dot(drv, x0 - radius, y0);
ssd1306_dot(drv, x0, y0 - radius);
}

270
src/st7789.c Normal file
View File

@ -0,0 +1,270 @@
#include <assert.h>
#include <stddef.h>
#include <stdint.h>
#include <unistd.h>
#include "st7789.h"
static void send_cmd(const struct driver *drv, uint8_t cmd);
static void send_data_8bit(const struct driver *drv, uint8_t data);
static void lcd_init(const struct driver *drv);
static void lcd_set_windows(const struct driver *drv, uint16_t x_start, uint16_t y_start, uint16_t x_end, uint16_t y_end);
#if 0
static void send_data_16bit(const struct driver *drv, uint16_t data);
static void lcd_clear(const struct driver *drv, uint16_t color);
static void lcd_display(const struct driver *drv, const uint16_t *image);
static void lcd_draw_pixel(const struct driver *drv, uint16_t x, uint16_t y, uint16_t color);
#endif
int st7789_open(const struct driver *drv)
{
assert(drv != NULL);
struct st7789 *this = (struct st7789*)(drv->dev);
int res = drv_open(this->rst);
if(res < 0) {
return res;
}
res = drv_ioctl(this->rst, 0, 1, 1);
if(res < 0) {
drv_close(this->rst);
return res;
}
res = drv_write(this->rst, "1", 1);
if(res < 0) {
drv_close(this->rst);
return res;
}
res = drv_open(this->dc);
if(res < 0) {
drv_close(this->rst);
return res;
}
res = drv_ioctl(this->dc, 0, 1, 1);
if(res < 0) {
drv_close(this->rst);
drv_close(this->dc);
return res;
}
res = drv_write(this->dc, "1", 1);
if(res < 0) {
drv_close(this->rst);
drv_close(this->dc);
return res;
}
res = drv_open(this->bl);
if(res < 0) {
drv_close(this->rst);
drv_close(this->dc);
return res;
}
res = drv_ioctl(this->bl, 0, 1, 1);
if(res < 0) {
drv_close(this->rst);
drv_close(this->dc);
drv_close(this->bl);
return res;
}
res = drv_write(this->bl, "1", 1);
if(res < 0) {
drv_close(this->rst);
drv_close(this->dc);
drv_close(this->bl);
return res;
}
res = drv_open(this->spi);
if(res < 0) {
drv_close(this->rst);
drv_close(this->dc);
drv_close(this->bl);
return res;
}
// hard reset
res = drv_write(this->rst, "0", 1);
usleep(100 * 1000);
res = drv_write(this->rst, "1", 1);
usleep(100 * 1000);
lcd_init(drv);
return 0;
}
int st7789_close(const struct driver *drv)
{
assert(drv != NULL);
struct st7789 *this = (struct st7789*)(drv->dev);
drv_close(this->rst);
drv_close(this->dc);
drv_close(this->bl);
drv_close(this->spi);
return 0;
}
int st7789_write(const struct driver *drv, const char *buffer, unsigned int len)
{
assert(drv != NULL);
struct st7789 *this = (struct st7789*)(drv->dev);
uint16_t *image = (uint16_t *)buffer;
lcd_set_windows(drv, 0, 0, this->width, this->height);
drv_write(this->dc, "1", 1);
for (uint16_t i = 0; i < this->height; i++) {
drv_write(this->spi, (const char *)&image[i * this->width], this->width * 2);
}
return len;
}
static void send_cmd(const struct driver *drv, uint8_t cmd)
{
assert(drv != NULL);
struct st7789 *this = (struct st7789*)(drv->dev);
drv_write(this->dc, "0", 1);
drv_write(this->spi, (const char* )&cmd, 1);
}
static void send_data_8bit(const struct driver *drv, uint8_t data)
{
assert(drv != NULL);
struct st7789 *this = (struct st7789*)(drv->dev);
drv_write(this->dc, "1", 1);
drv_write(this->spi, (const char* )&data, 1);
}
static void lcd_init(const struct driver *drv)
{
send_cmd(drv, 0x3A);
send_data_8bit(drv, 0x05);
send_cmd(drv, 0xB2);
send_data_8bit(drv, 0x0C);
send_data_8bit(drv, 0x0C);
send_data_8bit(drv, 0x00);
send_data_8bit(drv, 0x33);
send_data_8bit(drv, 0x33);
send_cmd(drv, 0xB7); //Gate Control
send_data_8bit(drv, 0x35);
send_cmd(drv, 0xBB); //VCOM Setting
send_data_8bit(drv, 0x19);
send_cmd(drv, 0xC0); //LCM Control
send_data_8bit(drv, 0x2C);
send_cmd(drv, 0xC2); //VDV and VRH Command Enable
send_data_8bit(drv, 0x01);
send_cmd(drv, 0xC3); //VRH Set
send_data_8bit(drv, 0x12);
send_cmd(drv, 0xC4); //VDV Set
send_data_8bit(drv, 0x20);
send_cmd(drv, 0xC6); //Frame Rate Control in Normal Mode
send_data_8bit(drv, 0x0F);
send_cmd(drv, 0xD0); // Power Control 1
send_data_8bit(drv, 0xA4);
send_data_8bit(drv, 0xA1);
send_cmd(drv, 0xE0); //Positive Voltage Gamma Control
send_data_8bit(drv, 0xD0);
send_data_8bit(drv, 0x04);
send_data_8bit(drv, 0x0D);
send_data_8bit(drv, 0x11);
send_data_8bit(drv, 0x13);
send_data_8bit(drv, 0x2B);
send_data_8bit(drv, 0x3F);
send_data_8bit(drv, 0x54);
send_data_8bit(drv, 0x4C);
send_data_8bit(drv, 0x18);
send_data_8bit(drv, 0x0D);
send_data_8bit(drv, 0x0B);
send_data_8bit(drv, 0x1F);
send_data_8bit(drv, 0x23);
send_cmd(drv, 0xE1); //Negative Voltage Gamma Control
send_data_8bit(drv, 0xD0);
send_data_8bit(drv, 0x04);
send_data_8bit(drv, 0x0C);
send_data_8bit(drv, 0x11);
send_data_8bit(drv, 0x13);
send_data_8bit(drv, 0x2C);
send_data_8bit(drv, 0x3F);
send_data_8bit(drv, 0x44);
send_data_8bit(drv, 0x51);
send_data_8bit(drv, 0x2F);
send_data_8bit(drv, 0x1F);
send_data_8bit(drv, 0x1F);
send_data_8bit(drv, 0x20);
send_data_8bit(drv, 0x23);
send_cmd(drv, 0x21); //Display Inversion On
send_cmd(drv, 0x11); //Sleep Out
send_cmd(drv, 0x29); //Display On
}
static void lcd_set_windows(const struct driver *drv, uint16_t x_start, uint16_t y_start, uint16_t x_end, uint16_t y_end)
{
//set the X coordinates
send_cmd(drv, 0x2A);
send_data_8bit(drv, (x_start >> 8) & 0xFF);
send_data_8bit(drv, x_start & 0xFF);
send_data_8bit(drv, ((x_end - 1) >> 8) & 0xFF);
send_data_8bit(drv, (x_end - 1) & 0xFF);
//set the Y coordinates
send_cmd(drv, 0x2B);
send_data_8bit(drv, (y_start >> 8) & 0xFF);
send_data_8bit(drv, y_start & 0xFF);
send_data_8bit(drv, ((y_end - 1) >> 8) & 0xFF);
send_data_8bit(drv, (y_end - 1) & 0xFF);
send_cmd(drv, 0X2C);
}
#if 0
static void send_data_16bit(const struct driver *drv, uint16_t data)
{
assert(drv != NULL);
struct st7789 *this = (struct st7789*)(drv->dev);
uint8_t buf[2] = {(data >> 8) & 0xff, data & 0xff};
drv_write(this->dc, "1", 1);
drv_write(this->spi, (const char* )buf, 2);
}
static void lcd_clear(const struct driver *drv, uint16_t color)
{
assert(drv != NULL);
struct st7789 *this = (struct st7789*)(drv->dev);
uint16_t image[this->height * this->width];
color = ((color << 8) & 0xff00) | (color >> 8);
for (uint16_t i = 0; i < this->height * this->width; i++) {
image[i] = color;
}
lcd_set_windows(drv, 0, 0, this->width, this->height);
drv_write(this->dc, "1", 1);
for(uint16_t i = 0; i < this->height; i++) {
drv_write(this->spi, (const char *)&image[i * this->width], this->width * 2);
}
}
static void lcd_display(const struct driver *drv, const uint16_t *image)
{
assert(drv != NULL);
struct st7789 *this = (struct st7789*)(drv->dev);
lcd_set_windows(drv, 0, 0, this->width, this->height);
drv_write(this->dc, "1", 1);
for (uint16_t i = 0; i < this->height; i++) {
drv_write(this->spi, (const char *)&image[i * this->width], this->width * 2);
}
}
static void lcd_draw_pixel(const struct driver *drv, uint16_t x, uint16_t y, uint16_t color)
{
lcd_set_windows(drv, x, y, x + 1, y + 1);
send_data_16bit(drv, color);
}
#endif