Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions drivers/Makefile.dep
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,11 @@ ifneq (,$(filter hts221,$(USEMODULE)))
FEATURES_REQUIRED += periph_i2c
endif

ifneq (,$(filter ili9341,$(USEMODULE)))
FEATURES_REQUIRED += periph_spi
FEATURES_REQUIRED += periph_gpio
endif

ifneq (,$(filter ina2%,$(USEMODULE)))
USEMODULE += ina2xx
endif
Expand Down
4 changes: 4 additions & 0 deletions drivers/Makefile.include
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,10 @@ ifneq (,$(filter hts221,$(USEMODULE)))
USEMODULE_INCLUDES += $(RIOTBASE)/drivers/hts221/include
endif

ifneq (,$(filter ili9341,$(USEMODULE)))
USEMODULE_INCLUDES += $(RIOTBASE)/drivers/ili9341/include
endif

ifneq (,$(filter ina2xx,$(USEMODULE)))
USEMODULE_INCLUDES += $(RIOTBASE)/drivers/ina2xx/include
endif
Expand Down
1 change: 1 addition & 0 deletions drivers/ili9341/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
include $(RIOTBASE)/Makefile.base
306 changes: 306 additions & 0 deletions drivers/ili9341/ili9341.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,306 @@
/*
* Copyright (C) 2018 Koen Zandberg
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/

/**
* @ingroup drivers_ili9341
* @{
*
* @file
* @brief Device driver implementation for the ili9341 display controller
*
* @author Koen Zandberg <[email protected]>
*
* @}
*/

#include <string.h>
#include "byteorder.h"
#include "periph/spi.h"
#include "xtimer.h"
#include "ili9341.h"
#include "ili9341_internal.h"

#define ENABLE_DEBUG (0)
#include "debug.h"

static void _ili9341_spi_acquire(ili9341_t *dev)
{
spi_acquire(dev->params->spi, dev->params->cs_pin, dev->params->spi_mode,
dev->params->spi_clk);
}

static void _ili9341_cmd_start(ili9341_t *dev, uint8_t cmd, bool cont)
{
gpio_clear(dev->params->dcx_pin);
spi_transfer_byte(dev->params->spi, dev->params->cs_pin, cont, cmd);
gpio_set(dev->params->dcx_pin);
}

/* datasheet page 178, table converted to equation.
* gvdd in 1mv increments: 4850 = 4.85V */
static uint8_t _ili9341_calc_pwrctl1(uint16_t gvdd)
{
return (gvdd - 2850) / 50;
}

static uint8_t _ili9341_calc_vmh(uint16_t vcomh)
{
return (vcomh - 2700) / 25;
}

static uint8_t _ili9341_calc_vml(int16_t vcoml)
{
return (vcoml + 2500) / 25;
}

static void _write_cmd(ili9341_t *dev, uint8_t cmd, const uint8_t *data,
size_t len)
{
_ili9341_cmd_start(dev, cmd, len ? true : false);
if (len) {
spi_transfer_bytes(dev->params->spi, dev->params->cs_pin, false, data,
NULL, len);
}
}

static void _ili9341_set_area(ili9341_t *dev, uint16_t x1, uint16_t x2,
uint16_t y1, uint16_t y2)
{
be_uint16_t params[2];

params[0] = byteorder_htons(x1);
params[1] = byteorder_htons(x2);
_write_cmd(dev, ILI9341_CMD_CASET, (uint8_t *)params,
sizeof(params));
params[0] = byteorder_htons(y1);
params[1] = byteorder_htons(y2);
_write_cmd(dev, ILI9341_CMD_PASET, (uint8_t *)params,
sizeof(params));
}

