/** ****************************************************************************** * @file spi.c * @author * @version * @date * @brief SPI通信程序,用于与AFE芯片(SH3673520)通信 ****************************************************************************** * @attention * * ****************************************************************************** */ /* Includes ------------------------------------------------------------------*/ #include "stm32f10x.h" #include "global.h" //SH3673517 SPI通信 //PB12 = SPI1_CS (GPIO推挽输出,软件控制片选) //PB13 = SPI1_SCK (AF1) - 时钟 //PB14 = SPI1_MISO(AF1) - 主机输入从机输出 //PB15 = SPI1_MOSI(AF0) - 主机输出从机输入 #define PIN_SPI_NSS GPIO_Pin_12 #define PIN_SPI_SCK GPIO_Pin_13 #define PIN_SPI_MISO GPIO_Pin_14 #define PIN_SPI_MOSI GPIO_Pin_15 #define SPI_Enable() GPIO_ResetBits(GPIOB, PIN_SPI_NSS) //使能通信 #define SPI_Disable() GPIO_SetBits(GPIOB, PIN_SPI_NSS) //关闭通信 /* SPI_MOSI PB15 主设备输出,从设备输入 SPI_MISO PB14 主设备输入,从设备输出 SPI_SCK PB13 时钟 SPI_CS PB12 片选信号 */ void uf_SPI2_Init(void) { /*定义SPI参数*/ GPIO_InitTypeDef GPIO_InitStructure; SPI_InitTypeDef SPI_InitStructure; // 使能SPI2和GPIOB时钟 RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE); // PB13 (SCK), PB15 (MOSI) GPIO_InitStructure.GPIO_Pin = PIN_SPI_SCK | PIN_SPI_MOSI; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB, &GPIO_InitStructure); // PB14 (MISO) GPIO_InitStructure.GPIO_Pin = PIN_SPI_MISO; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB, &GPIO_InitStructure); // PB12 (CS) GPIO_InitStructure.GPIO_Pin = PIN_SPI_NSS; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB, &GPIO_InitStructure); GPIO_SetBits(GPIOB, PIN_SPI_NSS); //初始化拉高CS,关闭SPI通信 /*配置SPI模式*/ SPI_I2S_DeInit(SPI2); // 配置SPI2与AFE芯片的SPI3通信方式:4线通信,全双工,主模式,数据同边传输,MSB在前 SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; //全双工模式 SPI_InitStructure.SPI_Mode = SPI_Mode_Master; //主模式 SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; //数据帧大小为 8 位 // 配置SPI3极性参数CPOL和CPHA SPI_InitStructure.SPI_CPOL = SPI_CPOL_High; //时钟极性为1,空闲时SCK电平状态为高电平 SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge; //时钟相位为1,在第二个跳变沿开始采样数据(第一个跳变沿,失效) SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; //软件控制 NSS 信号(PB12) SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_64;//波特率预分频系数为 64 //36MHz/64 = 0.5625MHz < 1MHz SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; //高位在前 SPI_InitStructure.SPI_CRCPolynomial = 7; //CRC值的生成多项式=x^8+x^2+x+1,省略高位,可为任意值1,只用到低8位,生成二进制编码为0000111=7 SPI_Init(SPI2, &SPI_InitStructure); // 使能SPI2 SPI_Cmd(SPI2, ENABLE); } //通信失败时,复位SPI void SPI2_Error(void) { //写也无法确有效,因为需要时序 //这里重新初始化SPI uf_SPI2_Init(); } //AFE只支持单字节写操作 //可写地址 40H~59H //rtnval 0-true; other-false uint8_t AFE_WriteOneByte(uint8_t addr, uint8_t *data) { uint8_t tx_buffer[5], rx_buffer[5]; uint8_t i; uint8_t response; // 构造发送数据帧: [0x01][reg_addr][write_data][CRC][0x00] tx_buffer[0] = 0x01; // 写命令 tx_buffer[1] = addr; // 寄存器地址 tx_buffer[2] = *data; // 写入数据 tx_buffer[3] = CRC8_Cal(tx_buffer, 3); // CRC8 tx_buffer[4] = 0x00; // 无效数据接收 // 拉低CS片选 SPI_Enable(); for (i = 0; i < 5; i++) { while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET); SPI_I2S_SendData(SPI2, tx_buffer[i]); while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) == RESET); rx_buffer[i] = SPI_I2S_ReceiveData(SPI2); } // 获取返回值 response = rx_buffer[4]; SPI_Disable(); delay_us(5); return (response == 0xA5) ? 0 : 1; } //AFE可1次读取多个字节操作 //可读取地址 40H~99H //rtnval 0-success, other-fail uint8_t AFE_ReadMulByte(uint8_t addr, uint8_t lenth, uint8_t *data) { uint8_t tx_buffer[4]; // 发送缓冲区 uint8_t rx_buffer[40]; // 接收缓冲区,最大可读取24字节,留有余量 uint8_t crc_calculated, crc_received; uint8_t i; // 构造发送数据帧: [0x02][reg_addr][data_length][0x00] tx_buffer[0] = 0x02; // 读命令 tx_buffer[1] = addr; // 寄存器地址 tx_buffer[2] = lenth; // 数据长度 tx_buffer[3] = 0x00; // 拉低CS片选 SPI_Enable(); // 第一阶段:发送时钟和命令,发送(命令/地址/长度/0x00) 接收(0xFF/命令/地址/长度) for( i=0; i<4; i++) { while(!SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE)); // 等待发送缓冲区空 SPI_I2S_SendData(SPI2, tx_buffer[i]); while(!SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE)); // 等待接收完成 rx_buffer[i] = SPI_I2S_ReceiveData(SPI2); } // 第二阶段:接收有效数据(0x00)发送接收数据(需要提供接收时钟) for( i=0; i