185 lines
5.2 KiB
C
185 lines
5.2 KiB
C
/* Copyright (c) 2017 dXplore
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#include "display_ili9340.h"
|
|
#include <drivers/display/ili9340.h>
|
|
|
|
#define SYS_LOG_DOMAIN "ILI9340"
|
|
#define SYS_LOG_LEVEL CONFIG_SYS_LOG_ILI9340_LEVEL
|
|
#include <logging/sys_log.h>
|
|
|
|
#include <gpio.h>
|
|
#include <misc/byteorder.h>
|
|
#include <spi.h>
|
|
|
|
struct ili9340_data {
|
|
struct device *reset_gpio;
|
|
struct device *command_data_gpio;
|
|
struct device *spi_dev;
|
|
struct spi_config spi_config;
|
|
#ifdef CONFIG_ILI9340_GPIO_CS
|
|
struct spi_cs_control cs_ctrl;
|
|
#endif
|
|
};
|
|
|
|
#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);
|
|
|
|
int ili9340_init(struct device *dev)
|
|
{
|
|
struct ili9340_data *data = (struct ili9340_data *)dev->driver_data;
|
|
|
|
SYS_LOG_DBG("Initializing display driver");
|
|
|
|
data->spi_dev = device_get_binding(CONFIG_ILI9340_SPI_DEV_NAME);
|
|
if (data->spi_dev == NULL) {
|
|
SYS_LOG_ERR("Could not get SPI device for ILI9340");
|
|
return -EPERM;
|
|
}
|
|
|
|
data->spi_config.frequency = CONFIG_ILI9340_SPI_FREQ;
|
|
data->spi_config.operation = SPI_OP_MODE_MASTER | SPI_WORD_SET(8);
|
|
data->spi_config.slave = CONFIG_ILI9340_SPI_SLAVE_NUMBER;
|
|
|
|
#ifdef CONFIG_ILI9340_GPIO_CS
|
|
data->cs_ctrl.gpio_dev =
|
|
device_get_binding(CONFIG_ILI9340_CS_GPIO_PORT_NAME);
|
|
data->cs_ctrl.gpio_pin = CONFIG_ILI9340_CS_GPIO_PIN;
|
|
data->cs_ctrl.delay = 0;
|
|
data->spi_config.cs = &(data->cs_ctrl);
|
|
#else
|
|
data->spi_config.cs = NULL;
|
|
#endif
|
|
|
|
data->reset_gpio =
|
|
device_get_binding(CONFIG_ILI9340_RESET_GPIO_PORT_NAME);
|
|
if (data->reset_gpio == NULL) {
|
|
SYS_LOG_ERR("Could not get GPIO port for ILI9340 reset");
|
|
return -EPERM;
|
|
}
|
|
|
|
gpio_pin_configure(data->reset_gpio, CONFIG_ILI9340_RESET_PIN,
|
|
GPIO_DIR_OUT);
|
|
|
|
data->command_data_gpio =
|
|
device_get_binding(CONFIG_ILI9340_CMD_DATA_GPIO_PORT_NAME);
|
|
if (data->command_data_gpio == NULL) {
|
|
SYS_LOG_ERR("Could not get GPIO port for ILI9340 command/data");
|
|
return -EPERM;
|
|
}
|
|
|
|
gpio_pin_configure(data->command_data_gpio, CONFIG_ILI9340_CMD_DATA_PIN,
|
|
GPIO_DIR_OUT);
|
|
|
|
SYS_LOG_DBG("Resetting display driver");
|
|
gpio_pin_write(data->reset_gpio, CONFIG_ILI9340_RESET_PIN, 1);
|
|
k_sleep(1);
|
|
gpio_pin_write(data->reset_gpio, CONFIG_ILI9340_RESET_PIN, 0);
|
|
k_sleep(1);
|
|
gpio_pin_write(data->reset_gpio, CONFIG_ILI9340_RESET_PIN, 1);
|
|
k_sleep(5);
|
|
|
|
SYS_LOG_DBG("Initializing LCD");
|
|
ili9340_lcd_init(data);
|
|
|
|
SYS_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;
|
|
}
|
|
|
|
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)
|
|
{
|
|
u8_t rgb_data[] = {r, g, b};
|
|
|
|
SYS_LOG_DBG("Writing pixel @ %dx%d (x,y)", x, y);
|
|
ili9340_write_bitmap(dev, x, y, 1, 1, &rgb_data[0]);
|
|
}
|
|
|
|
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)
|
|
{
|
|
struct ili9340_data *data = (struct ili9340_data *)dev->driver_data;
|
|
|
|
SYS_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;
|
|
|
|
SYS_LOG_DBG("Turning display on");
|
|
ili9340_transmit(data, ILI9340_CMD_DISPLAY_ON, NULL, 0);
|
|
}
|
|
|
|
void ili9340_display_off(struct device *dev)
|
|
{
|
|
struct ili9340_data *data = (struct ili9340_data *)dev->driver_data;
|
|
|
|
SYS_LOG_DBG("Turning display off");
|
|
ili9340_transmit(data, ILI9340_CMD_DISPLAY_OFF, NULL, 0);
|
|
}
|
|
|
|
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};
|
|
|
|
gpio_pin_write(data->command_data_gpio, CONFIG_ILI9340_CMD_DATA_PIN,
|
|
ILI9340_CMD_DATA_PIN_COMMAND);
|
|
spi_write(data->spi_dev, &data->spi_config, &tx_bufs);
|
|
|
|
if (tx_data != NULL) {
|
|
tx_buf.buf = tx_data;
|
|
tx_buf.len = tx_len;
|
|
gpio_pin_write(data->command_data_gpio,
|
|
CONFIG_ILI9340_CMD_DATA_PIN,
|
|
ILI9340_CMD_DATA_PIN_DATA);
|
|
spi_write(data->spi_dev, &data->spi_config, &tx_bufs);
|
|
}
|
|
}
|
|
|
|
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 struct ili9340_data ili9340_data;
|
|
|
|
DEVICE_INIT(ili9340, CONFIG_ILI9340_DEV_NAME, &ili9340_init, &ili9340_data,
|
|
NULL, APPLICATION, CONFIG_APPLICATION_INIT_PRIORITY);
|