华大HC32F460轮询方式SPI通讯配置

背景

需要控制几块SPI通讯接口的屏幕显示内容。因此需要配置芯片SPI接口,软件方式此前已经轻松实现,但是出于性能考虑,使用硬件方式是更优的方案。

浏览了华大提供的代码例子,均是全双工场景下两个芯片相互发送接收数据调用的SPI_TransReceive函数,案例对于我需要的单方发送场景不太合适。

同时例子里发送的数据内容是固定的,在实际使用中还需重新修改。

本文会提供一种更简单易用的配置方式,方便单发送场景下的SPI硬件配置,同时不会涉及到屏幕控制的实际指令,仅包含对SPI接口相关进行配置,方便您快速移植代码

设计思路

1、简单的屏幕控制需求,无需配置过于复杂,简单易用即可,因此采用了阻塞式的轮询方案进行SPI通讯。

2、对于SPI通讯来说,最快速和占用资源最小的方式应该是采用DMA+中断的方式进行配置,但是这样配置和调用会比较麻烦,另一方面小型SPI屏幕本身性能有限,芯片发送指令速度再快,屏幕显示的速度还是没有什么差别的,因此无需配置过于复杂。

代码实现

1、SPI初始化

下面代码中需要注意:

1、无需接收数据因此SPI_MISO接口无需配置;

2、SPI_SS接口对应屏幕的片选CS,在主机模式下,460芯片似乎不会自动控制该引脚拉高和拉低,因此将该引脚作为普通的GPIO初始化,以进行手动的拉低和拉高;

3、stcSpiInit.u32SpiMode用于控制SPI工作模式,关系到MOSI和MISO的波形,该配置是导致SPI通讯成功与否的重要内容,460有0~3共4种工作模式。

c 复制代码
void InitSPI(void)
{	
	stc_spi_init_t stcSpiInit;//SPI CONFIG
	stc_irq_signin_config_t stcIrqSignConfig;//RX/TX
	stc_gpio_init_t stcGpioInit;//GPIO
		
		//GPIO初始化
    (void)GPIO_StructInit(&stcGpioInit);
    stcGpioInit.u16PinDrv       = PIN_HIGH_DRV;
    //(void)GPIO_Init(IPS_SPI_SS_PORT,   IPS_SPI_SS_PIN,   &stcGpioInit);
    (void)GPIO_Init(IPS_SPI_SCK_PORT,  IPS_SPI_SCK_PIN,  &stcGpioInit);
    (void)GPIO_Init(IPS_SPI_MOSI_PORT, IPS_SPI_MOSI_PIN, &stcGpioInit);
    //(void)GPIO_Init(SPI_MISO_PORT, SPI_MISO_PIN, &stcGpioInit);

    /* 配置引脚Func模式 */
    //GPIO_SetFunc(IPS_SPI_SS_PORT,   IPS_SPI_SS_PIN,   IPS_SPI_SS_FUNC);
    GPIO_SetFunc(IPS_SPI_SCK_PORT,  IPS_SPI_SCK_PIN,  IPS_SPI_SCK_FUNC);
    GPIO_SetFunc(IPS_SPI_MOSI_PORT, IPS_SPI_MOSI_PIN, IPS_SPI_MOSI_FUNC);
    //GPIO_SetFunc(SPI_MISO_PORT, SPI_MISO_PIN, SPI_MISO_FUNC);

    /* 配置 SPI */
	FCG_Fcg1PeriphClockCmd(IPS_SPI_CLK, ENABLE);
	SPI_StructInit(&stcSpiInit);
	stcSpiInit.u32WireMode          = SPI_4_WIRE;//四线SPI
	stcSpiInit.u32TransMode         = SPI_SEND_ONLY;//仅发送模式(也可配置全双工)
	stcSpiInit.u32MasterSlave       = IPS_EXAMPLE_SPI_MASTER_SLAVE;//主从机模式
	stcSpiInit.u32Parity            = SPI_PARITY_INVD;//奇偶校验模式,配置无校验
	stcSpiInit.u32SpiMode           = SPI_MD_3;//SPI工作模式,空闲状态低电平、上升沿采样,下降沿变化
	stcSpiInit.u32BaudRatePrescaler = SPI_BR_CLK_DIV256;//速率分频
	stcSpiInit.u32DataBits          = SPI_DATA_SIZE_8BIT;//数据位
	stcSpiInit.u32FirstBit          = SPI_FIRST_MSB;//最高有效位先传输,D7、D6...D0顺序
	stcSpiInit.u32FrameLevel        = SPI_1_FRAME;//向寄存器写入1位数据后立即推送至TX
	(void)SPI_Init(IPS_SPI_UNIT, &stcSpiInit);
	SPI_Cmd(IPS_SPI_UNIT,ENABLE);
		//SPI_IntCmd(SPI_UNIT, (SPI_INT_TX_BUF_EMPTY), ENABLE);//仅启用TX
    //SPI_IntCmd(SPI_UNIT, (SPI_INT_TX_BUF_EMPTY | SPI_INT_RX_BUF_FULL), ENABLE);

    /* TX NVIC configure */
//    stcIrqSignConfig.enIntSrc    = SPI_TX_IRQ_SRC;
//    stcIrqSignConfig.enIRQn      = SPI_TX_IRQ_NUM;
//    stcIrqSignConfig.pfnCallback = &SPI_TransCompleteCallback;
//    (void)INTC_IrqSignIn(&stcIrqSignConfig);
//    NVIC_ClearPendingIRQ(stcIrqSignConfig.enIRQn);
//    NVIC_SetPriority(stcIrqSignConfig.enIRQn, DDL_IRQ_PRIO_DEFAULT);
//    NVIC_EnableIRQ(stcIrqSignConfig.enIRQn);
    /* RX NVIC configure */
//    stcIrqSignConfig.enIntSrc    = SPI_RX_IRQ_SRC;
//    stcIrqSignConfig.enIRQn      = SPI_RX_IRQ_NUM;
//    stcIrqSignConfig.pfnCallback = &SPI_ReceiveCompleteCallback;
//    (void)INTC_IrqSignIn(&stcIrqSignConfig);
//    NVIC_ClearPendingIRQ(stcIrqSignConfig.enIRQn);
//    NVIC_SetPriority(stcIrqSignConfig.enIRQn, DDL_IRQ_PRIO_DEFAULT - 1);
//    NVIC_EnableIRQ(stcIrqSignConfig.enIRQn);
		
		//普通IO初始化
		(void)GPIO_StructInit(&stcGpioInit);
		stcGpioInit.u16PinState = PIN_STAT_RST;//默认置0
		stcGpioInit.u16PinDir = PIN_DIR_OUT;//输出模式

		(void)GPIO_Init(IPS_SPI_RES_PORT, IPS_SPI_RES_PIN, &stcGpioInit);
		(void)GPIO_Init(IPS_SPI_DC_PORT, IPS_SPI_DC_PIN, &stcGpioInit);
		(void)GPIO_Init(IPS_SPI_CS_PORT, IPS_SPI_CS_PIN, &stcGpioInit);

		stcGpioInit.u16PinState = PIN_STAT_SET;//背光默认置1常亮
		(void)GPIO_Init(IPS_SPI_BLK_PORT, IPS_SPI_BLK_PIN, &stcGpioInit);
		IPS_CS_HIGH;//片选默认拉高
}

