diff options
Diffstat (limited to 'Marlin/src/HAL/STM32F1/tft')
-rw-r--r-- | Marlin/src/HAL/STM32F1/tft/tft_fsmc.cpp | 237 | ||||
-rw-r--r-- | Marlin/src/HAL/STM32F1/tft/tft_fsmc.h | 71 | ||||
-rw-r--r-- | Marlin/src/HAL/STM32F1/tft/tft_spi.cpp | 149 | ||||
-rw-r--r-- | Marlin/src/HAL/STM32F1/tft/tft_spi.h | 72 | ||||
-rw-r--r-- | Marlin/src/HAL/STM32F1/tft/xpt2046.cpp | 144 | ||||
-rw-r--r-- | Marlin/src/HAL/STM32F1/tft/xpt2046.h | 83 |
6 files changed, 756 insertions, 0 deletions
diff --git a/Marlin/src/HAL/STM32F1/tft/tft_fsmc.cpp b/Marlin/src/HAL/STM32F1/tft/tft_fsmc.cpp new file mode 100644 index 0000000..5b52fb4 --- /dev/null +++ b/Marlin/src/HAL/STM32F1/tft/tft_fsmc.cpp @@ -0,0 +1,237 @@ +/** + * 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_FSMC_TFT + +#include "tft_fsmc.h" +#include <libmaple/fsmc.h> +#include <libmaple/gpio.h> +#include <libmaple/dma.h> + +LCD_CONTROLLER_TypeDef *TFT_FSMC::LCD; + +/** + * FSMC LCD IO + */ +#define __ASM __asm +#define __STATIC_INLINE static inline + +__attribute__((always_inline)) __STATIC_INLINE void __DSB() { + __ASM volatile ("dsb 0xF":::"memory"); +} + +#define FSMC_CS_NE1 PD7 + +#if ENABLED(STM32_XL_DENSITY) + #define FSMC_CS_NE2 PG9 + #define FSMC_CS_NE3 PG10 + #define FSMC_CS_NE4 PG12 + + #define FSMC_RS_A0 PF0 + #define FSMC_RS_A1 PF1 + #define FSMC_RS_A2 PF2 + #define FSMC_RS_A3 PF3 + #define FSMC_RS_A4 PF4 + #define FSMC_RS_A5 PF5 + #define FSMC_RS_A6 PF12 + #define FSMC_RS_A7 PF13 + #define FSMC_RS_A8 PF14 + #define FSMC_RS_A9 PF15 + #define FSMC_RS_A10 PG0 + #define FSMC_RS_A11 PG1 + #define FSMC_RS_A12 PG2 + #define FSMC_RS_A13 PG3 + #define FSMC_RS_A14 PG4 + #define FSMC_RS_A15 PG5 +#endif + +#define FSMC_RS_A16 PD11 +#define FSMC_RS_A17 PD12 +#define FSMC_RS_A18 PD13 +#define FSMC_RS_A19 PE3 +#define FSMC_RS_A20 PE4 +#define FSMC_RS_A21 PE5 +#define FSMC_RS_A22 PE6 +#define FSMC_RS_A23 PE2 + +#if ENABLED(STM32_XL_DENSITY) + #define FSMC_RS_A24 PG13 + #define FSMC_RS_A25 PG14 +#endif + +/* Timing configuration */ +#define FSMC_ADDRESS_SETUP_TIME 15 // AddressSetupTime +#define FSMC_DATA_SETUP_TIME 15 // DataSetupTime + +static uint8_t fsmcInit = 0; +void TFT_FSMC::Init() { + uint8_t cs = FSMC_CS_PIN, rs = FSMC_RS_PIN; + uint32_t controllerAddress; + + #if ENABLED(LCD_USE_DMA_FSMC) + dma_init(FSMC_DMA_DEV); + dma_disable(FSMC_DMA_DEV, FSMC_DMA_CHANNEL); + dma_set_priority(FSMC_DMA_DEV, FSMC_DMA_CHANNEL, DMA_PRIORITY_MEDIUM); + #endif + + struct fsmc_nor_psram_reg_map* fsmcPsramRegion; + + if (fsmcInit) return; + fsmcInit = 1; + + switch (cs) { + case FSMC_CS_NE1: controllerAddress = (uint32_t)FSMC_NOR_PSRAM_REGION1; fsmcPsramRegion = FSMC_NOR_PSRAM1_BASE; break; + #if ENABLED(STM32_XL_DENSITY) + case FSMC_CS_NE2: controllerAddress = (uint32_t)FSMC_NOR_PSRAM_REGION2; fsmcPsramRegion = FSMC_NOR_PSRAM2_BASE; break; + case FSMC_CS_NE3: controllerAddress = (uint32_t)FSMC_NOR_PSRAM_REGION3; fsmcPsramRegion = FSMC_NOR_PSRAM3_BASE; break; + case FSMC_CS_NE4: controllerAddress = (uint32_t)FSMC_NOR_PSRAM_REGION4; fsmcPsramRegion = FSMC_NOR_PSRAM4_BASE; break; + #endif + default: return; + } + + #define _ORADDR(N) controllerAddress |= (_BV32(N) - 2) + + switch (rs) { + #if ENABLED(STM32_XL_DENSITY) + case FSMC_RS_A0: _ORADDR( 1); break; + case FSMC_RS_A1: _ORADDR( 2); break; + case FSMC_RS_A2: _ORADDR( 3); break; + case FSMC_RS_A3: _ORADDR( 4); break; + case FSMC_RS_A4: _ORADDR( 5); break; + case FSMC_RS_A5: _ORADDR( 6); break; + case FSMC_RS_A6: _ORADDR( 7); break; + case FSMC_RS_A7: _ORADDR( 8); break; + case FSMC_RS_A8: _ORADDR( 9); break; + case FSMC_RS_A9: _ORADDR(10); break; + case FSMC_RS_A10: _ORADDR(11); break; + case FSMC_RS_A11: _ORADDR(12); break; + case FSMC_RS_A12: _ORADDR(13); break; + case FSMC_RS_A13: _ORADDR(14); break; + case FSMC_RS_A14: _ORADDR(15); break; + case FSMC_RS_A15: _ORADDR(16); break; + #endif + case FSMC_RS_A16: _ORADDR(17); break; + case FSMC_RS_A17: _ORADDR(18); break; + case FSMC_RS_A18: _ORADDR(19); break; + case FSMC_RS_A19: _ORADDR(20); break; + case FSMC_RS_A20: _ORADDR(21); break; + case FSMC_RS_A21: _ORADDR(22); break; + case FSMC_RS_A22: _ORADDR(23); break; + case FSMC_RS_A23: _ORADDR(24); break; + #if ENABLED(STM32_XL_DENSITY) + case FSMC_RS_A24: _ORADDR(25); break; + case FSMC_RS_A25: _ORADDR(26); break; + #endif + default: return; + } + + rcc_clk_enable(RCC_FSMC); + + gpio_set_mode(GPIOD, 14, GPIO_AF_OUTPUT_PP); // FSMC_D00 + gpio_set_mode(GPIOD, 15, GPIO_AF_OUTPUT_PP); // FSMC_D01 + gpio_set_mode(GPIOD, 0, GPIO_AF_OUTPUT_PP); // FSMC_D02 + gpio_set_mode(GPIOD, 1, GPIO_AF_OUTPUT_PP); // FSMC_D03 + gpio_set_mode(GPIOE, 7, GPIO_AF_OUTPUT_PP); // FSMC_D04 + gpio_set_mode(GPIOE, 8, GPIO_AF_OUTPUT_PP); // FSMC_D05 + gpio_set_mode(GPIOE, 9, GPIO_AF_OUTPUT_PP); // FSMC_D06 + gpio_set_mode(GPIOE, 10, GPIO_AF_OUTPUT_PP); // FSMC_D07 + gpio_set_mode(GPIOE, 11, GPIO_AF_OUTPUT_PP); // FSMC_D08 + gpio_set_mode(GPIOE, 12, GPIO_AF_OUTPUT_PP); // FSMC_D09 + gpio_set_mode(GPIOE, 13, GPIO_AF_OUTPUT_PP); // FSMC_D10 + gpio_set_mode(GPIOE, 14, GPIO_AF_OUTPUT_PP); // FSMC_D11 + gpio_set_mode(GPIOE, 15, GPIO_AF_OUTPUT_PP); // FSMC_D12 + gpio_set_mode(GPIOD, 8, GPIO_AF_OUTPUT_PP); // FSMC_D13 + gpio_set_mode(GPIOD, 9, GPIO_AF_OUTPUT_PP); // FSMC_D14 + gpio_set_mode(GPIOD, 10, GPIO_AF_OUTPUT_PP); // FSMC_D15 + + gpio_set_mode(GPIOD, 4, GPIO_AF_OUTPUT_PP); // FSMC_NOE + gpio_set_mode(GPIOD, 5, GPIO_AF_OUTPUT_PP); // FSMC_NWE + + gpio_set_mode(PIN_MAP[cs].gpio_device, PIN_MAP[cs].gpio_bit, GPIO_AF_OUTPUT_PP); //FSMC_CS_NEx + gpio_set_mode(PIN_MAP[rs].gpio_device, PIN_MAP[rs].gpio_bit, GPIO_AF_OUTPUT_PP); //FSMC_RS_Ax + + fsmcPsramRegion->BCR = FSMC_BCR_WREN | FSMC_BCR_MTYP_SRAM | FSMC_BCR_MWID_16BITS | FSMC_BCR_MBKEN; + fsmcPsramRegion->BTR = (FSMC_DATA_SETUP_TIME << 8) | FSMC_ADDRESS_SETUP_TIME; + + afio_remap(AFIO_REMAP_FSMC_NADV); + + LCD = (LCD_CONTROLLER_TypeDef*)controllerAddress; +} + +void TFT_FSMC::Transmit(uint16_t Data) { + LCD->RAM = Data; + __DSB(); +} + +void TFT_FSMC::WriteReg(uint16_t Reg) { + LCD->REG = Reg; + __DSB(); +} + +uint32_t TFT_FSMC::GetID() { + uint32_t id; + WriteReg(0x0000); + id = LCD->RAM; + + if (id == 0) + id = ReadID(LCD_READ_ID); + if ((id & 0xFFFF) == 0 || (id & 0xFFFF) == 0xFFFF) + id = ReadID(LCD_READ_ID4); + if ((id & 0xFF00) == 0 && (id & 0xFF) != 0) + id = ReadID(LCD_READ_ID4); + return id; +} + + uint32_t TFT_FSMC::ReadID(uint16_t Reg) { + uint32_t id; + WriteReg(Reg); + id = LCD->RAM; // dummy read + id = Reg << 24; + id |= (LCD->RAM & 0x00FF) << 16; + id |= (LCD->RAM & 0x00FF) << 8; + id |= LCD->RAM & 0x00FF; + return id; + } + +bool TFT_FSMC::isBusy() { + return false; +} + +void TFT_FSMC::Abort() { + +} + +void TFT_FSMC::TransmitDMA(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); + #endif +} + +#endif // HAS_FSMC_TFT diff --git a/Marlin/src/HAL/STM32F1/tft/tft_fsmc.h b/Marlin/src/HAL/STM32F1/tft/tft_fsmc.h new file mode 100644 index 0000000..d9ee1f4 --- /dev/null +++ b/Marlin/src/HAL/STM32F1/tft/tft_fsmc.h @@ -0,0 +1,71 @@ +/** + * 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 + +#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 + +#include <libmaple/dma.h> + +#define DATASIZE_8BIT DMA_SIZE_8BITS +#define DATASIZE_16BIT DMA_SIZE_16BITS +#define TFT_IO_DRIVER TFT_FSMC + +typedef struct { + __IO uint16_t REG; + __IO uint16_t RAM; +} LCD_CONTROLLER_TypeDef; + +class TFT_FSMC { + private: + static LCD_CONTROLLER_TypeDef *LCD; + + 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 void Init(); + static uint32_t GetID(); + static bool isBusy(); + static void Abort(); + + static void DataTransferBegin(uint16_t DataWidth = DATASIZE_16BIT) {}; + static void DataTransferEnd() {}; + + 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 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; + } + } +}; diff --git a/Marlin/src/HAL/STM32F1/tft/tft_spi.cpp b/Marlin/src/HAL/STM32F1/tft/tft_spi.cpp new file mode 100644 index 0000000..1095389 --- /dev/null +++ b/Marlin/src/HAL/STM32F1/tft/tft_spi.cpp @@ -0,0 +1,149 @@ +/** + * 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 OUT_WRITE(TFT_CS_PIN, HIGH) +#define TFT_CS_L OUT_WRITE(TFT_CS_PIN, LOW) + +#define TFT_DC_H OUT_WRITE(TFT_DC_PIN, HIGH) +#define TFT_DC_L OUT_WRITE(TFT_DC_PIN, LOW) + +#define TFT_RST_H OUT_WRITE(TFT_RST_PIN, HIGH) +#define TFT_RST_L OUT_WRITE(TFT_RST_PIN, LOW) + +#define TFT_BLK_H OUT_WRITE(TFT_BACKLIGHT_PIN, HIGH) +#define TFT_BLK_L OUT_WRITE(TFT_BACKLIGHT_PIN, LOW) + +void TFT_SPI::Init() { + #if PIN_EXISTS(TFT_RESET) + // OUT_WRITE(TFT_RESET_PIN, HIGH); + TFT_RST_H; + delay(100); + #endif + + #if PIN_EXISTS(TFT_BACKLIGHT) + // OUT_WRITE(TFT_BACKLIGHT_PIN, HIGH); + TFT_BLK_H; + #endif + + 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 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 + } + SPIx.setModule(1); + SPIx.setClockDivider(clock); + 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) { + #if !PIN_EXISTS(TFT_MISO) + return 0; + #else + uint8_t d = 0; + uint32_t data = 0; + SPIx.setClockDivider(SPI_CLOCK_DIV16); + DataTransferBegin(DATASIZE_8BIT); + WriteReg(Reg); + + LOOP_L_N(i, 4) { + SPIx.read((uint8_t*)&d, 1); + data = (data << 8) | d; + } + + DataTransferEnd(); + SPIx.setClockDivider(SPI_CLOCK_MAX); + + return data >> 7; + #endif +} + +bool TFT_SPI::isBusy() { + return false; +} + +void TFT_SPI::Abort() { + 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(); + TFT_DC_H; + if (MemoryIncrease == DMA_MINC_ENABLE) { + SPIx.dmaSend(Data, Count, true); + } + else { + SPIx.dmaSend(Data, Count, false); + } + + DataTransferEnd(); +} + +#endif // HAS_SPI_TFT diff --git a/Marlin/src/HAL/STM32F1/tft/tft_spi.h b/Marlin/src/HAL/STM32F1/tft/tft_spi.h new file mode 100644 index 0000000..da9a8e0 --- /dev/null +++ b/Marlin/src/HAL/STM32F1/tft/tft_spi.h @@ -0,0 +1,72 @@ +/** + * 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> + +#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 DATA_SIZE_8BIT +#define DATASIZE_16BIT DATA_SIZE_16BIT +#define TFT_IO_DRIVER 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 = DATA_SIZE_16BIT); + static void DataTransferEnd() { WRITE(TFT_CS_PIN, HIGH); SPIx.end(); }; + 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 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; + while (Count > 0) { + TransmitDMA(DMA_MINC_DISABLE, &Data, Count > 0xFFFF ? 0xFFFF : Count); + Count = Count > 0xFFFF ? Count - 0xFFFF : 0; + } + } +}; diff --git a/Marlin/src/HAL/STM32F1/tft/xpt2046.cpp b/Marlin/src/HAL/STM32F1/tft/xpt2046.cpp new file mode 100644 index 0000000..98371c5 --- /dev/null +++ b/Marlin/src/HAL/STM32F1/tft/xpt2046.cpp @@ -0,0 +1,144 @@ +/** + * 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_TFT_XPT2046 || HAS_TOUCH_BUTTONS + +#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) { + /** + * 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 + */ + uint8_t clock; + switch (spiRate) { + case SPI_FULL_SPEED: clock = SPI_CLOCK_DIV4; 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 + } + XPT2046::SPIx.setModule(TOUCH_BUTTONS_HW_SPI_DEVICE); + XPT2046::SPIx.setClockDivider(clock); + XPT2046::SPIx.setBitOrder(MSBFIRST); + XPT2046::SPIx.setDataMode(SPI_MODE0); + } +#endif // TOUCH_BUTTONS_HW_SPI + +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); + 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); +} + +#if ENABLED(TOUCH_BUTTONS_HW_SPI) + uint16_t XPT2046::HardwareIO(uint16_t data) { + uint16_t result = SPIx.transfer(data); + return result; + } +#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 diff --git a/Marlin/src/HAL/STM32F1/tft/xpt2046.h b/Marlin/src/HAL/STM32F1/tft/xpt2046.h new file mode 100644 index 0000000..65602bd --- /dev/null +++ b/Marlin/src/HAL/STM32F1/tft/xpt2046.h @@ -0,0 +1,83 @@ +/** + * 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" + +#if ENABLED(TOUCH_BUTTONS_HW_SPI) + #include <SPI.h> +#endif + +#ifndef TOUCH_MISO_PIN + #define TOUCH_MISO_PIN SD_MISO_PIN +#endif +#ifndef TOUCH_MOSI_PIN + #define TOUCH_MOSI_PIN SD_MOSI_PIN +#endif +#ifndef TOUCH_SCK_PIN + #define TOUCH_SCK_PIN SD_SCK_PIN +#endif +#ifndef TOUCH_CS_PIN + #define TOUCH_CS_PIN SD_SS_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); +}; |