1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00
RIOT/drivers/ili9341/ili9341.c
Gunar Schorcht 6d61381d2a drivers: use inline functions for GPIO comparisons
The expandable GPIO API requires the comparison of structured GPIO types. This means that inline functions must be used instead of direct comparisons. For the migration process, drivers must first be changed so that they use the inline comparison functions.
2020-08-31 13:10:28 +02:00

320 lines
9.1 KiB
C

/*
* 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 <koen@bergzand.net>
*
* @}
*/
#include <assert.h>
#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(const 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(const 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(const 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(const 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)
{
assert(params->lines >= 16 && params->lines <= 320 && !(params->lines & 0x7));
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 (gpio_is_valid(dev->params->rst_pin)) {
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;
command_params[0] |= dev->params->rgb ? 0 : 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;
/* number of lines, see datasheet p. 166 (DISCTRL::NL) */
command_params[2] = (params->lines >> 3) - 1;
_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));
}
if (dev->params->inverted) {
_write_cmd(dev, ILI9341_CMD_DINVON, NULL, 0);
}
/* 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(const 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(const 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(const 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(const 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(const ili9341_t *dev)
{
uint8_t command = (dev->params->inverted) ? ILI9341_CMD_DINVOFF
: ILI9341_CMD_DINVON;
ili9341_write_cmd(dev, command, NULL, 0);
}
void ili9341_invert_off(const ili9341_t *dev)
{
uint8_t command = (dev->params->inverted) ? ILI9341_CMD_DINVON
: ILI9341_CMD_DINVOFF;
ili9341_write_cmd(dev, command, NULL, 0);
}
void ili9341_set_brightness(const 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);
}