int ili9341_init(ili9341_t *dev, const ili9341_params_t *params)
{
dev->params = params;
uint8_t command_params[4] = { 0 };
gpio_init(dev->params->dcx_pin, GPIO_OUT);
int res = spi_init_cs(dev->params->spi, dev->params->cs_pin);
if (res != SPI_OK) {
DEBUG("[ili9341] init: error initializing the CS pin [%i]\n", res);
return -1;
}

if (dev->params->rst_pin != GPIO_UNDEF) {
gpio_init(dev->params->rst_pin, GPIO_OUT);
gpio_clear(dev->params->rst_pin);
xtimer_usleep(120 * US_PER_MS);
gpio_set(dev->params->rst_pin);
}
xtimer_usleep(120 * US_PER_MS);

/* Acquire once at release at the end */
_ili9341_spi_acquire(dev);
/* Soft Reset */
_write_cmd(dev, ILI9341_CMD_SWRESET, NULL, 0);
xtimer_usleep(120 * US_PER_MS);

/* Display off */
_write_cmd(dev, ILI9341_CMD_DISPOFF, NULL, 0);

/* PWRCTL1/2 */
command_params[0] = _ili9341_calc_pwrctl1(ILI9341_GVDD);
_write_cmd(dev, ILI9341_CMD_PWCTRL1, command_params, 1);

command_params[0] = 0x10; /* PWRCTL 0 0 0 */
_write_cmd(dev, ILI9341_CMD_PWCTRL2, command_params, 1);

/* VCOMCTL */
command_params[0] = _ili9341_calc_vmh(ILI9341_VCOMH);
command_params[1] = _ili9341_calc_vml(ILI9341_VCOML);
_write_cmd(dev, ILI9341_CMD_VMCTRL1, command_params, 2);

command_params[0] = 0x86;
_write_cmd(dev, ILI9341_CMD_VMCTRL2, command_params, 1);

/* Memory access CTL */
command_params[0] = ILI9341_MADCTL_HORZ_FLIP | ILI9341_MADCTL_BGR;
_write_cmd(dev, ILI9341_CMD_MADCTL, command_params, 1);

/* Frame control */
command_params[0] = 0x00;
command_params[1] = 0x18;
_write_cmd(dev, ILI9341_CMD_FRAMECTL1, command_params, 2);

/* Display function control */
command_params[0] = 0x08;
command_params[1] = 0x82;
command_params[2] = 0x27; /* 320 lines */
_write_cmd(dev, ILI9341_CMD_DFUNC, command_params, 3);


/* Pixel format */
command_params[0] = 0x55; /* 16 bit mode */
_write_cmd(dev, ILI9341_CMD_PIXSET, command_params, 1);


command_params[0] = 0x01;
_write_cmd(dev, ILI9341_CMD_GAMSET, command_params, 1);

/* Gamma correction */
{
static const uint8_t gamma_pos[] = {
0x0F,
0x31,
0x2B,
0x0C,
0x0E,
0x08,
0x4E,
0xF1,
0x37,
0x07,
0x10,
0x03,
0x0E,
0x09,
0x00
};
_write_cmd(dev, ILI9341_CMD_PGAMCTRL, gamma_pos,
sizeof(gamma_pos));
}
{
static const uint8_t gamma_neg[] = {
0x00,
0x0E,
0x14,
0x03,
0x11,
0x07,
0x31,
0xC1,
0x48,
0x08,
0x0F,
0x0C,
0x31,
0x36,
0x0F
};
_write_cmd(dev, ILI9341_CMD_NGAMCTRL, gamma_neg,
sizeof(gamma_neg));

}
/* Sleep out (turn off sleep mode) */
_write_cmd(dev, ILI9341_CMD_SLPOUT, NULL, 0);
/* Display on */
_write_cmd(dev, ILI9341_CMD_DISPON, NULL, 0);
spi_release(dev->params->spi);
return 0;
}

void ili9341_write_cmd(ili9341_t *dev, uint8_t cmd, const uint8_t *data,
size_t len)
{
_ili9341_spi_acquire(dev);
_write_cmd(dev, cmd, data, len);
spi_release(dev->params->spi);
}

