123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472 |
- #include"stdio.h"
- #include"string.h"
- #include"gpio.h"
- #include"W25Q64.h"
- #ifdef USE_W25Q64
- /*************<macro>******************/
- #define W25X16_DATA_BUF_LEN (520)//读取写入BUF长度
- #define W25X16_WRRD_DAT_ADDR (0x00)
- /*************<enum>*******************/
- /*************<union>******************/
- /*************<struct>*****************/
- /*************<variable>***************/
- 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;//读取写入计时
- /*************<prototype>**************/
- 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-------------------------------------------
|