Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Restore async DMA data transfer for TFT_COLOR_UI #24980

Merged
merged 6 commits into from
Dec 12, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Marlin/Configuration.h
Original file line number Diff line number Diff line change
Expand Up @@ -3130,6 +3130,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
Expand Down
47 changes: 46 additions & 1 deletion Marlin/src/HAL/LPC1768/HAL_SPI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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);
}
Expand Down
1 change: 1 addition & 0 deletions Marlin/src/HAL/LPC1768/include/SPI.h
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ class SPIClass {
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
Expand Down
93 changes: 54 additions & 39 deletions Marlin/src/HAL/LPC1768/tft/tft_spi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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);

/**
* 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
OUT_WRITE(TFT_DC_PIN, HIGH);
OUT_WRITE(TFT_CS_PIN, HIGH);

#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);
Expand Down Expand Up @@ -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)

// DMA Channel 0 is hardcoded in dmaSendAsync() and dmaSend()
if (!__IS_DMA_CONFIGURED(LPC_GPDMACH0)) return false;

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::Abort() { DataTransferEnd(); }
DataTransferEnd();
}

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

void TFT_SPI::TransmitDMA(uint32_t MemoryIncrease, uint16_t *Data, uint16_t Count) {
void TFT_SPI::Transmit(uint32_t MemoryIncrease, uint16_t *Data, uint16_t Count) {
DataTransferBegin(DATASIZE_16BIT);
WRITE(TFT_DC_PIN, HIGH);
SPIx.dmaSend(Data, Count, MemoryIncrease);
DataTransferEnd();
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
42 changes: 27 additions & 15 deletions Marlin/src/HAL/LPC1768/tft/tft_spi.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,24 +27,38 @@
#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
#ifndef LCD_READ_ID4
#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:
Expand All @@ -56,22 +70,20 @@ class TFT_SPI {
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_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) { 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(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
}
};
8 changes: 5 additions & 3 deletions Marlin/src/HAL/LPC1768/tft/xpt2046.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
33 changes: 24 additions & 9 deletions Marlin/src/HAL/STM32/tft/tft_fsmc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
15 changes: 9 additions & 6 deletions Marlin/src/HAL/STM32/tft/tft_fsmc.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -59,27 +60,29 @@ 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() {};

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;
}
}
};
Expand Down
2 changes: 1 addition & 1 deletion Marlin/src/HAL/STM32/tft/tft_ltdc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
Loading