TFT (plus Hardware SPI) for LPC (#19139)

This commit is contained in:
Victor Oliveira 2020-08-26 07:13:58 -03:00 committed by Scott Lahteine
parent 5059586fc3
commit 3b4779fa15
11 changed files with 862 additions and 49 deletions

View File

@ -30,7 +30,7 @@
*/ */
/** /**
* Hardware SPI and a software SPI implementations are included in this file. * Hardware SPI and Software SPI implementations are included in this file.
* The hardware SPI runs faster and has higher throughput but is not compatible * The hardware SPI runs faster and has higher throughput but is not compatible
* with some LCD interfaces/adapters. * with some LCD interfaces/adapters.
* *
@ -51,6 +51,10 @@
#include "../../inc/MarlinConfig.h" #include "../../inc/MarlinConfig.h"
#include <SPI.h> #include <SPI.h>
// Hardware SPI and SPIClass
#include <lpc17xx_pinsel.h>
#include <lpc17xx_clkpwr.h>
// ------------------------ // ------------------------
// Public functions // Public functions
// ------------------------ // ------------------------
@ -96,12 +100,6 @@
#else #else
// Hardware SPI
#include <lpc17xx_pinsel.h>
#include <lpc17xx_ssp.h>
#include <lpc17xx_clkpwr.h>
// decide which HW SPI device to use // decide which HW SPI device to use
#ifndef LPC_HW_SPI_DEV #ifndef LPC_HW_SPI_DEV
#if (SCK_PIN == P0_07 && MISO_PIN == P0_08 && MOSI_PIN == P0_09) #if (SCK_PIN == P0_07 && MISO_PIN == P0_08 && MOSI_PIN == P0_09)
@ -114,7 +112,7 @@
#endif #endif
#endif #endif
#endif #endif
#if (LPC_HW_SPI_DEV == 0) #if LPC_HW_SPI_DEV == 0
#define LPC_SSPn LPC_SSP0 #define LPC_SSPn LPC_SSP0
#else #else
#define LPC_SSPn LPC_SSP1 #define LPC_SSPn LPC_SSP1
@ -192,7 +190,7 @@
for (uint16_t i = 0; i < nbyte; i++) buf[i] = doio(0xFF); for (uint16_t i = 0; i < nbyte; i++) buf[i] = doio(0xFF);
} }
static uint8_t spiTransfer(uint8_t b) { uint8_t spiTransfer(uint8_t b) {
return doio(b); return doio(b);
} }
@ -211,30 +209,236 @@
#endif // LPC_SOFTWARE_SPI #endif // LPC_SOFTWARE_SPI
void SPIClass::begin() { spiBegin(); } /**
* @brief Wait until TXE (tx empty) flag is set and BSY (busy) flag unset.
*/
static inline void waitSpiTxEnd(LPC_SSP_TypeDef *spi_d) {
while (SSP_GetStatus(spi_d, SSP_STAT_TXFIFO_EMPTY) == RESET) { /* nada */ } // wait until TXE=1
while (SSP_GetStatus(spi_d, SSP_STAT_BUSY) == SET) { /* nada */ } // wait until BSY=0
}
SPIClass::SPIClass(uint8_t device) {
// Init things specific to each SPI device
// clock divider setup is a bit of hack, and needs to be improved at a later date.
PINSEL_CFG_Type PinCfg; // data structure to hold init values
#if BOARD_NR_SPI >= 1
_settings[0].spi_d = LPC_SSP0;
// _settings[0].clockDivider = determine_baud_rate(_settings[0].spi_d, _settings[0].clock);
PinCfg.Funcnum = 2;
PinCfg.OpenDrain = 0;
PinCfg.Pinmode = 0;
PinCfg.Pinnum = LPC176x::pin_bit(BOARD_SPI1_SCK_PIN);
PinCfg.Portnum = LPC176x::pin_port(BOARD_SPI1_SCK_PIN);
PINSEL_ConfigPin(&PinCfg);
SET_OUTPUT(BOARD_SPI1_SCK_PIN);
PinCfg.Pinnum = LPC176x::pin_bit(BOARD_SPI1_MISO_PIN);
PinCfg.Portnum = LPC176x::pin_port(BOARD_SPI1_MISO_PIN);
PINSEL_ConfigPin(&PinCfg);
SET_INPUT(BOARD_SPI1_MISO_PIN);
PinCfg.Pinnum = LPC176x::pin_bit(BOARD_SPI1_MOSI_PIN);
PinCfg.Portnum = LPC176x::pin_port(BOARD_SPI1_MOSI_PIN);
PINSEL_ConfigPin(&PinCfg);
SET_OUTPUT(BOARD_SPI1_MOSI_PIN);
#endif
#if BOARD_NR_SPI >= 2
_settings[1].spi_d = LPC_SSP1;
// _settings[1].clockDivider = determine_baud_rate(_settings[1].spi_d, _settings[1].clock);
PinCfg.Funcnum = 2;
PinCfg.OpenDrain = 0;
PinCfg.Pinmode = 0;
PinCfg.Pinnum = LPC176x::pin_bit(BOARD_SPI2_SCK_PIN);
PinCfg.Portnum = LPC176x::pin_port(BOARD_SPI2_SCK_PIN);
PINSEL_ConfigPin(&PinCfg);
SET_OUTPUT(BOARD_SPI2_SCK_PIN);
PinCfg.Pinnum = LPC176x::pin_bit(BOARD_SPI2_MISO_PIN);
PinCfg.Portnum = LPC176x::pin_port(BOARD_SPI2_MISO_PIN);
PINSEL_ConfigPin(&PinCfg);
SET_INPUT(BOARD_SPI2_MISO_PIN);
PinCfg.Pinnum = LPC176x::pin_bit(BOARD_SPI2_MOSI_PIN);
PinCfg.Portnum = LPC176x::pin_port(BOARD_SPI2_MOSI_PIN);
PINSEL_ConfigPin(&PinCfg);
SET_OUTPUT(BOARD_SPI2_MOSI_PIN);
#endif
setModule(device);
/* Initialize GPDMA controller */
//TODO: call once in the constructor? or each time?
GPDMA_Init();
}
void SPIClass::begin() {
updateSettings();
SSP_Cmd(_currentSetting->spi_d, ENABLE); // start SSP running
}
void SPIClass::beginTransaction(const SPISettings &cfg) { void SPIClass::beginTransaction(const SPISettings &cfg) {
uint8_t spiRate; setBitOrder(cfg.bitOrder);
switch (cfg.spiRate()) { setDataMode(cfg.dataMode);
case 8000000: spiRate = 0; break; setDataSize(cfg.dataSize);
case 4000000: spiRate = 1; break; //setClockDivider(determine_baud_rate(_currentSetting->spi_d, settings.clock));
case 2000000: spiRate = 2; break; begin();
case 1000000: spiRate = 3; break;
case 500000: spiRate = 4; break;
case 250000: spiRate = 5; break;
case 125000: spiRate = 6; break;
default: spiRate = 2; break;
}
spiInit(spiRate);
} }
uint8_t SPIClass::transfer(const uint8_t B) { return spiTransfer(B); } uint8_t SPIClass::transfer(const uint16_t b) {
/* send and receive a single byte */
SSP_ReceiveData(_currentSetting->spi_d); // read any previous data
SSP_SendData(_currentSetting->spi_d, b);
waitSpiTxEnd(_currentSetting->spi_d); // wait for it to finish
return SSP_ReceiveData(_currentSetting->spi_d);
}
uint16_t SPIClass::transfer16(const uint16_t data) { uint16_t SPIClass::transfer16(const uint16_t data) {
return (transfer((data >> 8) & 0xFF) << 8) return (transfer((data >> 8) & 0xFF) << 8)
| (transfer(data & 0xFF) & 0xFF); | (transfer(data & 0xFF) & 0xFF);
} }
SPIClass SPI; void SPIClass::end() {
// SSP_Cmd(_currentSetting->spi_d, DISABLE); // stop device or SSP_DeInit?
SSP_DeInit(_currentSetting->spi_d);
}
void SPIClass::send(uint8_t data) {
SSP_SendData(_currentSetting->spi_d, data);
}
void SPIClass::dmaSend(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 = (minc ? length : 1);
// 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);
// if minc=false, I'm repeating the same byte 'length' times, as I could not find yet how do GPDMA without memory increment
do {
// Setup channel with given parameter
GPDMA_Setup(&GPDMACfg);
// enabled dma
GPDMA_ChannelCmd(0, ENABLE);
// wait data transfer
while (!GPDMA_IntGetStatus(GPDMA_STAT_INTTC, 0) && !GPDMA_IntGetStatus(GPDMA_STAT_INTERR, 0)) { }
// clear err and int
GPDMA_ClearIntPending (GPDMA_STATCLR_INTTC, 0);
GPDMA_ClearIntPending (GPDMA_STATCLR_INTERR, 0);
// dma disable
GPDMA_ChannelCmd(0, DISABLE);
--length;
} while (!minc && length > 0);
waitSpiTxEnd(_currentSetting->spi_d);
SSP_DMACmd(_currentSetting->spi_d, SSP_DMA_TX, DISABLE);
}
uint16_t SPIClass::read() {
return SSP_ReceiveData(_currentSetting->spi_d);
}
void SPIClass::read(uint8_t *buf, uint32_t len) {
for (uint16_t i = 0; i < len; i++) buf[i] = transfer(0xFF);
}
void SPIClass::setClock(uint32_t clock) {
_currentSetting->clock = clock;
}
void SPIClass::setModule(uint8_t device) {
_currentSetting = &_settings[device - 1];// SPI channels are called 1 2 and 3 but the array is zero indexed
}
void SPIClass::setBitOrder(uint8_t bitOrder) {
_currentSetting->bitOrder = bitOrder;
}
void SPIClass::setDataMode(uint8_t dataMode) {
_currentSetting->dataSize = dataMode;
}
void SPIClass::setDataSize(uint32_t ds) {
_currentSetting->dataSize = ds;
}
/**
* Set up/tear down
*/
void SPIClass::updateSettings() {
//SSP_DeInit(_currentSetting->spi_d); //todo: need force de init?!
// divide PCLK by 2 for SSP0
CLKPWR_SetPCLKDiv(_currentSetting->spi_d == LPC_SSP0 ? CLKPWR_PCLKSEL_SSP0 : CLKPWR_PCLKSEL_SSP1, CLKPWR_PCLKSEL_CCLK_DIV_2);
SSP_CFG_Type HW_SPI_init; // data structure to hold init values
SSP_ConfigStructInit(&HW_SPI_init); // set values for SPI mode
HW_SPI_init.ClockRate = _currentSetting->clock;
HW_SPI_init.Databit = _currentSetting->dataSize;
/**
* SPI Mode CPOL CPHA Shift SCK-edge Capture SCK-edge
* 0 0 0 Falling Rising
* 1 0 1 Rising Falling
* 2 1 0 Rising Falling
* 3 1 1 Falling Rising
*/
switch (_currentSetting->dataMode) {
case SPI_MODE0:
HW_SPI_init.CPHA = SSP_CPHA_FIRST;
HW_SPI_init.CPOL = SSP_CPOL_HI;
break;
case SPI_MODE1:
HW_SPI_init.CPHA = SSP_CPHA_SECOND;
HW_SPI_init.CPOL = SSP_CPOL_HI;
break;
case SPI_MODE2:
HW_SPI_init.CPHA = SSP_CPHA_FIRST;
HW_SPI_init.CPOL = SSP_CPOL_LO;
break;
case SPI_MODE3:
HW_SPI_init.CPHA = SSP_CPHA_SECOND;
HW_SPI_init.CPOL = SSP_CPOL_LO;
break;
default:
break;
}
// TODO: handle bitOrder
SSP_Init(_currentSetting->spi_d, &HW_SPI_init); // puts the values into the proper bits in the SSP0 registers
}
#if MISO_PIN == BOARD_SPI1_MISO_PIN
SPIClass SPI(1);
#elif MISO_PIN == BOARD_SPI2_MISO_PIN
SPIClass SPI(2);
#endif
#endif // TARGET_LPC1768 #endif // TARGET_LPC1768

View File

@ -21,6 +21,13 @@
*/ */
#pragma once #pragma once
#if HAS_SPI_TFT || HAS_FSMC_TFT #if HAS_FSMC_TFT
#error "Sorry! TFT displays are not available for HAL/LPC1768." #error "Sorry! FSMC TFT displays are not current available for HAL/LPC1768."
#endif
// This emulated DOGM has 'touch/xpt2046', not 'tft/xpt2046'
#if ENABLED(TOUCH_SCREEN) && !HAS_GRAPHICAL_TFT
#undef TOUCH_SCREEN
#undef TOUCH_SCREEN_CALIBRATION
#define HAS_TOUCH_XPT2046 1
#endif #endif

View File

@ -24,25 +24,139 @@
#include "../../shared/HAL_SPI.h" #include "../../shared/HAL_SPI.h"
#include <stdint.h> #include <stdint.h>
#include <lpc17xx_ssp.h>
#include <lpc17xx_gpdma.h>
#define MSBFIRST 1 //#define MSBFIRST 1
#define SPI_MODE3 0
#define SPI_MODE0 0
#define SPI_MODE1 1
#define SPI_MODE2 2
#define SPI_MODE3 3
#define DATA_SIZE_8BIT SSP_DATABIT_8
#define DATA_SIZE_16BIT SSP_DATABIT_16
#define SPI_CLOCK_DIV2 8333333 //(SCR: 2) desired: 8,000,000 actual: 8,333,333 +4.2% SPI_FULL_SPEED
#define SPI_CLOCK_DIV4 4166667 //(SCR: 5) desired: 4,000,000 actual: 4,166,667 +4.2% SPI_HALF_SPEED
#define SPI_CLOCK_DIV8 2083333 //(SCR: 11) desired: 2,000,000 actual: 2,083,333 +4.2% SPI_QUARTER_SPEED
#define SPI_CLOCK_DIV16 1000000 //(SCR: 24) desired: 1,000,000 actual: 1,000,000 SPI_EIGHTH_SPEED
#define SPI_CLOCK_DIV32 500000 //(SCR: 49) desired: 500,000 actual: 500,000 SPI_SPEED_5
#define SPI_CLOCK_DIV64 250000 //(SCR: 99) desired: 250,000 actual: 250,000 SPI_SPEED_6
#define SPI_CLOCK_DIV128 125000 //(SCR:199) desired: 125,000 actual: 125,000 Default from HAL.h
#define SPI_CLOCK_MAX SPI_CLOCK_DIV2
#define BOARD_NR_SPI 2
//#define BOARD_SPI1_NSS_PIN PA4 ?!
#define BOARD_SPI1_SCK_PIN P0_15
#define BOARD_SPI1_MISO_PIN P0_17
#define BOARD_SPI1_MOSI_PIN P0_18
//#define BOARD_SPI2_NSS_PIN PB12 ?!
#define BOARD_SPI2_SCK_PIN P0_07
#define BOARD_SPI2_MISO_PIN P0_08
#define BOARD_SPI2_MOSI_PIN P0_09
class SPISettings { class SPISettings {
public: public:
SPISettings(uint32_t speed, int, int) : spi_speed(speed) {}; SPISettings(uint32_t speed, int, int) : spi_speed(speed) {};
SPISettings(uint32_t inClock, uint8_t inBitOrder, uint8_t inDataMode, uint32_t inDataSize) {
if (__builtin_constant_p(inClock))
init_AlwaysInline(inClock, inBitOrder, inDataMode, inDataSize);
else
init_MightInline(inClock, inBitOrder, inDataMode, inDataSize);
}
SPISettings() {
init_AlwaysInline(4000000, MSBFIRST, SPI_MODE0, DATA_SIZE_8BIT);
}
uint32_t spiRate() const { return spi_speed; } uint32_t spiRate() const { return spi_speed; }
private: private:
void init_MightInline(uint32_t inClock, uint8_t inBitOrder, uint8_t inDataMode, uint32_t inDataSize) {
init_AlwaysInline(inClock, inBitOrder, inDataMode, inDataSize);
}
void init_AlwaysInline(uint32_t inClock, uint8_t inBitOrder, uint8_t inDataMode, uint32_t inDataSize) __attribute__((__always_inline__)) {
clock = inClock;
bitOrder = inBitOrder;
dataMode = inDataMode;
dataSize = inDataSize;
}
uint32_t spi_speed; uint32_t spi_speed;
uint32_t clock;
uint32_t dataSize;
//uint32_t clockDivider;
uint8_t bitOrder;
uint8_t dataMode;
LPC_SSP_TypeDef *spi_d;
friend class SPIClass;
}; };
/**
* @brief Wirish SPI interface.
*
* This is the same interface is available across HAL
*
* This implementation uses software slave management, so the caller
* is responsible for controlling the slave select line.
*/
class SPIClass { class SPIClass {
public: public:
/**
* @param spiPortNumber Number of the SPI port to manage.
*/
SPIClass(uint8_t spiPortNumber);
/**
* Select and configure the current selected SPI device to use
*/
void begin(); void begin();
/**
* Disable the current SPI device
*/
void end();
void beginTransaction(const SPISettings&); void beginTransaction(const SPISettings&);
void endTransaction() {}; void endTransaction() {};
uint8_t transfer(uint8_t data);
// Transfer using 1 "Data Size"
uint8_t transfer(uint16_t data);
// Transfer 2 bytes in 8 bit mode
uint16_t transfer16(uint16_t data); uint16_t transfer16(uint16_t data);
void send(uint8_t data);
uint16_t read();
void read(uint8_t *buf, uint32_t len);
void dmaSend(void *buf, uint16_t length, bool minc);
/**
* @brief Sets the number of the SPI peripheral to be used by
* this HardwareSPI instance.
*
* @param spi_num Number of the SPI port. 1-2 in low density devices
* or 1-3 in high density devices.
*/
void setModule(uint8_t device);
void setClock(uint32_t clock);
void setBitOrder(uint8_t bitOrder);
void setDataMode(uint8_t dataMode);
void setDataSize(uint32_t ds);
inline uint32_t getDataSize() { return _currentSetting->dataSize; }
private:
SPISettings _settings[BOARD_NR_SPI];
SPISettings *_currentSetting;
void updateSettings();
}; };
extern SPIClass SPI; extern SPIClass SPI;

View File

@ -0,0 +1,153 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
*
* Based on Sprinter and grbl.
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#include "../../../inc/MarlinConfig.h"
#if HAS_SPI_TFT
#include "tft_spi.h"
//TFT_SPI tft;
SPIClass TFT_SPI::SPIx(1);
#define TFT_CS_H WRITE(TFT_CS_PIN, HIGH)
#define TFT_CS_L WRITE(TFT_CS_PIN, LOW)
#define TFT_DC_H WRITE(TFT_DC_PIN, HIGH)
#define TFT_DC_L WRITE(TFT_DC_PIN, LOW)
#define TFT_RST_H WRITE(TFT_RESET_PIN, HIGH)
#define TFT_RST_L WRITE(TFT_RESET_PIN, LOW)
#define TFT_BLK_H WRITE(TFT_BACKLIGHT_PIN, HIGH)
#define TFT_BLK_L WRITE(TFT_BACKLIGHT_PIN, LOW)
void TFT_SPI::Init() {
#if PIN_EXISTS(TFT_RESET)
SET_OUTPUT(TFT_RESET_PIN);
TFT_RST_H;
delay(100);
#endif
#if PIN_EXISTS(TFT_BACKLIGHT)
SET_OUTPUT(TFT_BACKLIGHT_PIN);
TFT_BLK_H;
#endif
SET_OUTPUT(TFT_DC_PIN);
SET_OUTPUT(TFT_CS_PIN);
TFT_DC_H;
TFT_CS_H;
/**
* 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.setClock(SPI_CLOCK_MAX);
SPIx.setBitOrder(MSBFIRST);
SPIx.setDataMode(SPI_MODE0);
}
void TFT_SPI::DataTransferBegin(uint16_t DataSize) {
SPIx.setDataSize(DataSize);
SPIx.begin();
TFT_CS_L;
}
uint32_t TFT_SPI::GetID() {
uint32_t id;
id = ReadID(LCD_READ_ID);
if ((id & 0xFFFF) == 0 || (id & 0xFFFF) == 0xFFFF)
id = ReadID(LCD_READ_ID4);
return id;
}
uint32_t TFT_SPI::ReadID(uint16_t Reg) {
uint32_t data = 0;
#if PIN_EXISTS(TFT_MISO)
uint8_t d = 0;
SPIx.setDataSize(DATASIZE_8BIT);
SPIx.setClock(SPI_CLOCK_DIV64);
SPIx.begin();
TFT_CS_L;
WriteReg(Reg);
LOOP_L_N(i, 4) {
SPIx.read((uint8_t*)&d, 1);
data = (data << 8) | d;
}
DataTransferEnd();
SPIx.setClock(SPI_CLOCK_MAX);
#endif
return data >> 7;
}
bool TFT_SPI::isBusy() {
return false;
}
void TFT_SPI::Abort() {
DataTransferEnd();
}
void TFT_SPI::Transmit(uint16_t Data) {
SPIx.transfer(Data);
}
void TFT_SPI::TransmitDMA(uint32_t MemoryIncrease, uint16_t *Data, uint16_t Count) {
DataTransferBegin(DATASIZE_16BIT); //16
TFT_DC_H;
SPIx.dmaSend(Data, Count, MemoryIncrease);
DataTransferEnd();
}
#endif // HAS_SPI_TFT

View File

@ -0,0 +1,77 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
*
* Based on Sprinter and grbl.
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
#include "../../../inc/MarlinConfig.h"
#include <SPI.h>
#include <lpc17xx_ssp.h>
// #include <lpc17xx_gpdma.h>
#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 TFT_SPI
#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 TransmitDMA(uint32_t MemoryIncrease, uint16_t *Data, uint16_t Count);
public:
static SPIClass SPIx;
static void Init();
static uint32_t GetID();
static bool isBusy();
static void Abort();
static void DataTransferBegin(uint16_t DataWidth = DATASIZE_16BIT);
static void DataTransferEnd() { OUT_WRITE(TFT_CS_PIN, HIGH); SPIx.end(); };
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 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 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;
}
#undef MAX_DMA_SIZE
}
};

View File

@ -0,0 +1,129 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2019 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#include "../../../inc/MarlinConfig.h"
#if HAS_TFT_XPT2046 || HAS_TOUCH_XPT2046
#include "xpt2046.h"
#include <SPI.h>
uint16_t delta(uint16_t a, uint16_t b) { return a > b ? a - b : b - a; }
#if ENABLED(TOUCH_BUTTONS_HW_SPI)
#include <SPI.h>
SPIClass XPT2046::SPIx(TOUCH_BUTTONS_HW_SPI_DEVICE);
static void touch_spi_init(uint8_t spiRate) {
XPT2046::SPIx.setModule(TOUCH_BUTTONS_HW_SPI_DEVICE);
XPT2046::SPIx.setClock(SPI_CLOCK_DIV128);
XPT2046::SPIx.setBitOrder(MSBFIRST);
XPT2046::SPIx.setDataMode(SPI_MODE0);
XPT2046::SPIx.setDataSize(DATA_SIZE_8BIT);
}
#endif
void XPT2046::Init() {
SET_INPUT(TOUCH_MISO_PIN);
SET_OUTPUT(TOUCH_MOSI_PIN);
SET_OUTPUT(TOUCH_SCK_PIN);
OUT_WRITE(TOUCH_CS_PIN, HIGH);
#if PIN_EXISTS(TOUCH_INT)
// Optional Pendrive interrupt pin
SET_INPUT(TOUCH_INT_PIN);
#endif
TERN_(TOUCH_BUTTONS_HW_SPI, touch_spi_init(SPI_SPEED_6));
// Read once to enable pendrive status pin
getRawData(XPT2046_X);
}
bool XPT2046::isTouched() {
return isBusy() ? false : (
#if PIN_EXISTS(TOUCH_INT)
READ(TOUCH_INT_PIN) != HIGH
#else
getRawData(XPT2046_Z1) >= XPT2046_Z1_THRESHOLD
#endif
);
}
bool XPT2046::getRawPoint(int16_t *x, int16_t *y) {
if (isBusy()) return false;
if (!isTouched()) return false;
*x = getRawData(XPT2046_X);
*y = getRawData(XPT2046_Y);
SERIAL_ECHOLNPAIR("X: ", *x, ", Y: ", *y);
return isTouched();
}
uint16_t XPT2046::getRawData(const XPTCoordinate coordinate) {
uint16_t data[3];
DataTransferBegin();
TERN_(TOUCH_BUTTONS_HW_SPI, SPIx.begin());
for (uint16_t i = 0; i < 3 ; i++) {
IO(coordinate);
data[i] = (IO() << 4) | (IO() >> 4);
}
TERN_(TOUCH_BUTTONS_HW_SPI, SPIx.end());
DataTransferEnd();
uint16_t delta01 = delta(data[0], data[1]),
delta02 = delta(data[0], data[2]),
delta12 = delta(data[1], data[2]);
if (delta01 > delta02 || delta01 > delta12)
data[delta02 > delta12 ? 0 : 1] = data[2];
return (data[0] + data[1]) >> 1;
}
uint16_t XPT2046::IO(uint16_t data) {
return TERN(TOUCH_BUTTONS_HW_SPI, HardwareIO, SoftwareIO)(data);
}
extern uint8_t spiTransfer(uint8_t b);
#if ENABLED(TOUCH_BUTTONS_HW_SPI)
uint16_t XPT2046::HardwareIO(uint16_t data) {
return SPIx.transfer(data & 0xFF);
}
#endif
uint16_t XPT2046::SoftwareIO(uint16_t data) {
uint16_t result = 0;
for (uint8_t j = 0x80; j; j >>= 1) {
WRITE(TOUCH_SCK_PIN, LOW);
WRITE(TOUCH_MOSI_PIN, data & j ? HIGH : LOW);
if (READ(TOUCH_MISO_PIN)) result |= j;
WRITE(TOUCH_SCK_PIN, HIGH);
}
WRITE(TOUCH_SCK_PIN, LOW);
return result;
}
#endif // HAS_TFT_XPT2046

View File

@ -0,0 +1,80 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2019 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
#include "../../../inc/MarlinConfig.h"
#if ENABLED(TOUCH_BUTTONS_HW_SPI)
#include <SPI.h>
#endif
#ifndef TOUCH_MISO_PIN
#define TOUCH_MISO_PIN MISO_PIN
#endif
#ifndef TOUCH_MOSI_PIN
#define TOUCH_MOSI_PIN MOSI_PIN
#endif
#ifndef TOUCH_SCK_PIN
#define TOUCH_SCK_PIN SCK_PIN
#endif
#ifndef TOUCH_CS_PIN
#define TOUCH_CS_PIN CS_PIN
#endif
#ifndef TOUCH_INT_PIN
#define TOUCH_INT_PIN -1
#endif
#define XPT2046_DFR_MODE 0x00
#define XPT2046_SER_MODE 0x04
#define XPT2046_CONTROL 0x80
enum XPTCoordinate : uint8_t {
XPT2046_X = 0x10 | XPT2046_CONTROL | XPT2046_DFR_MODE,
XPT2046_Y = 0x50 | XPT2046_CONTROL | XPT2046_DFR_MODE,
XPT2046_Z1 = 0x30 | XPT2046_CONTROL | XPT2046_DFR_MODE,
XPT2046_Z2 = 0x40 | XPT2046_CONTROL | XPT2046_DFR_MODE,
};
#if !defined(XPT2046_Z1_THRESHOLD)
#define XPT2046_Z1_THRESHOLD 10
#endif
class XPT2046 {
private:
static bool isBusy() { return false; }
static uint16_t getRawData(const XPTCoordinate coordinate);
static bool isTouched();
static inline void DataTransferBegin() { WRITE(TOUCH_CS_PIN, LOW); };
static inline void DataTransferEnd() { WRITE(TOUCH_CS_PIN, HIGH); };
#if ENABLED(TOUCH_BUTTONS_HW_SPI)
static uint16_t HardwareIO(uint16_t data);
#endif
static uint16_t SoftwareIO(uint16_t data);
static uint16_t IO(uint16_t data = 0);
public:
#if ENABLED(TOUCH_BUTTONS_HW_SPI)
static SPIClass SPIx;
#endif
static void Init();
static bool getRawPoint(int16_t *x, int16_t *y);
};

View File

@ -82,11 +82,6 @@
#define U8G_COM_SSD_I2C_HAL u8g_com_arduino_ssd_i2c_fn #define U8G_COM_SSD_I2C_HAL u8g_com_arduino_ssd_i2c_fn
#if EITHER(FSMC_GRAPHICAL_TFT, SPI_GRAPHICAL_TFT)
uint8_t u8g_com_stm32duino_tft_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr);
#define U8G_COM_HAL_TFT_FN u8g_com_stm32duino_tft_fn
#endif
#elif defined(TARGET_LPC1768) #elif defined(TARGET_LPC1768)
uint8_t u8g_com_HAL_LPC1768_sw_spi_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr); uint8_t u8g_com_HAL_LPC1768_sw_spi_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr);
@ -117,6 +112,9 @@
#ifndef U8G_COM_SSD_I2C_HAL #ifndef U8G_COM_SSD_I2C_HAL
#define U8G_COM_SSD_I2C_HAL u8g_com_null_fn #define U8G_COM_SSD_I2C_HAL u8g_com_null_fn
#endif #endif
#ifndef U8G_COM_HAL_TFT_FN #if EITHER(FSMC_GRAPHICAL_TFT, SPI_GRAPHICAL_TFT)
uint8_t u8g_com_hal_tft_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr);
#define U8G_COM_HAL_TFT_FN u8g_com_hal_tft_fn
#else
#define U8G_COM_HAL_TFT_FN u8g_com_null_fn #define U8G_COM_HAL_TFT_FN u8g_com_null_fn
#endif #endif

View File

@ -760,7 +760,7 @@ uint8_t u8g_dev_tft_320x240_upscale_from_128x64_fn(u8g_t *u8g, u8g_dev_t *dev, u
static uint8_t msgInitCount = 2; // Ignore all messages until 2nd U8G_COM_MSG_INIT static uint8_t msgInitCount = 2; // Ignore all messages until 2nd U8G_COM_MSG_INIT
uint8_t u8g_com_stm32duino_tft_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr) { uint8_t u8g_com_hal_tft_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr) {
if (msgInitCount) { if (msgInitCount) {
if (msg == U8G_COM_MSG_INIT) msgInitCount--; if (msg == U8G_COM_MSG_INIT) msgInitCount--;
if (msgInitCount) return -1; if (msgInitCount) return -1;
@ -801,7 +801,7 @@ uint8_t u8g_com_stm32duino_tft_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void
break; break;
case U8G_COM_MSG_WRITE_SEQ: case U8G_COM_MSG_WRITE_SEQ:
tftio.DataTransferBegin(DATASIZE_8BIT); tftio.DataTransferBegin(DATASIZE_16BIT);
for (uint8_t i = 0; i < arg_val; i += 2) for (uint8_t i = 0; i < arg_val; i += 2)
tftio.WriteData(*(uint16_t *)(((uint32_t)arg_ptr) + i)); tftio.WriteData(*(uint16_t *)(((uint32_t)arg_ptr) + i));
tftio.DataTransferEnd(); tftio.DataTransferEnd();

View File

@ -274,6 +274,38 @@
#define FORCE_SOFT_SPI #define FORCE_SOFT_SPI
#define LCD_BACKLIGHT_PIN -1 #define LCD_BACKLIGHT_PIN -1
#elif HAS_SPI_TFT // Config for Classic UI (emulated DOGM) and Color UI
#define SS_PIN -1
//#define ONBOARD_SD_CS_PIN -1
#define TFT_CS_PIN P1_22
#define TFT_A0_PIN P1_23
#define TFT_DC_PIN P1_23
#define TFT_MISO_PIN P0_17
#define TFT_BACKLIGHT_PIN P1_18
#define TFT_RESET_PIN P1_19
#define LPC_HW_SPI_DEV 0
#define LCD_USE_DMA_SPI
#define TOUCH_INT_PIN P1_21
#define TOUCH_CS_PIN P1_20
#define TOUCH_BUTTONS_HW_SPI
#define TOUCH_BUTTONS_HW_SPI_DEVICE 1
#ifndef GRAPHICAL_TFT_UPSCALE
#define GRAPHICAL_TFT_UPSCALE 3
#endif
// SPI 1
#define SCK_PIN P0_15
#define MISO_PIN P0_17
#define MOSI_PIN P0_18
// Disable any LCD related PINs config
#define LCD_PINS_ENABLE -1
#define LCD_PINS_RS -1
#else #else
#define BTN_ENC P0_28 // (58) open-drain #define BTN_ENC P0_28 // (58) open-drain

View File

@ -1421,3 +1421,22 @@
#if PIN_EXISTS(ESP_WIFI_MODULE_GPIO2) #if PIN_EXISTS(ESP_WIFI_MODULE_GPIO2)
REPORT_NAME_DIGITAL(__LINE__, ESP_WIFI_MODULE_GPIO2_PIN) REPORT_NAME_DIGITAL(__LINE__, ESP_WIFI_MODULE_GPIO2_PIN)
#endif #endif
// TFT PINS
#if PIN_EXISTS(TFT_CS)
REPORT_NAME_DIGITAL(__LINE__, TFT_CS_PIN)
#endif
#if PIN_EXISTS(TFT_A0)
REPORT_NAME_DIGITAL(__LINE__, TFT_A0_PIN)
#endif
#if PIN_EXISTS(TFT_DC)
REPORT_NAME_DIGITAL(__LINE__, TFT_DC_PIN)
#endif
#if PIN_EXISTS(TFT_MISO)
REPORT_NAME_DIGITAL(__LINE__, TFT_MISO_PIN)
#endif
#if PIN_EXISTS(TFT_BACKLIGHT)
REPORT_NAME_DIGITAL(__LINE__, TFT_BACKLIGHT_PIN)
#endif
#if PIN_EXISTS(TFT_RESET)
REPORT_NAME_DIGITAL(__LINE__, TFT_RESET_PIN)
#endif