nuttx/configs/stm32f429i-disco/src/stm32_ili93414ws.c
Gregory Nutt 9537715ebb stm32f429i-disco: add wrapper for spi5 evice
initializing

As long as the method up_spiinitialize recognized the initialized state of the
spi device by the spi enable flag of the cr1 register, it isn't safe to disable
the spi device outside of the nuttx spi interface structure. But this has to be
done as long as the nuttx spi interface doesn't support bidirectional data
transfer for multiple devices share one spi bus. This wrapper store the
initialized state of the spi device after the first initializing and should be
used by each driver who shares the spi5 bus.

Note! Understand this as temporary workaround.

Signed-off-by: Marco Krahl <ocram.lhark@gmail.com>
2014-10-20 15:36:11 -06:00

1243 lines
35 KiB
C

/******************************************************************************
* configs/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 writen 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 <nuttx/arch.h>
#include <nuttx/spi/spi.h>
#include <sys/types.h>
#include <stdbool.h>
#include <errno.h>
#include <debug.h>
#include <arch/board/board.h>
#include "stm32f429i-disco.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 */
#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
# ifndef CONFIG_SPI_OWNBUS
# define ILI93414WS_SPI
# endif
#endif
/* Debug option */
#ifdef CONFIG_DEBUG_LCD
# define lcddbg dbg
# define lcdvdbg vdbg
#else
# define lcddbg(x...)
# define lcdvdbg(x...)
#endif
/******************************************************************************
* Private Type Definition
******************************************************************************/
struct ili93414ws_lcd_s
{
/* Publically 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
* neccessary. 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:
*
******************************************************************************/
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:
*
******************************************************************************/
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.
*/
(void)getreg16(ILI93414WS_SPI_DR);
}
/*****************************************************************************
* Name: stm32_ili93414ws_spisendmode
*
* Description:
* Sets the spi device to the bidirectional transmit mode
*
* Input Parameters:
*
* Returned Value:
*
******************************************************************************/
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:
*
* Returned Value:
*
******************************************************************************/
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:
*
* Returned Value:
*
******************************************************************************/
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:
*
******************************************************************************/
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 neccessary 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:
*
* 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 uint8_t n;
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 irqsave section here ensures that the spi device is disabled fast
* enough during a pixel is transmitted.
*/
flags = irqsave();
/* 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 neccessary 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 */
irqrestore(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 happend 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);
}
}
dbg("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. */
(void)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:
*
******************************************************************************/
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:
*
******************************************************************************/
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:
*
******************************************************************************/
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 = irqsave();
/* 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 neccessary 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);
irqrestore(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, cmd);
}
#else
static inline void stm32_ili93414ws_cmddata(
FAR struct ili9341_lcd_s *lcd, bool cmd)
{
(void)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, 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 */
(void)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 = irqsave();
/*
* 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();
irqrestore(flags);
/* de-select ili9341 and relinquish the spi bus. */
SPI_SELECT(priv->spi, SPIDEV_DISPLAY, false);
SPI_LOCK(priv->spi, false);
}
#else
static void stm32_ili93414ws_deselect(FAR struct ili9341_lcd_s *lcd)
{
(void)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);
lcdvdbg("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);
lcdvdbg("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;
lcdvdbg("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
lcdvdbg("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;
lcdvdbg("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;
lcddbg("initialize ili9341 4-wire serial subdriver\n");
lcdvdbg("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;
lcddbg("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 */
(void)stm32_configgpio(GPIO_CS_LCD); /* LCD chip select */
(void)stm32_configgpio(GPIO_LCD_DC); /* LCD Data/Command select */
(void)stm32_configgpio(GPIO_LCD_ENABLE); /* LCD enable select */
(void)stm32_configgpio(GPIO_SPI5_SCK); /* SPI clock */
(void)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 */
lcdvdbg("Configure spi device %d to bidirectional transfer mode\n",
ILI93414WS_SPI_DEVICE);
stm32_ili93414ws_spiconfig(&priv->dev);
return &priv->dev;
}
#endif