STM32CubeMX系列教程11:串行外设接口SPI(二)
在W25QXX.c文件中有很多操作函数,这个只接收几个简单的函数。
/**
* @brief Read Manufacture/Device ID.
* @param return value address
* @retval None
*/
void BSP_W25Qx_Read_ID(uint8_t *ID)
{
uint8_t cmd[4] = {READ_ID_CMD,0x00,0x00,0x00};
W25Qx_Enable();
/* Send the read ID command */
HAL_SPI_Transmit(&hspi1, cmd, 4, W25Qx_TIMEOUT_VALUE);
/* Reception of the data */
HAL_SPI_Receive(&hspi1,ID, 2, W25Qx_TIMEOUT_VALUE);
W25Qx_Disable();
}如下为W25QXX读函数。函数开始先将要发送的数据(命令和地址)存储在cmd数组中,然后后通过HAL_SPI_Transmit()函数发送出去,接着通过HAL_SPI_Receive()接收读取的数据。
/**
* @brief Reads an amount of data from the QSPI memory.
* @param pData: Pointer to data to be read
* @param ReadAddr: Read start address
* @param Size: Size of data to read
* @retval QSPI memory status
*/
uint8_t BSP_W25Qx_Read(uint8_t* pData, uint32_t ReadAddr, uint32_t Size)
{
uint8_t cmd[4];
/* Configure the command */
cmd[0] = READ_CMD;
cmd[1] = (uint8_t)(ReadAddr >> 16);
cmd[2] = (uint8_t)(ReadAddr >> 8);
cmd[3] = (uint8_t)(ReadAddr);
W25Qx_Enable();
/* Send the read ID command */
HAL_SPI_Transmit(&hspi1, cmd, 4, W25Qx_TIMEOUT_VALUE);
/* Reception of the data */
if (HAL_SPI_Receive(&hspi1, pData,Size,W25Qx_TIMEOUT_VALUE) != HAL_OK)
{
return W25Qx_ERROR;
}
W25Qx_Disable();
return W25Qx_OK;
}如下为W25Qxx写操作函数,采用页编程指令(02H),每次最多可以写入256字节。所以写函数中将要写入的数据分多次写入W25Qxx中,每次只写256个字节,不断循环直到数据完全写完。写数据前先使能写操作。
/**
* @brief Writes an amount of data to the QSPI memory.
* @param pData: Pointer to data to be written
* @param WriteAddr: Write start address
* @param Size: Size of data to write,No more than 256byte.
* @retval QSPI memory status
*/
uint8_t BSP_W25Qx_Write(uint8_t* pData, uint32_t WriteAddr, uint32_t Size)
{
uint8_t cmd[4];
uint32_t end_addr, current_size, current_addr;
uint32_t tickstart = HAL_GetTick();
/* Calculation of the size between the write address and the end of the page */
current_addr = 0;
while (current_addr <= WriteAddr)
{
current_addr += W25Q128FV_PAGE_SIZE;
}
current_size = current_addr - WriteAddr;
/* Check if the size of the data is less than the remaining place in the page */
if (current_size > Size)
{
current_size = Size;
}
/* Initialize the adress variables */
current_addr = WriteAddr;
end_addr = WriteAddr + Size;
/* Perform the write page by page */
do
{
/* Configure the command */
cmd[0] = PAGE_PROG_CMD;
cmd[1] = (uint8_t)(current_addr >> 16);
cmd[2] = (uint8_t)(current_addr >> 8);
cmd[3] = (uint8_t)(current_addr);
/* Enable write operations */
BSP_W25Qx_WriteEnable();
W25Qx_Enable();
/* Send the command */
if (HAL_SPI_Transmit(&hspi1,cmd, 4, W25Qx_TIMEOUT_VALUE) != HAL_OK)
{
return W25Qx_ERROR;
}
/* Transmission of the data */
if (HAL_SPI_Transmit(&hspi1, pData,current_size, W25Qx_TIMEOUT_VALUE) != HAL_OK)
{
return W25Qx_ERROR;
}
W25Qx_Disable();
/* Wait the end of Flash writing */
while(BSP_W25Qx_GetStatus() == W25Qx_BUSY);
{
/* Check for the Timeout */
if((HAL_GetTick() - tickstart) > W25Qx_TIMEOUT_VALUE)
{
return W25Qx_TIMEOUT;
}
}
/* Update the address and size variables for next page programming */
current_addr += current_size;
pData += current_size;
current_size = ((current_addr + W25Q128FV_PAGE_SIZE) > end_addr) ? (end_addr - current_addr) : W25Q128FV_PAGE_SIZE;
} while (current_addr < end_addr);
return W25Qx_OK;
}扇区擦除函数,和写函数一样,擦除扇区前必先使能写操作。发送扇区擦除指令后不断读取W25Qxx的状态寄存器,判断flash是否为忙状态,如果不为忙则擦除操作完成。
/**
* @brief Erases the specified block of the QSPI memory.
* @param BlockAddress: Block address to erase
* @retval QSPI memory status
*/
uint8_t BSP_W25Qx_Erase_Block(uint32_t Address)
{
uint8_t cmd[4];
uint32_t tickstart = HAL_GetTick();
cmd[0] = SECTOR_ERASE_CMD;
cmd[1] = (uint8_t)(Address >> 16);
cmd[2] = (uint8_t)(Address >> 8);
cmd[3] = (uint8_t)(Address);
/* Enable write operations */
BSP_W25Qx_WriteEnable();
/*Select the FLASH: Chip Select low */
W25Qx_Enable();
/* Send the read ID command */
HAL_SPI_Transmit(&hspi1, cmd, 4, W25Qx_TIMEOUT_VALUE);
/*Deselect the FLASH: Chip Select high */
W25Qx_Disable();
/* Wait the end of Flash writing */
while(BSP_W25Qx_GetStatus() == W25Qx_BUSY);
{
/* Check for the Timeout */
if((HAL_GetTick() - tickstart) > W25Q128FV_SECTOR_ERASE_MAX_TIME)
{
return W25Qx_TIMEOUT;
}
}
return W25Qx_OK;
}在main.c文件中声明变量,rData,wData分别存储读写的数据,ID存储读取的ID值。
/* USER CODE BEGIN PV */ /* Private variables ---------------------------------------------------------*/ uint8_t wData[0x100]; uint8_t rData[0x100]; uint32_t i; uint8_t ID[2]; /* USER CODE END PV */
在main函数中添加如下测试程序。
/* USER CODE BEGIN 2 */
printf("\r\n SPI-W25Qxxx Example \r\n\r\n");
/*##-1- Read the device ID ########################*/
BSP_W25Qx_Init();
BSP_W25Qx_Read_ID(ID);
printf(" W25Qxxx ID is : 0x%02X 0x%02X \r\n\r\n",ID[0],ID[1]);
/*##-2- Erase Block ##################################*/
if(BSP_W25Qx_Erase_Block(0) == W25Qx_OK)
printf(" SPI Erase Block ok\r\n");
else
Error_Handler();
/*##-3- Written to the flash ########################*/
/* fill buffer */
for(i =0;i<0x100;i ++)
{
wData[i] = i;
rData[i] = 0;
}
if(BSP_W25Qx_Write(wData,0x00,0x100)== W25Qx_OK)
printf(" SPI Write ok\r\n");
else
Error_Handler();
/*##-4- Read the flash ########################*/
if(BSP_W25Qx_Read(rData,0x00,0x100)== W25Qx_OK)
printf(" SPI Read ok\r\n\r\n");
else
Error_Handler();
printf("SPI Read Data : \r\n");
for(i =0;i<0x100;i++)
printf("0x%02X ",rData[i]);
printf("\r\n\r\n");
/*##-5- check date ########################*/
if(memcmp(wData,rData,0x100) == 0 )
printf(" W25Q128FV SPI Test OK\r\n");
else
printf(" W25Q128FV SPI Test False\r\n");
/* USER CODE END 2 */把程序中用的出错处理函数添加在main.c文件后面。
/* USER CODE BEGIN 4 */
/**
* @brief This function is executed in case of error occurrence.
* @param None
* @retval None
*/
static void Error_Handler(void)
{
printf("something wrong ....\r\n");
/* User may add here some code to deal with this error */
while(1)
{
}
}
/* USER CODE END 4 */在main.c文件开头添加应用的头文件。
/* USER CODE BEGIN Includes */ #include <string.h> #include "W25QXX.h" /* USER CODE END Includes */</string.h>
将W25QXX DataFlash Board模块插入到Open746I开发板SPI1中,编译程序并下载到开发板。打开串口调试助手。设置波特率为115200。串口助手上会显示如下信息。



















支付宝打赏
微信打赏 
