diff --git a/drivers/display/Kconfig.ili9340 b/drivers/display/Kconfig.ili9340 index ceefa4f5c6e..2fb272f542c 100644 --- a/drivers/display/Kconfig.ili9340 +++ b/drivers/display/Kconfig.ili9340 @@ -1,7 +1,7 @@ # Kconfig - ILI9340 display driver configuration options # -# Copyright (c) 2017 dXplore +# Copyright (c) 2017 Jan Van Winkel # # SPDX-License-Identifier: Apache-2.0 # diff --git a/drivers/display/Kconfig.microbit b/drivers/display/Kconfig.microbit index ec60d935222..ef46715d90c 100644 --- a/drivers/display/Kconfig.microbit +++ b/drivers/display/Kconfig.microbit @@ -1,7 +1,7 @@ # Kconfig - Microbit display driver configuration options # -# Copyright (c) 2017 dXplore +# Copyright (c) 2017 Jan Van Winkel # # SPDX-License-Identifier: Apache-2.0 # diff --git a/drivers/display/display_ili9340.c b/drivers/display/display_ili9340.c index e03c9884b16..bde1aa2994b 100644 --- a/drivers/display/display_ili9340.c +++ b/drivers/display/display_ili9340.c @@ -1,10 +1,11 @@ -/* Copyright (c) 2017 dXplore +/* + * Copyright (c) 2017 Jan Van Winkel * * SPDX-License-Identifier: Apache-2.0 */ #include "display_ili9340.h" -#include +#include #define LOG_LEVEL CONFIG_LOG_ILI9340_LEVEL #include @@ -13,6 +14,7 @@ LOG_MODULE_REGISTER(display); #include #include #include +#include struct ili9340_data { struct device *reset_gpio; @@ -27,12 +29,13 @@ struct ili9340_data { #define ILI9340_CMD_DATA_PIN_COMMAND 0 #define ILI9340_CMD_DATA_PIN_DATA 1 -static void ili9340_exit_sleep(struct ili9340_data *data); -static void ili9340_set_mem_area(struct ili9340_data *data, const u16_t x, - const u16_t y, const u16_t w, const u16_t h); -static int ili9340_init(struct device *dev); +static void ili9340_exit_sleep(struct ili9340_data *data) +{ + ili9340_transmit(data, ILI9340_CMD_EXIT_SLEEP, NULL, 0); + k_sleep(120); +} -int ili9340_init(struct device *dev) +static int ili9340_init(struct device *dev) { struct ili9340_data *data = (struct ili9340_data *)dev->driver_data; @@ -59,7 +62,7 @@ int ili9340_init(struct device *dev) #endif data->reset_gpio = - device_get_binding(CONFIG_ILI9340_RESET_GPIO_PORT_NAME); + device_get_binding(CONFIG_ILI9340_RESET_GPIO_PORT_NAME); if (data->reset_gpio == NULL) { LOG_ERR("Could not get GPIO port for ILI9340 reset"); return -EPERM; @@ -69,7 +72,7 @@ int ili9340_init(struct device *dev) GPIO_DIR_OUT); data->command_data_gpio = - device_get_binding(CONFIG_ILI9340_CMD_DATA_GPIO_PORT_NAME); + device_get_binding(CONFIG_ILI9340_CMD_DATA_GPIO_PORT_NAME); if (data->command_data_gpio == NULL) { LOG_ERR("Could not get GPIO port for ILI9340 command/data"); return -EPERM; @@ -92,57 +95,152 @@ int ili9340_init(struct device *dev) LOG_DBG("Exiting sleep mode"); ili9340_exit_sleep(data); - /* device_get_binding checks if driver_api is not zero before checking - * device name. - * So just set driver_api to 1 else the function call will fail - */ - dev->driver_api = (void *)1; + return 0; +} + +static void ili9340_set_mem_area(struct ili9340_data *data, const u16_t x, + const u16_t y, const u16_t w, const u16_t h) +{ + u16_t spi_data[2]; + + spi_data[0] = sys_cpu_to_be16(x); + spi_data[1] = sys_cpu_to_be16(x + w - 1); + ili9340_transmit(data, ILI9340_CMD_COLUMN_ADDR, &spi_data[0], 4); + + spi_data[0] = sys_cpu_to_be16(y); + spi_data[1] = sys_cpu_to_be16(y + h - 1); + ili9340_transmit(data, ILI9340_CMD_PAGE_ADDR, &spi_data[0], 4); +} + +static int ili9340_write(const struct device *dev, const u16_t x, + const u16_t y, + const struct display_buffer_descriptor *desc, + const void *buf) +{ + struct ili9340_data *data = (struct ili9340_data *)dev->driver_data; + const u8_t *write_data_start = (u8_t *) buf; + struct spi_buf tx_buf; + struct spi_buf_set tx_bufs; + u16_t write_cnt; + u16_t nbr_of_writes; + u16_t write_h; + + __ASSERT(desc->width <= desc->pitch, "Pitch is smaller then width"); + __ASSERT((3 * desc->pitch * desc->height) <= desc->bu_size, + "Input buffer to small"); + + LOG_DBG("Writing %dx%d (w,h) @ %dx%d (x,y)", desc->width, desc->height, + x, y); + ili9340_set_mem_area(data, x, y, desc->width, desc->height); + + if (desc->pitch > desc->width) { + write_h = 1; + nbr_of_writes = desc->height; + } else { + write_h = desc->height; + nbr_of_writes = 1; + } + + ili9340_transmit(data, ILI9340_CMD_MEM_WRITE, + (void *) write_data_start, 3 * desc->width * write_h); + + tx_bufs.buffers = &tx_buf; + tx_bufs.count = 1; + + write_data_start += (3 * desc->pitch); + for (write_cnt = 1; write_cnt < nbr_of_writes; ++write_cnt) { + tx_buf.buf = (void *)write_data_start; + tx_buf.len = 3 * desc->width * write_h; + spi_write(data->spi_dev, &data->spi_config, &tx_bufs); + write_data_start += (3 * desc->pitch); + } return 0; } -void ili9340_write_pixel(const struct device *dev, const u16_t x, const u16_t y, - const u8_t r, const u8_t g, const u8_t b) +static int ili9340_read(const struct device *dev, const u16_t x, + const u16_t y, + const struct display_buffer_descriptor *desc, + void *buf) { - u8_t rgb_data[] = {r, g, b}; - - LOG_DBG("Writing pixel @ %dx%d (x,y)", x, y); - ili9340_write_bitmap(dev, x, y, 1, 1, &rgb_data[0]); + LOG_ERR("Reading not supported"); + return -ENOTSUP; } -void ili9340_write_bitmap(const struct device *dev, const u16_t x, - const u16_t y, const u16_t w, const u16_t h, - const u8_t *rgb_data) +static void *ili9340_get_framebuffer(const struct device *dev) +{ + LOG_ERR("Direct framebuffer access not supported"); + return NULL; +} + +static int ili9340_display_blanking_off(const struct device *dev) { struct ili9340_data *data = (struct ili9340_data *)dev->driver_data; - LOG_DBG("Writing %dx%d (w,h) bitmap @ %dx%d (x,y)", w, h, x, y); - ili9340_set_mem_area(data, x, y, w, h); - ili9340_transmit(data, ILI9340_CMD_MEM_WRITE, (void *)rgb_data, - 3 * w * h); -} - -void ili9340_display_on(struct device *dev) -{ - struct ili9340_data *data = (struct ili9340_data *)dev->driver_data; - - LOG_DBG("Turning display on"); + LOG_DBG("Turning display blanking off"); ili9340_transmit(data, ILI9340_CMD_DISPLAY_ON, NULL, 0); + return 0; } -void ili9340_display_off(struct device *dev) +static int ili9340_display_blanking_on(const struct device *dev) { struct ili9340_data *data = (struct ili9340_data *)dev->driver_data; - LOG_DBG("Turning display off"); + LOG_DBG("Turning display blanking on"); ili9340_transmit(data, ILI9340_CMD_DISPLAY_OFF, NULL, 0); + return 0; +} + +static int ili9340_set_brightness(const struct device *dev, + const u8_t brightness) +{ + LOG_WRN("Set brightness not implemented"); + return -ENOTSUP; +} + +static int ili9340_set_contrast(const struct device *dev, const u8_t contrast) +{ + LOG_ERR("Set contrast not supported"); + return -ENOTSUP; +} + +static int ili9340_set_pixel_format(const struct device *dev, + const enum display_pixel_format + pixel_format) +{ + if (pixel_format == PIXEL_FORMAT_RGB_888) { + return 0; + } + LOG_ERR("Pixel format change not implemented"); + return -ENOTSUP; +} + +static int ili9340_set_orientation(const struct device *dev, + const enum display_orientation orientation) +{ + if (orientation == DISPLAY_ORIENTATION_NORMAL) { + return 0; + } + LOG_ERR("Changing display orientation not implemented"); + return -ENOTSUP; +} + +static void ili9340_get_capabilities(const struct device *dev, + struct display_capabilities *capabilities) +{ + memset(capabilities, 0, sizeof(struct display_capabilities)); + capabilities->x_resolution = 320; + capabilities->y_resolution = 240; + capabilities->supported_pixel_formats = PIXEL_FORMAT_RGB_888; + capabilities->current_pixel_format = PIXEL_FORMAT_RGB_888; + capabilities->current_orientation = DISPLAY_ORIENTATION_NORMAL; } void ili9340_transmit(struct ili9340_data *data, u8_t cmd, void *tx_data, size_t tx_len) { - struct spi_buf tx_buf = {.buf = &cmd, .len = 1}; - struct spi_buf_set tx_bufs = {.buffers = &tx_buf, .count = 1}; + struct spi_buf tx_buf = { .buf = &cmd, .len = 1 }; + struct spi_buf_set tx_bufs = { .buffers = &tx_buf, .count = 1 }; gpio_pin_write(data->command_data_gpio, CONFIG_ILI9340_CMD_DATA_PIN, ILI9340_CMD_DATA_PIN_COMMAND); @@ -158,27 +256,21 @@ void ili9340_transmit(struct ili9340_data *data, u8_t cmd, void *tx_data, } } -void ili9340_exit_sleep(struct ili9340_data *data) -{ - ili9340_transmit(data, ILI9340_CMD_EXIT_SLEEP, NULL, 0); - k_sleep(120); -} - -void ili9340_set_mem_area(struct ili9340_data *data, const u16_t x, - const u16_t y, const u16_t w, const u16_t h) -{ - u16_t spi_data[2]; - - spi_data[0] = sys_cpu_to_be16(x); - spi_data[1] = sys_cpu_to_be16(x + w - 1); - ili9340_transmit(data, ILI9340_CMD_COLUMN_ADDR, &spi_data[0], 4); - - spi_data[0] = sys_cpu_to_be16(y); - spi_data[1] = sys_cpu_to_be16(y + h - 1); - ili9340_transmit(data, ILI9340_CMD_PAGE_ADDR, &spi_data[0], 4); -} +static const struct display_driver_api ili9340_api = { + .blanking_on = ili9340_display_blanking_on, + .blanking_off = ili9340_display_blanking_off, + .write = ili9340_write, + .read = ili9340_read, + .get_framebuffer = ili9340_get_framebuffer, + .set_brightness = ili9340_set_brightness, + .set_contrast = ili9340_set_contrast, + .get_capabilities = ili9340_get_capabilities, + .set_pixel_format = ili9340_set_pixel_format, + .set_orientation = ili9340_set_orientation, +}; static struct ili9340_data ili9340_data; -DEVICE_INIT(ili9340, CONFIG_ILI9340_DEV_NAME, &ili9340_init, &ili9340_data, - NULL, APPLICATION, CONFIG_APPLICATION_INIT_PRIORITY); +DEVICE_AND_API_INIT(ili9340, CONFIG_ILI9340_DEV_NAME, &ili9340_init, + &ili9340_data, NULL, APPLICATION, + CONFIG_APPLICATION_INIT_PRIORITY, &ili9340_api); diff --git a/drivers/display/display_ili9340.h b/drivers/display/display_ili9340.h index 9182d0b7c67..633413a1070 100644 --- a/drivers/display/display_ili9340.h +++ b/drivers/display/display_ili9340.h @@ -1,4 +1,5 @@ -/* Copyright (c) 2017 dXplore +/* + * Copyright (c) 2017 Jan Van Winkel * * SPDX-License-Identifier: Apache-2.0 */ diff --git a/drivers/display/display_ili9340_adafruit_1480.c b/drivers/display/display_ili9340_adafruit_1480.c index 535741a341a..c5a6ca7c56a 100644 --- a/drivers/display/display_ili9340_adafruit_1480.c +++ b/drivers/display/display_ili9340_adafruit_1480.c @@ -1,4 +1,5 @@ -/* Copyright (c) 2017 dXplore +/* + * Copyright (c) 2017 Jan Van Winkel * * SPDX-License-Identifier: Apache-2.0 */ diff --git a/include/drivers/display/ili9340.h b/include/drivers/display/ili9340.h index 0bbceaf8f48..8c82a2a30c3 100644 --- a/include/drivers/display/ili9340.h +++ b/include/drivers/display/ili9340.h @@ -1,4 +1,5 @@ -/* Copyright (c) 2017 dXplore +/* + * Copyright (c) 2017 Jan Van Winkel * * SPDX-License-Identifier: Apache-2.0 */ @@ -35,23 +36,18 @@ void ili9340_write_pixel(const struct device *dev, const u16_t x, const u16_t y, * @param rgb_data pointer to the RGB data array, the data array should be at * minimum w * h * 3 bytes */ -void ili9340_write_bitmap(const struct device *dev, const u16_t x, - const u16_t y, const u16_t w, const u16_t h, - const u8_t *rgb_data); /** * @brief Turn display on * * @param dev Pointer to device structure */ -void ili9340_display_on(struct device *dev); /** * @brief Turn display off * * @param dev Pointer to device structure */ -void ili9340_display_off(struct device *dev); #ifdef __cplusplus } diff --git a/samples/display/ili9340/src/main.c b/samples/display/ili9340/src/main.c index ea354aa3b77..8101708b167 100644 --- a/samples/display/ili9340/src/main.c +++ b/samples/display/ili9340/src/main.c @@ -1,11 +1,11 @@ /* - * Copyright (c) 2017 dXplore + * Copyright (c) 2017 Jan Van Winkel * * SPDX-License-Identifier: Apache-2.0 */ #include -#include +#include #include #include #include @@ -14,9 +14,6 @@ #include LOG_MODULE_REGISTER(main); -#define SCREEN_WIDTH 320 -#define SCREEN_HEIGHT 240 - /* This example will update each 500ms one of the LCD corners * wit a rectangular bitmap. * The color of the bit map is changed for every @@ -26,6 +23,9 @@ void main(void) { struct device *dev; + struct display_capabilities capabilities; + struct display_buffer_descriptor buf_desc; + /* size of the rectangle */ const size_t w = 40; const size_t h = 20; @@ -33,14 +33,7 @@ void main(void) u8_t *buf; /* xy coordinates where to place rectangles*/ - const size_t x0 = 0; - const size_t y0 = 0; - const size_t x1 = SCREEN_WIDTH - w; - const size_t y1 = 0; - const size_t x2 = SCREEN_WIDTH - w; - const size_t y2 = SCREEN_HEIGHT - h; - const size_t x3 = 0; - const size_t y3 = SCREEN_HEIGHT - h; + size_t x0, y0, x1, y1, x2, y2, x3, y3; size_t color = 0; size_t cnt = 0; @@ -53,6 +46,18 @@ void main(void) return; } + display_get_capabilities(dev, &capabilities); + + x0 = 0; + y0 = 0; + x1 = capabilities.x_resolution - w; + y1 = 0; + x2 = capabilities.x_resolution - w; + y2 = capabilities.y_resolution - h; + x3 = 0; + y3 = capabilities.y_resolution - h; + + /* Allocate rectangular buffer for corner data */ buf = k_malloc(buf_size); @@ -64,13 +69,22 @@ void main(void) /* Clear ili9340 frame buffer before enabling LCD, reuse corner buffer */ (void)memset(buf, 0, buf_size); - h_step = (w * h) / SCREEN_WIDTH; + h_step = (w * h) / capabilities.x_resolution; - for (int idx = 0; idx < SCREEN_HEIGHT; idx += h_step) { - ili9340_write_bitmap(dev, 0, idx, SCREEN_WIDTH, h_step, buf); + buf_desc.buf_size = buf_size; + buf_desc.pitch = capabilities.x_resolution; + buf_desc.width = capabilities.x_resolution; + buf_desc.height = h_step; + + for (int idx = 0; idx < capabilities.y_resolution; idx += h_step) { + display_write(dev, 0, idx, &buf_desc, buf); } - ili9340_display_on(dev); + display_blanking_off(dev); + + buf_desc.pitch = w; + buf_desc.width = w; + buf_desc.height = h; while (1) { /* Update the color of the rectangle buffer and write the buffer @@ -82,16 +96,16 @@ void main(void) } switch (cnt % 4) { case 0: - ili9340_write_bitmap(dev, x0, y0, w, h, buf); + display_write(dev, x0, y0, &buf_desc, buf); break; case 1: - ili9340_write_bitmap(dev, x1, y1, w, h, buf); + display_write(dev, x1, y1, &buf_desc, buf); break; case 2: - ili9340_write_bitmap(dev, x2, y2, w, h, buf); + display_write(dev, x2, y2, &buf_desc, buf); break; case 3: - ili9340_write_bitmap(dev, x3, y3, w, h, buf); + display_write(dev, x3, y3, &buf_desc, buf); break; } ++cnt;