mirror of
https://github.com/ttrftech/NanoVNA.git
synced 2025-12-06 03:31:59 +01:00
Update SPI lib for display (prepare for add SD card support)
This commit is contained in:
parent
ff52ba1d45
commit
b3de8f0160
231
ili9341.c
231
ili9341.c
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
* Copyright (c) 2014-2015, TAKAHASHI Tomohiro (TTRFTECH) edy555@gmail.com
|
||||
* updated by DiSlord dislordlive@gmail.com
|
||||
* All rights reserved.
|
||||
*
|
||||
* This is free software; you can redistribute it and/or modify
|
||||
|
|
@ -134,16 +135,15 @@ uint16_t background_color = 0;
|
|||
#define DISPLAY_ROTATION_0 (ILI9341_MADCTL_MV | ILI9341_MADCTL_BGR)
|
||||
#define DISPLAY_ROTATION_180 (ILI9341_MADCTL_MX | ILI9341_MADCTL_MY \
|
||||
| ILI9341_MADCTL_MV | ILI9341_MADCTL_BGR)
|
||||
|
||||
//
|
||||
// Pin macros
|
||||
//
|
||||
#define RESET_ASSERT palClearPad(GPIOA, 15)
|
||||
#define RESET_NEGATE palSetPad(GPIOA, 15)
|
||||
#define CS_LOW palClearPad(GPIOB, 6)
|
||||
#define CS_HIGH palSetPad(GPIOB, 6)
|
||||
#define DC_CMD palClearPad(GPIOB, 7)
|
||||
#define DC_DATA palSetPad(GPIOB, 7)
|
||||
#define RESET_ASSERT palClearPad(GPIOA, GPIOA_LCD_RESET)
|
||||
#define RESET_NEGATE palSetPad(GPIOA, GPIOA_LCD_RESET)
|
||||
#define CS_LOW palClearPad(GPIOB, GPIOB_LCD_CS)
|
||||
#define CS_HIGH palSetPad(GPIOB, GPIOB_LCD_CS)
|
||||
#define DC_CMD palClearPad(GPIOB, GPIOB_LCD_CD)
|
||||
#define DC_DATA palSetPad(GPIOB, GPIOB_LCD_CD)
|
||||
|
||||
//*****************************************************************************
|
||||
//********************************** SPI bus **********************************
|
||||
|
|
@ -159,8 +159,26 @@ uint16_t background_color = 0;
|
|||
#define SPI_CR2_8BIT 0x0700
|
||||
#define SPI_CR2_16BIT 0x0F00
|
||||
|
||||
// SPI bus activity macros
|
||||
//*****************************************************
|
||||
// SPI bus baud rate (PPL/BR_DIV)
|
||||
//*****************************************************
|
||||
#define SPI_BR_DIV2 (0x00000000U)
|
||||
#define SPI_BR_DIV4 (SPI_CR1_BR_0)
|
||||
#define SPI_BR_DIV8 (SPI_CR1_BR_1)
|
||||
#define SPI_BR_DIV16 (SPI_CR1_BR_1|SPI_CR1_BR_0)
|
||||
#define SPI_BR_DIV32 (SPI_CR1_BR_2)
|
||||
#define SPI_BR_DIV64 (SPI_CR1_BR_2|SPI_CR1_BR_0)
|
||||
#define SPI_BR_DIV128 (SPI_CR1_BR_2|SPI_CR1_BR_1)
|
||||
#define SPI_BR_DIV256 (SPI_CR1_BR_2|SPI_CR1_BR_1|SPI_CR1_BR_0)
|
||||
|
||||
// Set SPI bus speed for LCD
|
||||
#define LCD_SPI_SPEED SPI_BR_DIV2
|
||||
|
||||
#define SPI_BR_SET(br) (SPI1->CR1 = (SPI1->CR1& ~(SPI_BR_DIV256))|br)
|
||||
|
||||
//*****************************************************
|
||||
// SPI bus activity macros
|
||||
//*****************************************************
|
||||
// The RXNE flag is set depending on the FRXTH bit value in the SPIx_CR2 register:
|
||||
// • If FRXTH is set, RXNE goes high and stays high until the RXFIFO level is greater or equal to 1/4 (8-bit).
|
||||
#define SPI_RX_IS_NOT_EMPTY (SPI1->SR&SPI_SR_RXNE)
|
||||
|
|
@ -175,45 +193,59 @@ uint16_t background_color = 0;
|
|||
// When BSY is set, it indicates that a data transfer is in progress on the SPI (the SPI bus is busy).
|
||||
#define SPI_IS_BUSY (SPI1->SR & SPI_SR_BSY)
|
||||
|
||||
// Tx or Rx in process
|
||||
#define SPI_IN_TX_RX ((SPI1->SR & (SPI_SR_TXE | SPI_SR_RXNE)) == 0 || SPI_IS_BUSY)
|
||||
|
||||
//*****************************************************
|
||||
// SPI send data macros
|
||||
//*****************************************************
|
||||
#define SPI_WRITE_8BIT(data) *(__IO uint8_t*)(&SPI1->DR) = (uint8_t) data
|
||||
#define SPI_WRITE_16BIT(data) SPI1->DR = data
|
||||
#define SPI_WRITE_16BIT(data) *(__IO uint16_t*)(&SPI1->DR) = (uint16_t) data
|
||||
|
||||
//*****************************************************
|
||||
// SPI read data macros
|
||||
#define SPI_READ_DATA SPI1->DR
|
||||
//*****************************************************
|
||||
#define SPI_READ_8BIT *(__IO uint8_t*)(&SPI1->DR)
|
||||
#define SPI_READ_16BIT *(__IO uint16_t*)(&SPI1->DR)
|
||||
|
||||
//*****************************************************
|
||||
// SPI DMA settings and data
|
||||
//*****************************************************
|
||||
#ifdef __USE_DISPLAY_DMA__
|
||||
static const stm32_dma_stream_t *dmatx =
|
||||
STM32_DMA_STREAM(STM32_SPI_SPI1_TX_DMA_STREAM);
|
||||
static uint32_t txdmamode =
|
||||
static const uint32_t txdmamode =
|
||||
STM32_DMA_CR_CHSEL(SPI1_TX_DMA_CHANNEL) // Select SPI1 Tx DMA
|
||||
| STM32_DMA_CR_PL(STM32_SPI_SPI1_DMA_PRIORITY) // Set priority
|
||||
| STM32_DMA_CR_DIR_M2P // Memory to Spi
|
||||
| STM32_DMA_CR_DMEIE //
|
||||
| STM32_DMA_CR_TEIE;
|
||||
| STM32_DMA_CR_DIR_M2P; // Memory to Spi
|
||||
|
||||
// Not handle interrupt
|
||||
#if 0
|
||||
static void spi_lld_serve_tx_interrupt(SPIDriver *spip, uint32_t flags)
|
||||
{
|
||||
(void)spip;
|
||||
(void)flags;
|
||||
}
|
||||
|
||||
#ifdef __USE_DISPLAY_DMA_RX__
|
||||
static const stm32_dma_stream_t *dmarx = STM32_DMA_STREAM(STM32_SPI_SPI1_RX_DMA_STREAM);
|
||||
static uint32_t rxdmamode = STM32_DMA_CR_CHSEL(SPI1_RX_DMA_CHANNEL)
|
||||
| STM32_DMA_CR_PL(STM32_SPI_SPI1_DMA_PRIORITY)
|
||||
| STM32_DMA_CR_DIR_P2M
|
||||
| STM32_DMA_CR_TCIE
|
||||
| STM32_DMA_CR_DMEIE
|
||||
| STM32_DMA_CR_TEIE;
|
||||
|
||||
static void spi_lld_serve_rx_interrupt(SPIDriver *spip, uint32_t flags)
|
||||
{
|
||||
(void)spip;
|
||||
(void)flags;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __USE_DISPLAY_DMA_RX__
|
||||
static const stm32_dma_stream_t *dmarx = STM32_DMA_STREAM(STM32_SPI_SPI1_RX_DMA_STREAM);
|
||||
static const uint32_t rxdmamode =
|
||||
STM32_DMA_CR_CHSEL(SPI1_RX_DMA_CHANNEL) // Select SPI1 Rx DMA
|
||||
| STM32_DMA_CR_PL(STM32_SPI_SPI1_DMA_PRIORITY) // Set priority
|
||||
| STM32_DMA_CR_DIR_P2M; // SPI to Memory
|
||||
|
||||
// Not handle interrupt
|
||||
#if 0
|
||||
static void spi_lld_serve_rx_interrupt(SPIDriver *spip, uint32_t flags)
|
||||
{
|
||||
(void)spip;
|
||||
(void)flags;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Send prepared DMA data, and wait completion
|
||||
static void dmaStreamFlush(uint32_t len)
|
||||
{
|
||||
while (len) {
|
||||
|
|
@ -227,14 +259,87 @@ static void dmaStreamFlush(uint32_t len)
|
|||
}
|
||||
#endif
|
||||
|
||||
// SPI transmit byte to SPI
|
||||
static void spi_TxByte(uint8_t data) {
|
||||
while (SPI_TX_IS_NOT_EMPTY);
|
||||
SPI_WRITE_8BIT(data);
|
||||
}
|
||||
|
||||
// Transmit word to SPI bus (if SPI in 8 bit mode LSB send first!!!!!)
|
||||
static inline void spi_TxWord(uint16_t data) {
|
||||
while (SPI_TX_IS_NOT_EMPTY);
|
||||
SPI_WRITE_16BIT(data);
|
||||
}
|
||||
|
||||
// Transmit byte to SPI bus (len should be > 0)
|
||||
static void spi_TxBuffer(uint8_t *buffer, uint16_t len) {
|
||||
do {
|
||||
while (SPI_TX_IS_NOT_EMPTY);
|
||||
SPI_WRITE_8BIT(*buffer++);
|
||||
}while(--len);
|
||||
}
|
||||
// Receive byte from SPI bus
|
||||
static uint8_t spi_RxByte(void) {
|
||||
// Start RX clock (by sending data)
|
||||
SPI_WRITE_8BIT(0xFF);
|
||||
while (SPI_RX_IS_EMPTY || SPI_IS_BUSY);
|
||||
return SPI_READ_8BIT;
|
||||
}
|
||||
|
||||
// Receive byte from SPI bus (len should be > 0)
|
||||
static void spi_RxBuffer(uint8_t *buffer, uint16_t len) {
|
||||
do{
|
||||
SPI_WRITE_8BIT(0xFF);
|
||||
while (SPI_RX_IS_EMPTY);
|
||||
*buffer++ = SPI_READ_8BIT;
|
||||
}while(--len);
|
||||
}
|
||||
|
||||
static void spi_DropRx(void){
|
||||
// Drop Rx buffer after tx
|
||||
while (SPI_RX_IS_NOT_EMPTY)
|
||||
(void)SPI_READ_8BIT;
|
||||
}
|
||||
|
||||
#ifdef __USE_DISPLAY_DMA__
|
||||
// SPI receive byte buffer use DMA
|
||||
static void spi_DMATxBuffer(uint8_t *buffer, uint16_t len) {
|
||||
dmaStreamSetMemory0(dmatx, buffer);
|
||||
dmaStreamSetMode(dmatx, txdmamode | STM32_DMA_CR_PSIZE_BYTE | STM32_DMA_CR_MSIZE_BYTE | STM32_DMA_CR_MINC);
|
||||
dmaStreamFlush(len);
|
||||
}
|
||||
#ifdef __USE_DISPLAY_DMA_RX__
|
||||
// SPI transmit byte buffer use DMA
|
||||
static void spi_DMARxBuffer(uint8_t *buffer, uint16_t len) {
|
||||
uint8_t dummy_tx = 0xFF;
|
||||
// Init Rx DMA buffer, size, mode (spi and mem data size is 8 bit)
|
||||
dmaStreamSetMemory0(dmarx, buffer);
|
||||
dmaStreamSetTransactionSize(dmarx, len);
|
||||
dmaStreamSetMode(dmarx, rxdmamode | STM32_DMA_CR_PSIZE_BYTE | STM32_DMA_CR_MSIZE_BYTE | STM32_DMA_CR_MINC);
|
||||
// Init dummy Tx DMA (for rx clock), size, mode (spi and mem data size is 8 bit)
|
||||
dmaStreamSetMemory0(dmatx, &dummy_tx);
|
||||
dmaStreamSetTransactionSize(dmatx, len);
|
||||
dmaStreamSetMode(dmatx, txdmamode | STM32_DMA_CR_PSIZE_BYTE | STM32_DMA_CR_MSIZE_BYTE);
|
||||
// Start DMA exchange
|
||||
dmaStreamEnable(dmarx);
|
||||
dmaStreamEnable(dmatx);
|
||||
// Wait DMA completion
|
||||
dmaWaitCompletion(dmatx);
|
||||
dmaWaitCompletion(dmarx);
|
||||
// Skip SPI rx buffer
|
||||
// spi_DropRx();
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
static void spi_init(void)
|
||||
{
|
||||
rccEnableSPI1(FALSE);
|
||||
SPI1->CR1 = 0;
|
||||
SPI1->CR1 = SPI_CR1_MSTR // SPI is MASTER
|
||||
| SPI_CR1_SSM // Software slave management (The external NSS pin is free for other application uses)
|
||||
| SPI_CR1_SSI; // Internal slave select (This bit has an effect only when the SSM bit is set. Allow use NSS pin as I/O)
|
||||
// | SPI_CR1_BR_1; // Baud rate control
|
||||
| SPI_CR1_SSI // Internal slave select (This bit has an effect only when the SSM bit is set. Allow use NSS pin as I/O)
|
||||
| LCD_SPI_SPEED; // Baud rate control
|
||||
|
||||
SPI1->CR2 = SPI_CR2_8BIT // SPI data size, set to 8 bit
|
||||
| SPI_CR2_FRXTH; // SPI_SR_RXNE generated every 8 bit data
|
||||
|
|
@ -242,12 +347,12 @@ static void spi_init(void)
|
|||
|
||||
#ifdef __USE_DISPLAY_DMA__
|
||||
// Tx DMA init
|
||||
dmaStreamAllocate(dmatx, STM32_SPI_SPI1_IRQ_PRIORITY, (stm32_dmaisr_t)spi_lld_serve_tx_interrupt, NULL);
|
||||
dmaStreamAllocate(dmatx, STM32_SPI_SPI1_IRQ_PRIORITY, NULL, NULL);
|
||||
dmaStreamSetPeripheral(dmatx, &SPI1->DR);
|
||||
SPI1->CR2|= SPI_CR2_TXDMAEN; // Tx DMA enable
|
||||
#ifdef __USE_DISPLAY_DMA_RX__
|
||||
// Rx DMA init
|
||||
dmaStreamAllocate(dmarx, STM32_SPI_SPI1_IRQ_PRIORITY, (stm32_dmaisr_t)spi_lld_serve_rx_interrupt, NULL);
|
||||
dmaStreamAllocate(dmarx, STM32_SPI_SPI1_IRQ_PRIORITY, NULL, NULL);
|
||||
dmaStreamSetPeripheral(dmarx, &SPI1->DR);
|
||||
// Enable DMA on SPI
|
||||
SPI1->CR2|= SPI_CR2_RXDMAEN; // Rx DMA enable
|
||||
|
|
@ -257,14 +362,15 @@ static void spi_init(void)
|
|||
}
|
||||
|
||||
// Disable inline for this function
|
||||
static void __attribute__ ((noinline)) send_command(uint8_t cmd, uint8_t len, const uint8_t *data)
|
||||
static void send_command(uint8_t cmd, uint8_t len, const uint8_t *data)
|
||||
{
|
||||
// Uncomment on low speed SPI (possible get here before previous tx complete)
|
||||
// while (SPI_IN_TX_RX);
|
||||
CS_LOW;
|
||||
// while (SPI_IS_BUSY);
|
||||
DC_CMD;
|
||||
SPI_WRITE_8BIT(cmd);
|
||||
// Need wait transfer complete and set data bit
|
||||
while (SPI_IS_BUSY)
|
||||
while (SPI_IN_TX_RX)
|
||||
;
|
||||
// Send command data (if need)
|
||||
DC_DATA;
|
||||
|
|
@ -357,6 +463,8 @@ void ili9341_init(void)
|
|||
|
||||
void ili9341_bulk_8bit(int x, int y, int w, int h, uint16_t *palette)
|
||||
{
|
||||
//uint8_t xx[4] = { x >> 8, x, (x+w-1) >> 8, (x+w-1) };
|
||||
//uint8_t yy[4] = { y >> 8, y, (y+h-1) >> 8, (y+h-1) };
|
||||
uint32_t xx = __REV16(x | ((x + w - 1) << 16));
|
||||
uint32_t yy = __REV16(y | ((y + h - 1) << 16));
|
||||
send_command(ILI9341_COLUMN_ADDRESS_SET, 4, (uint8_t *)&xx);
|
||||
|
|
@ -365,12 +473,8 @@ void ili9341_bulk_8bit(int x, int y, int w, int h, uint16_t *palette)
|
|||
|
||||
uint8_t *buf = (uint8_t *)spi_buffer;
|
||||
int32_t len = w * h;
|
||||
while (len-- > 0) {
|
||||
uint16_t color = palette[*buf++];
|
||||
while (SPI_TX_IS_NOT_EMPTY)
|
||||
;
|
||||
SPI_WRITE_16BIT(color);
|
||||
}
|
||||
while (len-- > 0)
|
||||
spi_TxWord(palette[*buf++]);
|
||||
}
|
||||
|
||||
#ifndef __USE_DISPLAY_DMA__
|
||||
|
|
@ -384,11 +488,8 @@ void ili9341_fill(int x, int y, int w, int h, uint16_t color)
|
|||
send_command(ILI9341_PAGE_ADDRESS_SET, 4, (uint8_t*)&yy);
|
||||
send_command(ILI9341_MEMORY_WRITE, 0, NULL);
|
||||
int32_t len = w * h;
|
||||
while (len-- > 0) {
|
||||
while (SPI_TX_IS_NOT_EMPTY)
|
||||
;
|
||||
SPI_WRITE_16BIT(color);
|
||||
}
|
||||
while (len-- > 0)
|
||||
spi_TxWord(color);
|
||||
}
|
||||
|
||||
void ili9341_bulk(int x, int y, int w, int h)
|
||||
|
|
@ -402,11 +503,8 @@ void ili9341_bulk(int x, int y, int w, int h)
|
|||
send_command(ILI9341_PAGE_ADDRESS_SET, 4, (uint8_t*)&yy);
|
||||
send_command(ILI9341_MEMORY_WRITE, 0, NULL);
|
||||
int32_t len = w * h;
|
||||
while (len-- > 0) {
|
||||
while (SPI_TX_IS_NOT_EMPTY)
|
||||
;
|
||||
SPI_WRITE_16BIT(*buf++);
|
||||
}
|
||||
while (len-- > 0)
|
||||
spi_TxWord(*buf++);
|
||||
}
|
||||
#else
|
||||
//
|
||||
|
|
@ -415,6 +513,8 @@ void ili9341_bulk(int x, int y, int w, int h)
|
|||
// Fill region by some color
|
||||
void ili9341_fill(int x, int y, int w, int h, uint16_t color)
|
||||
{
|
||||
//uint8_t xx[4] = { x >> 8, x, (x+w-1) >> 8, (x+w-1) };
|
||||
//uint8_t yy[4] = { y >> 8, y, (y+h-1) >> 8, (y+h-1) };
|
||||
uint32_t xx = __REV16(x | ((x + w - 1) << 16));
|
||||
uint32_t yy = __REV16(y | ((y + h - 1) << 16));
|
||||
send_command(ILI9341_COLUMN_ADDRESS_SET, 4, (uint8_t *)&xx);
|
||||
|
|
@ -444,14 +544,6 @@ void ili9341_bulk(int x, int y, int w, int h)
|
|||
#endif
|
||||
|
||||
#ifndef __USE_DISPLAY_DMA_RX__
|
||||
static uint8_t ssp_sendrecvdata(void)
|
||||
{
|
||||
// Start RX clock (by sending data)
|
||||
SPI_WRITE_8BIT(0);
|
||||
while (SPI_RX_IS_EMPTY && SPI_IS_BUSY)
|
||||
;
|
||||
return SPI_READ_DATA;
|
||||
}
|
||||
|
||||
void ili9341_read_memory(int x, int y, int w, int h, int len, uint16_t *out)
|
||||
{
|
||||
|
|
@ -462,18 +554,16 @@ void ili9341_read_memory(int x, int y, int w, int h, int len, uint16_t *out)
|
|||
send_command(ILI9341_COLUMN_ADDRESS_SET, 4, (uint8_t *)&xx);
|
||||
send_command(ILI9341_PAGE_ADDRESS_SET, 4, (uint8_t*)&yy);
|
||||
send_command(ILI9341_MEMORY_READ, 0, NULL);
|
||||
|
||||
// Skip data from rx buffer
|
||||
while (SPI_RX_IS_NOT_EMPTY)
|
||||
(void) SPI_READ_DATA;
|
||||
spi_DropRx();
|
||||
// require 8bit dummy clock
|
||||
ssp_sendrecvdata();
|
||||
spi_RxByte();
|
||||
while (len-- > 0) {
|
||||
uint8_t r, g, b;
|
||||
// read data is always 18bit
|
||||
r = ssp_sendrecvdata();
|
||||
g = ssp_sendrecvdata();
|
||||
b = ssp_sendrecvdata();
|
||||
r = spi_RxByte();
|
||||
g = spi_RxByte();
|
||||
b = spi_RxByte();
|
||||
*out++ = RGB565(r, g, b);
|
||||
}
|
||||
CS_HIGH;
|
||||
|
|
@ -492,8 +582,8 @@ void ili9341_read_memory(int x, int y, int w, int h, int len, uint16_t *out)
|
|||
send_command(ILI9341_COLUMN_ADDRESS_SET, 4, (uint8_t *)&xx);
|
||||
send_command(ILI9341_PAGE_ADDRESS_SET, 4, (uint8_t *)&yy);
|
||||
send_command(ILI9341_MEMORY_READ, 0, NULL);
|
||||
// Skip SPI rx buffer
|
||||
while (SPI_RX_IS_NOT_EMPTY) (void)SPI_READ_DATA;
|
||||
// Skip data from rx buffer
|
||||
spi_DropRx();
|
||||
// Init Rx DMA buffer, size, mode (spi and mem data size is 8 bit)
|
||||
dmaStreamSetMemory0(dmarx, rgbbuf);
|
||||
dmaStreamSetTransactionSize(dmarx, data_size);
|
||||
|
|
@ -505,8 +595,8 @@ void ili9341_read_memory(int x, int y, int w, int h, int len, uint16_t *out)
|
|||
dmaStreamSetMode(dmatx, txdmamode | STM32_DMA_CR_PSIZE_BYTE | STM32_DMA_CR_MSIZE_BYTE);
|
||||
|
||||
// Start DMA exchange
|
||||
dmaStreamEnable(dmatx);
|
||||
dmaStreamEnable(dmarx);
|
||||
dmaStreamEnable(dmatx);
|
||||
// Wait DMA completion
|
||||
dmaWaitCompletion(dmatx);
|
||||
dmaWaitCompletion(dmarx);
|
||||
|
|
@ -741,3 +831,4 @@ void ili9341_test(int mode)
|
|||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue