hal库相关函数
初始化结构体
typedef struct
{
uint32_t Mode; /*SPI模式*/
uint32_t Direction; /*SPI方向*/
uint32_t DataSize; /*数据大小*/
uint32_t CLKPolarity; /*时钟默认极性控制CPOL*/
uint32_t CLKPhase; /*有效边延控制CPOA*/
uint32_t NSS; /*外设选中*/
uint32_t BaudRatePrescaler; /*波特率分频*/
uint32_t FirstBit; /*设置先行位*/
uint32_t TIMode; /*仅当需要通过定时器触发SPI传输(如周期性发送数据)时启用,否则保持默认 DISABLE。*/
uint32_t CRCCalculation; /*CRC校验*/
uint32_t CRCPolynomial; /*循环冗余校验多项式*/
} SPI_InitTypeDef;
SPI句柄
typedef struct __SPI_HandleTypeDef
{
SPI_TypeDef *Instance; /*SPI外设地址*/
SPI_InitTypeDef Init; /*SPI初始化结构体*/
const uint8_t *pTxBuffPtr; /*发送缓存区*/
uint16_t TxXferSize; /*发送数据大小 */
__IO uint16_t TxXferCount; /*剩余发送数量*/
uint8_t *pRxBuffPtr; /*接收缓存区*/
uint16_t RxXferSize; /*接受数据大小*/
__IO uint16_t RxXferCount; /*剩余接收量*/
void (*RxISR)(struct __SPI_HandleTypeDef *hspi); /*接收的中断服务函数*/
void (*TxISR)(struct __SPI_HandleTypeDef *hspi); /*发送的中断服务函数*/
DMA_HandleTypeDef *hdmatx; /*SPI搭配DMA的发送部分*/
DMA_HandleTypeDef *hdmarx; /*SPI搭配DMA的接受部分*/
HAL_LockTypeDef Lock; /*配置锁存*/
__IO HAL_SPI_StateTypeDef State; /*SPI通讯状态*/
__IO uint32_t ErrorCode; /*SPI的错误状态*/
#if (USE_HAL_SPI_REGISTER_CALLBACKS == 1U)
void (* TxCpltCallback)(struct __SPI_HandleTypeDef *hspi); /*!< SPI Tx Completed callback */
void (* RxCpltCallback)(struct __SPI_HandleTypeDef *hspi); /*!< SPI Rx Completed callback */
void (* TxRxCpltCallback)(struct __SPI_HandleTypeDef *hspi); /*!< SPI TxRx Completed callback */
void (* TxHalfCpltCallback)(struct __SPI_HandleTypeDef *hspi); /*!< SPI Tx Half Completed callback */
void (* RxHalfCpltCallback)(struct __SPI_HandleTypeDef *hspi); /*!< SPI Rx Half Completed callback */
void (* TxRxHalfCpltCallback)(struct __SPI_HandleTypeDef *hspi); /*!< SPI TxRx Half Completed callback */
void (* ErrorCallback)(struct __SPI_HandleTypeDef *hspi); /*!< SPI Error callback */
void (* AbortCpltCallback)(struct __SPI_HandleTypeDef *hspi); /*!< SPI Abort callback */
void (* MspInitCallback)(struct __SPI_HandleTypeDef *hspi); /*!< SPI Msp Init callback */
void (* MspDeInitCallback)(struct __SPI_HandleTypeDef *hspi); /*!< SPI Msp DeInit callback */
#endif /* USE_HAL_SPI_REGISTER_CALLBACKS */
} SPI_HandleTypeDef;
SPI初始化函数
HAL_StatusTypeDef HAL_SPI_Init(SPI_HandleTypeDef *hspi);
HAL_StatusTypeDef HAL_SPI_DeInit(SPI_HandleTypeDef *hspi);
void HAL_SPI_MspInit(SPI_HandleTypeDef *hspi);
void HAL_SPI_MspDeInit(SPI_HandleTypeDef *hspi);
SPI收发相关函数
HAL_StatusTypeDef HAL_SPI_Transmit(SPI_HandleTypeDef *hspi, const uint8_t *pData, uint16_t Size, uint32_t Timeout);
HAL_StatusTypeDef HAL_SPI_Receive(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size, uint32_t Timeout);
HAL_StatusTypeDef HAL_SPI_TransmitReceive(SPI_HandleTypeDef *hspi, const uint8_t *pTxData, uint8_t *pRxData,
uint16_t Size, uint32_t Timeout);
HAL_StatusTypeDef HAL_SPI_Transmit_IT(SPI_HandleTypeDef *hspi, const uint8_t *pData, uint16_t Size);
HAL_StatusTypeDef HAL_SPI_Receive_IT(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size);
HAL_StatusTypeDef HAL_SPI_TransmitReceive_IT(SPI_HandleTypeDef *hspi, const uint8_t *pTxData, uint8_t *pRxData,
uint16_t Size);
HAL_StatusTypeDef HAL_SPI_Transmit_DMA(SPI_HandleTypeDef *hspi, const uint8_t *pData, uint16_t Size);
HAL_StatusTypeDef HAL_SPI_Receive_DMA(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size);
HAL_StatusTypeDef HAL_SPI_TransmitReceive_DMA(SPI_HandleTypeDef *hspi, const uint8_t *pTxData, uint8_t *pRxData,
uint16_t Size);
HAL_StatusTypeDef HAL_SPI_DMAPause(SPI_HandleTypeDef *hspi);
HAL_StatusTypeDef HAL_SPI_DMAResume(SPI_HandleTypeDef *hspi);
HAL_StatusTypeDef HAL_SPI_DMAStop(SPI_HandleTypeDef *hspi);
/* Transfer Abort functions */
HAL_StatusTypeDef HAL_SPI_Abort(SPI_HandleTypeDef *hspi);
HAL_StatusTypeDef HAL_SPI_Abort_IT(SPI_HandleTypeDef *hspi);
SPI发送接收,收发一体函数,以及DMA暂停恢复停止,SPI通讯中断
SPI读写W25Q64
按照江科大的配置来配置CubeMx
全双工主模式,数据宽度为8位,高位先行,波特率分频为128,CPOL为低,CPOA为1
NSS为软件触发(GPIO那边配置PA4为推完输出模式)
首先说一个通用的错误,我们得把数据的获取和处理,放在初始化函数后面...
CubeMx生成的初始化结构注释太多是带点混乱的,注意这个问题即可。
主函数我们直接把江科大的cv过来即可,对于SPI.c这个文件,我们需要进行修改,把江科大的SPI相关函数全部修改成hal库版本的SPI函数.
通过对GPIO口的PA4进行操作来选择时序的开启和关闭。
void MySPI_Start(void)
{
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,GPIO_PIN_RESET);//根据BitValue,设置SS引脚的电平//拉低SS,开始时序
}
void MySPI_Stop(void)
{
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,GPIO_PIN_SET); //拉高SS,终止时序
}
void W25Q64_ReadID(uint8_t *MID, uint16_t *DID)
{
uint8_t gid[3];
uint8_t id = W25Q64_JEDEC_ID;
MySPI_Start(); //SPI起始
HAL_SPI_Transmit(&hspi1,&id,1,1000);
HAL_SPI_Receive(&hspi1,gid,3,1000);//一次性接收三位数据
MySPI_Stop(); //SPI终止
*MID = gid[0]; //交换接收MID,通过输出参数返回
*DID = (gid[1] << 8) | gid[2]; //高8位移到高位,或上交换接收DID的低8位,通过输出参数返回
}
void W25Q64_ReadID(uint8_t *MID, uint16_t *DID)
{
MySPI_Start(); //SPI起始
MySPI_SwapByte(W25Q64_JEDEC_ID); //交换发送读取ID的指令
*MID = MySPI_SwapByte(W25Q64_DUMMY_BYTE); //交换接收MID,通过输出参数返回
*DID = MySPI_SwapByte(W25Q64_DUMMY_BYTE); //交换接收DID高8位
*DID <<= 8; //高8位移到高位
*DID |= MySPI_SwapByte(W25Q64_DUMMY_BYTE); //或上交换接收DID的低8位,通过输出参数返回
MySPI_Stop(); //SPI终止
}
江科大的交换函数我们可以通过hal库自带的交换函数来实现
HAL_SPI_TransmitReceive()
或者说对于数据的收发,我们通过hal库的收发函数来进行。
其他的几个函数也是通过类似的手段进行修改即可。
void W25Q64_WriteEnable(void)
{
uint8_t temp = W25Q64_WRITE_ENABLE;
MySPI_Start(); //SPI起始
HAL_SPI_Transmit(&hspi1,&temp,1,1000); //发送写使能的指令
MySPI_Stop(); //SPI终止
}
void W25Q64_WriteEnable(void)
{
MySPI_Start(); //SPI起始
MySPI_SwapByte(W25Q64_WRITE_ENABLE); //交换发送写使能的指令
MySPI_Stop(); //SPI终止
}
void W25Q64_WaitBusy(void)
{
uint32_t Timeout;
uint8_t temp = W25Q64_READ_STATUS_REGISTER_1;
MySPI_Start(); //SPI起始
HAL_SPI_Transmit(&hspi1,&temp,1,1000); //交换发送读状态寄存器1的指令
Timeout = 100000; //给定超时计数时间
HAL_SPI_Receive(&hspi1,&temp,1,1000);
while ((temp & 0x01) == 0x01) //循环等待忙标志位
{
HAL_SPI_Receive(&hspi1,&temp,1,1000);
Timeout --; //等待时,计数值自减
if (Timeout == 0) //自减到0后,等待超时
{
/*超时的错误处理代码,可以添加到此处*/
break; //跳出等待,不等了
}
}
MySPI_Stop(); //SPI终止
}
void W25Q64_WaitBusy(void)
{
uint32_t Timeout;
MySPI_Start(); //SPI起始
MySPI_SwapByte(W25Q64_READ_STATUS_REGISTER_1); //交换发送读状态寄存器1的指令
Timeout = 100000; //给定超时计数时间
while ((MySPI_SwapByte(W25Q64_DUMMY_BYTE) & 0x01) == 0x01) //循环等待忙标志位
{
Timeout --; //等待时,计数值自减
if (Timeout == 0) //自减到0后,等待超时
{
/*超时的错误处理代码,可以添加到此处*/
break; //跳出等待,不等了
}
}
MySPI_Stop(); //SPI终止
}
void W25Q64_PageProgram(uint32_t Address, uint8_t *DataArray, uint16_t Count)
{
uint8_t temp[4];
temp[0] = W25Q64_PAGE_PROGRAM;
temp[1] = (Address >> 16);
temp[2] = (Address >> 8);
temp[3] = (Address);
W25Q64_WriteEnable(); //写使能
MySPI_Start(); //SPI起始
HAL_SPI_Transmit(&hspi1,temp,4,1000); //交换发送页编程的指令,交换发送地址23~16位,交换发送地址15~8位,交换发送地址7~0位
HAL_SPI_Transmit(&hspi1,DataArray,Count,1000);//循环Count次,依次在起始地址后写入数据
MySPI_Stop(); //SPI终止
W25Q64_WaitBusy(); //等待忙
}
void W25Q64_PageProgram(uint32_t Address, uint8_t *DataArray, uint16_t Count)
{
uint16_t i;
W25Q64_WriteEnable(); //写使能
MySPI_Start(); //SPI起始
MySPI_SwapByte(W25Q64_PAGE_PROGRAM); //交换发送页编程的指令
MySPI_SwapByte(Address >> 16); //交换发送地址23~16位
MySPI_SwapByte(Address >> 8); //交换发送地址15~8位
MySPI_SwapByte(Address); //交换发送地址7~0位
for (i = 0; i < Count; i ++) //循环Count次
{
MySPI_SwapByte(DataArray[i]); //依次在起始地址后写入数据
}
MySPI_Stop(); //SPI终止
W25Q64_WaitBusy(); //等待忙
}
void W25Q64_SectorErase(uint32_t Address)
{
uint8_t temp[4];
temp[0] = W25Q64_SECTOR_ERASE_4KB;
temp[1] = (Address >> 16);
temp[2] = (Address >> 8);
temp[3] = (Address);
W25Q64_WriteEnable(); //写使能
MySPI_Start(); //SPI起始
HAL_SPI_Transmit(&hspi1,temp,4,1000); //交换发送扇区擦除的指令
MySPI_Stop(); //SPI终止
W25Q64_WaitBusy(); //等待忙
}
void W25Q64_SectorErase(uint32_t Address)
{
W25Q64_WriteEnable(); //写使能
MySPI_Start(); //SPI起始
MySPI_SwapByte(W25Q64_SECTOR_ERASE_4KB); //交换发送扇区擦除的指令
MySPI_SwapByte(Address >> 16); //交换发送地址23~16位
MySPI_SwapByte(Address >> 8); //交换发送地址15~8位
MySPI_SwapByte(Address); //交换发送地址7~0位
MySPI_Stop(); //SPI终止
W25Q64_WaitBusy(); //等待忙
}
void W25Q64_ReadData(uint32_t Address, uint8_t *DataArray, uint32_t Count)
{
uint8_t temp[4];
temp[0] = W25Q64_READ_DATA;
temp[1] = (Address >> 16);
temp[2] = (Address >> 8);
temp[3] = (Address);
MySPI_Start(); //SPI起始
HAL_SPI_Transmit(&hspi1,temp,4,1000); //交换发送读取数据的指令
HAL_SPI_Receive(&hspi1,DataArray,Count,1000);//循环Count次,依次在起始地址后读取数据
MySPI_Stop(); //SPI终止
}
void W25Q64_ReadData(uint32_t Address, uint8_t *DataArray, uint32_t Count)
{
uint32_t i;
MySPI_Start(); //SPI起始
MySPI_SwapByte(W25Q64_READ_DATA); //交换发送读取数据的指令
MySPI_SwapByte(Address >> 16); //交换发送地址23~16位
MySPI_SwapByte(Address >> 8); //交换发送地址15~8位
MySPI_SwapByte(Address); //交换发送地址7~0位
for (i = 0; i < Count; i ++) //循环Count次
{
DataArray[i] = MySPI_SwapByte(W25Q64_DUMMY_BYTE); //依次在起始地址后读取数据
}
MySPI_Stop(); //SPI终止
}
修改Swap函数实现江科大
或者说按照江科大的写法自己修改swap函数和nss即可
void MySPI_W_SS(uint8_t BitValue)
{
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, (GPIO_PinState)BitValue); //根据BitValue,设置SS引脚的电平
}
/**
* 函 数:SPI交换传输一个字节,使用SPI模式0
* 参 数:ByteSend 要发送的一个字节
* 返 回 值:接收的一个字节
*/
uint8_t MySPI_SwapByte(uint8_t ByteSend)
{
uint8_t tx,rx;
tx = ByteSend;
HAL_SPI_TransmitReceive(&hspi1,&tx,&rx,1,1000);
return rx;
// while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) != SET); //等待发送数据寄存器空
//
// SPI_I2S_SendData(SPI1, ByteSend); //写入数据到发送数据寄存器,开始产生时序
//
// while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) != SET); //等待接收数据寄存器非空
//
// return SPI_I2S_ReceiveData(SPI1); //读取接收到的数据并返回
}
直接用hal库自带的交换函数来替换江科大的swap函数,在修改一下软件控制nss的GPIO函数就能完成移植,移植的时候别忘记头文件这些都得移植过来。