lcd-clock - initial commit
This commit is contained in:
commit
495f2861e7
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
bin/
|
||||||
|
obj/
|
||||||
|
|
144
Makefile
Normal file
144
Makefile
Normal 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
168
include/posix/board.h
Normal 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
29
include/posix/gpio.h
Normal 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
25
include/posix/i2c.h
Normal 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
37
include/posix/spi.h
Normal 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
37
include/ssd1306.h
Normal 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
32
include/st7789.h
Normal 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
34
interface/driver.h
Normal 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
6
src/clock_face.h
Normal file
File diff suppressed because one or more lines are too long
67
src/driver.c
Normal file
67
src/driver.c
Normal 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
26
src/main.c
Normal 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
168
src/posix/gpio.c
Normal 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
67
src/posix/i2c.c
Normal 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
120
src/posix/spi.c
Normal 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
249
src/ssd1306.c
Normal 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
270
src/st7789.c
Normal 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
|
Loading…
x
Reference in New Issue
Block a user