Hi Mark.
I wrote GPIO driver that simulates this communication the following problems appeared:
- my driver works with PIT timer. By datasheet PIT timer in MK21 can work with 60MHz frequency. But instead this frequency I see about 3MHz maximum. On timer interrupt, I do toggle to GPIO for test timer frequency and see 1.88MHz frequency (1.88*2=3.76MHz). Here this timer configuration to 60MHz:
// SIM_SCGC6: PIT=1
SIM_SCGC6 |= SIM_SCGC6_PIT_MASK;
// Enable device clock
PIT_MCR = (uint32)0x00UL;
// Clear control register
PIT_TCTRL0 = (uint32)0x00UL;
// Clear timer flag register
PIT_TFLG0 = PIT_TFLG_TIF_MASK;
// Set up load register PIT_LDVAL0: 60MHz
PIT_LDVAL0 = PIT_LDVAL_TSV(PLAY_TIMER_PERIOD);
NVICIP48 = NVIC_IP_PRI48(0x00);
// Set up control register for Timer 0
PIT_TCTRL0 = (PIT_TCTRL_TEN_MASK | PIT_TCTRL_TIE_MASK);
PIT_TCTRL0 = (uint32_t)((PIT_TCTRL0 & (uint32_t)~(uint32_t)(PIT_TCTRL_TEN_MASK | 0xFFFFFFF8U)) |
(uint32_t)(PIT_TCTRL_TIE_MASK));
// Clear interrupt flag
PIT_ClearInterruptFlag(PIT_BASE_PTR, PIT_CHANNEL_0);
// Enable interrupts
Enable_IRQ(PIT0_IRQn);
To prepare command I use a function for every command.
typedef enum _SEND_Type
{
SEND_COMMAND, // Send Command
SEND_DATA_PARAM // Send Data or Parameter
} SEND_Type;
typedef enum _DATA_Type
{
DATA_CONTINUED, // Send continued data
DATA_SIMPLE_COLOR // Send simple color
} DATA_Type;
typedef struct
{
uint8_t Command; // Command for send to LCD
SEND_Type WhatSend; // Send Command or Data
DATA_Type WhatData; // Type of sent data
uint32_t DataLen; // LCD *data len
uint8_t *Data; // Pointer to data that contain LCD parameters
}LCD_SPI_PACKET;
For example,
/******************************************************************************
* Function Name: LCD_TFT_RAMWR_2C (Command 0x2C)
* Description: Memory write
* Parameters: none
* Return: none
* Build_Date: 11/01/2020
* Notes: --
******************************************************************************/
void LCD_TFT_RAMWR_2C(DATA_Type DataType, uint32_t DataLen, uint8_t *Data)
{
LCD_SPI.WhatSend = SEND_COMMAND;
LCD_SPI.Command = TFT_RAMWR;
LCD_SPI.WhatData = DataType;
if(DataType == DATA_SIMPLE_COLOR)
{
LCD_SPI.DataLen = DataLen * 2;
TFT_RAMWR_SimpleData[1] = Data[0];
TFT_RAMWR_SimpleData[0] = Data[1];
LCD_SPI.Data = TFT_RAMWR_SimpleData;
}
else
{
LCD_SPI.DataLen = DataLen;
LCD_SPI.Data = Data;
}
// Start timer for send Command/Data
TIMER_Enable(MAIN_TIMER);
while(MainTimer_Enabled);
}
// Global array
uint8_t TFT_FRCTRL1_Data[] = {0x54, 0x3F};
/******************************************************************************
* Function Name: LCD_TFT_FRCTRL1_B3 (0xB3)
* Description: Frame Rate Control 1
* Parameters: none
* Return: none
* Build_Date: 11/01/2020
* Notes: --
******************************************************************************/
void LCD_TFT_FRCTRL1_B3(void)
{
LCD_SPI.WhatSend = SEND_COMMAND;
LCD_SPI.Command = TFT_FRCTRL1;
LCD_SPI.DataLen = 2;
LCD_SPI.Data = TFT_FRCTRL1_Data;
// Start timer for send Command/Data
TIMER_Enable(MAIN_TIMER);
while(MainTimer_Enabled);
}
On timer event, I change CLK and on CLK low state call the next function:
void LCD_SPI_Send_Command(void)
{
static uint8_t cmd_state = 0;
static uint8_t SendVal = 0;
static uint32_t DataIndx = 0;
static uint8_t bit = 7;
switch(cmd_state)
{
case 0:
// CS='0' - Chip select enable
LCD_SPI_CS_ENABLE;
// 30ns delay
__NOP();
// DC=’0’- command selection pin in parallel interface
LCD_SPI_DC_COMMAND;
// 30ns delay
__NOP();
// Start to send Command value
// Set MSB bit on SDA
if((LCD_SPI.Command&0x80) == 0U)
{
SDA_PIN_SET_LOW;
}
else
{
SDA_PIN_SET_HIGH;
}
// Shift to the next bit at the next rising edge of SCL Shift<<1
SendVal = LCD_SPI.Command<<1;
bit--;
cmd_state++;
break;
case 1:
// Continue to send Command value
// Set MSB bit on SDA
if((SendVal&0x80) == 0U)
{
SDA_PIN_SET_LOW;
}
else
{
SDA_PIN_SET_HIGH;
}
if(bit > 0)
{
bit--;
// Shift to the next bit at the next rising edge of SCL Shift<<1
SendVal <<= 1;
}
else
{
bit = 7;
if(LCD_SPI.DataLen > 0)
{
cmd_state++;
}
else
{
cmd_state = 4;
}
}
break;
case 2:
LCD_SPI_DC_DATA_PARAM;
// 30ns delay
__NOP();
// Start to send Data
SendVal = LCD_SPI.Data[DataIndx];
// Set MSB bit on SDA
if((LCD_SPI.Data[DataIndx]&0x80) == 0U)
{
SDA_PIN_SET_LOW;
}
else
{
SDA_PIN_SET_HIGH;
}
// Shift to the next bit at the next rising edge of SCL Shift<<1
SendVal = LCD_SPI.Data[DataIndx]<<1;
bit--;
cmd_state++;
break;
case 3:
// Continue send Data values
// Set MSB bit on SDA
if((SendVal&0x80) == 0U)
{
SDA_PIN_SET_LOW;
}
else
{
SDA_PIN_SET_HIGH;
}
// Shift to the next bit at the next rising edge of SCL Shift<<1
SendVal <<= 1;
if(bit > 0)
{
bit--;
}
else
{
bit = 7;
if(--LCD_SPI.DataLen > 0)
{
if(LCD_SPI.WhatData == DATA_CONTINUED)
{
SendVal = LCD_SPI.Data[++DataIndx];
}
else if(LCD_SPI.WhatData == DATA_SIMPLE_COLOR)
{
SendVal = LCD_SPI.Data[DataIndx];
DataIndx ^= 1;
}
}
else
{
cmd_state++;
}
}
break;
case 4:
// CS='1' - Chip select disable
LCD_SPI_CS_DISABLE;
cmd_state++;
break;
case 5:
TIMER_Disable(MAIN_TIMER);
cmd_state = 0;
DataIndx = 0;
break;
}
}
As a result, I can config LCD and fill any color, but only once. After this no reaction. I tried different configurations but nothing helps. LCD does not respond next time.
LCD configuration:
Version 1
LCD_TFT_SWRESET_01();
Delay_us(150000);
LCD_TFT_SLPOUT_11();
Delay_us(120000);
LCD_TFT_COLMOD_3A();
LCD_TFT_MADCTL_36();
//LCD_TFT_INVON_21();
LCD_TFT_INVOFF_20();
LCD_TFT_NORON_13();
LCD_TFT_DISPON_29();
Delay_us(150000);
ST7789_FillScreen(BLUE);
Version 2
LCD_TFT_SWRESET_01();
Delay_us(120000);
LCD_TFT_SLPOUT_11();
Delay_us(120000);
LCD_TFT_GAMSET_26(); // Data 0x01
LCD_TFT_TEON_35();
LCD_TFT_MADCTL_36(); // Data 0x08
LCD_TFT_INVON_21();
LCD_TFT_COLMOD_3A(); // Data 0x55
LCD_TFT_FRCTRL1_B3(); // Data 0x54, 0x3F
LCD_TFT_LCMCTRL_C0(); // Data 0x01
LCD_TFT_IDSET_C1(); // Data 0x06
LCD_TFT_VDVS_C4(); // Data 0x25, 0x00
LCD_TFT_VMCTR1_C5(); // Data 0x44, 0x64
LCD_TFT_DISPON_29();
ST7789_FillScreen(BLUE);