/*
* SCK P0_7
* MOSI P0_5
* CS P0_11
* DC P1_6
* RST P0-19
*/
其中sck、mosi是使用SPI0这个通道,CS选用SS1即P0_11。
【注意】由于max硬件spi的时钟与MOSI会在正式发送数据之前会有一个方波,因此必须使用硬件CS来配合才能正常。经用逻辑分析仪查看他的时序如下:
DC与RST做为普通GPIO输出即可,BL目前采用直接接VCC3.3V开机即亮。
二、SPI初始化在max78000的SDK中提供了很多的常用屏的现成驱动,有但是没有st7796的驱动,因此我们可以借用SDK中的屏驱动来学习。
1、宏定义#define TFT_SPI_FREQ 25000000 // spi 总线线速度25MHz
#define TFT_SPI0_PINS MXC_GPIO_PIN_5 | MXC_GPIO_PIN_6 | MXC_GPIO_PIN_7 | MXC_GPIO_PIN_11
#define DC_SET MXC_GPIO_OutSet(DC_PORT,DC_PIN)
#define DC_CLR MXC_GPIO_OutClr(DC_PORT,DC_PIN)
#define RST_SET MXC_GPIO_OutSet(RST_PORT,RST_PIN)
#define RST_CLR MXC_GPIO_OutClr(RST_PORT,RST_PIN)
2、spi初始化static void tft_spi_init(void)
{
#if SOFT_SPI
mxc_gpio_cfg_t gpio_out;
gpio_out.port = DC_PORT;
gpio_out.mask = DC_PIN;
gpio_out.pad = MXC_GPIO_PAD_NONE;
gpio_out.func = MXC_GPIO_FUNC_OUT;
gpio_out.vssel = MXC_GPIO_VSSEL_VDDIOH;
gpio_out.drvstr = MXC_GPIO_DRVSTR_0;
MXC_GPIO_Config(&gpio_out);
gpio_out.port = SCK_PORT;
gpio_out.mask = SCK_PIN;
gpio_out.pad = MXC_GPIO_PAD_NONE;
gpio_out.func = MXC_GPIO_FUNC_OUT;
gpio_out.vssel = MXC_GPIO_VSSEL_VDDIOH;
gpio_out.drvstr = MXC_GPIO_DRVSTR_0;
MXC_GPIO_Config(&gpio_out);
gpio_out.port = MOSI_PORT;
gpio_out.mask = MOSI_PIN;
gpio_out.pad = MXC_GPIO_PAD_NONE;
gpio_out.func = MXC_GPIO_FUNC_OUT;
gpio_out.vssel = MXC_GPIO_VSSEL_VDDIOH;
gpio_out.drvstr = MXC_GPIO_DRVSTR_0;
MXC_GPIO_Config(&gpio_out);
gpio_out.port = CS_PORT;
gpio_out.mask = CS_PIN;
gpio_out.pad = MXC_GPIO_PAD_NONE;
gpio_out.func = MXC_GPIO_FUNC_OUT;
gpio_out.vssel = MXC_GPIO_VSSEL_VDDIOH;
gpio_out.drvstr = MXC_GPIO_DRVSTR_0;
MXC_GPIO_Config(&gpio_out);
gpio_out.port = RST_PORT;
gpio_out.mask = RST_PIN;
gpio_out.pad = MXC_GPIO_PAD_NONE;
gpio_out.func = MXC_GPIO_FUNC_OUT;
gpio_out.vssel = MXC_GPIO_VSSEL_VDDIOH;
gpio_out.drvstr = MXC_GPIO_DRVSTR_0;
MXC_GPIO_Config(&gpio_out);
DC_CLR;
CS_SET;
SCK_CLR;
RST_SET;
#else
int master = 1;
int quadMode = 0;
int numSlaves = 2;
int ssPol = 0;
unsigned int tft_hz = TFT_SPI_FREQ;
mxc_spi_pins_t tft_pins;
mxc_gpio_cfg_t gpio_out;
gpio_out.port = CS_PORT;
gpio_out.mask = CS_PIN;
gpio_out.pad = MXC_GPIO_PAD_NONE;
gpio_out.func = MXC_GPIO_FUNC_OUT;
gpio_out.vssel = MXC_GPIO_VSSEL_VDDIOH;
gpio_out.drvstr = MXC_GPIO_DRVSTR_0;
MXC_GPIO_Config(&gpio_out);
gpio_out.port = DC_PORT;
gpio_out.mask = DC_PIN;
gpio_out.pad = MXC_GPIO_PAD_NONE;
gpio_out.func = MXC_GPIO_FUNC_OUT;
gpio_out.vssel = MXC_GPIO_VSSEL_VDDIOH;
gpio_out.drvstr = MXC_GPIO_DRVSTR_0;
MXC_GPIO_Config(&gpio_out);
gpio_out.port = RST_PORT;
gpio_out.mask = RST_PIN;
gpio_out.pad = MXC_GPIO_PAD_NONE;
gpio_out.func = MXC_GPIO_FUNC_OUT;
gpio_out.vssel = MXC_GPIO_VSSEL_VDDIOH;
gpio_out.drvstr = MXC_GPIO_DRVSTR_0;
MXC_GPIO_Config(&gpio_out);
tft_pins.clock = true;
tft_pins.ss0 = (ssel == 0); ///< Slave select pin 0
tft_pins.ss1 = (ssel == 1); ///< Slave select pin 1
tft_pins.ss2 = (ssel == 2); ///< Slave select pin 2
tft_pins.miso = true; ///< miso pin
tft_pins.mosi = true; ///< mosi pin
tft_pins.sdio2 = false; ///< SDIO2 pin
tft_pins.sdio3 = false; ///< SDIO3 pin
spi = MXC_SPI0;
MXC_SPI_Init(spi, master, quadMode, numSlaves, ssPol, tft_hz, tft_pins);
// Set SPI0 pins to VDDIOH (3.3V) to be compatible with TFT display
MXC_GPIO_SetVSSEL(MXC_GPIO0, MXC_GPIO_VSSEL_VDDIOH, TFT_SPI0_PINS);
MXC_SPI_SetDataSize(spi, 8);
MXC_SPI_SetWidth(spi, SPI_WIDTH_STANDARD);
CS_SET;
#endif
}
在这个函数中,我使用条件编译添加要spi的硬件初始化,设置DMA中断发送,8位数据宽度发送。
3、st7796的数据发送static void spi_transmit(void* datain, unsigned int count)
{
unsigned int offset;
unsigned int fifo;
volatile unsigned short* u16ptrin = (volatile unsigned short*) datain;
unsigned int start = 0;
// HW requires disabling/renabling SPI block at end of each transaction (when SS is inactive).
spi->ctrl0 &= ~(MXC_F_SPI_CTRL0_EN);
// Setup the slave select
MXC_SETFIELD(spi->ctrl0, MXC_F_SPI_CTRL0_SS_ACTIVE, ((1 << ssel) << MXC_F_SPI_CTRL0_SS_ACTIVE_POS));
// number of RX Char is 0xffff
spi->ctrl1 &= ~(MXC_F_SPI_CTRL1_RX_NUM_CHAR);
//DMA RX FIFO disabled
spi->dma &= ~(MXC_F_SPI_DMA_RX_FIFO_EN);
// set number of char to be transmit
MXC_SETFIELD(spi->ctrl1, MXC_F_SPI_CTRL1_TX_NUM_CHAR, count << MXC_F_SPI_CTRL1_TX_NUM_CHAR_POS);
// DMA TX fifo enable
spi->dma |= MXC_F_SPI_DMA_TX_FIFO_EN;
/* Clear TX and RX FIFO in DMA
TX: Set this bit to clear the TX FIFO and all TX FIFO flags in the QSPIn_INT_FL register.
Note: The TX FIFO should be disabled (QSPIn_DMA.tx_fifo_en = 0) prior to setting this field.
Note: Setting this field to 0 has no effect.
RX: Clear the RX FIFO and any pending RX FIFO flags in QSPIn_INTFL.
This should be done when the RX FIFO is inactive.
*/
spi->dma |= (MXC_F_SPI_DMA_TX_FLUSH | MXC_F_SPI_DMA_RX_FLUSH);
// QSPIn port is enabled
spi->ctrl0 |= (MXC_F_SPI_CTRL0_EN);
// Clear master done flag
spi->intfl = MXC_F_SPI_INTFL_MST_DONE;
/* Loop until all data is transmitted */
offset = 0;
do {
fifo = (count > 8) ? 8 : count;
count -= fifo;
while (fifo > 0) {
/* Send data */
spi->fifo16[0] = u16ptrin[offset];
offset++;
fifo--;
}
/*
Master Start Data Transmission
Set this field to 1 to start a SPI master mode transaction.
0: No master mode transaction active.
1: Master initiates a data transmission. Ensure that all pending transactions are
complete before setting this field to 1.
Note: This field is only used when the QSPIn is configured for Master Mode
(QSPIn_CTRL0.master = 1).
*/
if (start == 0) {
spi->ctrl0 |= MXC_F_SPI_CTRL0_START;
start = 1;
}
/* Wait for data transmitting complete and then Deasserts nSS I/O */
// Deassert slave select at the end of the transaction
spi->ctrl0 &= ~MXC_F_SPI_CTRL0_SS_CTRL;
}
while (count);
while (!(spi->intfl & MXC_F_SPI_INTFL_MST_DONE)) {
// wait until done
}
return;
}
## 四、软件与硬件效果对比
使用逻辑分析仪对软件、硬件的sck时序对比,发送速度软件经过优化后最高可以工作到1MHZ
硬件SPI可以达到28MHz