bd4e8e19d3
and fix the wrong correction
1231 lines
35 KiB
C
1231 lines
35 KiB
C
/****************************************************************************
|
|
* boards/arm/stm32/stm32f429i-disco/src/stm32_ili93414ws.c
|
|
*
|
|
* Driver for the ILI9341 Single Chip LCD driver connected
|
|
* via 4 wire serial (spi) mcu interface
|
|
*
|
|
* Copyright (C) 2014 Marco Krahl. All rights reserved.
|
|
* Author: Marco Krahl <ocram.lhark@gmail.com>
|
|
*
|
|
* References: ILI9341_DS_V1.10.pdf (Rev: 1.10), "a-Si TFT LCD Single Chip
|
|
* Driver 240RGBx320 Resolution and 262K color", ILI TECHNOLOGY
|
|
* CORP., http://www.ilitek.com.
|
|
* ILI TECHNOLOGY CORP., http://www.ilitek.com.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
*
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in
|
|
* the documentation and/or other materials provided with the
|
|
* distribution.
|
|
* 3. Neither the name NuttX nor the names of its contributors may be
|
|
* used to endorse or promote products derived from this software
|
|
* without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
|
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
|
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
|
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
|
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
*
|
|
****************************************************************************/
|
|
|
|
/****************************************************************************
|
|
* Included Files
|
|
****************************************************************************/
|
|
|
|
#include <nuttx/config.h>
|
|
|
|
#include <sys/types.h>
|
|
#include <stdbool.h>
|
|
#include <errno.h>
|
|
#include <debug.h>
|
|
|
|
#include <nuttx/irq.h>
|
|
#include <nuttx/arch.h>
|
|
#include <nuttx/spi/spi.h>
|
|
|
|
#include "stm32_rcc.h"
|
|
#include "stm32_spi.h"
|
|
#include "stm32f429i-disco.h"
|
|
|
|
#include <arch/board/board.h>
|
|
|
|
/****************************************************************************
|
|
* Pre-processor Definitions
|
|
****************************************************************************/
|
|
|
|
/* Display is connected at spi5 device */
|
|
|
|
#define ILI93414WS_SPI_DEVICE 5
|
|
|
|
/* spi frequency based on arch/arm/src/stm32/stm32_spi.c */
|
|
|
|
#ifndef CONFIG_STM32F429I_DISCO_ILI9341_SPIFREQUENCY
|
|
# define CONFIG_STM32F429I_DISCO_ILI9341_SPIFREQUENCY 20000000
|
|
#endif
|
|
|
|
#if CONFIG_STM32F429I_DISCO_ILI9341_SPIFREQUENCY >= \
|
|
(STM32_PCLK1_FREQUENCY >> 1)
|
|
# define ILI93414WS_SPI_BR SPI_CR1_FPCLCKd2 /* 000: fPCLK/2 */
|
|
# define ILI93414WS_BAUD_DIVISOR 2
|
|
#elif CONFIG_STM32F429I_DISCO_ILI9341_SPIFREQUENCY >= \
|
|
(STM32_PCLK1_FREQUENCY >> 2)
|
|
# define ILI93414WS_SPI_BR SPI_CR1_FPCLCKd4 /* 001: fPCLK/4 */
|
|
# define ILI93414WS_BAUD_DIVISOR 4
|
|
#elif CONFIG_STM32F429I_DISCO_ILI9341_SPIFREQUENCY >= \
|
|
(STM32_PCLK1_FREQUENCY >> 3)
|
|
# define ILI93414WS_SPI_BR SPI_CR1_FPCLCKd8 /* 010: fPCLK/8 */
|
|
# define ILI93414WS_BAUD_DIVISOR 8
|
|
#elif CONFIG_STM32F429I_DISCO_ILI9341_SPIFREQUENCY >= \
|
|
(STM32_PCLK1_FREQUENCY >> 4)
|
|
# define ILI93414WS_SPI_BR SPI_CR1_FPCLCKd16 /* 011: fPCLK/16 */
|
|
# define ILI93414WS_BAUD_DIVISOR 16
|
|
#elif CONFIG_STM32F429I_DISCO_ILI9341_SPIFREQUENCY >= \
|
|
(STM32_PCLK1_FREQUENCY >> 5)
|
|
# define ILI93414WS_SPI_BR SPI_CR1_FPCLCKd32 /* 100: fPCLK/32 */
|
|
# define ILI93414WS_BAUD_DIVISOR 32
|
|
#elif CONFIG_STM32F429I_DISCO_ILI9341_SPIFREQUENCY >= \
|
|
(STM32_PCLK1_FREQUENCY >> 6)
|
|
# define ILI93414WS_SPI_BR SPI_CR1_FPCLCKd64 /* 101: fPCLK/64 */
|
|
# define ILI93414WS_BAUD_DIVISOR 64
|
|
#elif CONFIG_STM32F429I_DISCO_ILI9341_SPIFREQUENCY >= \
|
|
(STM32_PCLK1_FREQUENCY >> 7)
|
|
# define ILI93414WS_SPI_BR SPI_CR1_FPCLCKd128 /* 110: fPCLK/128 */
|
|
# define ILI93414WS_BAUD_DIVISOR 128
|
|
#else
|
|
# define ILI93414WS_SPI_BR SPI_CR1_FPCLCKd256 /* 111: fPCLK/256 */
|
|
# define ILI93414WS_BAUD_DIVISOR 256
|
|
#endif
|
|
|
|
/*
|
|
* Permitted clock delay for a pixel transmission from the LCD gram.
|
|
* Calculated by cpu clock / (spi clock / baud divisor)
|
|
*/
|
|
|
|
#define ILI93414WS_RECV_CLK (STM32_SYSCLK_FREQUENCY / \
|
|
(STM32_PCLK1_FREQUENCY / \
|
|
ILI93414WS_BAUD_DIVISOR))
|
|
|
|
/* Definition of the spi mcu register */
|
|
|
|
#define ILI93414WS_SPI_BASE STM32_SPI5_BASE
|
|
#define ILI93414WS_SPI_CR1 (ILI93414WS_SPI_BASE + STM32_SPI_CR1_OFFSET)
|
|
#define ILI93414WS_SPI_CR2 (ILI93414WS_SPI_BASE + STM32_SPI_CR2_OFFSET)
|
|
#define ILI93414WS_SPI_SR (ILI93414WS_SPI_BASE + STM32_SPI_SR_OFFSET)
|
|
#define ILI93414WS_SPI_DR (ILI93414WS_SPI_BASE + STM32_SPI_DR_OFFSET)
|
|
|
|
/* Activates the usage of the spi interface structure if several active devices
|
|
* connected on the SPI5 bus, e.g. LCD Display, MEMS. This will perform locking
|
|
* of the spi bus by SPI_LOCK at each selection of the SPI5 device.
|
|
*/
|
|
|
|
#ifdef CONFIG_STM32_SPI5
|
|
# define ILI93414WS_SPI
|
|
#endif
|
|
|
|
/****************************************************************************
|
|
* Private Type Definition
|
|
****************************************************************************/
|
|
|
|
struct ili93414ws_lcd_s
|
|
{
|
|
/* Publicly visible device structure */
|
|
|
|
struct ili9341_lcd_s dev;
|
|
|
|
#ifdef ILI93414WS_SPI
|
|
/* Reference to spi device structure */
|
|
|
|
FAR struct spi_dev_s *spi;
|
|
|
|
/* Backup cr1 register at selection */
|
|
|
|
uint16_t cr1;
|
|
|
|
/* Backup cr2 register at selection */
|
|
|
|
uint16_t cr2;
|
|
#endif
|
|
|
|
#ifndef CONFIG_STM32F429I_DISCO_ILI9341_SPIBITS16
|
|
/* Marks current display operation mode (gram or command/parameter)
|
|
* If 16-bit spi mode is enabled for pixel data operation, the flag is not
|
|
* necessary. The pixel data operation mode can then be recognized by the
|
|
* DFF flag in the cr1 register.
|
|
*/
|
|
|
|
uint8_t gmode;
|
|
#endif
|
|
};
|
|
|
|
/****************************************************************************
|
|
* Private Function Protototypes
|
|
****************************************************************************/
|
|
|
|
/* Low-level spi transfer */
|
|
|
|
static void stm32_ili93414ws_modifyreg(uint32_t reg, uint16_t setbits,
|
|
uint16_t clrbits);
|
|
static inline void stm32_ili93414ws_modifycr1(uint16_t setbits,
|
|
uint16_t clrbits);
|
|
static inline void stm32_ili93414ws_modifycr2(uint16_t setbits,
|
|
uint16_t clrbits);
|
|
static void stm32_ili93414ws_spisendmode(void);
|
|
static void stm32_ili93414ws_spirecvmode(void);
|
|
static void stm32_ili93414ws_spienable(void);
|
|
static void stm32_ili93414ws_spidisable(void);
|
|
|
|
static inline void stm32_ili93414ws_set8bitmode(
|
|
FAR struct ili93414ws_lcd_s *dev);
|
|
static inline void stm32_ili93414ws_set16bitmode(
|
|
FAR struct ili93414ws_lcd_s *dev);
|
|
|
|
/* Command and data transmission control */
|
|
|
|
static void stm32_ili93414ws_sndword(uint16_t wd);
|
|
static int stm32_ili93414ws_sendblock(FAR struct ili93414ws_lcd_s *lcd,
|
|
const uint16_t *wd, uint16_t nwords);
|
|
static uint16_t stm32_ili93414ws_recvword(void);
|
|
static int stm32_ili93414ws_recvblock(FAR struct ili93414ws_lcd_s *lcd,
|
|
uint16_t *wd, uint16_t nwords);
|
|
static inline void stm32_ili93414ws_cmddata(
|
|
FAR struct ili9341_lcd_s *lcd, bool cmd);
|
|
|
|
/* Initializing / Configuration */
|
|
|
|
static void stm32_ili93414ws_spiconfig(FAR struct ili9341_lcd_s *lcd);
|
|
|
|
/****************************************************************************
|
|
* Private Data
|
|
****************************************************************************/
|
|
|
|
struct ili93414ws_lcd_s g_lcddev;
|
|
|
|
/****************************************************************************
|
|
* Private Functions
|
|
****************************************************************************/
|
|
|
|
/****************************************************************************
|
|
* Name: stm32_ili93414ws_modifyreg
|
|
*
|
|
* Description:
|
|
* Clear and set bits in the CR register (based on
|
|
* arch/arm/src/stm32/stm32_spi.c).
|
|
*
|
|
* Input Parameters:
|
|
* reg - register to set
|
|
* clrbits - The bits to clear
|
|
* setbits - The bits to set
|
|
*
|
|
* Returned Value:
|
|
*
|
|
****************************************************************************/
|
|
|
|
static void stm32_ili93414ws_modifyreg(uint32_t reg, uint16_t setbits,
|
|
uint16_t clrbits)
|
|
{
|
|
uint16_t regval;
|
|
|
|
regval = getreg16(reg);
|
|
regval &= ~clrbits;
|
|
regval |= setbits;
|
|
putreg16(regval, reg);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: stm32_ili93414ws_modifycr1
|
|
*
|
|
* Description:
|
|
* Clear and set bits in the CR1 register.
|
|
*
|
|
* Input Parameters:
|
|
* clrbits - The bits to clear
|
|
* setbits - The bits to set
|
|
*
|
|
* Returned Value:
|
|
* None
|
|
*
|
|
****************************************************************************/
|
|
|
|
static inline void stm32_ili93414ws_modifycr1(uint16_t setbits,
|
|
uint16_t clrbits)
|
|
{
|
|
stm32_ili93414ws_modifyreg(ILI93414WS_SPI_CR1, setbits, clrbits);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: stm32_ili93414ws_modifycr2
|
|
*
|
|
* Description:
|
|
* Clear and set bits in the CR2 register.
|
|
*
|
|
* Input Parameters:
|
|
* clrbits - The bits to clear
|
|
* setbits - The bits to set
|
|
*
|
|
* Returned Value:
|
|
* None
|
|
*
|
|
****************************************************************************/
|
|
|
|
static inline void stm32_ili93414ws_modifycr2(uint16_t setbits,
|
|
uint16_t clrbits)
|
|
{
|
|
stm32_ili93414ws_modifyreg(ILI93414WS_SPI_CR2, setbits, clrbits);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: stm32_ili93414ws_spirecvmode
|
|
*
|
|
* Description:
|
|
* Sets the spi device to the bidirectional receive mode
|
|
*
|
|
* Input Parameters:
|
|
*
|
|
* Returned Value:
|
|
*
|
|
****************************************************************************/
|
|
|
|
static void stm32_ili93414ws_spirecvmode(void)
|
|
{
|
|
/* Set to bidirectional rxonly mode */
|
|
|
|
stm32_ili93414ws_modifycr1(0, SPI_CR1_BIDIOE);
|
|
|
|
/* Disable spi */
|
|
|
|
stm32_ili93414ws_spidisable();
|
|
|
|
/* Clear the rx buffer if received data exist e.g. from previous
|
|
* broken transfer.
|
|
*/
|
|
|
|
getreg16(ILI93414WS_SPI_DR);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: stm32_ili93414ws_spisendmode
|
|
*
|
|
* Description:
|
|
* Sets the spi device to the bidirectional transmit mode
|
|
*
|
|
* Input Parameters:
|
|
* None
|
|
*
|
|
* Returned Value:
|
|
* None
|
|
*
|
|
****************************************************************************/
|
|
|
|
static void stm32_ili93414ws_spisendmode(void)
|
|
{
|
|
/* Set to bidirectional transmit mode */
|
|
|
|
stm32_ili93414ws_modifycr1(SPI_CR1_BIDIOE, 0);
|
|
|
|
/* enable spi */
|
|
|
|
stm32_ili93414ws_spienable();
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: stm32_ili93414ws_spienable
|
|
*
|
|
* Description:
|
|
* Enable the spi device
|
|
*
|
|
* Input Parameters:
|
|
* None
|
|
*
|
|
* Returned Value:
|
|
* None
|
|
*
|
|
****************************************************************************/
|
|
|
|
static void stm32_ili93414ws_spienable(void)
|
|
{
|
|
uint16_t regval;
|
|
|
|
regval = getreg16(ILI93414WS_SPI_CR1);
|
|
regval |= SPI_CR1_SPE;
|
|
putreg16(regval, ILI93414WS_SPI_CR1);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: stm32_ili93414ws_spidisable
|
|
*
|
|
* Description:
|
|
* Disable the spi device
|
|
*
|
|
* Input Parameters:
|
|
* None
|
|
*
|
|
* Returned Value:
|
|
* None
|
|
*
|
|
****************************************************************************/
|
|
|
|
static void stm32_ili93414ws_spidisable(void)
|
|
{
|
|
uint16_t regval;
|
|
|
|
regval = getreg16(ILI93414WS_SPI_CR1);
|
|
regval &= ~SPI_CR1_SPE;
|
|
putreg16(regval, ILI93414WS_SPI_CR1);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: stm32_ili93414ws_sndword
|
|
*
|
|
* Description:
|
|
* Send a word to the lcd driver.
|
|
*
|
|
* Input Parameters:
|
|
* wd - word to send
|
|
*
|
|
* Returned Value:
|
|
* None
|
|
*
|
|
****************************************************************************/
|
|
|
|
static void stm32_ili93414ws_sndword(uint16_t wd)
|
|
{
|
|
/* Send the word */
|
|
|
|
putreg16(wd, ILI93414WS_SPI_DR);
|
|
|
|
/* Wait until the transmit buffer is empty */
|
|
|
|
while ((getreg16(ILI93414WS_SPI_SR) & SPI_SR_TXE) == 0);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: stm32_ili93414ws_sendblock
|
|
*
|
|
* Description:
|
|
* Send a number of words to the lcd driver.
|
|
*
|
|
* Input Parameters:
|
|
* spi - Reference to the private device structure
|
|
* wd - Reference to the words to send
|
|
* nwords - number of words to send
|
|
*
|
|
* Returned Value:
|
|
* On success - OK
|
|
*
|
|
****************************************************************************/
|
|
|
|
static int stm32_ili93414ws_sendblock(FAR struct ili93414ws_lcd_s *lcd,
|
|
const uint16_t *wd, uint16_t nwords)
|
|
{
|
|
/* Set to bidirectional transmit mode and enable spi */
|
|
|
|
stm32_ili93414ws_spisendmode();
|
|
|
|
/* Check if 16-bit spi mode is configured for transmit */
|
|
|
|
#ifdef CONFIG_STM32F429I_DISCO_ILI9341_SPIBITS16
|
|
if ((getreg16(ILI93414WS_SPI_CR1) & SPI_CR1_DFF) != 0)
|
|
{
|
|
/* 16-bit spi mode */
|
|
|
|
const uint16_t *src = wd;
|
|
uint16_t word;
|
|
|
|
while (nwords-- > 0)
|
|
{
|
|
word = *src++;
|
|
stm32_ili93414ws_sndword(word);
|
|
}
|
|
}
|
|
#else
|
|
/* 8-bit spi mode is enabled for pixel data operations.
|
|
* Each pixel must be transmitted by two write operations.
|
|
*/
|
|
|
|
if (lcd->gmode == 16)
|
|
{
|
|
/* 8-bit spi mode */
|
|
|
|
const uint16_t *src = wd;
|
|
uint16_t word;
|
|
|
|
while (nwords-- > 0)
|
|
{
|
|
word = *src++;
|
|
stm32_ili93414ws_sndword((word >> 8));
|
|
stm32_ili93414ws_sndword((word & 0xff));
|
|
}
|
|
}
|
|
#endif
|
|
else
|
|
{
|
|
/* 8-bit spi mode */
|
|
|
|
const uint8_t *src = (const uint8_t*)wd;
|
|
uint8_t word;
|
|
|
|
while (nwords-- > 0)
|
|
{
|
|
word = *src++;
|
|
stm32_ili93414ws_sndword((uint16_t)word);
|
|
}
|
|
|
|
}
|
|
|
|
/* Wait until transmit is not busy after the last word is transmitted, marked
|
|
* by the BSY flag in the cr1 register. This is necessary if entering in halt
|
|
* mode or disable the spi periphery.
|
|
*/
|
|
|
|
while ((getreg16(ILI93414WS_SPI_SR) & SPI_SR_BSY) != 0);
|
|
|
|
/* Disable spi */
|
|
|
|
stm32_ili93414ws_spidisable();
|
|
|
|
return OK;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: stm32_ili93414ws_recvword
|
|
*
|
|
* Description:
|
|
* Receive a word from the lcd driver.
|
|
*
|
|
* Input Parameters:
|
|
* None
|
|
*
|
|
* Returned Value:
|
|
* On success - The received word from the LCD Single Chip Driver.
|
|
* On error - 0 (If timeout during receiving)
|
|
*
|
|
****************************************************************************/
|
|
|
|
static uint16_t stm32_ili93414ws_recvword(void)
|
|
{
|
|
volatile int n;
|
|
volatile uint16_t regval;
|
|
irqstate_t flags;
|
|
|
|
/* Disable interrupts during time critical spi sequence.
|
|
* In bidrectional receive mode the data transfer can only be stopped by
|
|
* disabling the spi device. This is here done by disabling the spi device
|
|
* immediately after enabling it. If the pixel data stream is interrupted
|
|
* during receiving, a synchronized transfer can not ensure. Especially on
|
|
* higher frequency it can happen that the interrupted driver isn't fast
|
|
* enough to stop transmitting by disabling the spi device. So pixels lost but
|
|
* not recognized by the driver. This results in a big lock because the driver
|
|
* wants to receive missing pixel data.
|
|
* The critical section here ensures that the spi device is disabled fast
|
|
* enough during a pixel is transmitted.
|
|
*/
|
|
|
|
flags = enter_critical_section();
|
|
|
|
/* Backup the content of the current cr1 register only 1 times */
|
|
|
|
regval = getreg16(ILI93414WS_SPI_CR1);
|
|
|
|
/* Enable spi device followed by disable the spi device.
|
|
*
|
|
* Ensure that the spi is disabled within 8 or 16 spi clock cycles depending
|
|
* on the configured spi bit mode. This is necessary to prevent that the next
|
|
* data word is transmitted by the slave before the RX buffer is cleared.
|
|
* Otherwise the RX buffer will be overwritten.
|
|
*
|
|
* Physically the spi clock is disabled after the current 8/16 clock cycles
|
|
* are completed.
|
|
*/
|
|
|
|
regval |= SPI_CR1_SPE;
|
|
putreg16(regval, ILI93414WS_SPI_CR1);
|
|
|
|
/* Disable spi device */
|
|
|
|
regval &= ~SPI_CR1_SPE;
|
|
putreg16(regval, ILI93414WS_SPI_CR1);
|
|
|
|
/* The spi device is in disabled state so it is safe to enable interrupts */
|
|
|
|
leave_critical_section(flags);
|
|
|
|
/* Waits until the RX buffer is filled with the received data word signalized
|
|
* by the spi hardware through the RXNE flag.
|
|
* A busy loop is preferred against interrupt driven receiving method here
|
|
* because this happened fairly often. Also we have to ensure to avoid a big
|
|
* lock if the lcd driver doesn't send data anymore.
|
|
* A latency of CPU clock / SPI clock * 16 SPI clocks should be enough here.
|
|
*/
|
|
|
|
for (n = 0; n < ILI93414WS_RECV_CLK * 16; n++)
|
|
{
|
|
if ((getreg16(ILI93414WS_SPI_SR) & SPI_SR_RXNE) != 0)
|
|
{
|
|
/* Receive the data word from the RX buffer */
|
|
|
|
return getreg16(ILI93414WS_SPI_DR);
|
|
}
|
|
}
|
|
|
|
lcdinfo("Timeout during receiving pixel word\n");
|
|
|
|
return 0;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: stm32_ili93414ws_recvblock
|
|
*
|
|
* Description:
|
|
* Receive a number of words from to the lcd driver.
|
|
* Note: The first received word is the dummy word and discarded!
|
|
*
|
|
* Input Parameters:
|
|
* spi - Reference to the private device structure
|
|
* wd - Reference to where the words receive
|
|
* nwords - number of words to receive
|
|
*
|
|
* Returned Value:
|
|
* OK - On Success
|
|
*
|
|
****************************************************************************/
|
|
|
|
static int stm32_ili93414ws_recvblock(FAR struct ili93414ws_lcd_s *lcd,
|
|
uint16_t *wd, uint16_t nwords)
|
|
{
|
|
/* ili9341 uses a 18-bit pixel format packed in a 24-bit stream per pixel.
|
|
* The following format is transmitted: RRRRRR00 GGGGGG00 BBBBBB00
|
|
* Convert it to: RRRRRGGG GGGBBBBB
|
|
*/
|
|
|
|
/* Set to bidirectional transmit mode and disable spi */
|
|
|
|
stm32_ili93414ws_spirecvmode();
|
|
|
|
/* Check if 16-bit spi mode is configured for receive */
|
|
|
|
#ifdef CONFIG_STM32F429I_DISCO_ILI9341_SPIBITS16
|
|
/* Two contiguous pixel must be received by three read operations. */
|
|
|
|
if ((getreg16(ILI93414WS_SPI_CR1) & SPI_CR1_DFF) != 0)
|
|
{
|
|
/* 16-bit mode */
|
|
|
|
uint16_t *dest = wd;
|
|
uint16_t w1;
|
|
uint16_t w2;
|
|
|
|
/* Receive first pixel */
|
|
|
|
if (nwords)
|
|
{
|
|
/* Discard the first 8 bit dummy */
|
|
|
|
/* 00000000 RRRRRR00 */
|
|
w1 = stm32_ili93414ws_recvword();
|
|
|
|
/* GGGGGG00 BBBBBB00 */
|
|
w2 = stm32_ili93414ws_recvword();
|
|
|
|
*dest++ = (((w1 << 8) & 0xf800) |
|
|
((w2 >> 2) & 0x7e0) |
|
|
((w2 >> 3) & 0x1f));
|
|
|
|
--nwords;
|
|
}
|
|
|
|
/* Receive
|
|
* if nwords even and greater than 2: pixel 2 to n-1
|
|
* if nwords odd and greater than 2: pixel 2 to n
|
|
*/
|
|
|
|
while (nwords--)
|
|
{
|
|
/* RRRRRR00 GGGGGG00 */
|
|
|
|
w1 = stm32_ili93414ws_recvword();
|
|
|
|
/* BBBBBB00 RRRRRR00 */
|
|
|
|
w2 = stm32_ili93414ws_recvword();
|
|
|
|
*dest++ = ((w1 & 0xf800) | ((w1 << 3) & 0x7e0) | (w2 >> 11));
|
|
|
|
if (!nwords)
|
|
{
|
|
break;
|
|
}
|
|
|
|
/* GGGGGG00 BBBBBB00 */
|
|
|
|
w1 = stm32_ili93414ws_recvword();
|
|
|
|
*dest++ = (((w1 >> 5) & 0x7e0) |
|
|
((w1 >> 3) & 0x1f) |
|
|
((w2 << 8) & 0xf800));
|
|
|
|
--nwords;
|
|
}
|
|
}
|
|
#else
|
|
/* 8-bit spi mode is enabled for pixel data operations.
|
|
* Each pixel must be received by three read operations.
|
|
*/
|
|
|
|
if (lcd->gmode == 16)
|
|
{
|
|
/* 8-bit spi mode but 16-bit mode is done by two 8-bit transmits */
|
|
|
|
uint16_t *dest = wd;
|
|
|
|
/* Dummy read to discard the first 8 bit. */
|
|
|
|
stm32_ili93414ws_recvword();
|
|
|
|
while (nwords--)
|
|
{
|
|
uint8_t r, g, b;
|
|
r = (uint8_t)(stm32_ili93414ws_recvword() >> 3);
|
|
g = (uint8_t)(stm32_ili93414ws_recvword() >> 2);
|
|
b = (uint8_t)(stm32_ili93414ws_recvword() >> 3);
|
|
*dest++ = ((r << 11) | (g << 5) | b);
|
|
}
|
|
}
|
|
#endif
|
|
else
|
|
{
|
|
/* 8-bit mode */
|
|
|
|
uint8_t *dest = (uint8_t*)wd;
|
|
|
|
while (nwords--)
|
|
{
|
|
*dest++ = (uint8_t)stm32_ili93414ws_recvword();
|
|
}
|
|
}
|
|
|
|
/* Disable spi device is done by recvword */
|
|
|
|
return OK;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: stm32_ili93414ws_set8bitmode
|
|
*
|
|
* Description:
|
|
* Set spi device to 8-bit data format
|
|
*
|
|
* Input Parameters:
|
|
* dev - Reference to the private driver structure
|
|
*
|
|
* Returned Value:
|
|
* None
|
|
*
|
|
****************************************************************************/
|
|
|
|
static inline void stm32_ili93414ws_set8bitmode(
|
|
FAR struct ili93414ws_lcd_s *dev)
|
|
{
|
|
stm32_ili93414ws_modifycr1(0, SPI_CR1_DFF);
|
|
#ifndef CONFIG_STM32F429I_DISCO_ILI9341_SPIBITS16
|
|
dev->gmode = 8;
|
|
#endif
|
|
}
|
|
|
|
#ifdef CONFIG_STM32F429I_DISCO_ILI9341_SPIBITS16
|
|
/****************************************************************************
|
|
* Name: stm32_ili93414ws_set16bitmode
|
|
*
|
|
* Description:
|
|
* Set spi device to 16-bit data format.
|
|
*
|
|
* Input Parameters:
|
|
* dev - Reference to the private driver structure
|
|
*
|
|
* Returned Value:
|
|
* None
|
|
*
|
|
****************************************************************************/
|
|
|
|
static inline void stm32_ili93414ws_set16bitmode(
|
|
FAR struct ili93414ws_lcd_s *dev)
|
|
{
|
|
stm32_ili93414ws_modifycr1(SPI_CR1_DFF, 0);
|
|
}
|
|
#else
|
|
|
|
static inline void stm32_ili93414ws_set16bitmode(
|
|
FAR struct ili93414ws_lcd_s *dev)
|
|
{
|
|
dev->gmode = 16;
|
|
}
|
|
#endif
|
|
|
|
/****************************************************************************
|
|
* Name: stm32_ili93414ws_spiconfig
|
|
*
|
|
* Description:
|
|
* Disable spi device and configure to bidirectional mode.
|
|
*
|
|
* Input Parameters:
|
|
* lcd - Reference to the private driver structure
|
|
*
|
|
* Returned Value:
|
|
* None
|
|
*
|
|
****************************************************************************/
|
|
|
|
static void stm32_ili93414ws_spiconfig(FAR struct ili9341_lcd_s *lcd)
|
|
{
|
|
FAR struct ili93414ws_lcd_s *priv = (FAR struct ili93414ws_lcd_s *)lcd;
|
|
irqstate_t flags;
|
|
|
|
uint16_t clrbitscr1 = SPI_CR1_CPHA|SPI_CR1_CPOL|SPI_CR1_BR_MASK|
|
|
SPI_CR1_CRCEN|SPI_CR1_LSBFIRST|SPI_CR1_RXONLY|
|
|
SPI_CR1_DFF;
|
|
|
|
uint16_t setbitscr1 = SPI_CR1_BIDIOE|SPI_CR1_BIDIMODE|SPI_CR1_MSTR|
|
|
SPI_CR1_SSI|SPI_CR1_SSM|ILI93414WS_SPI_BR;
|
|
|
|
uint16_t clrbitscr2 = SPI_CR2_TXEIE|SPI_CR2_RXNEIE|SPI_CR2_ERRIE|
|
|
SPI_CR2_FRF|SPI_CR2_SSOE;
|
|
|
|
uint16_t setbitscr2 = 0;
|
|
|
|
|
|
flags = enter_critical_section();
|
|
|
|
/* Disable spi */
|
|
|
|
stm32_ili93414ws_spidisable();
|
|
|
|
/* Set to default 8-bit transfer mode */
|
|
|
|
stm32_ili93414ws_set8bitmode(priv);
|
|
|
|
#ifdef ILI93414WS_SPI
|
|
/* Backup cr1 and cr2 register to be sure they will be usable
|
|
* by default spi interface. Disable spi device here is necessary at the time
|
|
* restoring the register during deselection.
|
|
*/
|
|
|
|
priv->cr2 = getreg16(ILI93414WS_SPI_CR2);
|
|
priv->cr1 = getreg16(ILI93414WS_SPI_CR1);
|
|
#endif
|
|
|
|
/* Set spi device to bidirectional half duplex
|
|
* Configure to master with 8-bit data format and SPIDEV_MODE0
|
|
*/
|
|
|
|
stm32_ili93414ws_modifycr1(setbitscr1, clrbitscr1);
|
|
|
|
/* Disable dma, set to motorola spi. */
|
|
|
|
stm32_ili93414ws_modifycr2(setbitscr2, clrbitscr2);
|
|
|
|
leave_critical_section(flags);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: stm32_ili93414ws_cmddata
|
|
*
|
|
* Description:
|
|
* Select command or data transfer mode
|
|
*
|
|
* Input Parameters:
|
|
* lcd - Reference to the private driver structure
|
|
* cmd - Refers to command or parameter
|
|
*
|
|
* Returned Value:
|
|
*
|
|
****************************************************************************/
|
|
|
|
#ifdef ILI93414WS_SPI
|
|
static inline void stm32_ili93414ws_cmddata(
|
|
FAR struct ili9341_lcd_s *lcd, bool cmd)
|
|
{
|
|
FAR struct ili93414ws_lcd_s *priv = (FAR struct ili93414ws_lcd_s *)lcd;
|
|
|
|
SPI_CMDDATA(priv->spi, SPIDEV_DISPLAY(0), cmd);
|
|
}
|
|
#else
|
|
static inline void stm32_ili93414ws_cmddata(
|
|
FAR struct ili9341_lcd_s *lcd, bool cmd)
|
|
{
|
|
stm32_gpiowrite(GPIO_LCD_DC, !cmd);
|
|
}
|
|
#endif
|
|
|
|
/****************************************************************************
|
|
* Public Functions
|
|
****************************************************************************/
|
|
|
|
/****************************************************************************
|
|
* Name: stm32_ili93414ws_backlight
|
|
*
|
|
* Description:
|
|
* Set the backlight level of the connected display.
|
|
*
|
|
* Input Parameters:
|
|
* spi - Reference to the public driver structure
|
|
* level - backligth level
|
|
*
|
|
* Returned Value:
|
|
* OK - On Success
|
|
*
|
|
****************************************************************************/
|
|
|
|
static int stm32_ili93414ws_backlight(FAR struct ili9341_lcd_s *lcd, int level)
|
|
{
|
|
return OK;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: stm32_ili93414ws_select
|
|
*
|
|
* Description:
|
|
* Select the SPI, locking and re-configuring if necessary
|
|
*
|
|
* Input Parameters:
|
|
* spi - Reference to the public driver structure
|
|
*
|
|
* Returned Value:
|
|
*
|
|
****************************************************************************/
|
|
|
|
#ifdef ILI93414WS_SPI
|
|
static void stm32_ili93414ws_select(FAR struct ili9341_lcd_s *lcd)
|
|
{
|
|
FAR struct ili93414ws_lcd_s *priv = (FAR struct ili93414ws_lcd_s *)lcd;
|
|
|
|
/* Select ili9341 (locking the SPI bus in case there are multiple
|
|
* devices competing for the SPI bus
|
|
*/
|
|
|
|
SPI_LOCK(priv->spi, true);
|
|
SPI_SELECT(priv->spi, SPIDEV_DISPLAY(0), true);
|
|
|
|
/* Configure spi and disable */
|
|
|
|
stm32_ili93414ws_spiconfig(lcd);
|
|
}
|
|
#else
|
|
static void stm32_ili93414ws_select(FAR struct ili9341_lcd_s *lcd)
|
|
{
|
|
/* We own the spi bus, so just select the chip */
|
|
|
|
stm32_gpiowrite(GPIO_CS_LCD, false);
|
|
|
|
/* Disable spi */
|
|
|
|
stm32_ili93414ws_spidisable();
|
|
}
|
|
#endif
|
|
|
|
/****************************************************************************
|
|
* Name: stm32_ili93414ws_deselect
|
|
*
|
|
* Description:
|
|
* De-select the SPI
|
|
*
|
|
* Input Parameters:
|
|
* spi - Reference to the public driver structure
|
|
*
|
|
* Returned Value:
|
|
*
|
|
****************************************************************************/
|
|
|
|
#ifdef ILI93414WS_SPI
|
|
static void stm32_ili93414ws_deselect(FAR struct ili9341_lcd_s *lcd)
|
|
{
|
|
irqstate_t flags;
|
|
FAR struct ili93414ws_lcd_s *priv = (FAR struct ili93414ws_lcd_s *)lcd;
|
|
|
|
flags = enter_critical_section();
|
|
|
|
/* Restore cr1 and cr2 register to be sure they will be usable
|
|
* by default spi interface structure. (This is an important workarround as
|
|
* long as half duplex mode is not supported by the spi interface in
|
|
* arch/arm/src/stm32/stm32_spi.c).
|
|
*/
|
|
|
|
putreg16(priv->cr2, ILI93414WS_SPI_CR2);
|
|
putreg16(priv->cr1, ILI93414WS_SPI_CR1);
|
|
|
|
/* Enable spi device is default for initialized spi ports (see
|
|
* arch/arm/src/stm32/stm32_spi.c).
|
|
*/
|
|
|
|
stm32_ili93414ws_spienable();
|
|
|
|
leave_critical_section(flags);
|
|
|
|
/* de-select ili9341 and relinquish the spi bus. */
|
|
|
|
SPI_SELECT(priv->spi, SPIDEV_DISPLAY(0), false);
|
|
SPI_LOCK(priv->spi, false);
|
|
}
|
|
#else
|
|
static void stm32_ili93414ws_deselect(FAR struct ili9341_lcd_s *lcd)
|
|
{
|
|
stm32_gpiowrite(GPIO_CS_LCD, true);
|
|
}
|
|
#endif
|
|
|
|
/****************************************************************************
|
|
* Name: stm32_ili93414ws_sndcmd
|
|
*
|
|
* Description:
|
|
* Send a command to the lcd driver.
|
|
*
|
|
* Input Parameters:
|
|
* lcd - Reference to the ili9341_lcd_s driver structure
|
|
* cmd - command to send
|
|
*
|
|
* Returned Value:
|
|
* On success - OK
|
|
*
|
|
****************************************************************************/
|
|
|
|
static int stm32_ili93414ws_sendcmd(
|
|
FAR struct ili9341_lcd_s *lcd, const uint8_t cmd)
|
|
{
|
|
int ret;
|
|
const uint16_t bw = (const uint16_t)cmd;
|
|
FAR struct ili93414ws_lcd_s *priv = (FAR struct ili93414ws_lcd_s *)lcd;
|
|
|
|
/* Set to 8-bit mode in disabled state, spi device is in disabled state */
|
|
|
|
stm32_ili93414ws_set8bitmode(priv);
|
|
|
|
lcdinfo("cmd=%04x\n", bw);
|
|
stm32_ili93414ws_cmddata(lcd, true);
|
|
ret = stm32_ili93414ws_sendblock(priv, &bw, 1);
|
|
stm32_ili93414ws_cmddata(lcd, false);
|
|
|
|
return ret;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: stm32_ili93414ws_sendparam
|
|
*
|
|
* Description:
|
|
* Send a parameter to the lcd driver.
|
|
*
|
|
* Input Parameters:
|
|
* lcd - Reference to the ili9341_lcd_s driver structure
|
|
* param - parameter to send
|
|
*
|
|
* Returned Value:
|
|
* OK - On Success
|
|
*
|
|
****************************************************************************/
|
|
|
|
static int stm32_ili93414ws_sendparam(FAR struct ili9341_lcd_s *lcd,
|
|
const uint8_t param)
|
|
{
|
|
FAR struct ili93414ws_lcd_s *priv = (FAR struct ili93414ws_lcd_s *)lcd;
|
|
const uint16_t bw = (const uint16_t)param;
|
|
|
|
/* Set to 8-bit mode in disabled state, spi device is in disabled state */
|
|
|
|
stm32_ili93414ws_set8bitmode(priv);
|
|
|
|
lcdinfo("param=%04x\n", bw);
|
|
return stm32_ili93414ws_sendblock(priv, &bw, 1);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: stm32_ili93414ws_sendgram
|
|
*
|
|
* Description:
|
|
* Send a number of pixel words to the lcd driver gram.
|
|
*
|
|
* Input Parameters:
|
|
* lcd - Reference to the ili9341_lcd_s driver structure
|
|
* wd - Reference to the words to send
|
|
* nwords - number of words to send
|
|
*
|
|
* Returned Value:
|
|
* OK - On Success
|
|
*
|
|
****************************************************************************/
|
|
|
|
static int stm32_ili93414ws_sendgram(FAR struct ili9341_lcd_s *lcd,
|
|
const uint16_t *wd, uint32_t nwords)
|
|
{
|
|
FAR struct ili93414ws_lcd_s *priv = (FAR struct ili93414ws_lcd_s *)lcd;
|
|
|
|
lcdinfo("wd=%p, nwords=%d\n", wd, nwords);
|
|
|
|
/* Set to 16-bit mode transfer mode, spi device is in disabled state */
|
|
|
|
stm32_ili93414ws_set16bitmode(priv);
|
|
|
|
return stm32_ili93414ws_sendblock(priv, wd, nwords);
|
|
};
|
|
|
|
/****************************************************************************
|
|
* Name: stm32_ili93414ws_recvparam
|
|
*
|
|
* Description:
|
|
* Receive a parameter from the lcd driver.
|
|
*
|
|
* Input Parameters:
|
|
* lcd - Reference to the ili9341_lcd_s driver structure
|
|
* param - Reference to where parameter receive
|
|
*
|
|
* Returned Value:
|
|
* OK - On Success
|
|
*
|
|
****************************************************************************/
|
|
|
|
static int stm32_ili93414ws_recvparam(FAR struct ili9341_lcd_s *lcd,
|
|
uint8_t *param)
|
|
{
|
|
FAR struct ili93414ws_lcd_s *priv = (FAR struct ili93414ws_lcd_s *)lcd;
|
|
|
|
#ifdef CONFIG_STM32F429I_DISCO_ILI9341_SPIBITS16
|
|
/* Set to 8-bit mode in disabled state, spi device is in disabled state. */
|
|
|
|
stm32_ili93414ws_set8bitmode(priv);
|
|
#endif
|
|
|
|
lcdinfo("param=%04x\n", param);
|
|
return stm32_ili93414ws_recvblock(priv, (uint16_t*)param, 1);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: stm32_ili93414ws_recvgram
|
|
*
|
|
* Description:
|
|
* Receive pixel words from the lcd driver gram.
|
|
*
|
|
* Input Parameters:
|
|
* lcd - Reference to the public driver structure
|
|
* wd - Reference to where the pixel words receive
|
|
* nwords - number of pixel words to receive
|
|
*
|
|
* Returned Value:
|
|
* OK - On Success
|
|
*
|
|
****************************************************************************/
|
|
|
|
static int stm32_ili93414ws_recvgram(FAR struct ili9341_lcd_s *lcd,
|
|
uint16_t *wd, uint32_t nwords)
|
|
{
|
|
FAR struct ili93414ws_lcd_s *priv = (FAR struct ili93414ws_lcd_s *)lcd;
|
|
|
|
lcdinfo("wd=%p, nwords=%d\n", wd, nwords);
|
|
|
|
/* Set to 16-bit mode in disabled state */
|
|
|
|
stm32_ili93414ws_set16bitmode(priv);
|
|
|
|
return stm32_ili93414ws_recvblock(priv, wd, nwords);
|
|
};
|
|
|
|
/****************************************************************************
|
|
* Name: stm32_ili93414ws_initialize
|
|
*
|
|
* Description:
|
|
* Initialize the device structure to control the LCD Single chip driver.
|
|
*
|
|
* Input Parameters:
|
|
*
|
|
* Returned Value:
|
|
* On success, this function returns a reference to the LCD control object
|
|
* for the specified ILI9341 LCD Single chip driver connected as 4 wire serial
|
|
* (spi). NULL is returned on any failure.
|
|
*
|
|
****************************************************************************/
|
|
|
|
#ifdef ILI93414WS_SPI
|
|
FAR struct ili9341_lcd_s *stm32_ili93414ws_initialize(void)
|
|
{
|
|
FAR struct spi_dev_s *spi;
|
|
FAR struct ili93414ws_lcd_s *priv = &g_lcddev;
|
|
|
|
lcdinfo("initialize ili9341 4-wire serial subdriver\n");
|
|
|
|
lcdinfo("initialize spi device: %d\n", ILI93414WS_SPI_DEVICE);
|
|
spi = stm32_spi5initialize();
|
|
|
|
if (spi)
|
|
{
|
|
/* Initialize structure */
|
|
|
|
priv->dev.select = stm32_ili93414ws_select;
|
|
priv->dev.deselect = stm32_ili93414ws_deselect;
|
|
priv->dev.sendcmd = stm32_ili93414ws_sendcmd;
|
|
priv->dev.sendparam = stm32_ili93414ws_sendparam;
|
|
priv->dev.recvparam = stm32_ili93414ws_recvparam;
|
|
priv->dev.sendgram = stm32_ili93414ws_sendgram;
|
|
priv->dev.recvgram = stm32_ili93414ws_recvgram;
|
|
priv->dev.backlight = stm32_ili93414ws_backlight;
|
|
priv->spi = spi;
|
|
|
|
return &priv->dev;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
#else
|
|
|
|
FAR struct ili9341_lcd_s *stm32_ili93414ws_initialize(void)
|
|
{
|
|
uint32_t regval;
|
|
FAR struct ili93414ws_lcd_s *priv = &g_lcddev;
|
|
|
|
lcdinfo("initialize ili9341 4-wire serial subdriver\n");
|
|
|
|
/* Enable spi bus */
|
|
|
|
regval= getreg32(STM32_RCC_APB2ENR);
|
|
regval |= RCC_APB2ENR_SPI5EN;
|
|
putreg32(regval, STM32_RCC_APB2ENR);
|
|
|
|
/* Configure gpios */
|
|
|
|
stm32_configgpio(GPIO_CS_LCD); /* LCD chip select */
|
|
stm32_configgpio(GPIO_LCD_DC); /* LCD Data/Command select */
|
|
stm32_configgpio(GPIO_LCD_ENABLE); /* LCD enable select */
|
|
stm32_configgpio(GPIO_SPI5_SCK); /* SPI clock */
|
|
stm32_configgpio(GPIO_SPI5_MOSI); /* SPI MOSI */
|
|
|
|
/* Initialize structure */
|
|
|
|
priv->dev.select = stm32_ili93414ws_select;
|
|
priv->dev.deselect = stm32_ili93414ws_deselect;
|
|
priv->dev.sendcmd = stm32_ili93414ws_sendcmd;
|
|
priv->dev.sendparam = stm32_ili93414ws_sendparam;
|
|
priv->dev.recvparam = stm32_ili93414ws_recvparam;
|
|
priv->dev.sendgram = stm32_ili93414ws_sendgram;
|
|
priv->dev.recvgram = stm32_ili93414ws_recvgram;
|
|
priv->dev.backlight = stm32_ili93414ws_backlight;
|
|
|
|
|
|
/* Configure to bidirectional transfer mode */
|
|
|
|
lcdinfo("Configure spi device %d to bidirectional transfer mode\n",
|
|
ILI93414WS_SPI_DEVICE);
|
|
|
|
stm32_ili93414ws_spiconfig(&priv->dev);
|
|
|
|
return &priv->dev;
|
|
}
|
|
#endif
|