2、初始化代码对应的头文件声明内容

c 复制代码
/* SPI definition */
#define IPS_EXAMPLE_SPI_MASTER_SLAVE        (SPI_MASTER)
#define IPS_SPI_UNIT                        (CM_SPI1)
#define IPS_SPI_CLK                         (FCG1_PERIPH_SPI1)
#define IPS_SPI_TX_IRQ_SRC                  (INT_SRC_SPI1_SPTI)
#define IPS_SPI_TX_IRQ_NUM                  (INT013_IRQn)
#define IPS_SPI_RX_IRQ_SRC                  (INT_SRC_SPI1_SPRI)
#define IPS_SPI_RX_IRQ_NUM                  (INT014_IRQn)

/*SPI通讯配置引脚,4个,屏幕可不配置MISO*/
///* SS(CS) */
//#define IPS_SPI_SS_PORT                     (GPIO_PORT_B)
//#define IPS_SPI_SS_PIN                      (GPIO_PIN_09)
//#define IPS_SPI_SS_FUNC                     (GPIO_FUNC_42)
/* CS */
#define IPS_SPI_CS_PORT                     (GPIO_PORT_B)
#define IPS_SPI_CS_PIN                      (GPIO_PIN_09)

/* SCK(CLK/SCL) */
#define IPS_SPI_SCK_PORT                    (GPIO_PORT_A)
#define IPS_SPI_SCK_PIN                     (GPIO_PIN_07)
#define IPS_SPI_SCK_FUNC                    (GPIO_FUNC_43)
/* MOSI(Master Out Slave In/SDA/主机输出从机输入) */
#define IPS_SPI_MOSI_PORT                   (GPIO_PORT_A)
#define IPS_SPI_MOSI_PIN                    (GPIO_PIN_06)
#define IPS_SPI_MOSI_FUNC                   (GPIO_FUNC_40)
/* MISO(Master In Slave Out/主机输入从机输出) = PC5 */
//#define IPS_SPI_MISO_PORT                   (GPIO_PORT_C)
//#define IPS_SPI_MISO_PIN                    (GPIO_PIN_05)
//#define IPS_SPI_MISO_FUNC                   (GPIO_FUNC_41)

/* 额外的功能性引脚 */
/* RES */
#define IPS_SPI_RES_PORT                     (GPIO_PORT_A)
#define IPS_SPI_RES_PIN                      (GPIO_PIN_05)
/* DC */
#define IPS_SPI_DC_PORT                     (GPIO_PORT_A)
#define IPS_SPI_DC_PIN                      (GPIO_PIN_04)

/* BLK */
#define IPS_SPI_BLK_PORT                     (GPIO_PORT_A)
#define IPS_SPI_BLK_PIN                      (GPIO_PIN_03)

