/* * Copyright (c) 2006-2021, RT-Thread Development Team * * SPDX-License-Identifier: Apache-2.0 * * Change Logs: * Date Author Notes * 2020-11-08 bigmagic first version */ #include #include #include #include #include "drv_ili9486.h" #ifdef USING_LCD_CONSOLE #include "lcd_console.h" #endif //http://www.lcdwiki.com/MHS-3.5inch_RPi_Display #define LCD_DEVICE_NAME ("spi0.0") #define LCD_SPI_SEND_FAST //waveshare #define LCD_SCREEN_WIDTH (320) #define LCD_SCREEN_HEIGHT (480) #define LCD_RESET_PIN (25) #define LCD_RS_PIN (24) #define LCD_SPI_FREQ_MAX (125*1000*1000) uint16_t LCD_HEIGHT = LCD_SCREEN_HEIGHT; uint16_t LCD_WIDTH = LCD_SCREEN_WIDTH; #define SCREEN_VERTICAL_1 (0) #define SCREEN_HORIZONTAL_1 (1) #define SCREEN_VERTICAL_2 (2) #define SCREEN_HORIZONTAL_2 (3) struct rt_semaphore lcd_spi_lock; struct rt_semaphore lcd_lock; //rgb565 lcd buffer uint16_t _lcd_buffer[LCD_SCREEN_WIDTH * LCD_SCREEN_HEIGHT]; uint16_t send_buffer[LCD_SCREEN_WIDTH * LCD_SCREEN_HEIGHT]; static struct rt_spi_device *lcd_dev; static inline void send_cmd(void) { rt_pin_write(LCD_RS_PIN, PIN_LOW); } static inline void send_data(void) { rt_pin_write(LCD_RS_PIN, PIN_HIGH); } void writeData16(rt_uint16_t data) { rt_uint8_t send_data[2]; send_data[1] = data & 0x00FF; send_data[0] = ((data >> 8) & 0x00FF); rt_spi_transfer(lcd_dev, &send_data[0], RT_NULL, 2); } void writeData(void* dev,rt_uint8_t data) { writeData16((rt_uint16_t)(data)); } void writeCommand(void* dev, rt_uint8_t cmd) { send_cmd(); writeData16((rt_uint16_t)(cmd)); send_data(); } void lcd_write_commmand(rt_uint8_t cmd) { writeCommand(lcd_dev, cmd); } void lcd_write_data(rt_uint8_t data) { writeData(lcd_dev, data); } /*Ser rotation of the screen - changes x0 and y0*/ static inline void lcd_set_rotation(uint8_t rotation) { writeCommand(lcd_dev, 0x36); rt_thread_mdelay(100); switch(rotation) { case SCREEN_VERTICAL_1: writeData(lcd_dev, 0x48); LCD_WIDTH = 320; LCD_HEIGHT = 480; break; case SCREEN_HORIZONTAL_1: writeData(lcd_dev, 0x28); LCD_WIDTH = 480; LCD_HEIGHT = 320; break; case SCREEN_VERTICAL_2: writeData(lcd_dev, 0x98); LCD_WIDTH = 320; LCD_HEIGHT = 480; break; case SCREEN_HORIZONTAL_2: writeData(lcd_dev, 0xF8); LCD_WIDTH = 480; LCD_HEIGHT = 320; break; default: //EXIT IF SCREEN ROTATION NOT VALID! break; } if((rotation == SCREEN_VERTICAL_1) || (rotation == SCREEN_VERTICAL_2)) { lcd_write_commmand(0x2A); lcd_write_data(0x00); lcd_write_data(0x00); lcd_write_data(0x01); lcd_write_data(0x3F); lcd_write_commmand(0x2B); lcd_write_data(0x00); lcd_write_data(0x00); lcd_write_data(0x01); lcd_write_data(0xE0); } if((rotation == SCREEN_HORIZONTAL_1) || (rotation == SCREEN_HORIZONTAL_2)) { lcd_write_commmand(0x2B); lcd_write_data(0x00); lcd_write_data(0x00); lcd_write_data(0x01); lcd_write_data(0x3F); lcd_write_commmand(0x2A); lcd_write_data(0x00); lcd_write_data(0x00); lcd_write_data(0x01); lcd_write_data(0xE0); } } static inline void fast_send_data(void) { rt_uint32_t ii = 0; rt_uint32_t tx_index = 0; char *tx_data = (char *)send_buffer; rt_sem_take(&lcd_spi_lock, RT_WAITING_FOREVER); SPI_REG_CS(SPI_0_BASE) &= (~(3 << 0)); SPI_REG_CLK(SPI_0_BASE) = 4; SPI_REG_CS(SPI_0_BASE) |= SPI_CS_TA; for(tx_index=0;tx_index<(LCD_SCREEN_WIDTH * LCD_SCREEN_HEIGHT) * 2;tx_index++) { for(ii = 0; ii < 32; ii = ii + 2) { SPI_REG_FIFO(SPI_0_BASE) = tx_data[tx_index + ii + 1]; SPI_REG_FIFO(SPI_0_BASE) = tx_data[tx_index + ii]; } while (!(SPI_REG_CS(SPI_0_BASE) & SPI_CS_DONE)); SPI_REG_CS(SPI_0_BASE) |= (SPI_CS_CLEAR_TX) | (SPI_CS_CLEAR_RX); tx_index = tx_index + 31; } SPI_REG_CS(SPI_0_BASE) |= (SPI_CS_CLEAR_TX) | (SPI_CS_CLEAR_RX); SPI_REG_CS(SPI_0_BASE) &= (~SPI_CS_TA); rt_sem_release(&lcd_spi_lock); } static inline void lcd_show(void) { lcd_write_commmand(0x2C); // Memory write? //rt_thread_mdelay(150); #ifdef LCD_SPI_SEND_FAST fast_send_data(); #else int i, j; for (i = 0 ; i < 30 ; i ++) { uint16_t *tx_data = (uint16_t*)&send_buffer[5120* i]; int32_t data_sz = 5120; for( j=0; jpixel_format = RTGRAPHIC_PIXEL_FORMAT_RGB565; info->bits_per_pixel= 16; info->width = LCD_WIDTH; info->height = LCD_HEIGHT; info->framebuffer = (void *)_lcd_buffer;//lcd->fb; } break; } rt_sem_release(&lcd_lock); return RT_EOK; } #ifdef RT_USING_DEVICE_OPS const static struct rt_device_ops ili9486_ops = { RT_NULL, ili9486_open, ili9486_close, ili9486_read, ili9486_write, ili9486_control, }; #endif static int hw_ili9486_lcd_init(void) { struct rt_device *device; device = rt_malloc(sizeof(struct rt_device)); rt_memset(device, 0, sizeof(struct rt_device)); lcd_reset(); rt_pin_mode(LCD_RS_PIN, PIN_MODE_OUTPUT); lcd_dev = (struct rt_spi_device *)rt_device_find(LCD_DEVICE_NAME); if (!lcd_dev) { rt_kprintf("no %s!\n", LCD_DEVICE_NAME); } lcd_dev->config.max_hz = LCD_SPI_FREQ_MAX;//125M lcd_init(); rt_sem_init(&lcd_spi_lock, "lcd_spi_lock", 1, RT_IPC_FLAG_FIFO); rt_sem_init(&lcd_lock, "lcd_spi_lock", 1, RT_IPC_FLAG_FIFO); /* set device type */ device->type = RT_Device_Class_Graphic; /* initialize device interface */ #ifdef RT_USING_DEVICE_OPS device->ops = &ili9486_ops; #else device->init = RT_NULL; device->open = ili9486_open; device->close = ili9486_close; device->read = ili9486_read; device->write = ili9486_write; device->control = ili9486_control; #endif /* register to device manager */ rt_device_register(device, "lcd", RT_DEVICE_FLAG_RDWR); return RT_EOK; } INIT_DEVICE_EXPORT(hw_ili9486_lcd_init);