diff --git a/src/07_miniproj/oled/Makefile b/src/07_miniproj/oled/Makefile new file mode 100644 index 0000000..6eff97c --- /dev/null +++ b/src/07_miniproj/oled/Makefile @@ -0,0 +1,58 @@ +EXEC=oleds +DTB = mydt.dtb +SRCS=$(wildcard *.c) + +target=nano + +TOOLCHAIN_PATH=/buildroot/output/host/usr/bin/ +TOOLCHAIN=$(TOOLCHAIN_PATH)aarch64-linux- +CFLAGS=-Wall -Wextra -g -c -O0 -MD -std=gnu11 +CFLAGS+=-mcpu=cortex-a53 -funwind-tables +##CFLAGS+=-O2 -fno-omit-frame-pointer +OBJDIR=.obj/nano + +CC=$(TOOLCHAIN)gcc +LD=$(TOOLCHAIN)gcc +AR=$(TOOLCHAIN)ar +STRIP=$(TOOLCHAIN)strip + +OBJDIR=.obj/$(target) +OBJS= $(addprefix $(OBJDIR)/, $(SRCS:.c=.o)) + +$(OBJDIR)/%o: %c + $(CC) $(CFLAGS) $< -o $@ + +all: $(OBJDIR)/ $(EXEC) dtb + echo $(EXEC) + echo $(SRCS) + +$(EXEC): $(OBJS) $(LINKER_SCRIPT) + $(LD) $(OBJS) $(LDFLAGS) -o $@ + +$(OBJDIR)/: + mkdir -p $(OBJDIR) + +clean: + rm -Rf $(OBJDIR) $(EXEC) $(EXEC)_s .obj *.dtb *~ + +clean_all: clean + +CVER := aarch64-linux- +KVER := 5.15.21 +CPU := arm64 + +KDIR := /buildroot/output/build/linux-$(KVER)/ +PWD := $(shell pwd) + +INCL+=-I. -I$(KDIR)/include -I$(KDIR)/arch/arm64/boot/dts/ +DTS = $(DTB:.dtb=.dts) + +dtb: $(DTB) +$(DTB) : $(DTS) + ln -s $(KDIR)/arch/arm/boot/dts arm + -cpp $(INCL) -E -P -x assembler-with-cpp $(DTS) | dtc -I dts -O dtb -o $(DTB) - + rm arm + +-include $(OBJS:.o=.d) + +.PHONY: all clean clean_all dtb diff --git a/src/07_miniproj/oled/main.c b/src/07_miniproj/oled/main.c new file mode 100644 index 0000000..664e4dd --- /dev/null +++ b/src/07_miniproj/oled/main.c @@ -0,0 +1,23 @@ +#include "ssd1306.h" + +int main() +{ + ssd1306_init(); + + ssd1306_set_position (0,0); + ssd1306_puts("CSEL1a - SP.07"); + ssd1306_set_position (0,1); + ssd1306_puts(" Demo - SW"); + ssd1306_set_position (0,2); + ssd1306_puts("--------------"); + + ssd1306_set_position (0,3); + ssd1306_puts("Temp: 35'C"); + ssd1306_set_position (0,4); + ssd1306_puts("Freq: 1Hz"); + ssd1306_set_position (0,5); + ssd1306_puts("Duty: 50%"); + + return 0; +} + diff --git a/src/07_miniproj/oled/mydt.dts b/src/07_miniproj/oled/mydt.dts new file mode 100644 index 0000000..8841022 --- /dev/null +++ b/src/07_miniproj/oled/mydt.dts @@ -0,0 +1,13 @@ +/dts-v1/; + +#include "allwinner/sun50i-h5-nanopi-neo-plus2.dts" + +/ { + /delete-node/ leds; +}; + +&i2c0 { + status = "okay"; +}; + + diff --git a/src/07_miniproj/oled/ssd1306.c b/src/07_miniproj/oled/ssd1306.c new file mode 100644 index 0000000..a8e7195 --- /dev/null +++ b/src/07_miniproj/oled/ssd1306.c @@ -0,0 +1,236 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ssd1306.h" + +// this code is mainly based on Bakebit software: https://github.com/friendlyarm/BakeBit + +#define ARRAY_OF(x) (sizeof(x)/sizeof(x[0])) + +#define I2C_BUS "/dev/i2c-0" +#define OLED_ADDR 0x3c +#define OLED_COMMAND_MODE 0x00 +#define OLED_DATA_MODE 0x40 +#define OLED_DISPLAY_OFF_CMD 0xae +#define OLED_DISPLAY_ON_CMD 0xaf + +static const uint8_t font[][8] = { +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, +{0x00,0x00,0x5F,0x00,0x00,0x00,0x00,0x00}, +{0x00,0x00,0x07,0x00,0x07,0x00,0x00,0x00}, +{0x00,0x14,0x7F,0x14,0x7F,0x14,0x00,0x00}, +{0x00,0x24,0x2A,0x7F,0x2A,0x12,0x00,0x00}, +{0x00,0x23,0x13,0x08,0x64,0x62,0x00,0x00}, +{0x00,0x36,0x49,0x55,0x22,0x50,0x00,0x00}, +{0x00,0x00,0x05,0x03,0x00,0x00,0x00,0x00}, +{0x00,0x1C,0x22,0x41,0x00,0x00,0x00,0x00}, +{0x00,0x41,0x22,0x1C,0x00,0x00,0x00,0x00}, +{0x00,0x08,0x2A,0x1C,0x2A,0x08,0x00,0x00}, +{0x00,0x08,0x08,0x3E,0x08,0x08,0x00,0x00}, +{0x00,0xA0,0x60,0x00,0x00,0x00,0x00,0x00}, +{0x00,0x08,0x08,0x08,0x08,0x08,0x00,0x00}, +{0x00,0x60,0x60,0x00,0x00,0x00,0x00,0x00}, +{0x00,0x20,0x10,0x08,0x04,0x02,0x00,0x00}, +{0x00,0x3E,0x51,0x49,0x45,0x3E,0x00,0x00}, +{0x00,0x00,0x42,0x7F,0x40,0x00,0x00,0x00}, +{0x00,0x62,0x51,0x49,0x49,0x46,0x00,0x00}, +{0x00,0x22,0x41,0x49,0x49,0x36,0x00,0x00}, +{0x00,0x18,0x14,0x12,0x7F,0x10,0x00,0x00}, +{0x00,0x27,0x45,0x45,0x45,0x39,0x00,0x00}, +{0x00,0x3C,0x4A,0x49,0x49,0x30,0x00,0x00}, +{0x00,0x01,0x71,0x09,0x05,0x03,0x00,0x00}, +{0x00,0x36,0x49,0x49,0x49,0x36,0x00,0x00}, +{0x00,0x06,0x49,0x49,0x29,0x1E,0x00,0x00}, +{0x00,0x00,0x36,0x36,0x00,0x00,0x00,0x00}, +{0x00,0x00,0xAC,0x6C,0x00,0x00,0x00,0x00}, +{0x00,0x08,0x14,0x22,0x41,0x00,0x00,0x00}, +{0x00,0x14,0x14,0x14,0x14,0x14,0x00,0x00}, +{0x00,0x41,0x22,0x14,0x08,0x00,0x00,0x00}, +{0x00,0x02,0x01,0x51,0x09,0x06,0x00,0x00}, +{0x00,0x32,0x49,0x79,0x41,0x3E,0x00,0x00}, +{0x00,0x7E,0x09,0x09,0x09,0x7E,0x00,0x00}, +{0x00,0x7F,0x49,0x49,0x49,0x36,0x00,0x00}, +{0x00,0x3E,0x41,0x41,0x41,0x22,0x00,0x00}, +{0x00,0x7F,0x41,0x41,0x22,0x1C,0x00,0x00}, +{0x00,0x7F,0x49,0x49,0x49,0x41,0x00,0x00}, +{0x00,0x7F,0x09,0x09,0x09,0x01,0x00,0x00}, +{0x00,0x3E,0x41,0x41,0x51,0x72,0x00,0x00}, +{0x00,0x7F,0x08,0x08,0x08,0x7F,0x00,0x00}, +{0x00,0x41,0x7F,0x41,0x00,0x00,0x00,0x00}, +{0x00,0x20,0x40,0x41,0x3F,0x01,0x00,0x00}, +{0x00,0x7F,0x08,0x14,0x22,0x41,0x00,0x00}, +{0x00,0x7F,0x40,0x40,0x40,0x40,0x00,0x00}, +{0x00,0x7F,0x02,0x0C,0x02,0x7F,0x00,0x00}, +{0x00,0x7F,0x04,0x08,0x10,0x7F,0x00,0x00}, +{0x00,0x3E,0x41,0x41,0x41,0x3E,0x00,0x00}, +{0x00,0x7F,0x09,0x09,0x09,0x06,0x00,0x00}, +{0x00,0x3E,0x41,0x51,0x21,0x5E,0x00,0x00}, +{0x00,0x7F,0x09,0x19,0x29,0x46,0x00,0x00}, +{0x00,0x26,0x49,0x49,0x49,0x32,0x00,0x00}, +{0x00,0x01,0x01,0x7F,0x01,0x01,0x00,0x00}, +{0x00,0x3F,0x40,0x40,0x40,0x3F,0x00,0x00}, +{0x00,0x1F,0x20,0x40,0x20,0x1F,0x00,0x00}, +{0x00,0x3F,0x40,0x38,0x40,0x3F,0x00,0x00}, +{0x00,0x63,0x14,0x08,0x14,0x63,0x00,0x00}, +{0x00,0x03,0x04,0x78,0x04,0x03,0x00,0x00}, +{0x00,0x61,0x51,0x49,0x45,0x43,0x00,0x00}, +{0x00,0x7F,0x41,0x41,0x00,0x00,0x00,0x00}, +{0x00,0x02,0x04,0x08,0x10,0x20,0x00,0x00}, +{0x00,0x41,0x41,0x7F,0x00,0x00,0x00,0x00}, +{0x00,0x04,0x02,0x01,0x02,0x04,0x00,0x00}, +{0x00,0x80,0x80,0x80,0x80,0x80,0x00,0x00}, +{0x00,0x01,0x02,0x04,0x00,0x00,0x00,0x00}, +{0x00,0x20,0x54,0x54,0x54,0x78,0x00,0x00}, +{0x00,0x7F,0x48,0x44,0x44,0x38,0x00,0x00}, +{0x00,0x38,0x44,0x44,0x28,0x00,0x00,0x00}, +{0x00,0x38,0x44,0x44,0x48,0x7F,0x00,0x00}, +{0x00,0x38,0x54,0x54,0x54,0x18,0x00,0x00}, +{0x00,0x08,0x7E,0x09,0x02,0x00,0x00,0x00}, +{0x00,0x18,0xA4,0xA4,0xA4,0x7C,0x00,0x00}, +{0x00,0x7F,0x08,0x04,0x04,0x78,0x00,0x00}, +{0x00,0x00,0x7D,0x00,0x00,0x00,0x00,0x00}, +{0x00,0x80,0x84,0x7D,0x00,0x00,0x00,0x00}, +{0x00,0x7F,0x10,0x28,0x44,0x00,0x00,0x00}, +{0x00,0x41,0x7F,0x40,0x00,0x00,0x00,0x00}, +{0x00,0x7C,0x04,0x18,0x04,0x78,0x00,0x00}, +{0x00,0x7C,0x08,0x04,0x7C,0x00,0x00,0x00}, +{0x00,0x38,0x44,0x44,0x38,0x00,0x00,0x00}, +{0x00,0xFC,0x24,0x24,0x18,0x00,0x00,0x00}, +{0x00,0x18,0x24,0x24,0xFC,0x00,0x00,0x00}, +{0x00,0x00,0x7C,0x08,0x04,0x00,0x00,0x00}, +{0x00,0x48,0x54,0x54,0x24,0x00,0x00,0x00}, +{0x00,0x04,0x7F,0x44,0x00,0x00,0x00,0x00}, +{0x00,0x3C,0x40,0x40,0x7C,0x00,0x00,0x00}, +{0x00,0x1C,0x20,0x40,0x20,0x1C,0x00,0x00}, +{0x00,0x3C,0x40,0x30,0x40,0x3C,0x00,0x00}, +{0x00,0x44,0x28,0x10,0x28,0x44,0x00,0x00}, +{0x00,0x1C,0xA0,0xA0,0x7C,0x00,0x00,0x00}, +{0x00,0x44,0x64,0x54,0x4C,0x44,0x00,0x00}, +{0x00,0x08,0x36,0x41,0x00,0x00,0x00,0x00}, +{0x00,0x00,0x7F,0x00,0x00,0x00,0x00,0x00}, +{0x00,0x41,0x36,0x08,0x00,0x00,0x00,0x00}, +{0x00,0x02,0x01,0x01,0x02,0x01,0x00,0x00}, +{0x00,0x02,0x05,0x05,0x02,0x00,0x00,0x00}, +}; + + +static const uint8_t init_commands[] = { + 0xAE, //display off + 0x00, //set lower column address + 0x10, //set higher column address + 0x40, //set display start line + 0xB0, //set page address + 0x81, + 0xCF, //0~255???????????????? + 0xA1, //set segment remap + 0xA6, //normal / reverse + 0xA8, //multiplex ratio + 0x3F, //duty = 1/64 + 0xC8, //Com scan direction + 0xD3, //set display offset + 0x00, + 0xD5, //set osc division + 0x80, + 0xD9, //set pre-charge period + 0xF1, + 0xDA, //set COM pins + 0x12, + 0xDB, //set vcomh + 0x40, + 0x8D, //set charge pump enable + 0x14, + 0xAF, //display ON + +}; + +static int fd; + +static void send_command(uint8_t cmd) +{ + uint8_t buf[2]= { + [0] = OLED_COMMAND_MODE, + [1] = cmd, + }; + if (write(fd, buf, sizeof(buf)) != sizeof(buf)) { + printf ("error while sending command\n"); + } +} + +void send_data(uint8_t byte) +{ + uint8_t buf[2] = { + [0] = OLED_DATA_MODE, + [1] = byte, + }; + if (write(fd, buf, sizeof(buf)) != sizeof(buf)) { + printf ("error while sending data\n"); + } +} + +void ssd1306_set_position (uint32_t column, uint32_t row) +{ + send_command(0xb0 + row); //set page address + send_command(0x00 + (8*column & 0x0f)); //set column lower address + send_command(0x10 + ((8*column>>4)&0x0f)); //set column higher address +} + +void ssd1306_putc(char c) +{ + if ((c<32) || (c>127)) // Ignore non-printable ASCII characters + c=' '; + c-=32; + + for (int i=0; i<8; i++) { + uint8_t data=font[(int)c][i]; + send_data(data); + } +} + +void ssd1306_puts(const char* str) +{ + while (*str != 0) + ssd1306_putc(*str++); +} + +void ssd1306_clear_display() +{ + send_command(OLED_DISPLAY_OFF_CMD);// display off + for (int j=0; j<8; j++) { + ssd1306_set_position(0,j); + for (int i=0; i<16; i++) //clear all columns + ssd1306_putc(' '); + } + send_command(OLED_DISPLAY_ON_CMD); //display on + ssd1306_set_position(0,0); +} + +int ssd1306_init() +{ + fd = open(I2C_BUS, O_RDWR); + if (fd < 0) { + printf("ERROR: unable to open i2c bus interface (%s)\n", I2C_BUS); + return -1; + } + if (ioctl(fd, I2C_SLAVE, OLED_ADDR) < 0) { + printf("ERROR: unable to access OLED as slave\n"); + return -1; + } + + for (unsigned i=0; i + +int ssd1306_init(); +void ssd1306_set_position (uint32_t column, uint32_t row); +void ssd1306_putc(char c); +void ssd1306_puts(const char* str); +void ssd1306_clear_display(); + +#endif \ No newline at end of file