SPI 外设的三线/四线模式及时钟极性相位可以配置,支持主机/从机、全双工/半双
工,传送数据格式可灵活配置,并且有发送空接收满 SPI 错误等中断事件功能配合应用使用,更多功能详见本系列芯片手册的相关章节。
SPI四线模式框图:
串行通信模式参数:
1,时钟极性
根据硬件制造商的命名规则不同,时钟极性通常写为CKP或CPOL。时钟极性和相位共同决定读取数据的方式,比如信号上升沿读取数据还是信号下降沿读取数据。
CKP可以配置为1或0。这意味着你可以根据需要将时钟的默认状态(IDLE)设置为高或低。极性反转可以通过简单的逻辑逆变器实现。你必须参考设备的数据手册才能正确设置CKP和CKE。
CKP = 0:时钟空闲IDLE为低电平 0;
CKP = 1:时钟空闲IDLE为高电平1。
2、时钟相位
根据硬件制造商的不同,时钟相位通常写为CKE或CPHA。顾名思义,时钟相位/边沿,也就是采集数据时是在时钟信号的具体相位或者边沿;
CKE = 0:在时钟信号SCK的第一个跳变沿采样;
CKE = 1:在时钟信号SCK的第二个跳变沿采样。
3、四种模式
根据SPI的时钟极性和时钟相位特性可以设置4种不同的SPI通信操作模式,它们的区别是定义了在时钟脉冲的哪条边沿转换(toggles)输出信号,哪条边沿采样输入信号,还有时钟脉冲的稳定电平值(就是时钟信号无效时是高还是低),详情如下所示:
Mode0:CKP=0,CKE =0:当空闲态时,CS_N处于低电平,数据采样是在第1个边沿,也就是SCLK由低电平到高电平的跳变,所以数据采样是在上升沿(准备数据),(发送数据)数据发送是在下降沿。
Mode1:CKP=0,CKE=1:当空闲态时,CS_N处于低电平,数据发送是在第2个边沿,也就是SCLK由低电平到高电平的跳变,所以数据采样是在下降沿,数据发送是在上升沿。
Mode2:CKP=1,CKE=0:当空闲态时,CS_N处于高电平,数据采集是在第1个边沿,也就是SCLK由高电平到低电平的跳变,所以数据采集是在下降沿,数据发送是在上升沿。
Mode3:CKP=1,CKE=1:当空闲态时,CS_N处于高电平,数据发送是在第2个边沿,也就是SCLK由高电平到低电平的跳变,所以数据采集是在上升沿,数据发送是在下降沿。
以上参数由GPIO或者仪表设置.
举例说明:CKP = 1,CKE = 0
SPI读,关闭可用片选信号
SPI写
数据比特位解析:
起始位+读写标志位+数据长度 + 数据(地址+ 数据)
SPI 通信硬件连接相关 IO 如下 :
管脚名 | 端口方向 | 功能 | |
主机 | 从机 | ||
SCK | 输出 | 输入 | 通信时钟 |
MOSI | 输出 | 输入 | |
MISO | 输入 | 输出 | |
SS0 | 输出 | 输入 | 片选信号 |
设置参数
- 通过寄存器 SPI_CFG2.DSIZE 配置 SPI 数据帧长度为 4~16、 20、 24、 32 位, 寄存器SPI_CFG2.LSBF 配置数据格式为 MSB 或 LSB, 寄存器 SPI_CR1.PAE 配置数据奇偶校验是否使能 。
- 数据传送帧数
通过寄存器 SPI_CFG1.FTHLV 可配置数据传送帧数分别为 1 帧~4 帧,即启动一次数据传送的数据帧长度。当作为主机发送或接收数据时,向 DTR 寄存器写完所配置数据帧数目后才能启动一次数据传送;当作为从机接收数据时,收到了所配置数据帧数目的数据后才能产生 RDFF(接收缓冲器满)标志。 - SPI 的模式定义
SPI 外设通过 SPI_CFG2.CPHA 配置时钟相位(Clock Phase)和 SPI_CFG2.CPOL(ClockPolarity)配置时钟极性。 见四种模式说明
软件实现:
初始化:
static void Spi_Config(void)
{
stc_spi_init_t stcSpiInit;
stc_spi_delay_t stcSpiDelayCfg;
/* Configure SPI Port function for master */
GPIO_SetFunc(SPI_SCK_PORT, SPI_SCK_PIN, SPI_SCK_FUNC, PIN_SUBFUNC_DISABLE);
GPIO_SetFunc(SPI_MOSI_PORT, SPI_MOSI_PIN, SPI_MOSI_FUNC, PIN_SUBFUNC_DISABLE);
GPIO_SetFunc(SPI_MISO_PORT, SPI_MISO_PIN, SPI_MISO_FUNC, PIN_SUBFUNC_DISABLE);
/* Clear initialize structure */
(void)SPI_StructInit(&stcSpiInit);
(void)SPI_DelayStructInit(&stcSpiDelayCfg);
/* Port configurate */
(void)GPIO_StructInit(&stcGpioCfg);
/* High driving capacity for output pin. */
stcGpioCfg.u16PinDir = PIN_DIR_OUT;
stcGpioCfg.u16PinDrv = PIN_DRV_HIGH;
stcGpioCfg.u16PinState = PIN_STATE_SET;
(void)GPIO_Init(SPI_NSS_PORT, SPI_NSS_PIN, &stcGpioCfg)
/* Configure peripheral clock */
PWC_Fcg1PeriphClockCmd(SPI_UNIT_CLOCK, Enable);
/* SPI De-initialize */
SPI_DeInit(SPI_UNIT);
/* Configuration SPI structure */
stcSpiInit.u32WireMode = SPI_WIRE_3;
stcSpiInit.u32TransMode = SPI_FULL_DUPLEX;
stcSpiInit.u32MasterSlave = SPI_MASTER;
stcSpiInit.u32SuspMode = SPI_COM_SUSP_FUNC_OFF;
stcSpiInit.u32Modfe = SPI_MODFE_DISABLE;
stcSpiInit.u32Parity = SPI_PARITY_INVALID;
stcSpiInit.u32SpiMode = SPI_MODE_0;
stcSpiInit.u32BaudRatePrescaler = SPI_BR_PCLK1_DIV256;
stcSpiInit.u32DataBits = SPI_DATA_SIZE_8BIT;
stcSpiInit.u32FirstBit = SPI_FIRST_MSB;
(void)SPI_Init(SPI_UNIT, &stcSpiInit);
stcSpiDelayCfg.u32IntervalDelay = SPI_INTERVAL_TIME_8SCK_2PCLK1;
stcSpiDelayCfg.u32ReleaseDelay = SPI_RELEASE_TIME_8SCK;
stcSpiDelayCfg.u32SetupDelay = SPI_SETUP_TIME_1SCK;
(void)SPI_DelayTimeCfg(SPI_UNIT, &stcSpiDelayCfg);
SPI_FunctionCmd(SPI_UNIT, Enable);
}
读写: