You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
415 lines
13 KiB
415 lines
13 KiB
7 years ago
|
/*********************
|
||
|
* FT810_SPI.h *
|
||
|
*********************/
|
||
|
|
||
|
|
||
|
/****************************************************************************
|
||
|
* Written By Mark Pelletier 2017 - Aleph Objects, Inc. *
|
||
|
* *
|
||
|
* 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. *
|
||
|
* *
|
||
|
* To view a copy of the GNU General Public License, go to the following *
|
||
|
* location: <http://www.gnu.org/licenses/>. *
|
||
|
****************************************************************************/
|
||
|
#ifndef _AO_FT810_SPI_H
|
||
|
#define _AO_FT810_SPI_H
|
||
|
|
||
|
#if defined(PIN_DIR_OUT)
|
||
|
// If SET_OUTPUT is defined, then map Marlin routines to those
|
||
|
#define SET_OUTPUT PIN_DIR_OUT
|
||
|
#define SET_INPUT_PULLUP(a) _PIN_DIR_IN(a); _PIN_HIGH(a);
|
||
|
#define SET_INPUT PIN_DIR_IN
|
||
|
#define WRITE SET_PIN
|
||
|
#define READ GET_PIN
|
||
|
#endif
|
||
|
|
||
|
/********************************* SPI Functions *********************************/
|
||
|
|
||
|
void CLCD::spiInit (void) {
|
||
|
#if defined(USE_ARDUINO_HW_SPI)
|
||
|
SPI.begin();
|
||
|
SPI.beginTransaction(LCDsettings);
|
||
|
#else
|
||
|
SET_OUTPUT(CLCD_MOD_RESET); // CLCD_MOD_RST - Module Reset, not SPI
|
||
|
WRITE(CLCD_MOD_RESET, 1);
|
||
|
|
||
|
SET_OUTPUT(CLCD_BB_SPI_MOSI); // CLCD_MOSI
|
||
|
WRITE(CLCD_BB_SPI_MOSI, 1);
|
||
|
|
||
|
SET_OUTPUT(CLCD_BB_SPI_SCLK); // CLCD_SCLK
|
||
|
WRITE(CLCD_BB_SPI_SCLK, 0);
|
||
|
|
||
|
SET_OUTPUT(CLCD_BB_SPI_CS); // CLCD_CS
|
||
|
WRITE(CLCD_BB_SPI_CS, 1);
|
||
|
|
||
|
SET_INPUT_PULLUP(CLCD_BB_SPI_MISO); // CLCD_MISO
|
||
|
|
||
|
delay(50);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
void CLCD::spiSelect (void) { // CLCD Bitbanged SPI - Chip Select
|
||
|
WRITE(CLCD_BB_SPI_CS, 0);
|
||
|
}
|
||
|
|
||
|
|
||
|
void CLCD::spiDeselect (void) { // CLCD Bitbanged SPI - Chip Deselect
|
||
|
WRITE(CLCD_BB_SPI_CS, 1);
|
||
|
}
|
||
|
|
||
|
void CLCD::Reset (void) {
|
||
|
WRITE(CLCD_MOD_RESET, 0);
|
||
|
delay(100);
|
||
|
WRITE(CLCD_MOD_RESET, 1);
|
||
|
}
|
||
|
|
||
|
void CLCD::Test_Pulse(void)
|
||
|
{
|
||
|
WRITE(CLCD_AUX_0, 1);
|
||
|
delayMicroseconds(10);
|
||
|
WRITE(CLCD_AUX_0, 0);
|
||
|
}
|
||
|
|
||
|
uint8_t CLCD::spiTransfer (uint8_t spiOutByte) {
|
||
|
#ifdef IS_ARDUINO
|
||
|
SPI.transfer(spiOutByte);
|
||
|
#else
|
||
|
|
||
|
uint8_t spiIndex = 0x80;
|
||
|
uint8_t spiInByte = 0;
|
||
|
uint8_t k;
|
||
|
|
||
|
for(k = 0; k <8; k++) { // Output and Read each bit of spiOutByte and spiInByte
|
||
|
if(spiOutByte & spiIndex) { // Output MOSI Bit
|
||
|
WRITE(CLCD_BB_SPI_MOSI, 1);
|
||
|
}
|
||
|
else {
|
||
|
WRITE(CLCD_BB_SPI_MOSI, 0);
|
||
|
}
|
||
|
WRITE(CLCD_BB_SPI_SCLK, 1); // Pulse Clock
|
||
|
WRITE(CLCD_BB_SPI_SCLK, 0);
|
||
|
|
||
|
if(READ(CLCD_BB_SPI_MISO)) {
|
||
|
spiInByte |= spiIndex;
|
||
|
}
|
||
|
|
||
|
spiIndex >>= 1;
|
||
|
}
|
||
|
return spiInByte;
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
// MEMORY READ FUNCTIONS
|
||
|
|
||
|
void CLCD::Mem_ReadAddr (uint32_t Reg_Address) { // Write 4-Byte Address
|
||
|
CLCD::spiTransfer((Reg_Address >> 16) & 0x3F); // Address [21:16]
|
||
|
CLCD::spiTransfer((Reg_Address >> 8 ) & 0xFF); // Address [15:8]
|
||
|
CLCD::spiTransfer((Reg_Address >> 0) & 0xFF); // Address [7:0]
|
||
|
CLCD::spiTransfer(0x00); // Dummy Byte
|
||
|
}
|
||
|
|
||
|
void CLCD::Mem_Read_Bulk (uint32_t Reg_Address, uint8_t *Data, uint16_t Len) { // Write 4-Byte Address, Read Multiple Bytes
|
||
|
CLCD::spiSelect();
|
||
|
CLCD::Mem_ReadAddr(Reg_Address);
|
||
|
|
||
|
while(Len--) {
|
||
|
*Data = CLCD::spiTransfer(0x00); // Read 1 Byte
|
||
|
*Data++;
|
||
|
}
|
||
|
|
||
|
CLCD::spiDeselect();
|
||
|
}
|
||
|
|
||
|
uint8_t CLCD::Mem_Read8 (uint32_t Reg_Address) { // Write 4-Byte Address, Read 1-Byte Data
|
||
|
CLCD::spiSelect();
|
||
|
|
||
|
CLCD::Mem_ReadAddr(Reg_Address);
|
||
|
|
||
|
uint8_t R_Data = CLCD::spiTransfer(0x00); // Read 1 Byte
|
||
|
|
||
|
CLCD::spiDeselect();
|
||
|
|
||
|
return(R_Data);
|
||
|
}
|
||
|
|
||
|
|
||
|
uint16_t CLCD::Mem_Read16 (uint32_t Reg_Address) { // Write 4-Byte Address, Read 2-Bytes Data
|
||
|
CLCD::spiSelect();
|
||
|
|
||
|
CLCD::Mem_ReadAddr(Reg_Address);
|
||
|
|
||
|
uint16_t R_Data = (((uint16_t) CLCD::spiTransfer(0x00)) << 0) | // Read Byte 1
|
||
|
(((uint16_t) CLCD::spiTransfer(0x00)) << 8); // Read Byte 2
|
||
|
|
||
|
CLCD::spiDeselect();
|
||
|
|
||
|
return(R_Data);
|
||
|
}
|
||
|
|
||
|
uint32_t CLCD::Mem_Read32 (uint32_t Reg_Address) { // Write 4-Byte Address, Read 4-Bytes Data
|
||
|
CLCD::spiSelect();
|
||
|
|
||
|
CLCD::Mem_ReadAddr(Reg_Address);
|
||
|
|
||
|
uint32_t R_Data = (((uint32_t) CLCD::spiTransfer(0x00)) << 0) | // Read Byte 1
|
||
|
(((uint32_t) CLCD::spiTransfer(0x00)) << 8) | // Read Byte 2
|
||
|
(((uint32_t) CLCD::spiTransfer(0x00)) << 16) | // Read Byte 3
|
||
|
(((uint32_t) CLCD::spiTransfer(0x00)) << 24); // Read Byte 4
|
||
|
|
||
|
CLCD::spiDeselect();
|
||
|
|
||
|
return(R_Data);
|
||
|
}
|
||
|
|
||
|
|
||
|
// MEMORY WRITE FUNCTIONS
|
||
|
|
||
|
void CLCD::Mem_WriteAddr (uint32_t Reg_Address) { // Write 3-Byte Address
|
||
|
CLCD::spiTransfer((Reg_Address >> 16) | 0x80); // Address [21:16]
|
||
|
CLCD::spiTransfer((Reg_Address >> 8 ) & 0xFF); // Address [15:8]
|
||
|
CLCD::spiTransfer((Reg_Address >> 0) & 0xFF); // Address [7:0]
|
||
|
}
|
||
|
|
||
|
void CLCD::Mem_Write_Bulk (uint32_t Reg_Address, const void *Data, uint16_t Len, uint8_t Padding) { // Write 3-Byte Address, Multiple Bytes, plus padding bytes
|
||
|
const uint8_t* p = (const uint8_t *)Data;
|
||
|
CLCD::spiSelect();
|
||
|
CLCD::Mem_WriteAddr(Reg_Address);
|
||
|
|
||
|
while(Len--) {
|
||
|
CLCD::spiTransfer(*p++); // Write 1 Byte
|
||
|
}
|
||
|
|
||
|
while(Padding--) {
|
||
|
CLCD::spiTransfer(0); // Padding Bytes
|
||
|
}
|
||
|
|
||
|
CLCD::spiDeselect();
|
||
|
}
|
||
|
|
||
|
void CLCD::Mem_Write_Bulk (uint32_t Reg_Address, progmem_str Str, uint16_t Len, uint8_t Padding) { // Write 3-Byte Address, Multiple Bytes, plus padding bytes
|
||
|
const uint8_t* p = (const uint8_t *)Str;
|
||
|
CLCD::spiSelect();
|
||
|
CLCD::Mem_WriteAddr(Reg_Address);
|
||
|
|
||
|
while(Len--) {
|
||
|
CLCD::spiTransfer(pgm_read_byte_near(p++)); // Write 1 Byte
|
||
|
}
|
||
|
|
||
|
while(Padding--) {
|
||
|
CLCD::spiTransfer(0); // Padding Bytes
|
||
|
}
|
||
|
|
||
|
CLCD::spiDeselect();
|
||
|
}
|
||
|
|
||
|
void CLCD::Mem_Write8 (uint32_t Reg_Address, uint8_t W_Data) { // Write 3-Byte Address, Write 1-Byte Data
|
||
|
CLCD::spiSelect();
|
||
|
|
||
|
CLCD::Mem_WriteAddr(Reg_Address);
|
||
|
|
||
|
CLCD::spiTransfer(W_Data); // Write 1 Byte
|
||
|
|
||
|
CLCD::spiDeselect();
|
||
|
}
|
||
|
|
||
|
|
||
|
void CLCD::Mem_Write16 (uint32_t Reg_Address, uint16_t W_Data) { // Write 3-Byte Address, Write 2-Bytes Data
|
||
|
CLCD::spiSelect();
|
||
|
|
||
|
CLCD::Mem_WriteAddr(Reg_Address);
|
||
|
|
||
|
CLCD::spiTransfer((uint8_t) ((W_Data >> 0) & 0x00FF)); // Write Byte 0
|
||
|
CLCD::spiTransfer((uint8_t) ((W_Data >> 8) & 0x00FF)); // Write Byte 1
|
||
|
|
||
|
CLCD::spiDeselect();
|
||
|
}
|
||
|
|
||
|
|
||
|
void CLCD::Mem_Write32 (uint32_t Reg_Address, uint32_t W_Data) { // Write 3-Byte Address, Write 4-Bytes Data
|
||
|
CLCD::spiSelect();
|
||
|
|
||
|
CLCD::Mem_WriteAddr(Reg_Address);
|
||
|
|
||
|
CLCD::spiTransfer(W_Data >> 0); // Write Byte 0
|
||
|
CLCD::spiTransfer(W_Data >> 8); // Write Byte 1
|
||
|
CLCD::spiTransfer(W_Data >> 16); // Write Byte 2
|
||
|
CLCD::spiTransfer(W_Data >> 24); // Write Byte 3
|
||
|
|
||
|
CLCD::spiDeselect();
|
||
|
}
|
||
|
|
||
|
/**************************** FT800/810 Co-Processor Command FIFO ****************************/
|
||
|
|
||
|
uint32_t CLCD::CommandFifo::getRegCmdWrite() {
|
||
|
return Mem_Read32(REG_CMD_WRITE) & 0x0FFF;
|
||
|
}
|
||
|
|
||
|
uint32_t CLCD::CommandFifo::getRegCmdRead() {
|
||
|
return Mem_Read32(REG_CMD_READ) & 0x0FFF;
|
||
|
}
|
||
|
|
||
|
bool CLCD::CommandFifo::Cmd_Is_Idle() {
|
||
|
return getRegCmdRead() == getRegCmdWrite();
|
||
|
}
|
||
|
|
||
|
void CLCD::CommandFifo::Cmd_Wait_Until_Idle() {
|
||
|
#if defined(UI_FRAMEWORK_DEBUG)
|
||
|
const uint32_t startTime = millis();
|
||
|
#endif
|
||
|
do {
|
||
|
#if defined(UI_FRAMEWORK_DEBUG)
|
||
|
if(millis() - startTime > 3) {
|
||
|
#if defined (SERIAL_PROTOCOLLNPGM)
|
||
|
SERIAL_PROTOCOLLNPGM("Timeout on CommandFifo::Wait_Until_Idle()");
|
||
|
#else
|
||
|
Serial.println(F("Timeout on CommandFifo::Wait_Until_Idle()"));
|
||
|
#endif
|
||
|
break;
|
||
|
}
|
||
|
#endif
|
||
|
} while(!Cmd_Is_Idle());
|
||
|
}
|
||
|
|
||
|
#if defined(LCD_IS_FT800)
|
||
|
void CLCD::CommandFifo::Cmd_Start() {
|
||
|
if(command_write_ptr == 0xFFFFFFFFul) {
|
||
|
command_write_ptr = getRegCmdWrite();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void CLCD::CommandFifo::Cmd_Execute() {
|
||
|
if(command_write_ptr != 0xFFFFFFFFul) {
|
||
|
Mem_Write32(REG_CMD_WRITE, command_write_ptr);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void CLCD::CommandFifo::Cmd_Reset() {
|
||
|
Mem_Write32(REG_CMD_WRITE, 0x00000000);
|
||
|
Mem_Write32(REG_CMD_READ, 0x00000000);
|
||
|
command_write_ptr = 0xFFFFFFFFul;
|
||
|
};
|
||
|
|
||
|
template <class T> void CLCD::CommandFifo::_write_unaligned(T data, uint16_t len) {
|
||
|
const char *ptr = (const char*)data;
|
||
|
uint32_t bytes_tail, bytes_head;
|
||
|
uint32_t command_read_ptr;
|
||
|
|
||
|
#if defined(UI_FRAMEWORK_DEBUG)
|
||
|
if(command_write_ptr == 0xFFFFFFFFul) {
|
||
|
#if defined (SERIAL_PROTOCOLLNPGM)
|
||
|
SERIAL_PROTOCOLLNPGM("Attempt to write to FIFO before CommandFifo::Cmd_Start().");
|
||
|
#else
|
||
|
Serial.println(F("Attempt to write to FIFO before CommandFifo::Cmd_Start()."));
|
||
|
#endif
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
/* Wait until there is enough space in the circular buffer for the transfer */
|
||
|
do {
|
||
|
command_read_ptr = getRegCmdRead();
|
||
|
if (command_read_ptr <= command_write_ptr) {
|
||
|
bytes_tail = 4096U - command_write_ptr;
|
||
|
bytes_head = command_read_ptr;
|
||
|
} else {
|
||
|
bytes_tail = command_read_ptr - command_write_ptr;
|
||
|
bytes_head = 0;
|
||
|
}
|
||
|
} while((bytes_tail + bytes_head) < len);
|
||
|
|
||
|
/* Write as many bytes as possible following REG_CMD_WRITE */
|
||
|
uint16_t bytes_to_write = min(len, bytes_tail);
|
||
|
Mem_Write_Bulk (RAM_CMD + command_write_ptr, T(ptr), bytes_to_write);
|
||
|
command_write_ptr += bytes_to_write;
|
||
|
ptr += bytes_to_write;
|
||
|
len -= bytes_to_write;
|
||
|
|
||
|
if(len > 0) {
|
||
|
/* Write remaining bytes at start of circular buffer */
|
||
|
Mem_Write_Bulk (RAM_CMD, T(ptr), len);
|
||
|
command_write_ptr = len;
|
||
|
}
|
||
|
|
||
|
if(command_write_ptr == 4096U) {
|
||
|
command_write_ptr = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Writes len bytes into the FIFO, if len is not
|
||
|
// divisible by four, zero bytes will be written
|
||
|
// to align to the boundary.
|
||
|
|
||
|
template <class T> void CLCD::CommandFifo::write(T data, uint16_t len) {
|
||
|
const uint8_t padding = MULTIPLE_OF_4(len) - len;
|
||
|
|
||
|
uint8_t pad_bytes[] = {0, 0, 0, 0};
|
||
|
_write_unaligned(data, len);
|
||
|
_write_unaligned(pad_bytes, padding);
|
||
|
}
|
||
|
#else
|
||
|
uint32_t CLCD::CommandFifo::getRegCmdBSpace() {
|
||
|
return Mem_Read32(REG_CMDB_SPACE) & 0x0FFF;
|
||
|
}
|
||
|
|
||
|
void CLCD::CommandFifo::Cmd_Start() {
|
||
|
}
|
||
|
|
||
|
void CLCD::CommandFifo::Cmd_Execute() {
|
||
|
}
|
||
|
|
||
|
void CLCD::CommandFifo::Cmd_Reset() {
|
||
|
Mem_Write32(REG_CMD_WRITE, 0x00000000);
|
||
|
Mem_Write32(REG_CMD_READ, 0x00000000);
|
||
|
};
|
||
|
|
||
|
// Writes len bytes into the FIFO, if len is not
|
||
|
// divisible by four, zero bytes will be written
|
||
|
// to align to the boundary.
|
||
|
|
||
|
template <class T> void CLCD::CommandFifo::write(T data, uint16_t len) {
|
||
|
const uint8_t padding = MULTIPLE_OF_4(len) - len;
|
||
|
|
||
|
// The FT810 provides a special register that can be used
|
||
|
// for writing data without us having to do our own FIFO
|
||
|
// management.
|
||
|
uint32_t Command_Space = getRegCmdBSpace();
|
||
|
while(Command_Space < len + padding) {
|
||
|
Command_Space = getRegCmdBSpace();
|
||
|
}
|
||
|
Mem_Write_Bulk(REG_CMDB_WRITE, data, len, padding);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
// CO_PROCESSOR COMMANDS
|
||
|
|
||
|
void CLCD::CommandFifo::Cmd (uint32_t cmd32) { // Writes a 32-bit (4 Bytes) Value to the Co-processor Command Buffer FIFO
|
||
|
write(&cmd32, sizeof(uint32_t));
|
||
|
}
|
||
|
|
||
|
void CLCD::CommandFifo::Cmd (void* data, uint16_t len) { // Writes a data structure - always a multiple of 32 bits - to the Co_Processor FIFO. // Data structure includes the 32-bit Co_Processor command.
|
||
|
write(data, len);
|
||
|
}
|
||
|
|
||
|
|
||
|
void CLCD::CommandFifo::Cmd_Str (char* data) {
|
||
|
write(data, strlen(data)+1);
|
||
|
}
|
||
|
|
||
|
void CLCD::CommandFifo::Cmd_Str (progmem_str data) {
|
||
|
write(data, strlen_P((const char*)data)+1);
|
||
|
}
|
||
|
|
||
|
#endif // _AO_FT810_SPI_H
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|