From 596d0d3876587ec0fed72be092696614b41d0d76 Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Thu, 18 Aug 2016 15:57:23 +0200 Subject: [PATCH] [Ion] Much simpler display driver Change-Id: Ia64a14ca5ed58f70590a27b968569832a0ecb722 --- ion/src/device/Makefile | 9 +- ion/src/device/display.cpp | 192 ++++++++++++++++++++------- ion/src/device/display.h | 62 +++++++++ ion/src/device/display/display.c | 119 ----------------- ion/src/device/display/display.h | 6 - ion/src/device/display/dma.c | 60 --------- ion/src/device/display/dma.h | 1 - ion/src/device/display/framebuffer.c | 31 ----- ion/src/device/display/framebuffer.h | 16 --- ion/src/device/display/gpio.c | 50 ------- ion/src/device/display/gpio.h | 6 - ion/src/device/display/spi.c | 25 ---- ion/src/device/display/spi.h | 4 - ion/src/device/display/st7586.c | 160 ---------------------- ion/src/device/display/st7586.h | 22 --- ion/src/device/display/st7789.c | 191 -------------------------- ion/src/device/display/st7789.h | 29 ---- ion/src/device/init.c | 3 +- 18 files changed, 208 insertions(+), 778 deletions(-) create mode 100644 ion/src/device/display.h delete mode 100644 ion/src/device/display/display.c delete mode 100644 ion/src/device/display/display.h delete mode 100644 ion/src/device/display/dma.c delete mode 100644 ion/src/device/display/dma.h delete mode 100644 ion/src/device/display/framebuffer.c delete mode 100644 ion/src/device/display/framebuffer.h delete mode 100644 ion/src/device/display/gpio.c delete mode 100644 ion/src/device/display/gpio.h delete mode 100644 ion/src/device/display/spi.c delete mode 100644 ion/src/device/display/spi.h delete mode 100644 ion/src/device/display/st7586.c delete mode 100644 ion/src/device/display/st7586.h delete mode 100644 ion/src/device/display/st7789.c delete mode 100644 ion/src/device/display/st7789.h diff --git a/ion/src/device/Makefile b/ion/src/device/Makefile index c86bf76d1..0fadd2545 100644 --- a/ion/src/device/Makefile +++ b/ion/src/device/Makefile @@ -1,11 +1,5 @@ include ion/src/device/boot/Makefile -objs += $(addprefix ion/src/device/, init.o heap.o led.o) -objs += $(addprefix ion/src/device/display/,\ - display.o\ - gpio.o\ - spi.o\ - st7789.o\ -) +objs += $(addprefix ion/src/device/, init.o heap.o led.o display.o) # When using the register.h C++ file in production mode, we expect the compiler # to completely inline all bit manipulations. For some reason, if we build using @@ -16,6 +10,7 @@ objs += $(addprefix ion/src/device/display/,\ ifneq ($(DEBUG),1) ifneq ($(COMPILER),llvm) ion/src/device/led.o: SFLAGS+=-O3 +ion/src/device/display.o: SFLAGS+=-O3 endif endif diff --git a/ion/src/device/display.cpp b/ion/src/device/display.cpp index 1f7a4f8b6..de55f8c84 100644 --- a/ion/src/device/display.cpp +++ b/ion/src/device/display.cpp @@ -1,29 +1,13 @@ -extern "C" { -#include -} +#include "display.h" #include "regs/regs.h" -#include "regs/fsmc.h" - extern "C" { - void ion_lcd_init(); +#include } -/* Pinout: - * PA2 - D4 - * PA3 - D5 - * PA4 - D6 - * PA5 - D7 - * PB14 - D0 - * PC3 - A0 - * PC4 - NE4 - * PC5 - NOE - * PC6 - D1 - * PC11 - D2 - * PC12 - D3 - * PD2 - NWE - */ +#define SEND_COMMAND(c) {*CommandAddress = LCDCommand::c;} +#define SEND_DATA(...) { uint8_t data[] = {__VA_ARGS__}; for (unsigned int i=0;isetGPIOAEN(true); RCC.AHB1ENR()->setGPIOBEN(true); @@ -72,7 +56,7 @@ void ion_lcd_gpio_init() { GPIOD.AFR()->setAFR(2, GPIO::AFR::AlternateFunction::AF10); } -void ion_lcd_fsmc_init() { +void Ion::Screen::initFSMC() { // FSMC lives on the AHB3 bus. Let's enable its clock. */ RCC.AHB3ENR()->setFSMCEN(true); @@ -91,14 +75,102 @@ void ion_lcd_fsmc_init() { FSMC.BCR(4)->setMBKEN(true); // Timing register - /* - FSMC.BTR(1)->setADDSET(6); - FSMC.BTR(1)->setDATAST(10); - FSMC.BTR(1)->setBUSTURN(10); - */ + FSMC.BTR(4)->setADDSET(0); + FSMC.BTR(4)->setDATAST(0); + FSMC.BTR(4)->setBUSTURN(0); } -void ion_lcd_init() { +static inline void delayms(long ms) { + for (long i=0; i<1040*ms; i++) { + __asm volatile("nop"); + } +} + + +void Ion::Screen::initPanel() { + + //*CommandAddress = 0x01; //software reset + //delayms(5); + + *CommandAddress = LCDCommand::SleepOut; + delayms(120); + + *CommandAddress = LCDCommand::PowerControlB; + SEND_DATA(0x00, 0x83, 0x30); + //*DataAddress = 0x00; *DataAddress = 0x83; *DataAddress = 0X30; + + *CommandAddress = LCDCommand::PowerOnSequenceControl; + *DataAddress = 0x64; *DataAddress = 0x03; *DataAddress = 0X12; + *DataAddress = 0X81; + + *CommandAddress = LCDCommand::DriverTimingControlA; + *DataAddress = 0x85; *DataAddress = 0x01; *DataAddress = 0x79; + + *CommandAddress = LCDCommand::PowerControlA; + *DataAddress = 0x39; *DataAddress = 0x2C; *DataAddress = 0x00; + *DataAddress = 0x34; *DataAddress = 0x02; + + *CommandAddress = LCDCommand::PumpRatioControl; + *DataAddress = 0x20; + + *CommandAddress = LCDCommand::DriverTimingControlB; + *DataAddress = 0x00; *DataAddress = 0x00; + + *CommandAddress = LCDCommand::PowerControl2; //Power control + *DataAddress = 0x11; //SAP[2:0];BT[3:0] + + *CommandAddress = LCDCommand::VCOMControl1; //VCM control 1 + *DataAddress = 0x34; + *DataAddress = 0x3D; + + *CommandAddress = LCDCommand::VCOMControl2; //VCM control 2 + *DataAddress = 0xC0; + + *CommandAddress = LCDCommand::MemoryAccessControl; // Memory Access Control + *DataAddress = 0xA0; + + *CommandAddress = LCDCommand::PixelFormatSet; // Pixel format + *DataAddress = 0x55; //16bit + + *CommandAddress = LCDCommand::FrameRateControl; // Frame rate + *DataAddress = 0x00; + *DataAddress = 0x1D; //65Hz + + *CommandAddress = LCDCommand::DisplayFunctionControl; // Display Function Control + *DataAddress = 0x0A; *DataAddress = 0xA2; *DataAddress = 0x27; + *DataAddress = 0x00; + + *CommandAddress = LCDCommand::EntryMode; //Entry mode + *DataAddress = 0x07; + + + *CommandAddress = LCDCommand::Enable3G; // 3Gamma Function Disable + *DataAddress = 0x08; + + *CommandAddress = LCDCommand::GammaSet; //Gamma curve selected + *DataAddress = 0x01; + + *CommandAddress = LCDCommand::PositiveGammaCorrection; //positive gamma correction + *DataAddress = 0x1f; *DataAddress = 0x1a; *DataAddress = 0x18; + *DataAddress = 0x0a; *DataAddress = 0x0f; *DataAddress = 0x06; + *DataAddress = 0x45; *DataAddress = 0x87; *DataAddress = 0x32; + *DataAddress = 0x0a; *DataAddress = 0x07; *DataAddress = 0x02; + *DataAddress = 0x07; *DataAddress = 0x05; *DataAddress = 0x00; + + *CommandAddress = LCDCommand::NegativeGammaCorrection; //negamma correction + *DataAddress = 0x00; *DataAddress = 0x25; *DataAddress = 0x27; + *DataAddress = 0x05; *DataAddress = 0x10; *DataAddress = 0x09; + *DataAddress = 0x3a; *DataAddress = 0x78; *DataAddress = 0x4d; + *DataAddress = 0x05; *DataAddress = 0x18; *DataAddress = 0x0d; + *DataAddress = 0x38; *DataAddress = 0x3a; *DataAddress = 0x1f; + + *CommandAddress = LCDCommand::SleepOut; //Exit Sleep + delayms(120); + *CommandAddress = LCDCommand::DisplayOn; //Display on + delayms(50); +} + +void ion_screen_init() { // Turn on the backlight RCC.AHB1ENR()->setGPIOCEN(true); GPIOC.MODER()->setMODER(9, GPIO::MODER::MODE::Output); @@ -109,32 +181,54 @@ void ion_lcd_init() { GPIOB.MODER()->setMODER(13, GPIO::MODER::MODE::Output); GPIOB.ODR()->setODR(13, true); - ion_lcd_gpio_init(); - ion_lcd_fsmc_init(); + delayms(120); + Ion::Screen::initGPIO(); + Ion::Screen::initFSMC(); + Ion::Screen::initPanel(); +} - volatile uint16_t * command = (uint16_t *)0x6C000000; - volatile uint16_t * data = (uint16_t *)0x6C020000; +void Ion::Screen::setDrawingArea(uint16_t x, uint16_t y, uint16_t width, uint16_t height) { + uint16_t x_start = x; + uint16_t x_end = x + width - 1; + uint16_t y_start = y; + uint16_t y_end = y + height - 1; - /* - uint16_t j = 0; - while (true) { - *data = j++; - // *command = j++; - } - */ + *CommandAddress = LCDCommand::ColumnAddressSet; + *DataAddress = (x_start >> 8); + *DataAddress = (x_start & 0xFF); + *DataAddress = (x_end >> 8); + *DataAddress = (x_end & 0xFF); - while (true) { + *CommandAddress = LCDCommand::PageAddressSet; + *DataAddress = (y_start >> 8); + *DataAddress = (y_start & 0xFF); + *DataAddress = (y_end >> 8); + *DataAddress = (y_end & 0xFF); - for (int i=0; i< 100000; i++) { - } + *CommandAddress = LCDCommand::MemoryWrite; +} - *command = 0x11; - for (int i=0; i< 100000; i++) { - } - *command = 0x29; - - for (int i=0; i< 1000000; i++) { - } +void Ion::Screen::pushPixels(const ion_color_t * pixels, size_t numberOfPixels) { + assert(sizeof(ion_color_t) == 2); // We expect KDColor to be RGB565 + for (size_t i=0; i> 8); + *DataAddress = (pixels[i] & 0xFF); } } + +void ion_screen_push_rect(uint16_t x, uint16_t y, uint16_t width, uint16_t height, const ion_color_t * pixels) { + Ion::Screen::setDrawingArea(x, y, width, height); + Ion::Screen::pushPixels(pixels, width*height); +} + +void ion_screen_push_rect_uniform(uint16_t x, uint16_t y, uint16_t width, uint16_t height, ion_color_t color) { + Ion::Screen::setDrawingArea(x, y, width, height); + for (size_t i=0; i +#include +#include + void ion_screen_init(); +} + +/* Pinout: + * PA2 - D4 + * PA3 - D5 + * PA4 - D6 + * PA5 - D7 + * PB14 - D0 + * PC3 - A0 + * PC4 - NE4 + * PC5 - NOE + * PC6 - D1 + * PC11 - D2 + * PC12 - D3 + * PD2 - NWE + */ + +namespace Ion { +namespace Screen { + void init(); + void initGPIO(); + void initFSMC(); + void initPanel(); + + void setDrawingArea(uint16_t x, uint16_t y, uint16_t width, uint16_t height); + void pushPixels(const ion_color_t * pixels, size_t numberOfPixels); + + enum class LCDCommand : uint8_t { + SleepOut = 0x11, + DisplayOn = 0x29, + ColumnAddressSet = 0x2A, + GammaSet = 0x26, + PageAddressSet = 0x2B, + MemoryWrite = 0x2C, + MemoryAccessControl = 0x36, + PixelFormatSet = 0x3A, + FrameRateControl = 0xB1, + DisplayFunctionControl = 0xB6, + EntryMode = 0xB7, + PowerControl2 = 0xC1, + VCOMControl1 = 0xC5, + VCOMControl2 = 0xC7, + PowerControlA = 0xCB, + PowerControlB = 0xCF, + PositiveGammaCorrection = 0xE0, + NegativeGammaCorrection = 0xE1, + DriverTimingControlA = 0xE8, + DriverTimingControlB = 0xEA, + PowerOnSequenceControl = 0xED, + Enable3G = 0xF2, + PumpRatioControl = 0xF7, + }; + + static volatile LCDCommand * const CommandAddress = (LCDCommand *)0x6C000000; + static volatile uint8_t * const DataAddress = (uint8_t *)0x6C000001; +} +} diff --git a/ion/src/device/display/display.c b/ion/src/device/display/display.c deleted file mode 100644 index 4d9a97fc5..000000000 --- a/ion/src/device/display/display.c +++ /dev/null @@ -1,119 +0,0 @@ -/* LCD Initialisation code - * - * The LCD panel is connected via an SPI interface. The SPI interface is used to - * configure the panel and to stream the bitmap data. - * - * Here is the connection this file assumes: - * - * LCD | STM32 | Role - * --------------+-------+----- - * LCD_CS | PC13 | Chip-select for LCD panel (panel selected when low) - * LCD_RST | PB12 | Reset the LCD panel (panel active when high) - * LCD_DAT_INS | PB14 | Select "command" or "data" mode - * LCD_SPI_CLK | PB13 | SPI clock - * LCD_SPI_MOSI | PB15 | SPI data - * - * The entry point is init_display(); - */ - -#include -#include -#include - -#include "../registers/registers.h" - -#include "gpio.h" -#include "spi.h" -#include "dma.h" -#include "framebuffer.h" -#include "st7789.h" - -static st7789_t sDisplayController; - -void ion_display_on() { - // Initialize panel - // Start DMA transfer -} - -void ion_display_off() { - // Stop DMA transfer - // Turn off panel -} - -void ion_screen_push_rect(uint16_t x, uint16_t y, uint16_t width, uint16_t height, const ion_color_t * pixels) { - st7789_set_drawing_area(&sDisplayController, x, y, width, height); - st7789_push_pixels(&sDisplayController, pixels, width*height); -} - -void ion_screen_push_rect_uniform(uint16_t x, uint16_t y, uint16_t width, uint16_t height, ion_color_t color) { - st7789_set_drawing_area(&sDisplayController, x, y, width, height); - for (size_t i=0; i 0) { - int32_t blockSize = remainingSize > patternSize ? patternSize : remainingSize; - st7789_push_pixels(&sDisplayController, pattern, blockSize); - remainingSize -= blockSize; - } - return; - } -#endif - uint16_t remainingHeight = height; - uint16_t patternLine = 0; - while (remainingHeight-- > 0) { - uint16_t remainingWidth = width; - while (remainingWidth > 0) { - int32_t blockSize = remainingWidth > patternWidth ? patternWidth : remainingWidth; - st7789_push_pixels(&sDisplayController, pattern+patternLine*patternWidth, blockSize); - remainingWidth -= blockSize; - } - if (++patternLine >= patternHeight) { - patternLine = 0; - } - } -} -#endif - -void init_display() { - //assert(FRAMEBUFFER_LENGTH == (FRAMEBUFFER_WIDTH*FRAMEBUFFER_HEIGHT*FRAMEBUFFER_BITS_PER_PIXEL)/8); - - display_gpio_init(); - display_spi_init(); - - sDisplayController.chip_select_pin_write = gpio_c13_write; - sDisplayController.reset_pin_write = gpio_b12_write; - //sDisplayController.data_command_pin_write = gpio_b14_write; - sDisplayController.spi_write = spi_2_write; - - st7789_initialize(&sDisplayController); - - //st7789_set_display_area(&sDisplayController, 0, 240, 0, 320); - - //st7789_enable_frame_data_upload(&sDisplayController); - - /*while (1) { - }*/ - - //memset(FRAMEBUFFER_ADDRESS, 0, FRAMEBUFFER_LENGTH); - - //display_dma_init(); -} diff --git a/ion/src/device/display/display.h b/ion/src/device/display/display.h deleted file mode 100644 index 9d2b4d272..000000000 --- a/ion/src/device/display/display.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef ION_DEVICE_DISPLAY_H -#define ION_DEVICE_DISPLAY_H - -void init_display(); - -#endif diff --git a/ion/src/device/display/dma.c b/ion/src/device/display/dma.c deleted file mode 100644 index 9a3ac29e8..000000000 --- a/ion/src/device/display/dma.c +++ /dev/null @@ -1,60 +0,0 @@ -#include "../registers/registers.h" -#include "framebuffer.h" - -// DMA 1, channel 0, stream 4 = SPI2_TX -#define LCD_DMA_CHANNEL 0 -#define LCD_DMA_STREAM 4 - -void display_dma_init() { -// 0 - ENable DMA clock! - RCC_AHB1ENR |= DMA1EN; - - - // 1 - Reset DMA - // Stuff like this, and a wait loop... - //DMA_SCR(DMA1,4) |= DMA_EN; - //DMA_SCR(DMA1,4) ~= DMA_EN; - - // 2 - Set the peripheral address - DMA_SPAR(DMA1,LCD_DMA_STREAM) = (uint32_t)&SPI_DR(SPI2); - - // 3 - Set the memory address - DMA_SMA0R(DMA1,LCD_DMA_STREAM) = (uint32_t)FRAMEBUFFER_ADDRESS; - - // 4 - Number of data items - REGISTER_SET_VALUE(DMA_SNDTR(DMA1,LCD_DMA_STREAM), DMA_SNDTR, FRAMEBUFFER_LENGTH); - - // 5 - Select the DMA channel - REGISTER_SET_VALUE(DMA_SCR(DMA1,LCD_DMA_STREAM), DMA_CHSEL, LCD_DMA_CHANNEL); - - // 6 - Set peripheral flow control - // Does not apply, only for SD/MMC - - // 7 - Stream priority - // We don't care yet - - // 8 - Configure FIFO usage - // I think we don't care - - // 9 - Data transfer direction, peripheral/memory increment, single burst or transaction, peripheral and memory data width - REGISTER_SET_VALUE(DMA_SCR(DMA1,LCD_DMA_STREAM), DMA_DIR, DMA_DIR_MEMORY_TO_PERIPHERAL); - - DMA_SCR(DMA1,LCD_DMA_STREAM) |= DMA_CIRC; - - // Memory address is incremented - DMA_SCR(DMA1,LCD_DMA_STREAM) |= DMA_MINC; - - // Peripheral expects 8 bits values, default - //REGISTER_SET_VALUE(DMA_SCR(DMA1,LCD_DMA_STREAM), DMA_DIR, DMA_DIR_MEMORY_TO_PERIPHERAL); - - // 10 - Enable DMA transfer! - DMA_SCR(DMA1,LCD_DMA_STREAM) |= DMA_EN; - - // 11 - Bonux: enable DMA requests on SPI - SPI_CR2(SPI2) |= SPI_TXDMAEN; - - /*while (DMA_SCR(DMA1,LCD_DMA_STREAM) & DMA_EN) { - } - DMA_SCR(DMA1,LCD_DMA_STREAM) |= DMA_EN; - */ -} diff --git a/ion/src/device/display/dma.h b/ion/src/device/display/dma.h deleted file mode 100644 index 8fb02917c..000000000 --- a/ion/src/device/display/dma.h +++ /dev/null @@ -1 +0,0 @@ -void display_dma_init(); diff --git a/ion/src/device/display/framebuffer.c b/ion/src/device/display/framebuffer.c deleted file mode 100644 index 26053a36a..000000000 --- a/ion/src/device/display/framebuffer.c +++ /dev/null @@ -1,31 +0,0 @@ -#include -#include -#include "framebuffer.h" - -#define BIT_MASK(high, low) ((((uint32_t)1<<((high)-(low)+1))-1)<<(low)) -#define BIT_VALUE(value, high, low) (((value)<<(low))&BIT_MASK(high, low)) -#define BIT_SET(initial, value, high, low) ((initial&~BIT_MASK(high,low))|(BIT_VALUE(value,high,low)&BIT_MASK(high,low))) - - -/* We're using a pixel format imposed to us by the stupid st7586. We use a four - * color framebuffer, so that's 2 bits per pixels. Unfortunately we cannot pack - * those pixels and have to resort to two pixels per byte using the following - * format : AAxBBxxx, where AA and BB are the bits for two contiguous pixels. */ - -void ion_set_pixel(uint16_t x, uint16_t y, uint8_t color) { - assert(x <= FRAMEBUFFER_WIDTH); - assert(y <= FRAMEBUFFER_HEIGHT); - - char * byte = FRAMEBUFFER_ADDRESS + ((y*FRAMEBUFFER_WIDTH)+x)*FRAMEBUFFER_BITS_PER_PIXEL/8; - assert(byte <= &_framebuffer_end); - - char mask, value; - if (x & 1) { - mask = BIT_MASK(4,3); - value = BIT_VALUE(color,4,3); - } else { - mask = BIT_MASK(7,6); - value = BIT_VALUE(color,7,6); - } - *byte = (*byte & ~mask) | (value & mask); -} diff --git a/ion/src/device/display/framebuffer.h b/ion/src/device/display/framebuffer.h deleted file mode 100644 index 84def5842..000000000 --- a/ion/src/device/display/framebuffer.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef ION_DEVICE_DISPLAY_FRAMEBUFFER_H_ -#define ION_DEVICE_DISPLAY_FRAMEBUFFER_H_ - -#include - -extern char _framebuffer_start; -extern char _framebuffer_end; - -#define FRAMEBUFFER_ADDRESS (&_framebuffer_start) -#define FRAMEBUFFER_LENGTH (&_framebuffer_end-&_framebuffer_start) -#define FRAMEBUFFER_WIDTH SCREEN_WIDTH -#define FRAMEBUFFER_HEIGHT SCREEN_HEIGHT - -#define FRAMEBUFFER_BITS_PER_PIXEL 4 - -#endif // ION_DEVICE_DISPLAY_FRAMEBUFFER_H_ diff --git a/ion/src/device/display/gpio.c b/ion/src/device/display/gpio.c deleted file mode 100644 index 375eb3bc6..000000000 --- a/ion/src/device/display/gpio.c +++ /dev/null @@ -1,50 +0,0 @@ -/* The LCD panel is connected via an SPI interface. The SPI interface is used to - * configure the panel and to stream the bitmap data. - * - * Here is the connection this file assumes: - * - * LCD | STM32 | Role - * --------------+-------+----- - * LCD_CS | PC13 | Chip-select for LCD panel (panel selected when low) - * LCD_RST | PB12 | Reset the LCD panel (panel active when high) - * LCD_SPI_CLK | PB13 | SPI clock - * LCD_DAT_INS | PB14 | Select "command" or "data" mode - * LCD_SPI_MOSI | PB15 | SPI data - */ - -#include "../registers/registers.h" -#include "gpio.h" - -void display_gpio_init() { - // We are using GPIO B, which live on the AHB1 bus. Let's enable its clock. - RCC_AHB1ENR |= GPIOBEN; - // Same for GPIO C - RCC_AHB1ENR |= GPIOCEN; - - // LCD_CS(PC13), LCD_RST(PB12) and LCD_DAT_INS(PB14) are controlled directly - REGISTER_SET_VALUE(GPIO_MODER(GPIOC), MODER(13), GPIO_MODE_OUTPUT); - REGISTER_SET_VALUE(GPIO_MODER(GPIOB), MODER(12), GPIO_MODE_OUTPUT); - REGISTER_SET_VALUE(GPIO_MODER(GPIOB), MODER(14), GPIO_MODE_OUTPUT); - - /* LCD_SPI_CLK(PB13) and LCD_SPI_MOSI(PB15) are used for SPI, which is an - * alternate function. */ - REGISTER_SET_VALUE(GPIO_MODER(GPIOB), MODER(13), GPIO_MODE_ALTERNATE_FUNCTION); - REGISTER_SET_VALUE(GPIO_MODER(GPIOB), MODER(15), GPIO_MODE_ALTERNATE_FUNCTION); - - /* More precisely, we will use AF05, which maps PB15 to SPI2_MOSI and PB13 to - * SPI2_SCK. */ - REGISTER_SET_VALUE(GPIO_AFR(GPIOB, 13), AFR(13), 5); - REGISTER_SET_VALUE(GPIO_AFR(GPIOB, 15), AFR(15), 5); -} - -void gpio_b12_write(bool pin_state) { - REGISTER_SET_VALUE(GPIO_ODR(GPIOB), ODR(12), pin_state); -} - -void gpio_b14_write(bool pin_state) { - REGISTER_SET_VALUE(GPIO_ODR(GPIOB), ODR(14), pin_state); -} - -void gpio_c13_write(bool pin_state) { - REGISTER_SET_VALUE(GPIO_ODR(GPIOC), ODR(13), pin_state); -} diff --git a/ion/src/device/display/gpio.h b/ion/src/device/display/gpio.h deleted file mode 100644 index 346bd697f..000000000 --- a/ion/src/device/display/gpio.h +++ /dev/null @@ -1,6 +0,0 @@ -#include - -void display_gpio_init(); -void gpio_b12_write(bool pin_state); -void gpio_b14_write(bool pin_state); -void gpio_c13_write(bool pin_state); diff --git a/ion/src/device/display/spi.c b/ion/src/device/display/spi.c deleted file mode 100644 index 201b802fc..000000000 --- a/ion/src/device/display/spi.c +++ /dev/null @@ -1,25 +0,0 @@ -/* The LCD panel is connected via the SPI2 port. - * This file configures the port. */ - -#include "../registers/registers.h" -#include "spi.h" - -void display_spi_init() { - // Enable the SPI2 clock (SPI2 lives on the APB1 bus) - RCC_APB1ENR |= SPI2EN; - - // Configure the SPI port - SPI_CR1(SPI2) = (SPI_BIDIMODE | SPI_BIDIOE | SPI_MSTR | SPI_DFF_8_BITS | SPI_BR(SPI_BR_DIV_2) | SPI_SSM | SPI_SSI | SPI_SPE); -} - -void spi_2_write(char * data, size_t size) { - while (SPI_SR(SPI2) & SPI_BSY) { - } - for (size_t i=0; i - -void display_spi_init(); -void spi_2_write(char * data, size_t size); diff --git a/ion/src/device/display/st7586.c b/ion/src/device/display/st7586.c deleted file mode 100644 index 2a01c804f..000000000 --- a/ion/src/device/display/st7586.c +++ /dev/null @@ -1,160 +0,0 @@ -#include -#include "st7586.h" - -enum { - COMMAND_MODE = 0, - DATA_MODE = 1, - DELAY_MODE = 2 -}; - -enum { - NOP = 0x00, - RESET = 0x01, - SLEEP_IN = 0x10, - SLEEP_OUT = 0x11, - DISPLAY_OFF = 0x28, - DISPLAY_ON = 0x29, - SET_COLUMN_ADDRESS = 0x2A, - SET_ROW_ADDRESS = 0x2B, - WRITE_DISPLAY_DATA = 0x2C, - ENABLE_DDRAM = 0x3A, -}; - -typedef struct { - char mode; - char payload; -} instruction_t; - -#define COMMAND(c) (instruction_t){.mode = (char)COMMAND_MODE, .payload = (char)c} -#define DATA(d) (instruction_t){.mode = (char)DATA_MODE, .payload = (char)d} -#define DELAY(m) (instruction_t){.mode = (char)DELAY_MODE, .payload = (char)m} - -static void perform_instruction(st7586_t * c, instruction_t instruction) { - if (instruction.mode == DELAY_MODE) { - // FIXME: Should sleep instruction->payload miliseconds - for (int i = 0; i < 800*instruction.payload; i++) { - __asm volatile("nop"); - } - } else { - c->data_command_pin_write(instruction.mode); - c->spi_write(&instruction.payload, 1); - } -} - -static void perform_instructions(st7586_t * c, const instruction_t * instructions, size_t length) { - for (size_t i=0; ichip_select_pin_write(0); - - const instruction_t init_sequence[] = { -#define USE_MANUFACTURER_INIT 0 -#if USE_MANUFACTURER_INIT - COMMAND(0x01), // ADDED BY ME - DELAY(220), - COMMAND(0x11), // Sleep Out - COMMAND(0x28), // Display OFF - DELAY(50), - COMMAND(0xC0), // Vop = B9h - DATA(0x45), - DATA(0x01), - COMMAND(0xC3), // BIAS = 1/14 - DATA(0x00), - COMMAND(0xC4), // Booster = x8 - DATA(0x07), - COMMAND(0xD0), // Enable Analog Circuit - DATA(0x1D), - COMMAND(0xB5), // N-Line = 0 - DATA(0x00), - //COMMAND(0x39), // Monochrome Mode - COMMAND(0x38), // Grey Mode - COMMAND(0x3A), // Enable DDRAM Interface - DATA(0x02), - COMMAND(0x36), // Scan Direction Setting - DATA(0xc0), //COM:C160--C1 SEG: SEG384-SEG1 - COMMAND(0xB0), // Duty Setting - DATA(0x9F), - COMMAND(0x20), // Display Inversion OFF - COMMAND(0x2A), // Column Address Setting - DATA(0x00), // SEG0 -> SEG384 - DATA(0x00), - DATA(0x00), - DATA(0x7F), - COMMAND(0x2B), // Row Address Setting - DATA(0x00), // COM0 -> COM160 - DATA(0x00), - DATA(0x00), - DATA(0x9F), - COMMAND(0x29) // Display ON -#else - COMMAND(RESET), DELAY(50), // Software reset, then wait 5ms - COMMAND(DISPLAY_OFF), - - // Sleep out, requires a 100ms delay - COMMAND(SLEEP_OUT), DELAY(100), - - // Display on, requires a 20ms delay - COMMAND(DISPLAY_ON), DELAY(20), - - // Enable DDRAM interface - // The "DATA" makes no real sense but is mandatory according to the spec - COMMAND(ENABLE_DDRAM), DATA(0x2), - - - // This has been copy-pasted from the manufacturer. - // FIXME: Understand what it does, and maybe fix it! - COMMAND(0xC0), // Vop = B9h - DATA(0x45), - DATA(0x01), - COMMAND(0xC3), // BIAS = 1/14 - DATA(0x00), - COMMAND(0xC4), // Booster = x8 - DATA(0x07), - COMMAND(0xD0), // Enable Analog Circuit - DATA(0x1D), - COMMAND(0xB5), // N-Line = 0 - DATA(0x00), -#endif - }; - - // Send all the initialisation_sequence - perform_instructions(controller, init_sequence, sizeof(init_sequence)/sizeof(init_sequence[0])); -} - -void st7586_set_display_area(st7586_t * controller, uint16_t x_start, uint16_t x_length, uint16_t y_start, uint16_t y_length) { - /* The datasheet says the panel counts in "columns", groups of 3 pixels. - * It says 3, but from my understanding pixels are grouped by 2, not by 3. So - * so let's make this 2 instead of 3. Seems to be working fine! */ - uint16_t x_end = x_start + x_length/2 - 1; - uint16_t y_end = y_start + y_length - 1; - - assert(x_end >= x_start); - assert(x_end <= 0x7F); - assert(y_end >= y_start); - assert(y_end <= 0x9F); - - const instruction_t sequence[] = { - COMMAND(SET_COLUMN_ADDRESS), - DATA(x_start >> 8), - DATA(x_start), - DATA(x_end >> 8), - DATA(x_end), - COMMAND(SET_ROW_ADDRESS), - DATA(y_start >> 8), - DATA(y_start), - DATA(y_end >> 8), - DATA(y_end), - }; - - perform_instructions(controller, sequence, sizeof(sequence)/sizeof(sequence[0])); -} - -void st7586_enable_frame_data_upload(st7586_t * controller) { - // Put the screen in "receive frame data" - perform_instruction(controller, COMMAND(WRITE_DISPLAY_DATA)); - controller->data_command_pin_write(DATA_MODE); -} diff --git a/ion/src/device/display/st7586.h b/ion/src/device/display/st7586.h deleted file mode 100644 index 38c1cf332..000000000 --- a/ion/src/device/display/st7586.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef ION_DEVICE_DISPLAY_ST7586_H -#define ION_DEVICE_DISPLAY_ST7586_H - -#include -#include -#include - -/* This is the ST7586 driver - * - * It just needs to be pointed to a "write" function - */ -typedef struct { - void (*chip_select_pin_write)(bool pin_state); - void (*data_command_pin_write)(bool pin_state); - void (*spi_write)(char * data, size_t size); -} st7586_t; - -void st7586_initialize(st7586_t * controller); -void st7586_set_display_area(st7586_t * controller, uint16_t x_start, uint16_t x_length, uint16_t y_start, uint16_t y_length); -void st7586_enable_frame_data_upload(st7586_t * controller); - -#endif diff --git a/ion/src/device/display/st7789.c b/ion/src/device/display/st7789.c deleted file mode 100644 index f59df9e92..000000000 --- a/ion/src/device/display/st7789.c +++ /dev/null @@ -1,191 +0,0 @@ -#include -#include "st7789.h" - -enum { - COMMAND_MODE = 0, - DATA_MODE = 1, - DELAY_MODE = 2 -}; - -enum { - NOP = 0x00, - SWRESET = 0x01, // Software reset - SLPOUT = 0x11, // Sleep out - DISPOFF = 0x28, - DISPON = 0x29, - CASET = 0x2A, - RASET = 0x2B, - RAMRW = 0x2C, - MADCTL = 0x36, // Memory data access control - COLMOD = 0x3A, // Interface pixel format - PORCTRL = 0xB2, // Porch setting - GCTRL = 0xB7, // Gate control - VCOMS = 0xBB, // VCOM setting - LCMCTRL = 0xC0, // LCM control - VDVVRHEN = 0xC2, // VDV and VRH command enable - VRHS = 0xC3, // VRH set - VDVS = 0xC4, - VCMOFSET = 0xC5, - FRCTRL2 = 0xC6, - PWCTRL1 = 0xD0, - PVGAMCTRL = 0xE0, - NVGAMCTRL = 0xE1, -}; - -typedef struct { - uint8_t mode; - uint8_t payload; -} instruction_t; - -#define COMMAND(c) (instruction_t){.mode = (uint8_t)COMMAND_MODE, .payload = (uint8_t)(c)} -#define DATA(d) (instruction_t){.mode = (uint8_t)DATA_MODE, .payload = (uint8_t)(d)} -#define DELAY(m) (instruction_t){.mode = (uint8_t)DELAY_MODE, .payload = (uint8_t)(m)} - -// FIXME: This is ugly and should not live here -static inline void delay_ms(long ms) { - for (long i=0; i<1040*ms; i++) { - __asm volatile("nop"); - } -} - -#if ST7789_USE_9BIT_SPI -static void push_data_on_spi_queue(st7789_t * c, uint8_t data, int8_t numberOfBits) { - assert(numberOfBits >= 0); - c->spi_queue = (c->spi_queue << numberOfBits) | data; - c->spi_queue_usage_in_bits += numberOfBits; - assert(c->spi_queue_usage_in_bits < 8*sizeof(c->spi_queue)); -} - -static void flush_spi_buffer(st7789_t * c) { - while (c->spi_queue_usage_in_bits >= 8) { - char byte = (c->spi_queue >> (c->spi_queue_usage_in_bits - 8)); - c->spi_write(&byte, 1); - c->spi_queue = c->spi_queue & ((1>>(c->spi_queue_usage_in_bits-8))-1); // Clear the 8 first bytes - c->spi_queue_usage_in_bits = c->spi_queue_usage_in_bits-8; - } - // At this point, there remain c->spi_queue_usage_in_bits in the queue -} -#endif - -static void perform_instruction(st7789_t * c, instruction_t instruction) { - if (instruction.mode == DELAY_MODE) { - delay_ms(instruction.payload); - } else { - //c->chip_select_pin_write(0); -#if ST7789_USE_9BIT_SPI - push_data_on_spi_queue(c, (instruction.mode == DATA_MODE), 1); - push_data_on_spi_queue(c, instruction.payload, 8); - flush_spi_buffer(c); -#else - c->data_command_pin_write(instruction.mode); - c->spi_write(&instruction.payload, 1); -#endif - //c->chip_select_pin_write(1); - } -} - -static void perform_instructions(st7789_t * c, const instruction_t * instructions, size_t length) { - for (size_t i=0; ispi_queue = 0; - c->spi_queue_usage_in_bits = 0; -#endif - - /* The ST7789S has multiple interfaces to receive data. - * In this driver, we're using the SPI interface. To initialize this - * interface, the controller expects a falling edge on the CS pin. */ - c->chip_select_pin_write(1); - if (c->reset_pin_write != NULL) { - c->reset_pin_write(1); - delay_ms(10); - c->reset_pin_write(0); - delay_ms(10); - c->reset_pin_write(1); - delay_ms(100); - } - delay_ms(10); - c->chip_select_pin_write(0); - - /* We were provided the following init sequence by the manufacturer */ - const instruction_t init_sequence[] = { - COMMAND(SLPOUT), - COMMAND(NOP), // Just needed because of the delay and the 9-bit thing... - DELAY(120), //Delay 120ms - - // Manufacturer says MADCTL = 0 - // COMMAND(MADCTL), DATA(0x00), - - COMMAND(MADCTL), DATA(0xA0), - // D7 = MY = 1 : Bottom-to-top - // D5 = MV = 1 : Invert columns and rows (rotate 90deg) - - COMMAND(COLMOD), DATA(0x05), - - COMMAND(PORCTRL), - DATA(0x0c), DATA(0x0c), DATA(0x00), DATA(0x33), DATA(0x33), - - COMMAND(GCTRL), DATA(0x35), //VGH=13V, VGL=-10.4V - COMMAND(VCOMS), DATA(0x19), - COMMAND(LCMCTRL), DATA(0x2c), - COMMAND(VDVVRHEN), DATA(0x01), - COMMAND(VRHS), DATA(0x12), - COMMAND(VDVS), DATA(0x20), - COMMAND(FRCTRL2), DATA(0x0f), - COMMAND(PWCTRL1), DATA(0xa4), DATA(0xa1), - - COMMAND(PVGAMCTRL), //gamma setting - DATA(0xd0), DATA(0x04), DATA(0x0d), DATA(0x11), DATA(0x13), DATA(0x2b), - DATA(0x3f), DATA(0x54), DATA(0x4c), DATA(0x18), DATA(0x0d), DATA(0x0b), - DATA(0x1f), DATA(0x23), - - COMMAND(NVGAMCTRL), - DATA(0xd0), DATA(0x04), DATA(0x0c), DATA(0x11), DATA(0x13), DATA(0x2c), - DATA(0x3f), DATA(0x44), DATA(0x51), DATA(0x2f), DATA(0x1f), DATA(0x1f), - DATA(0x20), DATA(0x23), - - COMMAND(DISPON) //display on - }; - - // Send all the initialisation_sequence - perform_instructions(c, init_sequence, sizeof(init_sequence)/sizeof(init_sequence[0])); -} - -void st7789_set_drawing_area(st7789_t * controller, uint16_t x, uint16_t y, uint16_t width, uint16_t height) { - uint16_t x_start = x; - uint16_t x_end = x + width - 1; - uint16_t y_start = y; - uint16_t y_end = y + height - 1; - - const instruction_t sequence[] = { - COMMAND(CASET), - DATA(x_start >> 8), - DATA(x_start & 0xFF), - DATA(x_end >> 8), - DATA(x_end & 0xFF), - - COMMAND(RASET), - DATA(y_start >> 8), - DATA(y_start & 0xFF), - DATA(y_end >> 8), - DATA(y_end & 0xFF), - - COMMAND(RAMRW) - }; - - perform_instructions(controller, sequence, sizeof(sequence)/sizeof(sequence[0])); -} - - -void st7789_push_pixels(st7789_t * controller, - const ion_color_t * pixels, size_t numberOfPixels) { - assert(sizeof(ion_color_t) == 2); // We expect KDColor to be RGB565 - for (size_t i=0; i> 8)); - perform_instruction(controller, DATA(pixels[i] & 0xFF)); - } -} diff --git a/ion/src/device/display/st7789.h b/ion/src/device/display/st7789.h deleted file mode 100644 index 553f5d46a..000000000 --- a/ion/src/device/display/st7789.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef ION_DEVICE_DISPLAY_ST7789_H -#define ION_DEVICE_DISPLAY_ST7789_H - -#include -#include -#include -#include - -#define ST7789_USE_9BIT_SPI 1 - -typedef struct { - void (*reset_pin_write)(bool pin_state); - void (*chip_select_pin_write)(bool pin_state); - void (*spi_write)(char * data, size_t size); -#if ST7789_USE_9BIT_SPI - uint32_t spi_queue; - uint8_t spi_queue_usage_in_bits; -#else - void (*data_command_pin_write)(bool pin_state); -#endif -} st7789_t; - -void st7789_initialize(st7789_t * controller); - -void st7789_set_drawing_area(st7789_t * controller, uint16_t x, uint16_t y, uint16_t width, uint16_t height); - -void st7789_push_pixels(st7789_t * controller, - const ion_color_t * pixels, size_t numberOfPixels); -#endif diff --git a/ion/src/device/init.c b/ion/src/device/init.c index 0012237b3..518528593 100644 --- a/ion/src/device/init.c +++ b/ion/src/device/init.c @@ -1,7 +1,6 @@ #include #include #include "init.h" -#include "display/display.h" #include "keyboard/keyboard.h" #include "registers/registers.h" @@ -20,7 +19,7 @@ void init_platform() { enable_fpu(); init_keyboard(); ion_led_init(); - init_display(); + ion_screen_init(); } void ion_sleep() {