#include"stdio.h" #include"string.h" #include"gpio.h" #include"W25Q64.h" #ifdef USE_W25Q64 /*******************************/ #define W25X16_DATA_BUF_LEN (520)//读取写入BUF长度 #define W25X16_WRRD_DAT_ADDR (0x00) /********************************/ /*******************************/ /******************************/ /****************************/ uint8_t g_flashWrDataBuf[W25X16_DATA_BUF_LEN]; uint8_t g_flashRdDataBuf[W25X16_DATA_BUF_LEN]; #ifdef W25Q64_TEST #define W25X16_TEST_DAT_LEN (512)//测试数据BUF长度 uint8_t g_flshTstDataBuf[W25X16_TEST_DAT_LEN]; #endif uint8_t g_flashWrRdRdy; uint16_t g_flashWrRdTime;//读取写入计时 /***************************/ void SPI1_Callback(void *device, uint32_t wpara, uint32_t lpara); //static uint8_t W25Q64_IsBusy(void); //static void W25Q64_EnableWr(void); /** * @prototype W25Q64_Init(void) * * @param[in] void * @return void * * @brief 初始化 W25Q64. */ void W25Q64_Init(void) { SPI_ConfigType spiConfig; /*初始化SPI引脚,功能复用选择.*/ //GPIO_SetFunc(GPIOB, GPIO_PIN15, GPIO_FUN3);//SCK //GPIO_SetFunc(GPIOB, GPIO_PIN14, GPIO_FUN3);//MOSI //GPIO_SetFunc(GPIOC, GPIO_PIN0, GPIO_FUN3);//MISO //GPIO_SetFunc(GPIOC, GPIO_PIN1, GPIO_FUN3);//CS /*清零配置结构体变量.*/ memset(&spiConfig, 0x00, sizeof(spiConfig)); /*初始化SPI参数,波特率 = 2Mbps = (F_BCLK / (SCK_LOW+1 + SCK_HIGH+1)).*/ spiConfig.csSetup = 4;/*片选建立时间 = (CS_SETUP + 1) * CLK_PERIOD.*/ spiConfig.csHold = 4;/*片选保持时间 = (CS_HOLD + 1) * CLK_PERIOD.*/ spiConfig.sckHigh = 5;/*SCK高电平时间 = (SCK_HIGH + 1) * CLK_PERIOD.*/ spiConfig.sckLow = 5;/*SCK低电平时间 = (SCK_LOW + 1) * CLK_PERIOD.*/ spiConfig.csIdle = 4;/*两条数据间最短时间间隔 = (CS_IDLE + 1) * CLK_PERIOD.*/ spiConfig.mode = SPI_MASTER;//设置为主机模式 spiConfig.cpha = SPI_CPHA_2EDGE;//设置数据采样相位,第2个边沿采样数据 spiConfig.cpol = SPI_CPOL_HIGH;//设置SCK空闲时极性,空闲时SCK为低 spiConfig.frmSize = SPI_FRAME_SIZE_8BITS; spiConfig.rxMsbFirstEn = ENABLE;//选择从最高位开始接收 spiConfig.txMsbFirstEn = ENABLE;//选择从最高位开始发送 spiConfig.csOutputEn = ENABLE;//CS有SPI硬件控制 spiConfig.continuousCSEn= ENABLE;//片选连续模式 spiConfig.dmaRxEn = DISABLE;//禁止使用DMA接收数据 spiConfig.dmaTxEn = DISABLE;//禁止使用DMA发送数据 spiConfig.modeFaultEn = DISABLE;//模式故障禁止 spiConfig.wakeUpEn = DISABLE;//主机模式不支持唤醒功能 spiConfig.spiEn = ENABLE; spiConfig.callBack = SPI1_Callback; spiConfig.interruptEn = ENABLE;//使能NVIC中断 spiConfig.txUFInterruptEn = ENABLE;//打开TXUF中断,可禁止 spiConfig.rxOFInterruptEn = ENABLE;//打开RXOF中断,可禁止 spiConfig.modeFaultInterruptEn = DISABLE;//模式故障中断 SPI_Init(SPI1, &spiConfig); while( 0 == W25Q64_isGood()){ mdelay(1); } } /** * @prototype W25Q64_IsBusy(void) * * @param[in] void * @return 0->Not busy. 1->Busy. * * @brief 判断W25X16是否忙. */ static uint8_t W25Q64_IsBusy(void) { udelay(3); g_flashWrDataBuf[0] = W25Q64_rSTATUS_REG_CMD; SPI_TransmitReceivePoll(SPI1, g_flashRdDataBuf, g_flashWrDataBuf, 2); //printf("W25Q64_IsBusy 0x%x \r\n", g_flashRdDataBuf[1]); return (g_flashRdDataBuf[1] & W25Q64_BUSY_MSK); } static void W25Q64_Wait_Busy(void) { while(W25Q64_IsBusy()); } /** * @prototype W25Q64_EnableWr(void) * * @param[in] void * @return void * * @brief 使能写W25Q64. */ static void W25Q64_EnableWr(void) { /*先判断W25Q64是否忙.空闲时才能进行操作.*/ while(W25Q64_IsBusy()); g_flashWrDataBuf[0] = W25Q64_WRITE_ENABLE_CMD; SPI_TransmitPoll(SPI1, g_flashWrDataBuf, 1); } /** * @prototype W25Q64_DisableWr(void) * * @param[in] void * @return void * * @brief 禁止写W25Q64. */ static void W25Q64_DisableWr(void) { /*先判断W25Q64是否忙.空闲时才能进行操作.*/ while(W25Q64_IsBusy()); g_flashWrDataBuf[0] = W25Q64_WRITE_DISABLE_CMD; SPI_TransmitPoll(SPI1, g_flashWrDataBuf, 1); } /** * @prototype W25Q64_ReadBytes(uint32_t startAddr, uint8_t *pDataBuf, uint16_t dataLen) * * @param[in] startAddr: 起始地址 * @param[in] pDataBuf: 数据缓存 * @param[in] dataLen: 数据长度 * @return void * * @brief 从W25Q64读取指定长度字节数据. */ void W25Q64_ReadBytes(uint32_t startAddr, uint8_t *pDataBuf, uint16_t dataLen) { while(W25Q64_IsBusy()); //printf("W25Q64_ReadBytes 111 \r\n "); g_flashWrDataBuf[0] = W25Q64_READ_DATA_CMD; g_flashWrDataBuf[1] = (startAddr >> 16); g_flashWrDataBuf[2] = (startAddr >> 8); g_flashWrDataBuf[3] = (startAddr >> 0); SPI_TransmitReceivePoll(SPI1, g_flashRdDataBuf, g_flashWrDataBuf, (dataLen + 4));//可读取任意长度数据 //printf("W25Q64_ReadBytes 222 \r\n "); memcpy(pDataBuf, &g_flashRdDataBuf[4], dataLen); } /** * @prototype W25Q64_WriteBytes(uint32_t startAddr, uint8_t *pDataBuf, uint16_t dataLen) * * @param[in] startAddr: 起始地址 * @param[in] pDataBuf: 数据缓存 * @param[in] dataLen: 数据长度 * @return void * * @brief 向W25Q64写入指定长度字节数据. */ void W25Q64_WriteBytes(uint32_t startAddr, uint8_t *pDataBuf, uint16_t dataLen) { uint8_t ii,restLen, wrTimes; if ((startAddr + dataLen-1) > W25Q64_ADDR_MAX){return;} restLen = (dataLen % PAGE_SIZE);//少于256字节长度 wrTimes = (dataLen / PAGE_SIZE);//每次最多写入256字节 /*满足256字节的数据写入.*/ for (ii = 0; ii < wrTimes; ii++) { /*使能写.*/ W25Q64_EnableWr(); /*写入数据.*/ g_flashWrDataBuf[0] = W25Q64_PAGE_WRITE_CMD; g_flashWrDataBuf[1] = (startAddr >> 16); g_flashWrDataBuf[2] = (startAddr >> 8); g_flashWrDataBuf[3] = (startAddr >> 0); memcpy(&g_flashWrDataBuf[4], &pDataBuf[ii * PAGE_SIZE], PAGE_SIZE);//单次写入最多256字节 SPI_TransmitPoll(SPI1, g_flashWrDataBuf, (PAGE_SIZE + 4)); startAddr += PAGE_SIZE; } /*不足256字节的数据写入.*/ if (restLen > 0) { /*使能写.*/ W25Q64_EnableWr(); /*写入数据.*/ g_flashWrDataBuf[0] = W25Q64_PAGE_WRITE_CMD; g_flashWrDataBuf[1] = (startAddr >> 16); g_flashWrDataBuf[2] = (startAddr >> 8); g_flashWrDataBuf[3] = (startAddr >> 0); //memcpy(&g_flashWrDataBuf[4], &pDataBuf[wrTimes * 256], restLen); memcpy(&g_flashWrDataBuf[4], &pDataBuf[wrTimes * PAGE_SIZE], restLen); SPI_TransmitPoll(SPI1, g_flashWrDataBuf, (restLen + 4)); } } /** * @prototype W25Q64_ErsSector(uint32_t startAddr, uint8_t secErNum) * * @param[in] startAddr:擦除 sector 对齐 * @param[in] secErNum:需要擦除的sec数 * @return void * * @brief 擦除W25Q64. */ void W25Q64_ErsSector(uint32_t startAddr, uint8_t secErNum) { uint8_t ii; if (0 != startAddr%SECTOR_SIZE ){return;} if ((startAddr + secErNum*SECTOR_SIZE -1) > W25Q64_ADDR_MAX){return;} for (ii = 0; ii < secErNum; ii++) { /*使能写,在擦除、写入后自动关闭写.*/ W25Q64_EnableWr(); /*装载擦除指令,并发送指令.*/ g_flashWrDataBuf[0] = W25Q64_SECTOR_ERASE_CMD; g_flashWrDataBuf[1] = (startAddr >> 16); g_flashWrDataBuf[2] = (startAddr >> 8); g_flashWrDataBuf[3] = (startAddr >> 0); SPI_TransmitPoll(SPI1, g_flashWrDataBuf, 4); startAddr += SECTOR_SIZE; } } /** * @prototype W25Q64_ErsBlock(uint32_t startAddr, uint8_t blkErNum) * * @param[in] startAddr:擦除 BLOCK 对齐 * @param[in] blkErNum:需要擦除的blk数 * @return void * * @brief 擦除W25Q64 */ void W25Q64_ErsBlock(uint32_t startAddr, uint8_t blkErNum) { uint8_t ii; if (0 != startAddr%BLOCK_SIZE ){return;} if ((startAddr + blkErNum*BLOCK_SIZE -1) > W25Q64_ADDR_MAX){return;} for (ii = 0; ii < blkErNum; ii++) { /*使能写,在擦除、写入后自动关闭写.*/ W25Q64_EnableWr(); /*装载擦除指令,并发送指令.*/ g_flashWrDataBuf[0] = W25Q64_BLOCK_ERASE_CMD; g_flashWrDataBuf[1] = (startAddr >> 16); g_flashWrDataBuf[2] = (startAddr >> 8); g_flashWrDataBuf[3] = (startAddr >> 0); SPI_TransmitPoll(SPI1, g_flashWrDataBuf, 4); startAddr += BLOCK_SIZE; } } /** * @prototype W25Q64_ErsChip(void) * * @return void * * @brief 擦除W25Q64. */ void W25Q64_ErsChip(void) { /*使能写,在擦除、写入后自动关闭写.*/ W25Q64_EnableWr(); /*装载擦除指令,并发送指令.*/ g_flashWrDataBuf[0] = W25Q64_CHIP_ERASE_CMD; SPI_TransmitPoll(SPI1, g_flashWrDataBuf, 1); } //Power Down mode void W25Q64_Power_Down() { /*先判断W25Q64是否忙.空闲时才能进行操作.*/ //while(W25Q64_IsBusy()); g_flashWrDataBuf[0] = W25Q64_PWR_DOWN_CMD; SPI_TransmitPoll(SPI1, g_flashWrDataBuf, 1); } //Weka up Mode void W25Q64_ReleasePowerDown(void) { /*先判断W25Q64是否忙.空闲时才能进行操作.*/ //while(W25Q64_IsBusy()); g_flashWrDataBuf[0] = W25Q64_RELEASE_PWR_DOWN_CMD; SPI_TransmitPoll(SPI1, g_flashWrDataBuf, 1); } /** * @prototype SPI1_Callback(void *device, uint32_t wpara, uint32_t lpara) * * @param[in] ... * @return void * * @brief SPI1中断回调函数. */ void SPI1_Callback(void *device, uint32_t wpara, uint32_t lpara) { if (wpara & SPI_STATUS_TXUF_Msk) { //TX下溢处理 } else if (wpara & SPI_STATUS_RXOF_Msk) { //RX溢出处理 } } //ID uint32_t W25Q64_ReadDevID(void) { uint32_t dev_id=0; g_flashWrDataBuf[0] = W25Q64_JEDEC_DEVICE_ID; SPI_TransmitReceivePoll(SPI1, g_flashRdDataBuf, g_flashWrDataBuf, 4);//可读取任意长度数据 dev_id = (uint32_t)((uint32_t)g_flashRdDataBuf[1]<<16)| ((uint32_t)g_flashRdDataBuf[2]<<8)| g_flashRdDataBuf[3]; return dev_id; } uint8_t W25Q64_isGood(void) { g_flashWrDataBuf[0] = W25Q64_JEDEC_DEVICE_ID; SPI_TransmitReceivePoll(SPI1, g_flashRdDataBuf, g_flashWrDataBuf, 4);//可读取任意长度数据 if(0xef == g_flashRdDataBuf[1]){ return 1; }else{ return 0; } } #ifdef W25Q64_TEST /* ################################################################## */ /** * @prototype W25Q64_ReadDataTest(void) * * @param[in] void * @return void * * @brief 测试W25Q64读取功能. */ void W25Q64_ReadDataTest(void) { /*准备计时.*/ g_flashWrRdRdy = 1; g_flashWrRdTime = 0; /*读取数据.*/ memset(g_flshTstDataBuf, 0x00, W25X16_TEST_DAT_LEN); printf("W25Q64_ReadDataTest 1111\r\n"); W25Q64_ReadBytes(W25X16_WRRD_DAT_ADDR, g_flshTstDataBuf, W25X16_TEST_DAT_LEN); printf("W25Q64_ReadDataTest 2222\r\n"); /*停止计时.*/ g_flashWrRdRdy = 0; /*打印数据和时间.*/ for (uint16_t ii = 0; ii < W25X16_TEST_DAT_LEN; ii++) { printf("%d ", g_flshTstDataBuf[ii]); } printf("\r\n"); printf("Read W25Q64 1K bytes time is: %d ms", g_flashWrRdTime); printf("\r\n"); } /** * @prototype W25Q64_WriteDataTest(void) * * @param[in] void * @return void * * @brief 测试W25Q64写功能. */ void W25Q64_WriteDataTest(void) { /*擦除数据.*/ W25Q64_ErsSector(W25X16_WRRD_DAT_ADDR, 1);//擦除1个扇区4KB /*准备数据.*/ for (uint16_t ii = 0; ii < W25X16_TEST_DAT_LEN; ii++) { g_flshTstDataBuf[ii] = ii/10; printf("%d ", g_flshTstDataBuf[ii]); } printf("\r\n"); /*准备计时.*/ g_flashWrRdRdy = 1; g_flashWrRdTime = 0; /*写入数据.*/ W25Q64_WriteBytes(W25X16_WRRD_DAT_ADDR, g_flshTstDataBuf, W25X16_TEST_DAT_LEN); /*停止计时.*/ g_flashWrRdRdy = 0; /*打印时间.*/ printf("Write W25Q64 1K bytes time is: %d ms", g_flashWrRdTime); printf("\r\n"); } #endif void W25Q64_PrintInfo(void) { printf("\r\n"); printf("W25Q64 DeviceID: 0x%x", W25Q64_ReadDevID()); printf("\r\n"); } #endif //------------------------------- End-------------------------------------------