Skip to content

Commit ec6349f

Browse files
jmz52thinkyhead
authored andcommitted
✨ TFT_COLOR_UI async DMA SPI (MarlinFirmware#24980)
1 parent d082223 commit ec6349f

File tree

31 files changed

+498
-225
lines changed

31 files changed

+498
-225
lines changed

Marlin/Configuration.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3132,6 +3132,10 @@
31323132
//#define TFT_COLOR_UI
31333133
//#define TFT_LVGL_UI
31343134

3135+
#if ENABLED(TFT_COLOR_UI)
3136+
//#define TFT_SHARED_SPI // SPI is shared between TFT display and other devices. Disable async data transfer
3137+
#endif
3138+
31353139
#if ENABLED(TFT_LVGL_UI)
31363140
//#define MKS_WIFI_MODULE // MKS WiFi module
31373141
#endif

Marlin/src/HAL/LPC1768/HAL_SPI.cpp

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -318,8 +318,16 @@ void SPIClass::dmaSend(void *buf, uint16_t length, bool minc) {
318318
// Enable DMA
319319
GPDMA_ChannelCmd(0, ENABLE);
320320

321+
/*
322+
* Observed behaviour on normal data transfer completion (SKR 1.3 board / LPC1768 MCU)
323+
* GPDMA_STAT_INTTC flag is SET
324+
* GPDMA_STAT_INTERR flag is NOT SET
325+
* GPDMA_STAT_RAWINTTC flag is NOT SET
326+
* GPDMA_STAT_RAWINTERR flag is SET
327+
*/
328+
321329
// Wait for data transfer
322-
while (!GPDMA_IntGetStatus(GPDMA_STAT_RAWINTTC, 0) && !GPDMA_IntGetStatus(GPDMA_STAT_RAWINTERR, 0)) { }
330+
while (!GPDMA_IntGetStatus(GPDMA_STAT_INTTC, 0) && !GPDMA_IntGetStatus(GPDMA_STAT_INTERR, 0)) {}
323331

324332
// Clear err and int
325333
GPDMA_ClearIntPending (GPDMA_STATCLR_INTTC, 0);
@@ -333,6 +341,43 @@ void SPIClass::dmaSend(void *buf, uint16_t length, bool minc) {
333341
SSP_DMACmd(_currentSetting->spi_d, SSP_DMA_TX, DISABLE);
334342
}
335343

344+
void SPIClass::dmaSendAsync(void *buf, uint16_t length, bool minc) {
345+
//TODO: LPC dma can only write 0xFFF bytes at once.
346+
GPDMA_Channel_CFG_Type GPDMACfg;
347+
348+
/* Configure GPDMA channel 0 -------------------------------------------------------------*/
349+
/* DMA Channel 0 */
350+
GPDMACfg.ChannelNum = 0;
351+
// Source memory
352+
GPDMACfg.SrcMemAddr = (uint32_t)buf;
353+
// Destination memory - Not used
354+
GPDMACfg.DstMemAddr = 0;
355+
// Transfer size
356+
GPDMACfg.TransferSize = length;
357+
// Transfer width
358+
GPDMACfg.TransferWidth = (_currentSetting->dataSize == DATA_SIZE_16BIT) ? GPDMA_WIDTH_HALFWORD : GPDMA_WIDTH_BYTE;
359+
// Transfer type
360+
GPDMACfg.TransferType = GPDMA_TRANSFERTYPE_M2P;
361+
// Source connection - unused
362+
GPDMACfg.SrcConn = 0;
363+
// Destination connection
364+
GPDMACfg.DstConn = (_currentSetting->spi_d == LPC_SSP0) ? GPDMA_CONN_SSP0_Tx : GPDMA_CONN_SSP1_Tx;
365+
366+
GPDMACfg.DMALLI = 0;
367+
368+
// Enable dma on SPI
369+
SSP_DMACmd(_currentSetting->spi_d, SSP_DMA_TX, ENABLE);
370+
371+
// Only increase memory if minc is true
372+
GPDMACfg.MemoryIncrease = (minc ? GPDMA_DMACCxControl_SI : 0);
373+
374+
// Setup channel with given parameter
375+
GPDMA_Setup(&GPDMACfg);
376+
377+
// Enable DMA
378+
GPDMA_ChannelCmd(0, ENABLE);
379+
}
380+
336381
uint16_t SPIClass::read() {
337382
return SSP_ReceiveData(_currentSetting->spi_d);
338383
}

Marlin/src/HAL/LPC1768/include/SPI.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,7 @@ class SPIClass {
155155
void read(uint8_t *buf, uint32_t len);
156156

157157
void dmaSend(void *buf, uint16_t length, bool minc);
158+
void dmaSendAsync(void *buf, uint16_t length, bool minc);
158159

159160
/**
160161
* @brief Sets the number of the SPI peripheral to be used by

Marlin/src/HAL/LPC1768/tft/tft_spi.cpp

Lines changed: 54 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626

2727
#include "tft_spi.h"
2828

29-
SPIClass TFT_SPI::SPIx(1);
29+
SPIClass TFT_SPI::SPIx(TFT_SPI_DEVICE);
3030

3131
void TFT_SPI::Init() {
3232
#if PIN_EXISTS(TFT_RESET)
@@ -38,40 +38,10 @@ void TFT_SPI::Init() {
3838
OUT_WRITE(TFT_BACKLIGHT_PIN, HIGH);
3939
#endif
4040

41-
SET_OUTPUT(TFT_DC_PIN);
42-
SET_OUTPUT(TFT_CS_PIN);
43-
WRITE(TFT_DC_PIN, HIGH);
44-
WRITE(TFT_CS_PIN, HIGH);
45-
46-
/**
47-
* STM32F1 APB2 = 72MHz, APB1 = 36MHz, max SPI speed of this MCU if 18Mhz
48-
* STM32F1 has 3 SPI ports, SPI1 in APB2, SPI2/SPI3 in APB1
49-
* so the minimum prescale of SPI1 is DIV4, SPI2/SPI3 is DIV2
50-
*/
51-
#if 0
52-
#if SPI_DEVICE == 1
53-
#define SPI_CLOCK_MAX SPI_CLOCK_DIV4
54-
#else
55-
#define SPI_CLOCK_MAX SPI_CLOCK_DIV2
56-
#endif
57-
uint8_t clock;
58-
uint8_t spiRate = SPI_FULL_SPEED;
59-
switch (spiRate) {
60-
case SPI_FULL_SPEED: clock = SPI_CLOCK_MAX ; break;
61-
case SPI_HALF_SPEED: clock = SPI_CLOCK_DIV4 ; break;
62-
case SPI_QUARTER_SPEED: clock = SPI_CLOCK_DIV8 ; break;
63-
case SPI_EIGHTH_SPEED: clock = SPI_CLOCK_DIV16; break;
64-
case SPI_SPEED_5: clock = SPI_CLOCK_DIV32; break;
65-
case SPI_SPEED_6: clock = SPI_CLOCK_DIV64; break;
66-
default: clock = SPI_CLOCK_DIV2; // Default from the SPI library
67-
}
68-
#endif
41+
OUT_WRITE(TFT_DC_PIN, HIGH);
42+
OUT_WRITE(TFT_CS_PIN, HIGH);
6943

70-
#if TFT_MISO_PIN == BOARD_SPI1_MISO_PIN
71-
SPIx.setModule(1);
72-
#elif TFT_MISO_PIN == BOARD_SPI2_MISO_PIN
73-
SPIx.setModule(2);
74-
#endif
44+
SPIx.setModule(TFT_SPI_DEVICE);
7545
SPIx.setClock(SPI_CLOCK_MAX_TFT);
7646
SPIx.setBitOrder(MSBFIRST);
7747
SPIx.setDataMode(SPI_MODE0);
@@ -114,17 +84,62 @@ uint32_t TFT_SPI::ReadID(uint16_t Reg) {
11484
return data >> 7;
11585
}
11686

117-
bool TFT_SPI::isBusy() { return false; }
87+
bool TFT_SPI::isBusy() {
88+
#define __IS_DMA_CONFIGURED(__HANDLE__) ((__HANDLE__)->DMACCSrcAddr != 0)
89+
90+
// DMA Channel 0 is hardcoded in dmaSendAsync() and dmaSend()
91+
if (!__IS_DMA_CONFIGURED(LPC_GPDMACH0)) return false;
92+
93+
if (GPDMA_IntGetStatus(GPDMA_STAT_INTERR, 0)) {
94+
// You should not be here - DMA transfer error flag is set
95+
// Abort DMA transfer and release SPI
96+
}
97+
else {
98+
// Check if DMA transfer completed flag is set
99+
if (!GPDMA_IntGetStatus(GPDMA_STAT_INTTC, 0)) return true;
100+
// Check if SPI TX butter is empty and SPI is idle
101+
if ((SSP_GetStatus(LPC_SSPx, SSP_STAT_TXFIFO_EMPTY) == RESET) || (SSP_GetStatus(LPC_SSPx, SSP_STAT_BUSY) == SET)) return true;
102+
}
103+
104+
Abort();
105+
return false;
106+
}
107+
108+
void TFT_SPI::Abort() {
109+
// DMA Channel 0 is hardcoded in dmaSendAsync() and dmaSend()
110+
111+
// Disable DMA
112+
GPDMA_ChannelCmd(0, DISABLE);
113+
114+
// Clear ERR and TC
115+
GPDMA_ClearIntPending(GPDMA_STATCLR_INTTC, 0);
116+
GPDMA_ClearIntPending(GPDMA_STATCLR_INTERR, 0);
117+
118+
// Disable DMA on SPI
119+
SSP_DMACmd(LPC_SSPx, SSP_DMA_TX, DISABLE);
120+
121+
// Deconfigure DMA Channel 0
122+
LPC_GPDMACH0->DMACCControl = 0U;
123+
LPC_GPDMACH0->DMACCConfig = 0U;
124+
LPC_GPDMACH0->DMACCSrcAddr = 0U;
125+
LPC_GPDMACH0->DMACCDestAddr = 0U;
118126

119-
void TFT_SPI::Abort() { DataTransferEnd(); }
127+
DataTransferEnd();
128+
}
120129

121130
void TFT_SPI::Transmit(uint16_t Data) { SPIx.transfer(Data); }
122131

123-
void TFT_SPI::TransmitDMA(uint32_t MemoryIncrease, uint16_t *Data, uint16_t Count) {
132+
void TFT_SPI::Transmit(uint32_t MemoryIncrease, uint16_t *Data, uint16_t Count) {
124133
DataTransferBegin(DATASIZE_16BIT);
125-
WRITE(TFT_DC_PIN, HIGH);
126134
SPIx.dmaSend(Data, Count, MemoryIncrease);
127-
DataTransferEnd();
135+
Abort();
136+
}
137+
138+
void TFT_SPI::TransmitDMA(uint32_t MemoryIncrease, uint16_t *Data, uint16_t Count) {
139+
DataTransferBegin(DATASIZE_16BIT);
140+
SPIx.dmaSendAsync(Data, Count, MemoryIncrease);
141+
142+
TERN_(TFT_SHARED_SPI, while (isBusy()));
128143
}
129144

130145
#endif // HAS_SPI_TFT

Marlin/src/HAL/LPC1768/tft/tft_spi.h

Lines changed: 27 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -27,24 +27,38 @@
2727
#include <lpc17xx_ssp.h>
2828
// #include <lpc17xx_gpdma.h>
2929

30+
#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))
31+
#if IS_SPI(1)
32+
#define TFT_SPI_DEVICE 1
33+
#define LPC_SSPx LPC_SSP0
34+
#elif IS_SPI(2)
35+
#define TFT_SPI_DEVICE 2
36+
#define LPC_SSPx LPC_SSP1
37+
#else
38+
#error "Invalid TFT SPI configuration."
39+
#endif
40+
#undef IS_SPI
41+
3042
#ifndef LCD_READ_ID
3143
#define LCD_READ_ID 0x04 // Read display identification information (0xD3 on ILI9341)
3244
#endif
3345
#ifndef LCD_READ_ID4
3446
#define LCD_READ_ID4 0xD3 // Read display identification information (0xD3 on ILI9341)
3547
#endif
3648

37-
#define DATASIZE_8BIT SSP_DATABIT_8
38-
#define DATASIZE_16BIT SSP_DATABIT_16
39-
#define TFT_IO_DRIVER TFT_SPI
49+
#define DATASIZE_8BIT SSP_DATABIT_8
50+
#define DATASIZE_16BIT SSP_DATABIT_16
51+
#define TFT_IO_DRIVER TFT_SPI
52+
#define DMA_MAX_SIZE 0xFFF
4053

41-
#define DMA_MINC_ENABLE 1
42-
#define DMA_MINC_DISABLE 0
54+
#define DMA_MINC_ENABLE 1
55+
#define DMA_MINC_DISABLE 0
4356

4457
class TFT_SPI {
4558
private:
4659
static uint32_t ReadID(uint16_t Reg);
4760
static void Transmit(uint16_t Data);
61+
static void Transmit(uint32_t MemoryIncrease, uint16_t *Data, uint16_t Count);
4862
static void TransmitDMA(uint32_t MemoryIncrease, uint16_t *Data, uint16_t Count);
4963

5064
public:
@@ -56,22 +70,20 @@ class TFT_SPI {
5670
static void Abort();
5771

5872
static void DataTransferBegin(uint16_t DataWidth = DATASIZE_16BIT);
59-
static void DataTransferEnd() { OUT_WRITE(TFT_CS_PIN, HIGH); SPIx.end(); };
73+
static void DataTransferEnd() { WRITE(TFT_CS_PIN, HIGH); SSP_Cmd(LPC_SSPx, DISABLE); };
6074
static void DataTransferAbort();
6175

6276
static void WriteData(uint16_t Data) { Transmit(Data); }
63-
static void WriteReg(uint16_t Reg) { OUT_WRITE(TFT_A0_PIN, LOW); Transmit(Reg); OUT_WRITE(TFT_A0_PIN, HIGH); }
77+
static void WriteReg(uint16_t Reg) { WRITE(TFT_DC_PIN, LOW); Transmit(Reg); WRITE(TFT_DC_PIN, HIGH); }
78+
79+
static void WriteSequence_DMA(uint16_t *Data, uint16_t Count) { TransmitDMA(DMA_MINC_ENABLE, Data, Count); }
80+
static void WriteMultiple_DMA(uint16_t Color, uint16_t Count) { static uint16_t Data; Data = Color; TransmitDMA(DMA_MINC_DISABLE, &Data, Count); }
6481

65-
static void WriteSequence(uint16_t *Data, uint16_t Count) { TransmitDMA(DMA_MINC_ENABLE, Data, Count); }
66-
// static void WriteMultiple(uint16_t Color, uint16_t Count) { static uint16_t Data; Data = Color; TransmitDMA(DMA_MINC_DISABLE, &Data, Count); }
82+
static void WriteSequence(uint16_t *Data, uint16_t Count) { Transmit(DMA_MINC_ENABLE, Data, Count); }
6783
static void WriteMultiple(uint16_t Color, uint32_t Count) {
68-
static uint16_t Data; Data = Color;
69-
//LPC dma can only write 0xFFF bytes at once.
70-
#define MAX_DMA_SIZE (0xFFF - 1)
7184
while (Count > 0) {
72-
TransmitDMA(DMA_MINC_DISABLE, &Data, Count > MAX_DMA_SIZE ? MAX_DMA_SIZE : Count);
73-
Count = Count > MAX_DMA_SIZE ? Count - MAX_DMA_SIZE : 0;
85+
Transmit(DMA_MINC_DISABLE, &Color, Count > DMA_MAX_SIZE ? DMA_MAX_SIZE : Count);
86+
Count = Count > DMA_MAX_SIZE ? Count - DMA_MAX_SIZE : 0;
7487
}
75-
#undef MAX_DMA_SIZE
7688
}
7789
};

Marlin/src/HAL/LPC1768/tft/xpt2046.cpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,11 @@ uint16_t delta(uint16_t a, uint16_t b) { return a > b ? a - b : b - a; }
4444
#endif
4545

4646
void XPT2046::Init() {
47-
SET_INPUT(TOUCH_MISO_PIN);
48-
SET_OUTPUT(TOUCH_MOSI_PIN);
49-
SET_OUTPUT(TOUCH_SCK_PIN);
47+
#if DISABLED(TOUCH_BUTTONS_HW_SPI)
48+
SET_INPUT(TOUCH_MISO_PIN);
49+
SET_OUTPUT(TOUCH_MOSI_PIN);
50+
SET_OUTPUT(TOUCH_SCK_PIN);
51+
#endif
5052
OUT_WRITE(TOUCH_CS_PIN, HIGH);
5153

5254
#if PIN_EXISTS(TOUCH_INT)

Marlin/src/HAL/STM32/tft/tft_fsmc.cpp

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -148,20 +148,35 @@ uint32_t TFT_FSMC::ReadID(tft_data_t Reg) {
148148

149149
bool TFT_FSMC::isBusy() {
150150
#ifdef STM32F1xx
151-
volatile bool dmaEnabled = (DMAtx.Instance->CCR & DMA_CCR_EN) != RESET;
151+
#define __IS_DMA_ENABLED(__HANDLE__) ((__HANDLE__)->Instance->CCR & DMA_CCR_EN)
152+
#define __IS_DMA_CONFIGURED(__HANDLE__) ((__HANDLE__)->Instance->CPAR != 0)
152153
#elif defined(STM32F4xx)
153-
volatile bool dmaEnabled = DMAtx.Instance->CR & DMA_SxCR_EN;
154+
#define __IS_DMA_ENABLED(__HANDLE__) ((__HANDLE__)->Instance->CR & DMA_SxCR_EN)
155+
#define __IS_DMA_CONFIGURED(__HANDLE__) ((__HANDLE__)->Instance->PAR != 0)
154156
#endif
155-
if (dmaEnabled) {
156-
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)
157-
Abort();
158-
}
159-
else
160-
Abort();
161-
return dmaEnabled;
157+
158+
if (!__IS_DMA_CONFIGURED(&DMAtx)) return false;
159+
160+
// Check if DMA transfer error or transfer complete flags are set
161+
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;
162+
163+
__DSB();
164+
Abort();
165+
return false;
166+
}
167+
168+
void TFT_FSMC::Abort() {
169+
HAL_DMA_Abort(&DMAtx); // Abort DMA transfer if any
170+
HAL_DMA_DeInit(&DMAtx); // Deconfigure DMA
162171
}
163172

164173
void TFT_FSMC::TransmitDMA(uint32_t MemoryIncrease, uint16_t *Data, uint16_t Count) {
174+
DMAtx.Init.PeriphInc = MemoryIncrease;
175+
HAL_DMA_Init(&DMAtx);
176+
HAL_DMA_Start(&DMAtx, (uint32_t)Data, (uint32_t)&(LCD->RAM), Count);
177+
}
178+
179+
void TFT_FSMC::Transmit(uint32_t MemoryIncrease, uint16_t *Data, uint16_t Count) {
165180
DMAtx.Init.PeriphInc = MemoryIncrease;
166181
HAL_DMA_Init(&DMAtx);
167182
DataTransferBegin();

Marlin/src/HAL/STM32/tft/tft_fsmc.h

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
#define DATASIZE_8BIT SPI_DATASIZE_8BIT
4242
#define DATASIZE_16BIT SPI_DATASIZE_16BIT
4343
#define TFT_IO_DRIVER TFT_FSMC
44+
#define DMA_MAX_SIZE 0xFFFF
4445

4546
#define TFT_DATASIZE TERN(TFT_INTERFACE_FSMC_8BIT, DATASIZE_8BIT, DATASIZE_16BIT)
4647
typedef TERN(TFT_INTERFACE_FSMC_8BIT, uint8_t, uint16_t) tft_data_t;
@@ -59,27 +60,29 @@ class TFT_FSMC {
5960

6061
static uint32_t ReadID(tft_data_t Reg);
6162
static void Transmit(tft_data_t Data) { LCD->RAM = Data; __DSB(); }
63+
static void Transmit(uint32_t MemoryIncrease, uint16_t *Data, uint16_t Count);
6264
static void TransmitDMA(uint32_t MemoryIncrease, uint16_t *Data, uint16_t Count);
6365

6466
public:
6567
static void Init();
6668
static uint32_t GetID();
6769
static bool isBusy();
68-
static void Abort() { __HAL_DMA_DISABLE(&DMAtx); }
70+
static void Abort();
6971

7072
static void DataTransferBegin(uint16_t DataWidth = TFT_DATASIZE) {}
7173
static void DataTransferEnd() {};
7274

7375
static void WriteData(uint16_t Data) { Transmit(tft_data_t(Data)); }
7476
static void WriteReg(uint16_t Reg) { LCD->REG = tft_data_t(Reg); __DSB(); }
7577

76-
static void WriteSequence(uint16_t *Data, uint16_t Count) { TransmitDMA(DMA_PINC_ENABLE, Data, Count); }
77-
static void WriteMultiple(uint16_t Color, uint16_t Count) { static uint16_t Data; Data = Color; TransmitDMA(DMA_PINC_DISABLE, &Data, Count); }
78+
static void WriteSequence_DMA(uint16_t *Data, uint16_t Count) { TransmitDMA(DMA_PINC_ENABLE, Data, Count); }
79+
static void WriteMultiple_DMA(uint16_t Color, uint16_t Count) { static uint16_t Data; Data = Color; TransmitDMA(DMA_PINC_DISABLE, &Data, Count); }
80+
81+
static void WriteSequence(uint16_t *Data, uint16_t Count) { Transmit(DMA_PINC_ENABLE, Data, Count); }
7882
static void WriteMultiple(uint16_t Color, uint32_t Count) {
79-
static uint16_t Data; Data = Color;
8083
while (Count > 0) {
81-
TransmitDMA(DMA_MINC_DISABLE, &Data, Count > 0xFFFF ? 0xFFFF : Count);
82-
Count = Count > 0xFFFF ? Count - 0xFFFF : 0;
84+
Transmit(DMA_MINC_DISABLE, &Color, Count > DMA_MAX_SIZE ? DMA_MAX_SIZE : Count);
85+
Count = Count > DMA_MAX_SIZE ? Count - DMA_MAX_SIZE : 0;
8386
}
8487
}
8588
};

Marlin/src/HAL/STM32/tft/tft_ltdc.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -356,7 +356,7 @@ void TFT_LTDC::WriteReg(uint16_t Reg) {
356356
reg = Reg;
357357
}
358358

359-
void TFT_LTDC::TransmitDMA(uint32_t MemoryIncrease, uint16_t *Data, uint16_t Count) {
359+
void TFT_LTDC::Transmit(uint32_t MemoryIncrease, uint16_t *Data, uint16_t Count) {
360360

361361
while (x_cur != x_min && Count) {
362362
Transmit(*Data);

0 commit comments

Comments
 (0)