void ili9341_read_cmd(ili9341_t *dev, uint8_t cmd, uint8_t *data, size_t len)
{
assert(len);
_ili9341_spi_acquire(dev);
_ili9341_cmd_start(dev, cmd, true);
/* Dummy transfer */
spi_transfer_byte(dev->params->spi, dev->params->cs_pin, true, 0x00);
spi_transfer_bytes(dev->params->spi, dev->params->cs_pin, false, NULL,
data, len);
spi_release(dev->params->spi);
}


void ili9341_fill(ili9341_t *dev, uint16_t x1, uint16_t x2, uint16_t y1,
uint16_t y2, uint16_t color)
{
/* Send fill area to the display */

/* Calculate number of pixels */
int32_t num_pix = (x2 - x1 + 1) * (y2 - y1 + 1);

DEBUG("[ili9341]: Write x1: %" PRIu16 ", x2: %" PRIu16 ", "
"y1: %" PRIu16 ", y2: %" PRIu16 ". Num pixels: %lu\n",
x1, x2, y1, y2, (unsigned long)num_pix);

/* Send fill area to the display */
_ili9341_spi_acquire(dev);

_ili9341_set_area(dev, x1, x2, y1, y2);
/* Memory access command */
_ili9341_cmd_start(dev, ILI9341_CMD_RAMWR, true);
#if ILI9341_LE_MODE
color = htons(color);
#endif
for (int i = 0; i < (num_pix - 1); i++) {
spi_transfer_bytes(dev->params->spi, dev->params->cs_pin, true,
(uint8_t *)&color, NULL, sizeof(color));
}
spi_transfer_bytes(dev->params->spi, dev->params->cs_pin, false,
(uint8_t *)&color, NULL, sizeof(color));
spi_release(dev->params->spi);
}

void ili9341_pixmap(ili9341_t *dev, uint16_t x1, uint16_t x2,
uint16_t y1, uint16_t y2, const uint16_t *color)
{
size_t num_pix = (x2 - x1 + 1) * (y2 - y1 + 1);

DEBUG("[ili9341]: Write x1: %" PRIu16 ", x2: %" PRIu16 ", "
"y1: %" PRIu16 ", y2: %" PRIu16 ". Num pixels: %lu\n",
x1, x2, y1, y2, (unsigned long)num_pix);

_ili9341_spi_acquire(dev);

/* Send fill area to the display */
_ili9341_set_area(dev, x1, x2, y1, y2);

/* Memory access command */
_ili9341_cmd_start(dev, ILI9341_CMD_RAMWR, true);

#if ILI9341_LE_MODE
for (size_t i = 0; i < num_pix - 1; i++) {
uint16_t ncolor = htons(*(color + i));
spi_transfer_bytes(dev->params->spi, dev->params->cs_pin, true,
&ncolor, NULL, sizeof(uint16_t));
}
uint16_t ncolor = htons(*(color + num_pix - 1));
spi_transfer_bytes(dev->params->spi, dev->params->cs_pin, false,
&ncolor, NULL, sizeof(uint16_t));
#else
spi_transfer_bytes(dev->params->spi, dev->params->cs_pin, false,
(const uint8_t *)color, NULL, num_pix * 2);

#endif

spi_release(dev->params->spi);
}

void ili9341_invert_on(ili9341_t *dev)
{
ili9341_write_cmd(dev, ILI9341_CMD_DINVON, NULL, 0);
}

void ili9341_invert_off(ili9341_t *dev)
{
ili9341_write_cmd(dev, ILI9341_CMD_DINVOFF, NULL, 0);
}

void ili9341_set_brightness(ili9341_t *dev, uint8_t brightness)
{
ili9341_write_cmd(dev, ILI9341_CMD_WRDISBV, &brightness, 1);
uint8_t param = 0x26;
ili9341_write_cmd(dev, ILI9341_CMD_WRCTRLD, &param, 1);
}
Loading