driver: Updated ILI9340 driver to use display API
Updated ILI9340 display driver and sample application to make use off the display API Signed-off-by: Jan Van Winkel <jan.van_winkel@dxplore.eu>
This commit is contained in:
parent
7926a34a31
commit
d332ae5b6a
7 changed files with 194 additions and 90 deletions
|
@ -1,7 +1,7 @@
|
|||
# Kconfig - ILI9340 display driver configuration options
|
||||
|
||||
#
|
||||
# Copyright (c) 2017 dXplore
|
||||
# Copyright (c) 2017 Jan Van Winkel <jan.van_winkel@dxplore.eu>
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# Kconfig - Microbit display driver configuration options
|
||||
|
||||
#
|
||||
# Copyright (c) 2017 dXplore
|
||||
# Copyright (c) 2017 Jan Van Winkel <jan.van_winkel@dxplore.eu>
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
/* Copyright (c) 2017 dXplore
|
||||
/*
|
||||
* Copyright (c) 2017 Jan Van Winkel <jan.van_winkel@dxplore.eu>
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "display_ili9340.h"
|
||||
#include <drivers/display/ili9340.h>
|
||||
#include <display.h>
|
||||
|
||||
#define LOG_LEVEL CONFIG_LOG_ILI9340_LEVEL
|
||||
#include <logging/log.h>
|
||||
|
@ -13,6 +14,7 @@ LOG_MODULE_REGISTER(display);
|
|||
#include <gpio.h>
|
||||
#include <misc/byteorder.h>
|
||||
#include <spi.h>
|
||||
#include <string.h>
|
||||
|
||||
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);
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
/* Copyright (c) 2017 dXplore
|
||||
/*
|
||||
* Copyright (c) 2017 Jan Van Winkel <jan.van_winkel@dxplore.eu>
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
/* Copyright (c) 2017 dXplore
|
||||
/*
|
||||
* Copyright (c) 2017 Jan Van Winkel <jan.van_winkel@dxplore.eu>
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
/* Copyright (c) 2017 dXplore
|
||||
/*
|
||||
* Copyright (c) 2017 Jan Van Winkel <jan.van_winkel@dxplore.eu>
|
||||
*
|
||||
* 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
|
||||
}
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
/*
|
||||
* Copyright (c) 2017 dXplore
|
||||
* Copyright (c) 2017 Jan Van Winkel <jan.van_winkel@dxplore.eu>
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <device.h>
|
||||
#include <drivers/display/ili9340.h>
|
||||
#include <display.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <zephyr.h>
|
||||
|
@ -14,9 +14,6 @@
|
|||
#include <logging/log.h>
|
||||
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;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue