一、目标;
使用东芝TT_M3HQ开发板的开发板点亮5寸的12864LCD。
二、工具
东芝TT_M3HQ开发板,逻辑分析仪(用于时序调试),5寸12864LCD
三、硬件连接
1、开发板使用TSPI1 + GPIO与LCD Demo板连接。
a) 使用到的开发板的接口如下:
TSPI1SCK: PB2 --> CN8-18P
TSPI1TXD: PB3 --> TP7
TSPI1CS0: PB5 --> CN8-14P
GPIO: PB1 --> CN7-22P (与LCD的命令控制引脚相连)
GPIO: PB0 --> CN7-7P (与LCD的复位引脚相连)
b) LCD的引脚如下图所示:
如表中所示:LCD与开发板引脚的来连接关系如下所示:
RS <--> PB1
RES <--> PB0
CS <--> PB5
SDA <--> TSPI1TXD
SCK <--> TSPI1SCK
其余电源和地线连接按要求连接即可,如下图所示:
四、软件移植
此款LCD以前使用过,这块LCD不带字库,需要自己制作字库,关于字库的制作以及对字库的描画程序不需要修改,只需要修改底层
SPI驱动以及相应的GPIO引脚定义即可,移植过程如下:
1、TSPI1寄存器组基址:0x40099000
2、TSPI1寄存器组:
通过这些寄存器设置SPI的时钟、使能、时序等。
3、IO端口和引脚复用初始化:
移植工作我是在TSPI工程的基础上进行的修改。
bsp_initialize() -> port_initialize()
//RES <--> PB0
if (gpio_func(&port, GPIO_PORT_B, GPIO_PORT_0, (uint32_t)GPIO_PB0_OUTPUT, GPIO_PIN_OUTPUT) != TXZ_SUCCESS)
{
bsp_error();
}
//RS <--> PB1
if (gpio_func(&port, GPIO_PORT_B, GPIO_PORT_1, (uint32_t)GPIO_PB1_OUTPUT, GPIO_PIN_OUTPUT) != TXZ_SUCCESS)
{
bsp_error();
}
//SCK <--> TSPI1SCK(PB2)
if (gpio_func(&port, GPIO_PORT_B, GPIO_PORT_2, (uint32_t)GPIO_PB2_TSPI1SCK, GPIO_PIN_OUTPUT) != TXZ_SUCCESS)
{
bsp_error();
}
//SDA <--> TSPI1TXD(PB3)
if (gpio_func(&port, GPIO_PORT_B, GPIO_PORT_3, (uint32_t)GPIO_PB3_TSPI1TXD, GPIO_PIN_OUTPUT) != TXZ_SUCCESS)
{
bsp_error();
}
//CS <--> PB5 为了便于控制,将CS配置为GPIO引脚,便于我们自己控制使能
if (gpio_func(&port, GPIO_PORT_B, GPIO_PORT_5, (uint32_t)GPIO_PB5_OUTPUT, GPIO_PIN_OUTPUT) != TXZ_SUCCESS)
{
bsp_error();
}
4、TSPI1时序初始化
首先来看一下LCD的SPI时序:
从图中我们主要关注一下几点:
a) SCK时钟IDLE时为高电平
b) SCK时钟上升沿数据保持不变。
c) 数据为8bit,先传高位数据
d) cs低电平使能
根据TSPI的手册,与下述时序吻合:
所以将CSnPOL设置为0,CKPOL设为1即可
综上,看看一下程序中TSPI的初始化,将其修改为我们需要的配置。
switch (bsp_get_tspi_tx_ch(BSP_SFLASH_1))//此处选在TSPI1
{
case 0:
instance.tspi_tx_obj.p_instance = TSB_TSPI0;
break;
case 1:
instance.tspi_tx_obj.p_instance = TSB_TSPI1;
break;
case 2:
instance.tspi_tx_obj.p_instance = TSB_TSPI2;
break;
case 3:
instance.tspi_tx_obj.p_instance = TSB_TSPI3;
break;
default:
instance.tspi_tx_obj.p_instance = MAIN_NULL;
break;
}
/* Set Initial parameter of TSPIxCR1 */
instance.tspi_tx_obj.init.cnt1.trxe = TSPI_DISABLE;
instance.tspi_tx_obj.init.cnt1.tspims = TSPI_SPI_MODE; //SPI模式
instance.tspi_tx_obj.init.cnt1.mstr = TSPI_MASTER_OPEARTION; //主机模式
instance.tspi_tx_obj.init.cnt1.tmmd = TSPI_TX_ONLY; //用于发送
instance.tspi_tx_obj.init.cnt1.cssel = TSPI_TSPIxCS0_ENABLE;
instance.tspi_tx_obj.init.cnt1.fc = TSPI_TRANS_RANGE_SINGLE;
/* Set Initial parameter of TSPIxCR2 */
instance.tspi_tx_obj.init.cnt2.tidle = TSPI_TIDLE_Hiz;
instance.tspi_tx_obj.init.cnt2.txdemp = TSPI_TXDEMP_HI;
instance.tspi_tx_obj.init.cnt2.rxdly = TSPI_RXDLY_40MHz_OVER;
instance.tspi_tx_obj.init.cnt2.til = TSPI_TX_FILL_LEVEL_7;
instance.tspi_tx_obj.init.cnt2.ril = TSPI_RX_FILL_LEVEL_7;
instance.tspi_tx_obj.init.cnt2.inttxwe = TSPI_TX_INT_DISABLE;//所有中断都禁止,使用查询模式
instance.tspi_tx_obj.init.cnt2.intrxwe = TSPI_RX_INT_DISABLE;
instance.tspi_tx_obj.init.cnt2.inttxfe = TSPI_TX_FIFO_INT_DISABLE;
instance.tspi_tx_obj.init.cnt2.intrxfe = TSPI_RX_FIFO_INT_DISABLE;
instance.tspi_tx_obj.init.cnt2.interr = TSPI_ERR_INT_DISABLE;
instance.tspi_tx_obj.init.cnt2.dmate = TSPI_TX_DMA_INT_DISABLE;
instance.tspi_tx_obj.init.cnt2.dmare = TSPI_RX_DMA_INT_DISABLE;
/* Set Initial parameter of TSPIxBR */
instance.tspi_tx_obj.init.brd.brck = TSPI_BR_CLOCK_1;
instance.tspi_tx_obj.init.brd.brs = TSPI_BR_DIVIDER_2; //sck = 10MHZ
/* Set Initial parameter of TSPIxFMTR0 */
instance.tspi_tx_obj.init.fmr0.dir = TSPI_DATA_DIRECTION_MSB;//高位优先
instance.tspi_tx_obj.init.fmr0.fl = TSPI_DATA_LENGTH_8;//8bit
instance.tspi_tx_obj.init.fmr0.fint = TSPI_INTERVAL_TIME_0;
instance.tspi_tx_obj.init.fmr0.cs3pol = TSPI_TSPIxCS3_NEGATIVE;
instance.tspi_tx_obj.init.fmr0.cs2pol = TSPI_TSPIxCS2_NEGATIVE;
instance.tspi_tx_obj.init.fmr0.cs1pol = TSPI_TSPIxCS1_NEGATIVE;
instance.tspi_tx_obj.init.fmr0.cs0pol = TSPI_TSPIxCS0_NEGATIVE;
instance.tspi_tx_obj.init.fmr0.ckpha = TSPI_SERIAL_CK_2ND_EDGE;
instance.tspi_tx_obj.init.fmr0.ckpol = TSPI_SERIAL_CK_IDLE_HI;//SCK IDEL HIGH
instance.tspi_tx_obj.init.fmr0.csint = TSPI_MIN_IDLE_TIME_1;
instance.tspi_tx_obj.init.fmr0.cssckdl = TSPI_SERIAL_CK_DELAY_1;
instance.tspi_tx_obj.init.fmr0.sckcsdl = TSPI_NEGATE_1;
/* Set Initial parameter of TSPIxFMTR1 */
instance.tspi_tx_obj.init.fmr1.vpe = TSPI_PARITY_DISABLE;
instance.tspi_tx_obj.init.fmr1.vpm = TSPI_PARITY_BIT_ODD;
instance.tspi_tx_obj.transmit.handler = transmit_handler;
if ( instance.tspi_tx_obj.p_instance != MAIN_NULL)
{
if (tspi_init(&instance.tspi_tx_obj) != TXZ_SUCCESS)
{
result = TXZ_ERROR;
}
}
else
{
result = TXZ_ERROR;
}
5、LCD时序初始化
根据LCD手册,有如下LCD初始化过程
#define RESET_1 gpio_write_bit(NULL, GPIO_PORT_B, GPIO_PORT_0, GPIO_Mode_DATA, GPIO_PIN_SET)
#define RESET_0 gpio_write_bit(NULL, GPIO_PORT_B, GPIO_PORT_0, GPIO_Mode_DATA, GPIO_PIN_RESET)
#define CS_1 gpio_write_bit(NULL, GPIO_PORT_B, GPIO_PORT_5, GPIO_Mode_DATA, GPIO_PIN_SET)
#define CS_0 gpio_write_bit(NULL, GPIO_PORT_B, GPIO_PORT_5, GPIO_Mode_DATA, GPIO_PIN_RESET)
#define AD_1 gpio_write_bit(NULL, GPIO_PORT_B, GPIO_PORT_1, GPIO_Mode_DATA, GPIO_PIN_SET)
#define AD_0 gpio_write_bit(NULL, GPIO_PORT_B, GPIO_PORT_1, GPIO_Mode_DATA, GPIO_PIN_RESET)
需要说明一下,为了使用方便,gpio_write_bit函数中,我将check部分屏蔽掉,一个参数使用NULL。
void InitiateLCD(void)
{
CS_1;
RESET_1;
delay(200);
RESET_0;
delay(5);
RESET_1;
delay(200);
LCDInstructionWrite(0x30); //EXT=0
LCDInstructionWrite(0x94); //Sleep out
LCDInstructionWrite(0x31); //EXT=1
LCDInstructionWrite(0xD7); //Autoread disable
LcdDataWrite(0X9F); //
LCDInstructionWrite(0x32); //Analog SET
LcdDataWrite(0x00); //OSC Frequency adjustment
LcdDataWrite(0x01); //Frequency on booster capacitors->6KHz
LcdDataWrite(0x03); //Bias=1/11
LCDInstructionWrite(0x20); // Gray Level
LcdDataWrite(0x01);
LcdDataWrite(0x03);
LcdDataWrite(0x05);
LcdDataWrite(0x07);
LcdDataWrite(0x09);
LcdDataWrite(0x0b);
LcdDataWrite(0x0d);
LcdDataWrite(0x10);
LcdDataWrite(0x11);
LcdDataWrite(0x13);
LcdDataWrite(0x15);
LcdDataWrite(0x17);
LcdDataWrite(0x19);
LcdDataWrite(0x1b);
LcdDataWrite(0x1d);
LcdDataWrite(0x1f);
LCDInstructionWrite(0x30); //EXT=0
LCDInstructionWrite(0x75); //Page Address setting
LcdDataWrite(0X00); // XS=0
LcdDataWrite(0X28); // XE=159 0x28
LCDInstructionWrite(0x15); //Clumn Address setting
LcdDataWrite(0X00); // XS=0
LcdDataWrite(0Xff); // XE=256
LCDInstructionWrite(0xBC); //Data scan direction
LcdDataWrite(0x00); //MX.MY=Normal lcd direction
LcdDataWrite(0xA6);
LCDInstructionWrite(0x0C); //D0-D7 or D7-D0
LCDInstructionWrite(0xCA); //Display Control
LcdDataWrite(0X00); //
LcdDataWrite(0X9F); //Duty=160
LcdDataWrite(0X20); //Nline=off
LCDInstructionWrite(0xF0); //Display Mode
LcdDataWrite(0X10); //10=Monochrome Mode,11=4Gray
LCDInstructionWrite(0x81); //EV control
LcdDataWrite(0x38); //VPR[5-0] //0x38
LcdDataWrite(0x04); //VPR[8-6]
LCDInstructionWrite(0x20); //Power control
LcdDataWrite(0x0B); //D0=regulator ; D1=follower ; D3=booste, on:1 off:0
delay(100);
LCDInstructionWrite(0xAF); //Display on
}
//写命令函数
void LCDInstructionWrite(unsigned char WriteData)
{
CS_0;
delay(10);
AD_0;
delay(10);
SPI_MasterTransmit(WriteData);
CS_1;
delay(20);
}
//写数据函数
void LcdDataWrite(unsigned char WriteData)
{
//CS_1;
CS_0;
delay(10);
AD_1;
delay(10);
SPI_MasterTransmit(WriteData);
CS_1;
delay(20);
}
//底层发送数据函数
void SPI_MasterTransmit(unsigned char data)
{
/* Receive TRXE Enable */
instance.tspi_rx_obj.p_instance->CR1 |= TSPI_TRXE_ENABLE;
/* Send Data Set */
t_info.tx8.p_data = &data;
t_info.tx8.num = 1;
tspi_master_write(&instance.tspi_tx_obj, &t_info, 10000);
delay(10);
}
6、时序验证
修改程序后,使用逻辑分析仪对时序进行捕捉,如下图所示:
这是所有信号的时序图,我对着LCD的时序图,没有问题,其中RS=0,写的是命令,RS=1写的是数据。
下图是对第一包数据放大后的SPI时序图。
从图中可以看出,SPI时钟为10MHZ,与程序设计的一致,而且数据在下降沿保持,从图中可以分析出第一包数据是0x30,与程序中写入的一致。
所以到目前来看,TSPI1控制器已经正常工作,时序已经没有问题。
五、目前问题
经过以上移植,可以看出,各时序已经没有问题,而且我也对着所有时序检查TSPI1TXD端子输出的数据,与LCD初始化的顺序保持一致,
但目前LCD不知为何仍无法点亮,已经调试了2天,后续会继续寻找问题原因。