#define IPS_CS_LOW  ( GPIO_ResetPins(IPS_SPI_CS_PORT, IPS_SPI_CS_PIN) )
#define IPS_CS_HIGH  ( GPIO_SetPins(IPS_SPI_CS_PORT, IPS_SPI_CS_PIN) )

/* TFT屏相关引脚高低电平控制 */
//额外的通用引脚
#define IPS_DC_LOW  ( GPIO_ResetPins(IPS_SPI_DC_PORT, IPS_SPI_DC_PIN) )
#define IPS_DC_HIGH  ( GPIO_SetPins(IPS_SPI_DC_PORT, IPS_SPI_DC_PIN) )
#define IPS_RES_LOW  ( GPIO_ResetPins(IPS_SPI_RES_PORT, IPS_SPI_RES_PIN) )
#define IPS_RES_HIGH  ( GPIO_SetPins(IPS_SPI_RES_PORT, IPS_SPI_RES_PIN) )
#define IPS_BLK_LOW  ( GPIO_ResetPins(IPS_SPI_BLK_PORT, IPS_SPI_BLK_PIN) )
#define IPS_BLK_HIGH  ( GPIO_SetPins(IPS_SPI_BLK_PORT, IPS_SPI_BLK_PIN) )

3、SPI数据发送接口

为确保发送数据的时序,发送前需要等待SPI_FLAG_TX_BUF_EMPTY状态,发送后需要等待SPI_FLAG_IDLE状态确保发送完成。

否则数据还未发送完成就拉高CS会导致硬件SPI还未发送出刚写入的数据就通知屏幕停止接收数据,导致数据帧截断。

经测试,SPI_FLAG_TX_BUF_EMPTY可以不等待,但是必须等待SPI_FLAG_IDLE状态,出于严谨考虑,两个状态都进行等待较好。

c 复制代码
void IPS_SPI_WriteData_M(u8 Data)
{
	//CS_LOW; /* 拉低片选 */
	while(RESET == SPI_GetStatus(IPS_SPI_UNIT,SPI_FLAG_TX_BUF_EMPTY));
	SPI_WriteData(IPS_SPI_UNIT, Data);
	/* 等待 SPI 完全发送完成(关键) */ 
	while (RESET == SPI_GetStatus(IPS_SPI_UNIT, SPI_FLAG_IDLE));
	//CS_HIGH; /* 拉高片选 */
}

如下为屏幕指令写入接口和数据写入接口,通过DC脚的状态不同来控制屏幕区分下面发送的是指令还是数据。

c 复制代码
/**
 * @brief  液晶屏写指令.
 * @param  Data[in] 指令数据
 * @retval None
 */
void TFT_WriteCmd(u8 Data)
{
	IPS_DC_LOW;
	IPS_CS_LOW; /* 拉低片选 */
	IPS_SPI_WriteData_M(Data);
	IPS_CS_HIGH; /* 拉高片选 */
	IPS_DC_HIGH;	
}
/**
 * @brief  液晶屏写数据.
 * @param  Data[in] 数据
 * @retval None
 */
void TFT_WriteData(u8 Data)
{	
	IPS_DC_HIGH;
	IPS_CS_LOW; /* 拉低片选 */
	IPS_SPI_WriteData_M(Data);
	IPS_CS_HIGH; /* 拉高片选 */
	IPS_DC_HIGH;
}

/**
 * @brief  液晶屏写数据.
 * @param  Data[in] 2字节数据
 * @retval None
 */
void TFT_WriteData_16(u32 Data)
{
	IPS_DC_HIGH;
	IPS_CS_LOW; /* 拉低片选 */
	IPS_SPI_WriteData_M(Data>>8);
	IPS_SPI_WriteData_M(Data&0xFF);
	IPS_CS_HIGH; /* 拉高片选 */
	IPS_DC_HIGH;
}
相关推荐
Mapple.2 小时前
TMS320C6748的初始化与STM32做个类比
stm32·单片机·嵌入式硬件
兆龙电子单片机设计3 小时前
【STM32项目开源】STM32单片机智能家居安防控制系统
stm32·单片机·开源·毕业设计·电子信息
听情歌落俗3 小时前
MPU6050
单片机·嵌入式硬件
d111111111d3 小时前
STM32定时器中断配置详解:以TIM2为例
笔记·stm32·单片机·嵌入式硬件·学习
Q_21932764553 小时前
基于51单片机的智能家居防火防盗报警系统设计
嵌入式硬件·51单片机·智能家居
QK_003 小时前
STM32--USART(串口)
stm32·单片机·嵌入式硬件
jencepan3 小时前
纳安级功耗,5.5V/2A,23-6封装,单节锂电升压DCDC方案,晶艺LA2112N
单片机·嵌入式硬件
BMS小旭3 小时前
CubeMx-CAN
单片机·学习·cubemx·can
EVERSPIN12 小时前
基于灵动MM32F0140国产32位单片机的Mini-LED应用
单片机·嵌入式硬件·32位单片机·国产32位单片机