TFT_COLOR_UI async DMA SPI (#24980)

This commit is contained in:
Alexander Gavrilenko 2022-12-13 00:13:31 +03:00 committed by Scott Lahteine
parent d082223fee
commit ec6349f2ac
31 changed files with 500 additions and 227 deletions

View File

@ -3132,6 +3132,10 @@
//#define TFT_COLOR_UI
//#define TFT_LVGL_UI
#if ENABLED(TFT_COLOR_UI)
//#define TFT_SHARED_SPI // SPI is shared between TFT display and other devices. Disable async data transfer
#endif
#if ENABLED(TFT_LVGL_UI)
//#define MKS_WIFI_MODULE // MKS WiFi module
#endif

View File

@ -318,8 +318,16 @@ void SPIClass::dmaSend(void *buf, uint16_t length, bool minc) {
// Enable DMA
GPDMA_ChannelCmd(0, ENABLE);
/*
* Observed behaviour on normal data transfer completion (SKR 1.3 board / LPC1768 MCU)
* GPDMA_STAT_INTTC flag is SET
* GPDMA_STAT_INTERR flag is NOT SET
* GPDMA_STAT_RAWINTTC flag is NOT SET
* GPDMA_STAT_RAWINTERR flag is SET
*/
// Wait for data transfer
while (!GPDMA_IntGetStatus(GPDMA_STAT_RAWINTTC, 0) && !GPDMA_IntGetStatus(GPDMA_STAT_RAWINTERR, 0)) { }
while (!GPDMA_IntGetStatus(GPDMA_STAT_INTTC, 0) && !GPDMA_IntGetStatus(GPDMA_STAT_INTERR, 0)) {}
// Clear err and int
GPDMA_ClearIntPending (GPDMA_STATCLR_INTTC, 0);
@ -333,6 +341,43 @@ void SPIClass::dmaSend(void *buf, uint16_t length, bool minc) {
SSP_DMACmd(_currentSetting->spi_d, SSP_DMA_TX, DISABLE);
}
void SPIClass::dmaSendAsync(void *buf, uint16_t length, bool minc) {
//TODO: LPC dma can only write 0xFFF bytes at once.
GPDMA_Channel_CFG_Type GPDMACfg;
/* Configure GPDMA channel 0 -------------------------------------------------------------*/
/* DMA Channel 0 */
GPDMACfg.ChannelNum = 0;
// Source memory
GPDMACfg.SrcMemAddr = (uint32_t)buf;
// Destination memory - Not used
GPDMACfg.DstMemAddr = 0;
// Transfer size
GPDMACfg.TransferSize = length;
// Transfer width
GPDMACfg.TransferWidth = (_currentSetting->dataSize == DATA_SIZE_16BIT) ? GPDMA_WIDTH_HALFWORD : GPDMA_WIDTH_BYTE;
// Transfer type
GPDMACfg.TransferType = GPDMA_TRANSFERTYPE_M2P;
// Source connection - unused
GPDMACfg.SrcConn = 0;
// Destination connection
GPDMACfg.DstConn = (_currentSetting->spi_d == LPC_SSP0) ? GPDMA_CONN_SSP0_Tx : GPDMA_CONN_SSP1_Tx;
GPDMACfg.DMALLI = 0;
// Enable dma on SPI
SSP_DMACmd(_currentSetting->spi_d, SSP_DMA_TX, ENABLE);
// Only increase memory if minc is true
GPDMACfg.MemoryIncrease = (minc ? GPDMA_DMACCxControl_SI : 0);
// Setup channel with given parameter
GPDMA_Setup(&GPDMACfg);
// Enable DMA
GPDMA_ChannelCmd(0, ENABLE);
}
uint16_t SPIClass::read() {
return SSP_ReceiveData(_currentSetting->spi_d);
}

View File

@ -155,6 +155,7 @@ public:
void read(uint8_t *buf, uint32_t len);
void dmaSend(void *buf, uint16_t length, bool minc);
void dmaSendAsync(void *buf, uint16_t length, bool minc);
/**
* @brief Sets the number of the SPI peripheral to be used by

View File

@ -26,7 +26,7 @@
#include "tft_spi.h"
SPIClass TFT_SPI::SPIx(1);
SPIClass TFT_SPI::SPIx(TFT_SPI_DEVICE);
void TFT_SPI::Init() {
#if PIN_EXISTS(TFT_RESET)
@ -38,40 +38,10 @@ void TFT_SPI::Init() {
OUT_WRITE(TFT_BACKLIGHT_PIN, HIGH);
#endif
SET_OUTPUT(TFT_DC_PIN);
SET_OUTPUT(TFT_CS_PIN);
WRITE(TFT_DC_PIN, HIGH);
WRITE(TFT_CS_PIN, HIGH);
OUT_WRITE(TFT_DC_PIN, HIGH);
OUT_WRITE(TFT_CS_PIN, HIGH);
/**
* STM32F1 APB2 = 72MHz, APB1 = 36MHz, max SPI speed of this MCU if 18Mhz
* STM32F1 has 3 SPI ports, SPI1 in APB2, SPI2/SPI3 in APB1
* so the minimum prescale of SPI1 is DIV4, SPI2/SPI3 is DIV2
*/
#if 0
#if SPI_DEVICE == 1
#define SPI_CLOCK_MAX SPI_CLOCK_DIV4
#else
#define SPI_CLOCK_MAX SPI_CLOCK_DIV2
#endif
uint8_t clock;
uint8_t spiRate = SPI_FULL_SPEED;
switch (spiRate) {
case SPI_FULL_SPEED: clock = SPI_CLOCK_MAX ; break;
case SPI_HALF_SPEED: clock = SPI_CLOCK_DIV4 ; break;
case SPI_QUARTER_SPEED: clock = SPI_CLOCK_DIV8 ; break;
case SPI_EIGHTH_SPEED: clock = SPI_CLOCK_DIV16; break;
case SPI_SPEED_5: clock = SPI_CLOCK_DIV32; break;
case SPI_SPEED_6: clock = SPI_CLOCK_DIV64; break;
default: clock = SPI_CLOCK_DIV2; // Default from the SPI library
}
#endif
#if TFT_MISO_PIN == BOARD_SPI1_MISO_PIN
SPIx.setModule(1);
#elif TFT_MISO_PIN == BOARD_SPI2_MISO_PIN
SPIx.setModule(2);
#endif
SPIx.setModule(TFT_SPI_DEVICE);
SPIx.setClock(SPI_CLOCK_MAX_TFT);
SPIx.setBitOrder(MSBFIRST);
SPIx.setDataMode(SPI_MODE0);
@ -114,17 +84,62 @@ uint32_t TFT_SPI::ReadID(uint16_t Reg) {
return data >> 7;
}
bool TFT_SPI::isBusy() { return false; }
bool TFT_SPI::isBusy() {
#define __IS_DMA_CONFIGURED(__HANDLE__) ((__HANDLE__)->DMACCSrcAddr != 0)
void TFT_SPI::Abort() { DataTransferEnd(); }
// DMA Channel 0 is hardcoded in dmaSendAsync() and dmaSend()
if (!__IS_DMA_CONFIGURED(LPC_GPDMACH0)) return false;
void TFT_SPI::Transmit(uint16_t Data) { SPIx.transfer(Data); }
if (GPDMA_IntGetStatus(GPDMA_STAT_INTERR, 0)) {
// You should not be here - DMA transfer error flag is set
// Abort DMA transfer and release SPI
}
else {
// Check if DMA transfer completed flag is set
if (!GPDMA_IntGetStatus(GPDMA_STAT_INTTC, 0)) return true;
// Check if SPI TX butter is empty and SPI is idle
if ((SSP_GetStatus(LPC_SSPx, SSP_STAT_TXFIFO_EMPTY) == RESET) || (SSP_GetStatus(LPC_SSPx, SSP_STAT_BUSY) == SET)) return true;
}
Abort();
return false;
}
void TFT_SPI::Abort() {
// DMA Channel 0 is hardcoded in dmaSendAsync() and dmaSend()
// Disable DMA
GPDMA_ChannelCmd(0, DISABLE);
// Clear ERR and TC
GPDMA_ClearIntPending(GPDMA_STATCLR_INTTC, 0);
GPDMA_ClearIntPending(GPDMA_STATCLR_INTERR, 0);
// Disable DMA on SPI
SSP_DMACmd(LPC_SSPx, SSP_DMA_TX, DISABLE);
// Deconfigure DMA Channel 0
LPC_GPDMACH0->DMACCControl = 0U;
LPC_GPDMACH0->DMACCConfig = 0U;
LPC_GPDMACH0->DMACCSrcAddr = 0U;
LPC_GPDMACH0->DMACCDestAddr = 0U;
void TFT_SPI::TransmitDMA(uint32_t MemoryIncrease, uint16_t *Data, uint16_t Count) {
DataTransferBegin(DATASIZE_16BIT);
WRITE(TFT_DC_PIN, HIGH);
SPIx.dmaSend(Data, Count, MemoryIncrease);
DataTransferEnd();
}
void TFT_SPI::Transmit(uint16_t Data) { SPIx.transfer(Data); }
void TFT_SPI::Transmit(uint32_t MemoryIncrease, uint16_t *Data, uint16_t Count) {
DataTransferBegin(DATASIZE_16BIT);
SPIx.dmaSend(Data, Count, MemoryIncrease);
Abort();
}
void TFT_SPI::TransmitDMA(uint32_t MemoryIncrease, uint16_t *Data, uint16_t Count) {
DataTransferBegin(DATASIZE_16BIT);
SPIx.dmaSendAsync(Data, Count, MemoryIncrease);
TERN_(TFT_SHARED_SPI, while (isBusy()));
}
#endif // HAS_SPI_TFT

View File

@ -27,6 +27,18 @@
#include <lpc17xx_ssp.h>
// #include <lpc17xx_gpdma.h>
#define IS_SPI(N) (BOARD_NR_SPI >= N && (TFT_SCK_PIN == BOARD_SPI##N##_SCK_PIN) && (TFT_MOSI_PIN == BOARD_SPI##N##_MOSI_PIN) && (TFT_MISO_PIN == BOARD_SPI##N##_MISO_PIN))
#if IS_SPI(1)
#define TFT_SPI_DEVICE 1
#define LPC_SSPx LPC_SSP0
#elif IS_SPI(2)
#define TFT_SPI_DEVICE 2
#define LPC_SSPx LPC_SSP1
#else
#error "Invalid TFT SPI configuration."
#endif
#undef IS_SPI
#ifndef LCD_READ_ID
#define LCD_READ_ID 0x04 // Read display identification information (0xD3 on ILI9341)
#endif
@ -34,17 +46,19 @@
#define LCD_READ_ID4 0xD3 // Read display identification information (0xD3 on ILI9341)
#endif
#define DATASIZE_8BIT SSP_DATABIT_8
#define DATASIZE_16BIT SSP_DATABIT_16
#define TFT_IO_DRIVER TFT_SPI
#define DATASIZE_8BIT SSP_DATABIT_8
#define DATASIZE_16BIT SSP_DATABIT_16
#define TFT_IO_DRIVER TFT_SPI
#define DMA_MAX_SIZE 0xFFF
#define DMA_MINC_ENABLE 1
#define DMA_MINC_DISABLE 0
#define DMA_MINC_ENABLE 1
#define DMA_MINC_DISABLE 0
class TFT_SPI {
private:
static uint32_t ReadID(uint16_t Reg);
static void Transmit(uint16_t Data);
static void Transmit(uint32_t MemoryIncrease, uint16_t *Data, uint16_t Count);
static void TransmitDMA(uint32_t MemoryIncrease, uint16_t *Data, uint16_t Count);
public:
@ -56,22 +70,20 @@ public:
static void Abort();
static void DataTransferBegin(uint16_t DataWidth = DATASIZE_16BIT);
static void DataTransferEnd() { OUT_WRITE(TFT_CS_PIN, HIGH); SPIx.end(); };
static void DataTransferEnd() { WRITE(TFT_CS_PIN, HIGH); SSP_Cmd(LPC_SSPx, DISABLE); };
static void DataTransferAbort();
static void WriteData(uint16_t Data) { Transmit(Data); }
static void WriteReg(uint16_t Reg) { OUT_WRITE(TFT_A0_PIN, LOW); Transmit(Reg); OUT_WRITE(TFT_A0_PIN, HIGH); }
static void WriteReg(uint16_t Reg) { WRITE(TFT_DC_PIN, LOW); Transmit(Reg); WRITE(TFT_DC_PIN, HIGH); }
static void WriteSequence(uint16_t *Data, uint16_t Count) { TransmitDMA(DMA_MINC_ENABLE, Data, Count); }
// static void WriteMultiple(uint16_t Color, uint16_t Count) { static uint16_t Data; Data = Color; TransmitDMA(DMA_MINC_DISABLE, &Data, Count); }
static void WriteSequence_DMA(uint16_t *Data, uint16_t Count) { TransmitDMA(DMA_MINC_ENABLE, Data, Count); }
static void WriteMultiple_DMA(uint16_t Color, uint16_t Count) { static uint16_t Data; Data = Color; TransmitDMA(DMA_MINC_DISABLE, &Data, Count); }
static void WriteSequence(uint16_t *Data, uint16_t Count) { Transmit(DMA_MINC_ENABLE, Data, Count); }
static void WriteMultiple(uint16_t Color, uint32_t Count) {
static uint16_t Data; Data = Color;
//LPC dma can only write 0xFFF bytes at once.
#define MAX_DMA_SIZE (0xFFF - 1)
while (Count > 0) {
TransmitDMA(DMA_MINC_DISABLE, &Data, Count > MAX_DMA_SIZE ? MAX_DMA_SIZE : Count);
Count = Count > MAX_DMA_SIZE ? Count - MAX_DMA_SIZE : 0;
Transmit(DMA_MINC_DISABLE, &Color, Count > DMA_MAX_SIZE ? DMA_MAX_SIZE : Count);
Count = Count > DMA_MAX_SIZE ? Count - DMA_MAX_SIZE : 0;
}
#undef MAX_DMA_SIZE
}
};

View File

@ -44,9 +44,11 @@ uint16_t delta(uint16_t a, uint16_t b) { return a > b ? a - b : b - a; }
#endif
void XPT2046::Init() {
SET_INPUT(TOUCH_MISO_PIN);
SET_OUTPUT(TOUCH_MOSI_PIN);
SET_OUTPUT(TOUCH_SCK_PIN);
#if DISABLED(TOUCH_BUTTONS_HW_SPI)
SET_INPUT(TOUCH_MISO_PIN);
SET_OUTPUT(TOUCH_MOSI_PIN);
SET_OUTPUT(TOUCH_SCK_PIN);
#endif
OUT_WRITE(TOUCH_CS_PIN, HIGH);
#if PIN_EXISTS(TOUCH_INT)

View File

@ -148,20 +148,35 @@ uint32_t TFT_FSMC::ReadID(tft_data_t Reg) {
bool TFT_FSMC::isBusy() {
#ifdef STM32F1xx
volatile bool dmaEnabled = (DMAtx.Instance->CCR & DMA_CCR_EN) != RESET;
#define __IS_DMA_ENABLED(__HANDLE__) ((__HANDLE__)->Instance->CCR & DMA_CCR_EN)
#define __IS_DMA_CONFIGURED(__HANDLE__) ((__HANDLE__)->Instance->CPAR != 0)
#elif defined(STM32F4xx)
volatile bool dmaEnabled = DMAtx.Instance->CR & DMA_SxCR_EN;
#define __IS_DMA_ENABLED(__HANDLE__) ((__HANDLE__)->Instance->CR & DMA_SxCR_EN)
#define __IS_DMA_CONFIGURED(__HANDLE__) ((__HANDLE__)->Instance->PAR != 0)
#endif
if (dmaEnabled) {
if (__HAL_DMA_GET_FLAG(&DMAtx, __HAL_DMA_GET_TC_FLAG_INDEX(&DMAtx)) != 0 || __HAL_DMA_GET_FLAG(&DMAtx, __HAL_DMA_GET_TE_FLAG_INDEX(&DMAtx)) != 0)
Abort();
}
else
Abort();
return dmaEnabled;
if (!__IS_DMA_CONFIGURED(&DMAtx)) return false;
// Check if DMA transfer error or transfer complete flags are set
if ((__HAL_DMA_GET_FLAG(&DMAtx, __HAL_DMA_GET_TE_FLAG_INDEX(&DMAtx)) == 0) && (__HAL_DMA_GET_FLAG(&DMAtx, __HAL_DMA_GET_TC_FLAG_INDEX(&DMAtx)) == 0)) return true;
__DSB();
Abort();
return false;
}
void TFT_FSMC::Abort() {
HAL_DMA_Abort(&DMAtx); // Abort DMA transfer if any
HAL_DMA_DeInit(&DMAtx); // Deconfigure DMA
}
void TFT_FSMC::TransmitDMA(uint32_t MemoryIncrease, uint16_t *Data, uint16_t Count) {
DMAtx.Init.PeriphInc = MemoryIncrease;
HAL_DMA_Init(&DMAtx);
HAL_DMA_Start(&DMAtx, (uint32_t)Data, (uint32_t)&(LCD->RAM), Count);
}
void TFT_FSMC::Transmit(uint32_t MemoryIncrease, uint16_t *Data, uint16_t Count) {
DMAtx.Init.PeriphInc = MemoryIncrease;
HAL_DMA_Init(&DMAtx);
DataTransferBegin();

View File

@ -41,6 +41,7 @@
#define DATASIZE_8BIT SPI_DATASIZE_8BIT
#define DATASIZE_16BIT SPI_DATASIZE_16BIT
#define TFT_IO_DRIVER TFT_FSMC
#define DMA_MAX_SIZE 0xFFFF
#define TFT_DATASIZE TERN(TFT_INTERFACE_FSMC_8BIT, DATASIZE_8BIT, DATASIZE_16BIT)
typedef TERN(TFT_INTERFACE_FSMC_8BIT, uint8_t, uint16_t) tft_data_t;
@ -59,13 +60,14 @@ class TFT_FSMC {
static uint32_t ReadID(tft_data_t Reg);
static void Transmit(tft_data_t Data) { LCD->RAM = Data; __DSB(); }
static void Transmit(uint32_t MemoryIncrease, uint16_t *Data, uint16_t Count);
static void TransmitDMA(uint32_t MemoryIncrease, uint16_t *Data, uint16_t Count);
public:
static void Init();
static uint32_t GetID();
static bool isBusy();
static void Abort() { __HAL_DMA_DISABLE(&DMAtx); }
static void Abort();
static void DataTransferBegin(uint16_t DataWidth = TFT_DATASIZE) {}
static void DataTransferEnd() {};
@ -73,13 +75,14 @@ class TFT_FSMC {
static void WriteData(uint16_t Data) { Transmit(tft_data_t(Data)); }
static void WriteReg(uint16_t Reg) { LCD->REG = tft_data_t(Reg); __DSB(); }
static void WriteSequence(uint16_t *Data, uint16_t Count) { TransmitDMA(DMA_PINC_ENABLE, Data, Count); }
static void WriteMultiple(uint16_t Color, uint16_t Count) { static uint16_t Data; Data = Color; TransmitDMA(DMA_PINC_DISABLE, &Data, Count); }
static void WriteSequence_DMA(uint16_t *Data, uint16_t Count) { TransmitDMA(DMA_PINC_ENABLE, Data, Count); }
static void WriteMultiple_DMA(uint16_t Color, uint16_t Count) { static uint16_t Data; Data = Color; TransmitDMA(DMA_PINC_DISABLE, &Data, Count); }
static void WriteSequence(uint16_t *Data, uint16_t Count) { Transmit(DMA_PINC_ENABLE, Data, Count); }
static void WriteMultiple(uint16_t Color, uint32_t Count) {
static uint16_t Data; Data = Color;
while (Count > 0) {
TransmitDMA(DMA_MINC_DISABLE, &Data, Count > 0xFFFF ? 0xFFFF : Count);
Count = Count > 0xFFFF ? Count - 0xFFFF : 0;
Transmit(DMA_MINC_DISABLE, &Color, Count > DMA_MAX_SIZE ? DMA_MAX_SIZE : Count);
Count = Count > DMA_MAX_SIZE ? Count - DMA_MAX_SIZE : 0;
}
}
};

View File

@ -356,7 +356,7 @@ void TFT_LTDC::WriteReg(uint16_t Reg) {
reg = Reg;
}
void TFT_LTDC::TransmitDMA(uint32_t MemoryIncrease, uint16_t *Data, uint16_t Count) {
void TFT_LTDC::Transmit(uint32_t MemoryIncrease, uint16_t *Data, uint16_t Count) {
while (x_cur != x_min && Count) {
Transmit(*Data);

View File

@ -32,6 +32,7 @@
#define DATASIZE_8BIT SPI_DATASIZE_8BIT
#define DATASIZE_16BIT SPI_DATASIZE_16BIT
#define TFT_IO_DRIVER TFT_LTDC
#define DMA_MAX_SIZE 0xFFFF
#define TFT_DATASIZE DATASIZE_16BIT
typedef uint16_t tft_data_t;
@ -49,7 +50,7 @@ class TFT_LTDC {
static void DrawRect(uint16_t sx, uint16_t sy, uint16_t ex, uint16_t ey, uint16_t color);
static void DrawImage(uint16_t sx, uint16_t sy, uint16_t ex, uint16_t ey, uint16_t *colors);
static void Transmit(tft_data_t Data);
static void TransmitDMA(uint32_t MemoryIncrease, uint16_t *Data, uint16_t Count);
static void Transmit(uint32_t MemoryIncrease, uint16_t *Data, uint16_t Count);
public:
static void Init();
@ -63,13 +64,15 @@ class TFT_LTDC {
static void WriteData(uint16_t Data);
static void WriteReg(uint16_t Reg);
static void WriteSequence(uint16_t *Data, uint16_t Count) { TransmitDMA(DMA_PINC_ENABLE, Data, Count); }
static void WriteMultiple(uint16_t Color, uint16_t Count) { static uint16_t Data; Data = Color; TransmitDMA(DMA_PINC_DISABLE, &Data, Count); }
// Non-blocking DMA data transfer is not implemented for LTDC interface
inline static void WriteSequence_DMA(uint16_t *Data, uint16_t Count) { WriteSequence(Data, Count); }
inline static void WriteMultiple_DMA(uint16_t Color, uint16_t Count) { WriteMultiple(Color, Count); }
static void WriteSequence(uint16_t *Data, uint16_t Count) { Transmit(DMA_PINC_ENABLE, Data, Count); }
static void WriteMultiple(uint16_t Color, uint32_t Count) {
static uint16_t Data; Data = Color;
while (Count > 0) {
TransmitDMA(DMA_MINC_DISABLE, &Data, Count > 0xFFFF ? 0xFFFF : Count);
Count = Count > 0xFFFF ? Count - 0xFFFF : 0;
Transmit(DMA_PINC_DISABLE, &Color, Count > DMA_MAX_SIZE ? DMA_MAX_SIZE : Count);
Count = Count > DMA_MAX_SIZE ? Count - DMA_MAX_SIZE : 0;
}
}
};

View File

@ -160,16 +160,13 @@ uint32_t TFT_SPI::ReadID(uint16_t Reg) {
for (i = 0; i < 4; i++) {
#if TFT_MISO_PIN != TFT_MOSI_PIN
//if (hspi->Init.Direction == SPI_DIRECTION_2LINES) {
while (!__HAL_SPI_GET_FLAG(&SPIx, SPI_FLAG_TXE)) {}
SPIx.Instance->DR = 0;
//}
while (!__HAL_SPI_GET_FLAG(&SPIx, SPI_FLAG_TXE)) {}
SPIx.Instance->DR = 0;
#endif
while (!__HAL_SPI_GET_FLAG(&SPIx, SPI_FLAG_RXNE)) {}
Data = (Data << 8) | SPIx.Instance->DR;
}
__HAL_SPI_DISABLE(&SPIx);
DataTransferEnd();
SPIx.Init.BaudRatePrescaler = BaudRatePrescaler;
@ -180,35 +177,43 @@ uint32_t TFT_SPI::ReadID(uint16_t Reg) {
bool TFT_SPI::isBusy() {
#ifdef STM32F1xx
volatile bool dmaEnabled = (DMAtx.Instance->CCR & DMA_CCR_EN) != RESET;
#define __IS_DMA_ENABLED(__HANDLE__) ((__HANDLE__)->Instance->CCR & DMA_CCR_EN)
#define __IS_DMA_CONFIGURED(__HANDLE__) ((__HANDLE__)->Instance->CPAR != 0)
#elif defined(STM32F4xx)
volatile bool dmaEnabled = DMAtx.Instance->CR & DMA_SxCR_EN;
#define __IS_DMA_ENABLED(__HANDLE__) ((__HANDLE__)->Instance->CR & DMA_SxCR_EN)
#define __IS_DMA_CONFIGURED(__HANDLE__) ((__HANDLE__)->Instance->PAR != 0)
#endif
if (dmaEnabled) {
if (__HAL_DMA_GET_FLAG(&DMAtx, __HAL_DMA_GET_TC_FLAG_INDEX(&DMAtx)) != 0 || __HAL_DMA_GET_FLAG(&DMAtx, __HAL_DMA_GET_TE_FLAG_INDEX(&DMAtx)) != 0)
Abort();
if (!__IS_DMA_CONFIGURED(&DMAtx)) return false;
if (__HAL_DMA_GET_FLAG(&DMAtx, __HAL_DMA_GET_TE_FLAG_INDEX(&DMAtx))) {
// You should not be here - DMA transfer error flag is set
// Abort DMA transfer and release SPI
}
else
Abort();
return dmaEnabled;
else {
// Check if DMA transfer completed flag is set
if (__HAL_DMA_GET_FLAG(&DMAtx, __HAL_DMA_GET_TC_FLAG_INDEX(&DMAtx)) == 0) return true;
// Check if SPI transmit butter is empty and SPI is idle
if ((!__HAL_SPI_GET_FLAG(&SPIx, SPI_FLAG_TXE)) || (__HAL_SPI_GET_FLAG(&SPIx, SPI_FLAG_BSY))) return true;
}
Abort();
return false;
}
void TFT_SPI::Abort() {
// Wait for any running spi
while (!__HAL_SPI_GET_FLAG(&SPIx, SPI_FLAG_TXE)) {}
while ( __HAL_SPI_GET_FLAG(&SPIx, SPI_FLAG_BSY)) {}
// First, abort any running dma
HAL_DMA_Abort(&DMAtx);
// DeInit objects
HAL_DMA_Abort(&DMAtx); // Abort DMA transfer if any
HAL_DMA_DeInit(&DMAtx);
HAL_SPI_DeInit(&SPIx);
// Deselect CS
DataTransferEnd();
CLEAR_BIT(SPIx.Instance->CR2, SPI_CR2_TXDMAEN);
DataTransferEnd(); // Stop SPI and deselect CS
}
void TFT_SPI::Transmit(uint16_t Data) {
if (TFT_MISO_PIN == TFT_MOSI_PIN)
#if TFT_MISO_PIN == TFT_MOSI_PIN
SPI_1LINE_TX(&SPIx);
#endif
__HAL_SPI_ENABLE(&SPIx);
@ -217,14 +222,31 @@ void TFT_SPI::Transmit(uint16_t Data) {
while (!__HAL_SPI_GET_FLAG(&SPIx, SPI_FLAG_TXE)) {}
while ( __HAL_SPI_GET_FLAG(&SPIx, SPI_FLAG_BSY)) {}
if (TFT_MISO_PIN != TFT_MOSI_PIN)
__HAL_SPI_CLEAR_OVRFLAG(&SPIx); // Clear overrun flag in 2 Lines communication mode because received is not read
#if TFT_MISO_PIN != TFT_MOSI_PIN
__HAL_SPI_CLEAR_OVRFLAG(&SPIx); // Clear overrun flag in 2 Lines communication mode because received data is not read
#endif
}
void TFT_SPI::TransmitDMA(uint32_t MemoryIncrease, uint16_t *Data, uint16_t Count) {
// Wait last dma finish, to start another
while (isBusy()) { /* nada */ }
DMAtx.Init.MemInc = MemoryIncrease;
HAL_DMA_Init(&DMAtx);
#if TFT_MISO_PIN == TFT_MOSI_PIN
SPI_1LINE_TX(&SPIx);
#endif
DataTransferBegin();
HAL_DMA_Start(&DMAtx, (uint32_t)Data, (uint32_t)&(SPIx.Instance->DR), Count);
__HAL_SPI_ENABLE(&SPIx);
SET_BIT(SPIx.Instance->CR2, SPI_CR2_TXDMAEN); // Enable Tx DMA Request
TERN_(TFT_SHARED_SPI, while (isBusy()));
}
void TFT_SPI::Transmit(uint32_t MemoryIncrease, uint16_t *Data, uint16_t Count) {
DMAtx.Init.MemInc = MemoryIncrease;
HAL_DMA_Init(&DMAtx);
@ -243,7 +265,6 @@ void TFT_SPI::TransmitDMA(uint32_t MemoryIncrease, uint16_t *Data, uint16_t Coun
}
#if ENABLED(USE_SPI_DMA_TC)
void TFT_SPI::TransmitDMA_IT(uint32_t MemoryIncrease, uint16_t *Data, uint16_t Count) {
DMAtx.Init.MemInc = MemoryIncrease;
@ -262,8 +283,7 @@ void TFT_SPI::TransmitDMA(uint32_t MemoryIncrease, uint16_t *Data, uint16_t Coun
SET_BIT(SPIx.Instance->CR2, SPI_CR2_TXDMAEN); // Enable Tx DMA Request
}
extern "C" void DMA2_Stream3_IRQHandler(void) { HAL_DMA_IRQHandler(&TFT_SPI::DMAtx); }
extern "C" void DMA2_Stream3_IRQHandler(void) { TFT_SPI::DMA_IRQHandler(); }
#endif
#endif // HAS_SPI_TFT

View File

@ -39,46 +39,47 @@
#define DATASIZE_8BIT SPI_DATASIZE_8BIT
#define DATASIZE_16BIT SPI_DATASIZE_16BIT
#define TFT_IO_DRIVER TFT_SPI
#define DMA_MAX_SIZE 0xFFFF
class TFT_SPI {
private:
static SPI_HandleTypeDef SPIx;
static DMA_HandleTypeDef DMAtx;
static uint32_t ReadID(uint16_t Reg);
static void Transmit(uint16_t Data);
static void Transmit(uint32_t MemoryIncrease, uint16_t *Data, uint16_t Count);
static void TransmitDMA(uint32_t MemoryIncrease, uint16_t *Data, uint16_t Count);
#if ENABLED(USE_SPI_DMA_TC)
static void TransmitDMA_IT(uint32_t MemoryIncrease, uint16_t *Data, uint16_t Count);
#endif
public:
static DMA_HandleTypeDef DMAtx;
static void Init();
static uint32_t GetID();
static bool isBusy();
static void Abort();
static void DataTransferBegin(uint16_t DataWidth = DATASIZE_16BIT);
static void DataTransferEnd() { WRITE(TFT_CS_PIN, HIGH); };
static void DataTransferEnd() { WRITE(TFT_CS_PIN, HIGH); __HAL_SPI_DISABLE(&SPIx); };
static void DataTransferAbort();
static void WriteData(uint16_t Data) { Transmit(Data); }
static void WriteReg(uint16_t Reg) { WRITE(TFT_A0_PIN, LOW); Transmit(Reg); WRITE(TFT_A0_PIN, HIGH); }
static void WriteSequence(uint16_t *Data, uint16_t Count) { TransmitDMA(DMA_MINC_ENABLE, Data, Count); }
static void WriteSequence_DMA(uint16_t *Data, uint16_t Count) { TransmitDMA(DMA_MINC_ENABLE, Data, Count); }
static void WriteMultiple_DMA(uint16_t Color, uint16_t Count) { static uint16_t Data; Data = Color; TransmitDMA(DMA_MINC_DISABLE, &Data, Count); }
#if ENABLED(USE_SPI_DMA_TC)
static void WriteSequenceIT(uint16_t *Data, uint16_t Count) { TransmitDMA_IT(DMA_MINC_ENABLE, Data, Count); }
inline static void DMA_IRQHandler() { HAL_DMA_IRQHandler(&TFT_SPI::DMAtx); }
#endif
static void WriteMultiple(uint16_t Color, uint16_t Count) { static uint16_t Data; Data = Color; TransmitDMA(DMA_MINC_DISABLE, &Data, Count); }
static void WriteSequence(uint16_t *Data, uint16_t Count) { Transmit(DMA_MINC_ENABLE, Data, Count); }
static void WriteMultiple(uint16_t Color, uint32_t Count) {
static uint16_t Data; Data = Color;
while (Count > 0) {
TransmitDMA(DMA_MINC_DISABLE, &Data, Count > 0xFFFF ? 0xFFFF : Count);
Count = Count > 0xFFFF ? Count - 0xFFFF : 0;
Transmit(DMA_MINC_DISABLE, &Color, Count > DMA_MAX_SIZE ? DMA_MAX_SIZE : Count);
Count = Count > DMA_MAX_SIZE ? Count - DMA_MAX_SIZE : 0;
}
}
};

View File

@ -526,23 +526,22 @@ void SPIClass::onReceive(void(*callback)()) {
_currentSetting->receiveCallback = callback;
if (callback) {
switch (_currentSetting->spi_d->clk_id) {
#if BOARD_NR_SPI >= 1
case RCC_SPI1:
dma_attach_interrupt(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel, &SPIClass::_spi1EventCallback);
break;
#endif
#if BOARD_NR_SPI >= 2
case RCC_SPI2:
dma_attach_interrupt(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel, &SPIClass::_spi2EventCallback);
break;
#endif
#if BOARD_NR_SPI >= 3
case RCC_SPI3:
dma_attach_interrupt(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel, &SPIClass::_spi3EventCallback);
break;
#endif
default:
ASSERT(0);
#if BOARD_NR_SPI >= 1
case RCC_SPI1:
dma_attach_interrupt(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel, &SPIClass::_spi1EventCallback);
break;
#endif
#if BOARD_NR_SPI >= 2
case RCC_SPI2:
dma_attach_interrupt(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel, &SPIClass::_spi2EventCallback);
break;
#endif
#if BOARD_NR_SPI >= 3
case RCC_SPI3:
dma_attach_interrupt(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel, &SPIClass::_spi3EventCallback);
break;
#endif
default: ASSERT(0);
}
}
else {
@ -554,23 +553,22 @@ void SPIClass::onTransmit(void(*callback)()) {
_currentSetting->transmitCallback = callback;
if (callback) {
switch (_currentSetting->spi_d->clk_id) {
#if BOARD_NR_SPI >= 1
case RCC_SPI1:
dma_attach_interrupt(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, &SPIClass::_spi1EventCallback);
break;
#endif
#if BOARD_NR_SPI >= 2
case RCC_SPI2:
dma_attach_interrupt(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, &SPIClass::_spi2EventCallback);
break;
#endif
#if BOARD_NR_SPI >= 3
case RCC_SPI3:
dma_attach_interrupt(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, &SPIClass::_spi3EventCallback);
break;
#endif
default:
ASSERT(0);
#if BOARD_NR_SPI >= 1
case RCC_SPI1:
dma_attach_interrupt(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, &SPIClass::_spi1EventCallback);
break;
#endif
#if BOARD_NR_SPI >= 2
case RCC_SPI2:
dma_attach_interrupt(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, &SPIClass::_spi2EventCallback);
break;
#endif
#if BOARD_NR_SPI >= 3
case RCC_SPI3:
dma_attach_interrupt(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, &SPIClass::_spi3EventCallback);
break;
#endif
default: ASSERT(0);
}
}
else {

View File

@ -33,6 +33,15 @@
#include <stdint.h>
#include <wirish.h>
// Number of SPI ports
#ifdef BOARD_SPI3_SCK_PIN
#define BOARD_NR_SPI 3
#elif defined(BOARD_SPI2_SCK_PIN)
#define BOARD_NR_SPI 2
#elif defined(BOARD_SPI1_SCK_PIN)
#define BOARD_NR_SPI 1
#endif
// SPI_HAS_TRANSACTION means SPI has
// - beginTransaction()
// - endTransaction()

View File

@ -215,22 +215,47 @@ uint32_t TFT_FSMC::GetID() {
}
bool TFT_FSMC::isBusy() {
#define __IS_DMA_CONFIGURED(__DMAx__, __CHx__) (dma_channel_regs(__DMAx__, __CHx__)->CPAR != 0)
if (!__IS_DMA_CONFIGURED(FSMC_DMA_DEV, FSMC_DMA_CHANNEL)) return false;
// Check if DMA transfer error or transfer complete flags are set
if ((dma_get_isr_bits(FSMC_DMA_DEV, FSMC_DMA_CHANNEL) & (DMA_ISR_TCIF | DMA_ISR_TEIF)) == 0) return true;
__DSB();
Abort();
return false;
}
void TFT_FSMC::Abort() {
dma_channel_reg_map *channel_regs = dma_channel_regs(FSMC_DMA_DEV, FSMC_DMA_CHANNEL);
dma_disable(FSMC_DMA_DEV, FSMC_DMA_CHANNEL); // Abort DMA transfer if any
// Deconfigure DMA
channel_regs->CCR = 0U;
channel_regs->CNDTR = 0U;
channel_regs->CMAR = 0U;
channel_regs->CPAR = 0U;
}
void TFT_FSMC::TransmitDMA(uint32_t MemoryIncrease, uint16_t *Data, uint16_t Count) {
// TODO: HAL STM32 uses DMA2_Channel1 for FSMC on STM32F1
dma_setup_transfer(FSMC_DMA_DEV, FSMC_DMA_CHANNEL, Data, DMA_SIZE_16BITS, &LCD->RAM, DMA_SIZE_16BITS, DMA_MEM_2_MEM | MemoryIncrease);
dma_set_num_transfers(FSMC_DMA_DEV, FSMC_DMA_CHANNEL, Count);
dma_clear_isr_bits(FSMC_DMA_DEV, FSMC_DMA_CHANNEL);
dma_enable(FSMC_DMA_DEV, FSMC_DMA_CHANNEL);
}
void TFT_FSMC::Transmit(uint32_t MemoryIncrease, uint16_t *Data, uint16_t Count) {
#if defined(FSMC_DMA_DEV) && defined(FSMC_DMA_CHANNEL)
dma_setup_transfer(FSMC_DMA_DEV, FSMC_DMA_CHANNEL, Data, DMA_SIZE_16BITS, &LCD->RAM, DMA_SIZE_16BITS, DMA_MEM_2_MEM | MemoryIncrease);
dma_set_num_transfers(FSMC_DMA_DEV, FSMC_DMA_CHANNEL, Count);
dma_clear_isr_bits(FSMC_DMA_DEV, FSMC_DMA_CHANNEL);
dma_enable(FSMC_DMA_DEV, FSMC_DMA_CHANNEL);
while ((dma_get_isr_bits(FSMC_DMA_DEV, FSMC_DMA_CHANNEL) & 0x0A) == 0) {};
dma_disable(FSMC_DMA_DEV, FSMC_DMA_CHANNEL);
while ((dma_get_isr_bits(FSMC_DMA_DEV, FSMC_DMA_CHANNEL) & (DMA_CCR_TEIE | DMA_CCR_TCIE)) == 0) {}
Abort();
#endif
}

View File

@ -33,6 +33,10 @@
#define DATASIZE_8BIT DMA_SIZE_8BITS
#define DATASIZE_16BIT DMA_SIZE_16BITS
#define TFT_IO_DRIVER TFT_FSMC
#define DMA_MAX_SIZE 0xFFFF
#define DMA_PINC_ENABLE DMA_PINC_MODE
#define DMA_PINC_DISABLE 0
typedef struct {
__IO uint16_t REG;
@ -45,6 +49,7 @@ class TFT_FSMC {
static uint32_t ReadID(uint16_t Reg);
static void Transmit(uint16_t Data);
static void Transmit(uint32_t MemoryIncrease, uint16_t *Data, uint16_t Count);
static void TransmitDMA(uint32_t MemoryIncrease, uint16_t *Data, uint16_t Count);
public:
@ -59,13 +64,14 @@ class TFT_FSMC {
static void WriteData(uint16_t Data) { Transmit(Data); }
static void WriteReg(uint16_t Reg);
static void WriteSequence(uint16_t *Data, uint16_t Count) { TransmitDMA(DMA_PINC_MODE, Data, Count); }
static void WriteMultiple(uint16_t Color, uint16_t Count) { static uint16_t Data; Data = Color; TransmitDMA(DMA_CIRC_MODE, &Data, Count); }
static void WriteSequence_DMA(uint16_t *Data, uint16_t Count) { TransmitDMA(DMA_PINC_ENABLE, Data, Count); }
static void WriteMultiple_DMA(uint16_t Color, uint16_t Count) { static uint16_t Data; Data = Color; TransmitDMA(DMA_PINC_DISABLE, &Data, Count); }
static void WriteSequence(uint16_t *Data, uint16_t Count) { Transmit(DMA_PINC_ENABLE, Data, Count); }
static void WriteMultiple(uint16_t Color, uint32_t Count) {
static uint16_t Data; Data = Color;
while (Count > 0) {
TransmitDMA(DMA_CIRC_MODE, &Data, Count > 0xFFFF ? 0xFFFF : Count);
Count = Count > 0xFFFF ? Count - 0xFFFF : 0;
Transmit(DMA_PINC_DISABLE, &Color, Count > DMA_MAX_SIZE ? DMA_MAX_SIZE : Count);
Count = Count > DMA_MAX_SIZE ? Count - DMA_MAX_SIZE : 0;
}
}
};

View File

@ -26,7 +26,7 @@
#include "tft_spi.h"
SPIClass TFT_SPI::SPIx(1);
SPIClass TFT_SPI::SPIx(TFT_SPI_DEVICE);
void TFT_SPI::Init() {
#if PIN_EXISTS(TFT_RESET)
@ -46,7 +46,7 @@ void TFT_SPI::Init() {
* STM32F1 has 3 SPI ports, SPI1 in APB2, SPI2/SPI3 in APB1
* so the minimum prescale of SPI1 is DIV4, SPI2/SPI3 is DIV2
*/
#if SPI_DEVICE == 1
#if TFT_SPI_DEVICE == 1
#define SPI_CLOCK_MAX SPI_CLOCK_DIV4
#else
#define SPI_CLOCK_MAX SPI_CLOCK_DIV2
@ -62,7 +62,7 @@ void TFT_SPI::Init() {
case SPI_SPEED_6: clock = SPI_CLOCK_DIV64; break;
default: clock = SPI_CLOCK_DIV2; // Default from the SPI library
}
SPIx.setModule(1);
SPIx.setModule(TFT_SPI_DEVICE);
SPIx.setClockDivider(clock);
SPIx.setBitOrder(MSBFIRST);
SPIx.setDataMode(SPI_MODE0);
@ -71,7 +71,7 @@ void TFT_SPI::Init() {
void TFT_SPI::DataTransferBegin(uint16_t DataSize) {
SPIx.setDataSize(DataSize);
SPIx.begin();
OUT_WRITE(TFT_CS_PIN, LOW);
WRITE(TFT_CS_PIN, LOW);
}
#ifdef TFT_DEFAULT_DRIVER
@ -113,15 +113,53 @@ uint32_t TFT_SPI::ReadID(uint16_t Reg) {
#endif
}
bool TFT_SPI::isBusy() { return false; }
bool TFT_SPI::isBusy() {
#define __IS_DMA_CONFIGURED(__DMAx__, __CHx__) (dma_channel_regs(__DMAx__, __CHx__)->CPAR != 0)
void TFT_SPI::Abort() { DataTransferEnd(); }
if (!__IS_DMA_CONFIGURED(DMAx, DMA_CHx)) return false;
if (dma_get_isr_bits(DMAx, DMA_CHx) & DMA_ISR_TEIF) {
// You should not be here - DMA transfer error flag is set
// Abort DMA transfer and release SPI
}
else {
// Check if DMA transfer completed flag is set
if (!(dma_get_isr_bits(DMAx, DMA_CHx) & DMA_ISR_TCIF)) return true;
// Check if SPI TX butter is empty and SPI is idle
if (!(SPIdev->regs->SR & SPI_SR_TXE) || (SPIdev->regs->SR & SPI_SR_BSY)) return true;
}
Abort();
return false;
}
void TFT_SPI::Abort() {
dma_channel_reg_map *channel_regs = dma_channel_regs(DMAx, DMA_CHx);
dma_disable(DMAx, DMA_CHx); // Abort DMA transfer if any
spi_tx_dma_disable(SPIdev);
// Deconfigure DMA
channel_regs->CCR = 0U;
channel_regs->CNDTR = 0U;
channel_regs->CMAR = 0U;
channel_regs->CPAR = 0U;
DataTransferEnd();
}
void TFT_SPI::Transmit(uint16_t Data) { SPIx.send(Data); }
void TFT_SPI::TransmitDMA(uint32_t MemoryIncrease, uint16_t *Data, uint16_t Count) {
DataTransferBegin();
OUT_WRITE(TFT_DC_PIN, HIGH);
SPIx.dmaSendAsync(Data, Count, MemoryIncrease == DMA_MINC_ENABLE);
TERN_(TFT_SHARED_SPI, while (isBusy()));
}
void TFT_SPI::Transmit(uint32_t MemoryIncrease, uint16_t *Data, uint16_t Count) {
WRITE(TFT_DC_PIN, HIGH);
DataTransferBegin();
SPIx.dmaSend(Data, Count, MemoryIncrease == DMA_MINC_ENABLE);
DataTransferEnd();
}

View File

@ -25,6 +25,27 @@
#include <SPI.h>
#define IS_SPI(N) (BOARD_NR_SPI >= N && (TFT_SCK_PIN == BOARD_SPI##N##_SCK_PIN) && (TFT_MOSI_PIN == BOARD_SPI##N##_MOSI_PIN) && (TFT_MISO_PIN == BOARD_SPI##N##_MISO_PIN))
#if IS_SPI(1)
#define TFT_SPI_DEVICE 1
#define SPIdev SPI1
#define DMAx DMA1
#define DMA_CHx DMA_CH3
#elif IS_SPI(2)
#define TFT_SPI_DEVICE 2
#define SPIdev SPI2
#define DMAx DMA1
#define DMA_CHx DMA_CH5
#elif IS_SPI(3)
#define TFT_SPI_DEVICE 3
#define SPIdev SPI3
#define DMAx DMA2
#define DMA_CHx DMA_CH2
#else
#error "Invalid TFT SPI configuration."
#endif
#undef IS_SPI
#ifndef LCD_READ_ID
#define LCD_READ_ID 0x04 // Read display identification information (0xD3 on ILI9341)
#endif
@ -32,17 +53,19 @@
#define LCD_READ_ID4 0xD3 // Read display identification information (0xD3 on ILI9341)
#endif
#define DATASIZE_8BIT DATA_SIZE_8BIT
#define DATASIZE_16BIT DATA_SIZE_16BIT
#define TFT_IO_DRIVER TFT_SPI
#define DATASIZE_8BIT DATA_SIZE_8BIT
#define DATASIZE_16BIT DATA_SIZE_16BIT
#define TFT_IO_DRIVER TFT_SPI
#define DMA_MAX_SIZE 0xFFFF
#define DMA_MINC_ENABLE 1
#define DMA_MINC_DISABLE 0
#define DMA_MINC_ENABLE DMA_MINC_MODE
#define DMA_MINC_DISABLE 0
class TFT_SPI {
private:
static uint32_t ReadID(uint16_t Reg);
static void Transmit(uint16_t Data);
static void Transmit(uint32_t MemoryIncrease, uint16_t *Data, uint16_t Count);
static void TransmitDMA(uint32_t MemoryIncrease, uint16_t *Data, uint16_t Count);
public:
@ -58,15 +81,16 @@ public:
static void DataTransferAbort();
static void WriteData(uint16_t Data) { Transmit(Data); }
static void WriteReg(uint16_t Reg) { WRITE(TFT_A0_PIN, LOW); Transmit(Reg); WRITE(TFT_A0_PIN, HIGH); }
static void WriteReg(uint16_t Reg) { WRITE(TFT_DC_PIN, LOW); Transmit(Reg); WRITE(TFT_DC_PIN, HIGH); }
static void WriteSequence(uint16_t *Data, uint16_t Count) { TransmitDMA(DMA_MINC_ENABLE, Data, Count); }
static void WriteMultiple(uint16_t Color, uint16_t Count) { static uint16_t Data; Data = Color; TransmitDMA(DMA_MINC_DISABLE, &Data, Count); }
static void WriteSequence_DMA(uint16_t *Data, uint16_t Count) { TransmitDMA(DMA_MINC_ENABLE, Data, Count); }
static void WriteMultiple_DMA(uint16_t Color, uint16_t Count) { static uint16_t Data; Data = Color; TransmitDMA(DMA_MINC_DISABLE, &Data, Count); }
static void WriteSequence(uint16_t *Data, uint16_t Count) { Transmit(DMA_MINC_ENABLE, Data, Count); }
static void WriteMultiple(uint16_t Color, uint32_t Count) {
static uint16_t Data; Data = Color;
while (Count > 0) {
TransmitDMA(DMA_MINC_DISABLE, &Data, Count > 0xFFFF ? 0xFFFF : Count);
Count = Count > 0xFFFF ? Count - 0xFFFF : 0;
Transmit(DMA_MINC_DISABLE, &Color, Count > DMA_MAX_SIZE ? DMA_MAX_SIZE : Count);
Count = Count > DMA_MAX_SIZE ? Count - DMA_MAX_SIZE : 0;
}
}
};

View File

@ -65,9 +65,9 @@
#endif
#endif
#if TFT_BUFFER_SIZE > 65535
#if TFT_BUFFER_SIZE > DMA_MAX_SIZE
// DMA Count parameter is uint16_t
#error "TFT_BUFFER_SIZE can not exceed 65535"
#error "TFT_BUFFER_SIZE can not exceed DMA_MAX_SIZE"
#endif
class TFT {
@ -86,8 +86,8 @@ class TFT {
static bool is_busy() { return io.isBusy(); }
static void abort() { io.Abort(); }
static void write_multiple(uint16_t Data, uint16_t Count) { io.WriteMultiple(Data, Count); }
static void write_sequence(uint16_t *Data, uint16_t Count) { io.WriteSequence(Data, Count); }
static void write_multiple(uint16_t Data, uint16_t Count) { io.WriteMultipleDMA(Data, Count); }
static void write_sequence(uint16_t *Data, uint16_t Count) { io.WriteSequenceDMA(Data, Count); }
static void set_window(uint16_t Xmin, uint16_t Ymin, uint16_t Xmax, uint16_t Ymax) { io.set_window(Xmin, Ymin, Xmax, Ymax); }
static void fill(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint16_t color) { queue.fill(x, y, width, height, color); }

View File

@ -86,9 +86,9 @@ void TFT_Queue::fill(queueTask_t *task) {
task->state = TASK_STATE_IN_PROGRESS;
}
if (task_parameters->count > 65535) {
count = 65535;
task_parameters->count -= 65535;
if (task_parameters->count > DMA_MAX_SIZE) {
count = DMA_MAX_SIZE;
task_parameters->count -= DMA_MAX_SIZE;
}
else {
count = task_parameters->count;

View File

@ -135,6 +135,7 @@ class TFT_Queue {
static void reset();
static void async();
static void sync() { while (current_task != nullptr) async(); }
static bool is_empty() { return current_task == nullptr; }
static void fill(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint16_t color);
static void canvas(uint16_t x, uint16_t y, uint16_t width, uint16_t height);

View File

@ -57,7 +57,8 @@ void MarlinUI::tft_idle() {
#endif
tft.queue.async();
TERN_(TOUCH_SCREEN, touch.idle());
TERN_(TOUCH_SCREEN, if (tft.queue.is_empty()) touch.idle()); // Touch driver is not DMA-aware, so only check for touch controls after screen drawing is completed
}
#if ENABLED(SHOW_BOOTSCREEN)
@ -325,7 +326,10 @@ void MarlinUI::draw_status_screen() {
#if ENABLED(TOUCH_SCREEN)
add_control(900, y, menu_main, imgSettings);
TERN_(SDSUPPORT, add_control(12, y, menu_media, imgSD, !printingIsActive(), COLOR_CONTROL_ENABLED, card.isMounted() && printingIsActive() ? COLOR_BUSY : COLOR_CONTROL_DISABLED));
#if ENABLED(SDSUPPORT)
const bool cm = card.isMounted(), pa = printingIsActive();
add_control(12, y, menu_media, imgSD, cm && !pa, COLOR_CONTROL_ENABLED, cm && pa ? COLOR_BUSY : COLOR_CONTROL_DISABLED);
#endif
#endif
y += 100;

View File

@ -57,7 +57,8 @@ void MarlinUI::tft_idle() {
#endif
tft.queue.async();
TERN_(TOUCH_SCREEN, touch.idle());
TERN_(TOUCH_SCREEN, if (tft.queue.is_empty()) touch.idle()); // Touch driver is not DMA-aware, so only check for touch controls after screen drawing is completed
}
#if ENABLED(SHOW_BOOTSCREEN)
@ -342,7 +343,10 @@ void MarlinUI::draw_status_screen() {
#if ENABLED(TOUCH_SCREEN)
add_control(256, 130, menu_main, imgSettings);
TERN_(SDSUPPORT, add_control(0, 130, menu_media, imgSD, !printingIsActive(), COLOR_CONTROL_ENABLED, card.isMounted() && printingIsActive() ? COLOR_BUSY : COLOR_CONTROL_DISABLED));
#if ENABLED(SDSUPPORT)
const bool cm = card.isMounted(), pa = printingIsActive();
add_control(0, 130, menu_media, imgSD, cm && !pa, COLOR_CONTROL_ENABLED, cm && pa ? COLOR_BUSY : COLOR_CONTROL_DISABLED);
#endif
#endif
}

View File

@ -57,7 +57,8 @@ void MarlinUI::tft_idle() {
#endif
tft.queue.async();
TERN_(TOUCH_SCREEN, touch.idle());
TERN_(TOUCH_SCREEN, if (tft.queue.is_empty()) touch.idle()); // Touch driver is not DMA-aware, so only check for touch controls after screen drawing is completed
}
#if ENABLED(SHOW_BOOTSCREEN)
@ -319,7 +320,10 @@ void MarlinUI::draw_status_screen() {
#if ENABLED(TOUCH_SCREEN)
add_control(404, y, menu_main, imgSettings);
TERN_(SDSUPPORT, add_control(12, y, menu_media, imgSD, !printingIsActive(), COLOR_CONTROL_ENABLED, card.isMounted() && printingIsActive() ? COLOR_BUSY : COLOR_CONTROL_DISABLED));
#if ENABLED(SDSUPPORT)
const bool cm = card.isMounted(), pa = printingIsActive();
add_control(12, y, menu_media, imgSD, cm && !pa, COLOR_CONTROL_ENABLED, cm && pa ? COLOR_BUSY : COLOR_CONTROL_DISABLED);
#endif
#endif
y += TERN(HAS_UI_480x272, 36, 44);

View File

@ -60,7 +60,7 @@ TFT_IO_DRIVER TFT_IO::io;
uint32_t TFT_IO::lcd_id = 0xFFFFFFFF;
void TFT_IO::InitTFT() {
if (lcd_id != 0xFFFFFFFF) return;
if (lcd_id != 0xFFFFFFFF) return;
#if PIN_EXISTS(TFT_BACKLIGHT)
OUT_WRITE(TFT_BACKLIGHT_PIN, LOW);
@ -243,7 +243,7 @@ void TFT_IO::write_esc_sequence(const uint16_t *Sequence) {
continue;
}
data = *Sequence++;
if (data == 0x7FFF) return;
if (data == 0x7FFF) break;
if (data == 0xFFFF)
io.WriteData(0xFFFF);
else if (data & 0x8000)

View File

@ -30,7 +30,11 @@
#elif HAS_LTDC_TFT
#include HAL_PATH(../../HAL, tft/tft_ltdc.h)
#else
#error "TFT IO only supports SPI, FSMC or LTDC interface"
#error "TFT IO only supports SPI, FSMC or LTDC interface."
#endif
#ifndef DMA_MAX_SIZE
#error "MAX_DMA_SIZE is not configured for this platform."
#endif
#define TFT_EXCHANGE_XY _BV32(1)
@ -108,27 +112,33 @@ public:
static void write_esc_sequence(const uint16_t *Sequence);
// Deletaged methods
inline static void Init() { io.Init(); io.Abort(); };
inline static bool isBusy() { return io.isBusy(); };
inline static void Abort() { io.Abort(); };
inline static uint32_t GetID() { return io.GetID(); };
inline static void Init() { io.Init(); }
inline static bool isBusy() { return io.isBusy(); }
inline static void Abort() { io.Abort(); }
inline static uint32_t GetID() { return io.GetID(); }
inline static void DataTransferBegin(uint16_t DataWidth = DATASIZE_16BIT) { io.DataTransferBegin(DataWidth); }
inline static void DataTransferEnd() { io.DataTransferEnd(); };
// inline static void DataTransferAbort() { io.DataTransferAbort(); };
inline static void DataTransferEnd() { io.DataTransferEnd(); }
inline static void WriteData(uint16_t Data) { io.WriteData(Data); };
inline static void WriteReg(uint16_t Reg) { io.WriteReg(Reg); };
inline static void WriteData(uint16_t Data) { io.WriteData(Data); }
inline static void WriteReg(uint16_t Reg) { io.WriteReg(Reg); }
inline static void WriteSequence(uint16_t *Data, uint16_t Count) { io.WriteSequence(Data, Count); };
// Blocking IO used by TFT_CLASSIC_UI and TFT_LVGL_UI
// These functions start data transfer and WAIT for data transfer completion
inline static void WriteSequence(uint16_t *Data, uint16_t Count) { io.WriteSequence(Data, Count); }
inline static void WriteMultiple(uint16_t Color, uint32_t Count) { io.WriteMultiple(Color, Count); }
// Non-blocking DMA-based IO used by TFT_COLOR_UI only
// These functions start data transfer using DMA and do NOT wait for data transfer completion
inline static void WriteSequenceDMA(uint16_t *Data, uint16_t Count) { io.WriteSequence_DMA(Data, Count); }
inline static void WriteMultipleDMA(uint16_t Color, uint16_t Count) { io.WriteMultiple_DMA(Color, Count); }
// Non-blocking DMA-based IO with IRQ callback used by TFT_LVGL_UI only
// This function starts data transfer using DMA and does NOT wait for data transfer completion
#if ENABLED(USE_SPI_DMA_TC)
inline static void WriteSequenceIT(uint16_t *Data, uint16_t Count) { io.WriteSequenceIT(Data, Count); };
inline static void WriteSequenceIT(uint16_t *Data, uint16_t Count) { io.WriteSequenceIT(Data, Count); }
#endif
// static void WriteMultiple(uint16_t Color, uint16_t Count) { static uint16_t Data; Data = Color; TransmitDMA(DMA_MINC_DISABLE, &Data, Count); }
inline static void WriteMultiple(uint16_t Color, uint32_t Count) { io.WriteMultiple(Color, Count); };
protected:
static uint32_t lcd_id;
};

View File

@ -323,6 +323,9 @@
#define BTN_EN1 EXP2_03_PIN
#define BTN_ENC EXP1_02_PIN
#define BEEPER_PIN EXP1_01_PIN
#define SDCARD_CONNECTION ONBOARD
#define TOUCH_BUTTONS_HW_SPI
#define TOUCH_BUTTONS_HW_SPI_DEVICE 1

View File

@ -140,7 +140,38 @@
//
// LCD / Controller
//
#if HAS_WIRED_LCD
#if EITHER(TFT_COLOR_UI, TFT_CLASSIC_UI)
#define BEEPER_PIN EXP1_01_PIN
#define BTN_ENC EXP1_02_PIN
#define BTN_EN1 EXP2_03_PIN
#define BTN_EN2 EXP2_05_PIN
#define TFT_CS_PIN EXP1_07_PIN
#define TFT_SCK_PIN EXP2_02_PIN
#define TFT_MISO_PIN EXP2_01_PIN
#define TFT_MOSI_PIN EXP2_06_PIN
#define TFT_DC_PIN EXP1_08_PIN
#define TFT_A0_PIN TFT_DC_PIN
#define TFT_RESET_PIN EXP1_04_PIN
#define LCD_BACKLIGHT_PIN EXP1_03_PIN
#define TFT_BACKLIGHT_PIN LCD_BACKLIGHT_PIN
#define TOUCH_BUTTONS_HW_SPI
#define TOUCH_BUTTONS_HW_SPI_DEVICE 3
#define TOUCH_CS_PIN EXP1_05_PIN // SPI3_NSS
#define TOUCH_SCK_PIN EXP2_02_PIN // SPI3_SCK
#define TOUCH_MISO_PIN EXP2_01_PIN // SPI3_MISO
#define TOUCH_MOSI_PIN EXP2_06_PIN // SPI3_MOSI
#define LCD_READ_ID 0xD3
#define LCD_USE_DMA_SPI
#define TFT_BUFFER_SIZE 9600
#elif HAS_WIRED_LCD
#define BEEPER_PIN EXP1_01_PIN
#define BTN_ENC EXP1_02_PIN
@ -253,5 +284,7 @@
#define SD_MOSI_PIN PA7
#define SD_SS_PIN PA4
#endif
#define ONBOARD_SPI_DEVICE 1 // SPI1
#define ONBOARD_SD_CS_PIN PA4 // Chip select for "System" SD card
#define SDSS SD_SS_PIN

View File

@ -63,7 +63,6 @@
* SPI3 is unusable due to pin 43 (PB4) and NRST tie-together :(, but
* leave the definitions so as not to clutter things up. This is only
* OK since RET6 Ed. is specifically advertised as a beta board. */
#define BOARD_NR_SPI 3
#define BOARD_SPI1_NSS_PIN PA4
#define BOARD_SPI1_SCK_PIN PA5
#define BOARD_SPI1_MISO_PIN PA6
@ -79,7 +78,6 @@
#define BOARD_SPI3_MISO_PIN PB4
#define BOARD_SPI3_MOSI_PIN PB5
/* GPIO A to E = 5 * 16 - BOOT1 not used = 79*/
#define BOARD_NR_GPIO_PINS 112
/* Note: NOT 19. The missing one is D38 a.k.a. BOARD_BUTTON_PIN, which

View File

@ -63,26 +63,21 @@
* SPI3 is unusable due to pin 43 (PB4) and NRST tie-together :(, but
* leave the definitions so as not to clutter things up. This is only
* OK since RET6 Ed. is specifically advertised as a beta board. */
#define BOARD_NR_SPI 3
#define BOARD_SPI1_NSS_PIN PA4
#define BOARD_SPI1_SCK_PIN PA5
#define BOARD_SPI1_MISO_PIN PA6
#define BOARD_SPI1_MOSI_PIN PA7
#define BOARD_SPI2_NSS_PIN PB12
#define BOARD_SPI2_SCK_PIN PB13
#define BOARD_SPI2_MISO_PIN PB14
#define BOARD_SPI2_MOSI_PIN PB15
#define BOARD_SPI3_NSS_PIN PA15
#define BOARD_SPI3_SCK_PIN PB3
#define BOARD_SPI3_MISO_PIN PB4
#define BOARD_SPI3_MOSI_PIN PB5
/* GPIO A to E = 5 * 16 - BOOT1 not used = 79*/
#define BOARD_NR_GPIO_PINS 51
/* Note: NOT 19. The missing one is D38 a.k.a. BOARD_BUTTON_PIN, which

View File

@ -217,21 +217,21 @@ build_flags = ${STM32F1_maple.build_flags} -DMCU_STM32F103VE -DSS_TIMER
# MKS Robin (STM32F103ZET6)
#
[env:mks_robin_maple]
extends = STM32F1_maple
board = genericSTM32F103ZE
board_build.address = 0x08007000
board_build.rename = Robin.bin
board_build.ldscript = mks_robin.ld
build_flags = ${STM32F1_maple.build_flags} -DSS_TIMER=4 -DSTM32_XL_DENSITY
extends = STM32F1_maple
board = genericSTM32F103ZE
board_build.address = 0x08007000
board_build.encrypt_mks = Robin.bin
board_build.ldscript = mks_robin.ld
build_flags = ${STM32F1_maple.build_flags} -DSS_TIMER=4 -DSTM32_XL_DENSITY
#
# MKS Robin Pro (STM32F103ZET6)
#
[env:mks_robin_pro_maple]
extends = env:mks_robin_maple
board_build.address = 0x08007000
board_build.rename = Robin_pro.bin
board_build.ldscript = mks_robin_pro.ld
extends = env:mks_robin_maple
board_build.address = 0x08007000
board_build.encrypt_mks = Robin_pro.bin
board_build.ldscript = mks_robin_pro.ld
#
# TRIGORILLA PRO (STM32F103ZET6)