STM32F103访问W25Q64

STM32F103的W25Q64的DMA高效数据访问实现

1. 关于DMA

首先任何FLASH的写操作都是非常耗时的,体现在擦除FLASH上,且写操作不能太频繁,故而用DMA方式实现写操作程序逻辑会非常复杂,程序逻辑在各种中断处理中容易乱,与之相反采用DMA读大批量数据时及具有优势.
比如36MHzSPI时种,采用轮询方式读一页数据需要花费250us时间,二用了DMA后只需要80us时间,提高了三倍还多,且启动DMA只需要5us,节省了245us时间.

2. W25Q64实用的函数

① 读ID号,用于确定芯片是否能正常访问
② 轮询方式读数据
③ 擦除指令
④ 写一页数据指令,(事先要擦除)
⑤ DMA方式读取一块数据

3. 程序正文W25Q64.c

[cpp]  view plain  copy
  1. /*********************************Copyright (c)********************************* 
  2. **                                
  3. **                                 FIVE工作组 
  4. ** 
  5. **---------------------------------File Info------------------------------------ 
  6. ** File Name:               w25q64.c 
  7. ** Last modified Date:      2013/9/10 9:32:33 
  8. ** Last Version:            V1.2    
  9. ** Description:             none 
  10. ** 
  11. **------------------------------------------------------------------------------ 
  12. ** Created By:              wanxuncpx 
  13. ** Created date:            2013/8/6 21:12:35 
  14. ** Version:                 V1.2 
  15. ** Descriptions:            none 
  16. **------------------------------------------------------------------------------ 
  17. ** HW_CMU:                  STM32F103ZET6 
  18. ** Libraries:               STM32F10x_StdPeriph_Driver 
  19. ** version                  V3.5 
  20. *******************************************************************************/  
  21.   
  22.   
  23. /****************************************************************************** 
  24. 更新说明: 
  25. ******************************************************************************/  
  26.   
  27.   
  28.   
  29.   
  30. /****************************************************************************** 
  31. *********************************  应 用 资 料 ******************************** 
  32. ******************************************************************************/  
  33.   
  34.   
  35.   
  36.   
  37. /****************************************************************************** 
  38. ********************************* 文件引用部分 ******************************** 
  39. ******************************************************************************/  
  40. #include "w25q64.h"  
  41.   
  42.   
  43. /****************************************************************************** 
  44. ********************************* 数 据 声 明 ********************************* 
  45. ******************************************************************************/  
  46. /*---------------------*  
  47. *     数据定义(输出) 
  48. *----------------------*/  
  49. uint8_t W25X_Buffer[W25X_SECTOR_SIZE];  
  50. volatile bool sem_W25X_DMA_Busy = true;  
  51. volatile bool sem_W25X_DMA_RxRdy= false;  
  52.   
  53.   
  54. /*---------------------*  
  55. *       数据定义(内部用)  
  56. *----------------------*/  
  57. static uint8_t  W25X_TX_Byte=0xFF;  
  58.   
  59.   
  60.   
  61.   
  62.   
  63.   
  64. /****************************************************************************** 
  65. ********************************* 函 数 声 明 ********************************* 
  66. ******************************************************************************/  
  67. /****************************************************************************** 
  68. / 函数功能:初始化W25Q64的GPIO口连接 
  69. / 修改日期:2013/9/10 19:04:15 
  70. / 输入参数:none 
  71. / 输出参数:none 
  72. / 使用说明:none 
  73. ******************************************************************************/  
  74. void W25X_GPIO_Config(void)  
  75. {  
  76.     /* Private typedef ---------------------------------------------------------*/  
  77.     GPIO_InitTypeDef GPIO_InitStruct;  
  78.   
  79.   
  80.   
  81.   
  82.     /** SPI1 GPIO Configuration  
  83.          PA5     ------> SPI1_SCK 
  84.          PA6     ------> SPI1_MISO 
  85.          PA7     ------> SPI1_MOSI 
  86.     */  
  87.     /*Enable or disable APB2 peripheral clock */  
  88.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);  
  89.   
  90.   
  91.     /*Configure GPIO pin */  
  92.     GPIO_InitStruct.GPIO_Pin = GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7;  
  93.     GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;  
  94.     GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;  
  95.     GPIO_Init(GPIOA, &GPIO_InitStruct);  
  96.   
  97.   
  98.     /** Configure pins as GPIO 
  99.          PA4     ------> GPIO_Output 
  100.          PB0     ------> GPIO_Output 
  101.     */  
  102.     /*Enable or disable APB2 peripheral clock */  
  103.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB, ENABLE);  
  104.     W25X_WP_EN();  
  105.     W25X_CS_H();  
  106.       
  107.     /*Configure GPIO pin */  
  108.     GPIO_InitStruct.GPIO_Pin = GPIO_Pin_4;  
  109.     GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;  
  110.     GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;  
  111.     GPIO_Init(GPIOA, &GPIO_InitStruct);  
  112.   
  113.   
  114.     /*Configure GPIO pin */  
  115.     GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0;  
  116.     GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;  
  117.     GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;  
  118.     GPIO_Init(GPIOB, &GPIO_InitStruct);   
  119.       
  120.     /*Lock of the gpio */  
  121.     GPIO_PinLockConfig(GPIOA,GPIO_Pin_4);  
  122.     GPIO_PinLockConfig(GPIOB,GPIO_Pin_0);  
  123. }  
  124.   
  125.   
  126. /****************************************************************************** 
  127. / 函数功能:初始化W25Q64 
  128. / 修改日期:2013/9/10 19:04:16 
  129. / 输入参数:none 
  130. / 输出参数:none 
  131. / 使用说明:none 
  132. ******************************************************************************/  
  133. void W25X_Init(void)  
  134. {  
  135.     SPI_InitTypeDef  SPI_InitStructure ;  
  136.     DMA_InitTypeDef  DMA_InitStructure;  
  137.     NVIC_InitTypeDef NVIC_InitStructure;  
  138.       
  139.     //配置DMA通道,DMA1_CH2收  
  140.     //读取SPI FLASH时多数为空数据故而数据地址无需增加  
  141.     //启动DMA1的时钟  
  142.     RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);  
  143.     DMA_DeInit(DMA1_Channel2);  
  144.     DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(&SPI1->DR);  
  145.     DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)W25X_Buffer;  
  146.     DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;  
  147.     DMA_InitStructure.DMA_BufferSize = 0;  
  148.     DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;  
  149.     DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;  
  150.     DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;  
  151.     DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;  
  152.     DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;  
  153.     DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;  
  154.     DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;  
  155.     DMA_Init(DMA1_Channel2, &DMA_InitStructure);  
  156.   
  157.   
  158.     //配置DMA通道,DMA1_CH3发送  
  159.     DMA_DeInit(DMA1_Channel3);  
  160.     DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(&SPI1->DR);  
  161.     DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)(&W25X_TX_Byte);  
  162.     DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;  
  163.     DMA_InitStructure.DMA_BufferSize = 0;  
  164.     DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;  
  165.     DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable;  
  166.     DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;  
  167.     DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;  
  168.     DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;  
  169.     DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;  
  170.     DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;  
  171.     DMA_Init(DMA1_Channel3, &DMA_InitStructure);  
  172.       
  173.     //关闭DMA,清DMA标记,使能DMA1_CH2的传输完成中断  
  174.     DMA_Cmd(DMA1_Channel3, DISABLE);            //关闭发送DMA  
  175.     DMA_Cmd(DMA1_Channel2, DISABLE);            //关闭接收DMA  
  176.     DMA_ClearFlag(DMA1_FLAG_GL3|DMA1_FLAG_TC3|DMA1_FLAG_HT3|DMA1_FLAG_TE3);  
  177.     DMA_ClearFlag(DMA1_FLAG_GL2|DMA1_FLAG_TC2|DMA1_FLAG_HT2|DMA1_FLAG_TE2);  
  178.     DMA_ITConfig(DMA1_Channel2,DMA_IT_TC,ENABLE);  
  179.       
  180.     //初始化SPI时钟    
  181.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1,ENABLE);  
  182.   
  183.   
  184.     // SPI配置  
  185.     SPI_Cmd(SPI1,DISABLE);  
  186.     SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex ;  
  187.     SPI_InitStructure.SPI_Mode = SPI_Mode_Master ;  
  188.     SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b ;  
  189.     SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low ;  
  190.     SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge ;  
  191.     SPI_InitStructure.SPI_NSS = SPI_NSS_Soft ;  
  192.     SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2 ;    //72MHz分频  
  193.     SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB ; //SPI设置成LSB模式  
  194.     SPI_InitStructure.SPI_CRCPolynomial = 7 ;  
  195.     SPI_Init( SPI1, &SPI_InitStructure ) ;  
  196.     SPI_Cmd(SPI1,ENABLE);           //启动SPI  
  197.       
  198.     //打开SPI1的DMA发送接收请求  
  199.     SPI_I2S_DMACmd(SPI1, SPI_I2S_DMAReq_Rx, ENABLE);  
  200.     SPI_I2S_DMACmd(SPI1, SPI_I2S_DMAReq_Tx, ENABLE);  
  201.       
  202.     //清DMA忙信号  
  203.     sem_W25X_DMA_Busy = false;  
  204.       
  205.     //使能NVIC中断  
  206.     NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel2_IRQn;  
  207.     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;  
  208.     NVIC_InitStructure.NVIC_IRQChannelSubPriority = W25X_DMA_TC_PRIO;  
  209.     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;  
  210.     NVIC_Init(&NVIC_InitStructure);  
  211. }  
  212.   
  213.   
  214. /****************************************************************************** 
  215. / 函数功能:SPI发送一个字节的数据 
  216. / 修改日期:2013/9/10 19:04:16 
  217. / 输入参数:none 
  218. / 输出参数:none 
  219. / 使用说明:none 
  220. ******************************************************************************/  
  221. uint8_t W25X_ReadWriteByte(uint8_t dat)  
  222. {  
  223.     while ((SPI1->SR & SPI_I2S_FLAG_TXE) == (uint16_t)RESET);  
  224.     SPI1->DR = dat;  
  225.     while ((SPI1->SR & SPI_I2S_FLAG_RXNE) == (uint16_t)RESET);  
  226.     return (SPI1->DR);  
  227. }  
  228.   
  229.   
  230. /****************************************************************************** 
  231. / 函数功能:读取SPI_FLASH的状态寄存器 
  232. / 修改日期:2013/9/10 20:38:48 
  233. / 输入参数:none 
  234. / 输出参数:none 
  235. / 使用说明:none 
  236. /   BIT7  6   5   4   3   2   1   0 
  237. /   SPR   RV  TB BP2 BP1 BP0 WEL BUSY 
  238. / 
  239. /   SPR:默认0,状态寄存器保护位,配合WP使用 
  240. /   TB,BP2,BP1,BP0:FLASH区域写保护设置 
  241. /   WEL:写使能锁定, 1 
  242. /   BUSY:忙标记位(1,忙;0,空闲) 
  243. /   默认:0x00 
  244. ******************************************************************************/  
  245. uint8_t W25X_ReadSR(void)     
  246. {    
  247.     uint8_t byte=0;     
  248.     W25X_CS_L();                            //使能器件     
  249.     W25X_ReadWriteByte(W25X_ReadStatusReg); //发送读取状态寄存器命令      
  250.     byte=W25X_ReadWriteByte(0Xff);          //读取一个字节    
  251.     W25X_CS_H();                            //使能器件       
  252.     return byte;     
  253. }  
  254.   
  255.   
  256. /****************************************************************************** 
  257. / 函数功能:读取芯片ID 
  258. / 修改日期:2013/9/10 20:43:20 
  259. / 输入参数:none 
  260. / 输出参数: 
  261. /   返回值如下:        
  262. /   0XEF13,表示芯片型号为W25Q80   
  263. /   0XEF14,表示芯片型号为W25Q16     
  264. /   0XEF15,表示芯片型号为W25Q32   
  265. /   0XEF16,表示芯片型号为W25Q64  
  266. / 使用说明:none 
  267. ******************************************************************************/       
  268. uint16_t W25X_ReadID(void)  
  269. {  
  270.     uint16_t Temp = 0;  
  271.         
  272.     W25X_CS_L();         
  273.     W25X_ReadWriteByte(0x90);       //发送读取ID命令       
  274.     W25X_ReadWriteByte(0x00);        
  275.     W25X_ReadWriteByte(0x00);        
  276.     W25X_ReadWriteByte(0x00);           
  277.     Temp|=W25X_ReadWriteByte(0xFF)<<8;    
  278.     Temp|=W25X_ReadWriteByte(0xFF);    
  279.     W25X_CS_H();          
  280.     return Temp;  
  281. }   
  282.   
  283.   
  284. /****************************************************************************** 
  285. / 函数功能:等待芯片执行完毕 
  286. / 修改日期:2013/9/10 20:43:20 
  287. / 输入参数:none 
  288. / 输出参数:none 
  289. / 使用说明:none 
  290. ******************************************************************************/  
  291. void W25X_Wait_Busy(void)  
  292. {  
  293.     while((W25X_ReadSR()&0x01)==0x01);   // 等待BUSY位清空   
  294. }  
  295.   
  296.   
  297. /****************************************************************************** 
  298. / 函数功能:读取芯片看是否为忙 
  299. / 修改日期:2013/9/10 20:43:20 
  300. / 输入参数:none 
  301. / 输出参数:none 
  302. / 使用说明:none 
  303. ******************************************************************************/  
  304. bool W25X_Read_BusyState(void)  
  305. {  
  306.     if((W25X_ReadSR()&0x01))return true;  
  307.     else return false;    
  308. }  
  309.   
  310.   
  311. /****************************************************************************** 
  312. / 函数功能:SPI_FLASH写使能  
  313. / 修改日期:2013/9/10 20:43:20 
  314. / 输入参数:none 
  315. / 输出参数:none 
  316. / 使用说明:none 
  317. ******************************************************************************/   
  318. void W25X_Write_Enable(void)  
  319. {  
  320.     W25X_WP_EN();                           //打开硬件写使能  
  321.     W25X_CS_L();                            //使能器件     
  322.     W25X_ReadWriteByte(W25X_WriteEnable);   //发送写使能    
  323.     W25X_CS_H();                            //取消片选              
  324. }   
  325.   
  326.   
  327. /****************************************************************************** 
  328. / 函数功能:SPI_FLASH写禁止  
  329. / 修改日期:2013/9/10 20:43:20 
  330. / 输入参数:none 
  331. / 输出参数:none 
  332. / 使用说明:none 
  333. ******************************************************************************/  
  334. void W25X_Write_Disable(void)     
  335. {    
  336.     W25X_WP_DIS();                          //关闭硬件写使能  
  337.     W25X_CS_L();                            //使能器件     
  338.     W25X_ReadWriteByte(W25X_WriteDisable);  //发送写禁止指令      
  339.     W25X_CS_H();                            //取消片选                  
  340. }  
  341.   
  342.   
  343. /****************************************************************************** 
  344. / 函数功能:使SPI FLASH掉电  
  345. / 修改日期:2013/9/10 20:43:20 
  346. / 输入参数:none 
  347. / 输出参数:none 
  348. / 使用说明:none 
  349. ******************************************************************************/  
  350. void SPI_Flash_PowerDown(void)     
  351. {   
  352.     uint16_t i;  
  353.           
  354.     W25X_CS_L();                        //使能器件     
  355.     W25X_ReadWriteByte(W25X_PowerDown); //发送掉电命令    
  356.     W25X_CS_H();                        //取消片选              
  357.     i= (72)*3;while(i--);               //等待约3us  
  358. }  
  359.     
  360. /****************************************************************************** 
  361. / 函数功能:唤醒SPI FLASH 
  362. / 修改日期:2013/9/10 20:43:20 
  363. / 输入参数:none 
  364. / 输出参数:none 
  365. / 使用说明:none 
  366. ******************************************************************************/   
  367. void SPI_Flash_WakeUp(void)     
  368. {   
  369.     uint16_t i;  
  370.       
  371.     W25X_CS_L();                        //使能器件     
  372.     W25X_ReadWriteByte(W25X_ReleasePowerDown); //发送掉电命令    
  373.     W25X_CS_H();                        //取消片选  
  374.     i= (72)*3;while(i--);               //等待约3us  
  375. }  
  376.   
  377.   
  378. /****************************************************************************** 
  379. / 函数功能:擦除整个芯片 ,等待时间超长...  
  380. / 修改日期:2013/9/10 20:43:20 
  381. / 输入参数:none 
  382. / 输出参数:none 
  383. / 使用说明:none 
  384. ******************************************************************************/  
  385. void W25X_Erase_Chip(bool bwait)     
  386. {                                     
  387.     W25X_Write_Enable();            //SET WEL   
  388.     W25X_Wait_Busy();     
  389.     W25X_CS_L();                    //使能器件     
  390.     W25X_ReadWriteByte(W25X_ChipErase);   //发送片擦除命令    
  391.     W25X_CS_H();                    //取消片选  
  392.     if(bwait)W25X_Wait_Busy();      //等待芯片擦除结束  
  393. }  
  394.   
  395.   
  396. /****************************************************************************** 
  397. / 函数功能:擦除一个扇区 
  398. / 修改日期:2013/9/10 20:43:20 
  399. / 输入参数:Dst_Addr:扇区地址 根据实际容量设置 
  400. / 输出参数:none 
  401. / 使用说明:none擦除一个扇区的最少时间:65ms 
  402. ******************************************************************************/  
  403. void W25X_Erase_Sector(uint32_t Dst_Addr,bool bwait)     
  404. {    
  405.     W25X_Write_Enable();            //SET WEL     
  406.     W25X_Wait_Busy();     
  407.     W25X_CS_L();                    //使能器件      
  408.     W25X_ReadWriteByte(W25X_SectorErase);           //发送扇区擦除指令   
  409.     W25X_ReadWriteByte((uint8_t)((Dst_Addr)>>16));  //发送24bit地址      
  410.     W25X_ReadWriteByte((uint8_t)((Dst_Addr)>>8));     
  411.     W25X_ReadWriteByte((uint8_t)Dst_Addr);    
  412.     W25X_CS_H();                    //取消片选  
  413.     if(bwait)W25X_Wait_Busy();      //等待擦除完成  
  414. }   
  415.   
  416.   
  417. /****************************************************************************** 
  418. / 函数功能:读出一页数据,无限制 
  419. / 修改日期:2013/9/10 20:43:20 
  420. / 输入参数:none 
  421. / 输出参数:none 
  422. / 使用说明:none 
  423. ******************************************************************************/  
  424. void W25X_Read_Page(uint8_t * pBuffer,uint32_t PageAddr)  
  425. {  
  426.     uint32_t    ReadAddr;  
  427.     uint16_t    i;  
  428.       
  429.     if(PageAddr < W25X_PAGE_NUM)  
  430.     {                 
  431.         ReadAddr = PageAddr *W25X_PAGE_SIZE;  
  432.         W25X_CS_L();    
  433.         W25X_ReadWriteByte(W25X_ReadData);         //发送读取命令     
  434.         W25X_ReadWriteByte((uint8_t)((ReadAddr)>>16));  //发送24bit地址      
  435.         W25X_ReadWriteByte((uint8_t)((ReadAddr)>>8));     
  436.         W25X_ReadWriteByte((uint8_t)ReadAddr);     
  437.         for(i=0;i<W25X_PAGE_SIZE;i++)  
  438.         {   
  439.             pBuffer[i]=W25X_ReadWriteByte(0XFF);   //循环读数    
  440.         }  
  441.         W25X_CS_H();      
  442.     }  
  443. }  
  444.   
  445.   
  446. /****************************************************************************** 
  447. / 函数功能:写一页数据到指定的页,必须该页已被擦除!!! 
  448. / 修改日期:2013/9/10 20:43:20 
  449. / 输入参数:none 
  450. / 输出参数:none 
  451. / 使用说明:none 
  452. ******************************************************************************/   
  453. void W25X_Write_Page(uint8_t * pBuffer,uint32_t PageAddr)  
  454. {  
  455.     uint16_t    i;   
  456.     uint32_t    WriteAddr;  
  457.       
  458.     //打开写状态,并等待上次写操作完成  
  459.     W25X_Write_Enable();  
  460.     W25X_Wait_Busy();      //等待擦除完成  
  461.       
  462.     //将数据写入FLASH  
  463.     WriteAddr =PageAddr* W25X_PAGE_SIZE;  
  464.     W25X_CS_L();   
  465.     W25X_ReadWriteByte(W25X_PageProgram);      //发送写页命令     
  466.     W25X_ReadWriteByte((uint8_t)((WriteAddr)>>16)); //发送24bit地址      
  467.     W25X_ReadWriteByte((uint8_t)((WriteAddr)>>8));     
  468.     W25X_ReadWriteByte((uint8_t)WriteAddr);     
  469.     for(i=0;i<W25X_PAGE_SIZE;i++)W25X_ReadWriteByte(pBuffer[i]);//循环写数    
  470.     W25X_CS_H();  
  471.     //W25X_Wait_Busy();      //等待擦除完成  
  472. }  
  473.   
  474.   
  475. /****************************************************************************** 
  476. / 函数功能:在指定地址开始读取指定长度的数据(最大64KB字节),连续读取模式 
  477. / 修改日期:2013/9/10 20:43:20 
  478. / 输入参数: 
  479. /   pBuffer:数据存储区 
  480. /   ReadAddr:开始读取的地址(24bit) 
  481. /   NumByteToRead:要读取的字节数(最大65535) 
  482. / 输出参数:none 
  483. / 使用说明:none 
  484. ******************************************************************************/   
  485. void W25X_Read_Data(uint8_t * pBuffer,uint32_t ReadAddr,uint16_t NumByteToRead)     
  486. {   
  487.     uint16_t i;                   
  488.     W25X_CS_L();    
  489.     W25X_ReadWriteByte(W25X_ReadData);         //发送读取命令     
  490.     W25X_ReadWriteByte((uint8_t)((ReadAddr)>>16));  //发送24bit地址      
  491.     W25X_ReadWriteByte((uint8_t)((ReadAddr)>>8));     
  492.     W25X_ReadWriteByte((uint8_t)ReadAddr);     
  493.     for(i=0;i<NumByteToRead;i++)  
  494.     {   
  495.         pBuffer[i]=W25X_ReadWriteByte(0XFF);   //循环读数    
  496.     }  
  497.     W25X_CS_H();                   
  498. }  
  499.   
  500.   
  501. /****************************************************************************** 
  502. / 函数功能:DMA方式高效读取一批数据,小余64KB即可 
  503. / 修改日期:2013/9/11 9:06:27 
  504. / 输入参数:none 
  505. / 输出参数:none 
  506. / 使用说明:none 
  507. ******************************************************************************/  
  508. void W25X_DMARead_Data(uint8_t * pBuffer,uint32_t ReadAddr,uint16_t NumByteToRead)  
  509. {  
  510.     //判断DMA是否仍处于工作状态,若是则等待传输完成,  
  511.     if( (DMA1_Channel2->CCR & DMA_CCR1_EN) || (DMA1_Channel3->CCR & DMA_CCR1_EN) )  
  512.     {  
  513.         //while( !DMA_GetFlagStatus(DMA1_FLAG_TC2));//高效写法如下  
  514.         while( !(DMA1->ISR & DMA1_FLAG_TC2));       //等待传送完成  
  515.         sem_W25X_DMA_RxRdy  = true;                 //标记DMA接收数据信号  
  516.         W25X_CS_H();                                //结束片选  
  517.         __NOP();__NOP();__NOP();__NOP();            //短延时,使CS有足够的拉高时间      
  518.     }  
  519.       
  520.     //设置DMA数据载荷,并清DMA标记  
  521.     sem_W25X_DMA_Busy = true;               //标记为DMA忙  
  522.     DMA1_Channel3->CMAR = (uint32_t)(&W25X_TX_Byte);    //设置发送数据的源SRAM地址  
  523.     DMA1_Channel3->CNDTR= NumByteToRead;    //设置发送字节长度,发送SRAM地址不增加  
  524.     DMA1_Channel2->CMAR =(uint32_t)pBuffer; //设置接收数据个数  
  525.     DMA1_Channel2->CNDTR= NumByteToRead;    //设置接收数据的目标SRAM地址  
  526.       
  527.     //发送前导字节  
  528.     W25X_CS_L();    
  529.     W25X_ReadWriteByte(W25X_ReadData);         //发送读取命令     
  530.     W25X_ReadWriteByte((uint8_t)((ReadAddr)>>16));  //发送24bit地址      
  531.     W25X_ReadWriteByte((uint8_t)((ReadAddr)>>8));     
  532.     W25X_ReadWriteByte((uint8_t)ReadAddr);  
  533.     SPI1->DR ;                                //接送前读一次SPI1->DR,保证接收缓冲区为空  
  534.       
  535.     //清DMA标记  
  536.     DMA_ClearFlag(DMA1_FLAG_GL3|DMA1_FLAG_TC3|DMA1_FLAG_HT3|DMA1_FLAG_TE2);  
  537.     DMA_ClearFlag(DMA1_FLAG_GL2|DMA1_FLAG_TC2|DMA1_FLAG_HT2|DMA1_FLAG_TE2);  
  538.   
  539.   
  540.     //启动DMA发送数据  
  541.     while ((SPI1->SR & SPI_I2S_FLAG_TXE) == (uint16_t)RESET);  
  542.     DMA_Cmd(DMA1_Channel3, ENABLE);  
  543.     DMA_Cmd(DMA1_Channel2, ENABLE);     
  544.   
  545.   
  546.     //等待DMA传送数据完毕  
  547.     /* 
  548.     while( !DMA_GetFlagStatus(DMA1_FLAG_TC2));  //等待接收DMA的传输完成 
  549.     DMA_Cmd(DMA1_Channel3, DISABLE);            //关闭发送DMA 
  550.     DMA_Cmd(DMA1_Channel2, DISABLE);            //关闭接收DMA 
  551.     sem_W25X_DMA_RxRdy = true;                  //标记DMA接收数据信号 
  552.     W25X_CS_H(); 
  553.     */  
  554.       
  555.        
  556. }  
  557.   
  558.   
  559. /****************************************************************************** 
  560. / 函数功能:读唯一ID号,8个字节 
  561. / 修改日期:2013/9/11 9:38:49 
  562. / 输入参数:none 
  563. / 输出参数:none 
  564. / 使用说明:none 
  565. ******************************************************************************/  
  566. void W25X_Read_UID(uint8_t * pBuffer)  
  567. {   
  568.     uint8_t i;  
  569.       
  570.     W25X_CS_L();         
  571.     W25X_ReadWriteByte(W25X_ReadUniqueID);      
  572.     W25X_ReadWriteByte(0x00);        
  573.     W25X_ReadWriteByte(0x00);        
  574.     W25X_ReadWriteByte(0x00);  
  575.     W25X_ReadWriteByte(0x00);          
  576.     for(i=0;i<8;i++)  
  577.         pBuffer[i]=W25X_ReadWriteByte(0XFF);   //循环读数  
  578.     W25X_CS_H();  
  579. }  
  580.   
  581.   
  582. /****************************************************************************** 
  583. / 函数功能:DMA数据接收完毕中断 
  584. / 修改日期:2013/9/11 9:38:47 
  585. / 输入参数:none 
  586. / 输出参数:none 
  587. / 使用说明:none 
  588. ******************************************************************************/  
  589. void DMA1_Channel2_IRQHandler(void)  
  590. {      
  591.     //空读ISR状态  
  592.     DMA1->ISR;                            
  593.       
  594.     //关闭DMA通道  
  595.     //DMA_Cmd(DMA1_Channel2, DISABLE);//以下为等效写法  
  596.     //DMA_Cmd(DMA1_Channel3, DISABLE);//以下为等效写法  
  597.     DMA1_Channel2->CCR &= ~DMA_CCR1_EN;     //关闭DMA1_CH2  
  598.     DMA1_Channel3->CCR &= ~DMA_CCR1_EN;     //关闭DMA1_CH2  
  599.       
  600.     //清DMA中断标记  
  601.     //DMA_ClearITPendingBit(DMA1_IT_GL2|DMA1_IT_TC2|DMA1_IT_HT2|DMA1_IT_TE2);//以下为等待模式  
  602.     DMA1->IFCR = DMA1_IT_GL2|DMA1_IT_TC2|DMA1_IT_HT2|DMA1_IT_TE2;  
  603.   
  604.   
  605.     //置信号量  
  606.     DMA_Cmd(DMA1_Channel3, DISABLE);            //关闭发送DMA  
  607.     DMA_Cmd(DMA1_Channel2, DISABLE);            //关闭接收DMA  
  608.     sem_W25X_DMA_Busy   = false;                //标记为DMA空闲  
  609.     sem_W25X_DMA_RxRdy  = true;                 //标记DMA接收数据信号  
  610.     W25X_CS_H();                                //结束片选        
  611. }  


4. 头文件W25Q64.h

[cpp]  view plain  copy
  1. /*********************************Copyright (c)********************************* 
  2. **                                
  3. **                                 FIVE工作组 
  4. ** 
  5. **---------------------------------File Info------------------------------------ 
  6. ** File Name:               w25q64.h 
  7. ** Last modified Date:      2013/9/10 9:32:33 
  8. ** Last Version:            V1.2    
  9. ** Description:             none 
  10. ** 
  11. **------------------------------------------------------------------------------ 
  12. ** Created By:              wanxuncpx 
  13. ** Created date:            2013/8/6 21:12:35 
  14. ** Version:                 V1.2 
  15. ** Descriptions:            none 
  16. **------------------------------------------------------------------------------ 
  17. ** HW_CMU:                  STM32F103ZET6 
  18. ** Libraries:               STM32F10x_StdPeriph_Driver 
  19. ** version                  V3.5 
  20. *******************************************************************************/  
  21.   
  22. /****************************************************************************** 
  23. 更新说明: 
  24. ******************************************************************************/  
  25.   
  26.   
  27. /****************************************************************************** 
  28. *********************************  应 用 资 料 ******************************** 
  29. ******************************************************************************* 
  30.     1. W25Q64 拥有32 768个页,每页256个字节故有8MB的容量 
  31.     2. W25Q64 16个页为一个扇区 
  32.     3. W25Q64 256个页为一个Block 
  33.     2. 指令表 
  34.  
  35. ┌-----------------------┬--------┬-----------┬-----------┬-----------┬-----------┬-----------┐ 
  36. |       令名             |  BYTE1  |   BYTE2    |    BYTE3   |   BYTE4    |   BYTE5    |   BYTE6    | 
  37. |                        | (CODE)  |            |            |            |            |            | 
  38. ├-----------------------┼--------┼-----------┼-----------┼-----------┼-----------┼-----------┤ 
  39. | Write Enable           |   06h   |            |            |            |            |            | 
  40. | 允许写状态寄存器       |   50h   |            |            |            |            |            | 
  41. | Write Disable          |   04h   |            |            |            |            |            | 
  42. | Read Status Register-1 |   05h   | S7–S0     |            |            |            |            | 
  43. | Read Status Register-2 |   35h   | S15–S8    |            |            |            |            | 
  44. | Write Status Register  |   01h   | S7–S0     | S15-S8     |            |            |            | 
  45. | Page Program           |   02h   | A23–A16   | A15–A8    |  A7–A0    |D7–D0      |            | 
  46. | Quad Page Program      |   32h   | A23–A16   | A15–A8    |  A7–A0    |D7–D0,..(3)|            | 
  47. | Sector Erase (4KB)     |   20h   | A23–A16   | A15–A8    |  A7–A0    |            |            | 
  48. | Block Erase (32KB)     |   52h   | A23–A16   | A15–A8    |  A7–A0    |            |            | 
  49. | Block Erase (64KB)     |   D8h   | A23–A16   | A15–A8    |  A7–A0    |            |            | 
  50. | Chip Erase             | C7h/60h |            |            |            |            |            | 
  51. | Erase / Program Suspend|   75h   |            |            |            |            |            | 
  52. | Erase / Program Resume |   7Ah   |            |            |            |            |            | 
  53. | Power-down             |   B9h   |            |            |            |            |            | 
  54. | 复位连续读模式         |   FFh   |    FFh     |            |            |            |            | 
  55. ├-----------------------┼--------┼-----------┼-----------┼-----------┼-----------┼-----------┤ 
  56. | Read Data              |   03h   |  A23-A16   | A15-A8     |  A7-A0     |  (D7-D0)   |            | 
  57. | Fast Read              |   0Bh   |  A23-A16   | A15-A8     |  A7-A0     |  dummy     |(D7-D0)     | 
  58. | Fast Read Dual Output  |   3Bh   |  A23-A16   | A15-A8     |  A7-A0     |  dummy     |(D7-D0, …) | 
  59. | Fast Read Quad Output  |   6Bh   |  A23-A16   | A15-A8     |  A7-A0     |  dummy     |(D7-D0, …) | 
  60. | Fast Read Dual I/O     |   BBh   |  A23-A8(2) | A7-A0,     |  M7-M0(2)  | (D7-D0,..) |            | 
  61. | Fast Read Quad I/O     |   EBh   |A23-A0,M7-M0|xxxx,D7-D0,.|(D7-D0,..)  |            |            | 
  62. | Word Read Quad I/O     |   E7h   |A23-A0,M7-M0|xx,D7-D0,.  |(D7-D0,..)  |            |            | 
  63. |Octal Word Read Quad I/O|   E3h   |A23-A0,M7-M0|(D7-D0,.)   |            |            |            | 
  64. | Set Burst with Wrap    |     77h |xxxxxx,W6-W4|            |            |            |            | 
  65. ├-----------------------┼--------┼-----------┼-----------┼-----------┼-----------┼-----------┤ 
  66. |Release Device ID       |  ABh    | dummy      |  dummy     |  dummy     |  (ID7-ID0) |            | 
  67. |ID                      |  90h    | dummy      |  dummy     |  00h       |  (MF7-MF0) | (ID7-ID0)  |  
  68. |ID by Dual I/O          |  92h    | A23-A8     |A7-A0,M[7:0]|MF[7:0],ID[7:0] |        |            |    
  69. |ID  by Quad I/O         |  94h    | A23-A0,M[7:0]| xxxx,(MF[7:0],ID[7:0])|(MF[7:0], ID[7:0], …)| ||    
  70. |JEDEC ID                |  9Fh    | (MF7-MF0)  | (ID15-ID8) | (ID7-ID0)  |            |            | 
  71. |Read Unique ID          |  4Bh    | dummy      |  dummy     |  dummy     |  dummy     | (ID63-ID0) | 
  72. |Erase Security Registers|  44h    | A23–A16   |  A15–A8   |  A7–A0    |            |            | 
  73. |Program Security Registers|42h    | A23–A16   |  A15–A8   |  A7–A0    |  D7-D0     | D7-D0      | 
  74. |Read Security Registers |  48h    | A23–A16   |  A15–A8   |  A7–A0    |  dummy     | (D7-0)     | 
  75. └-----------------------┴--------┴-----------┴-----------┴-----------┴-----------┴-----------┘ 
  76.  
  77. ******************************************************************************/  
  78.   
  79. #ifndef _W25Q64_H_  
  80. #define _W25Q64_H_  
  81.   
  82. /****************************************************************************** 
  83. ********************************* 文件引用部分 ******************************** 
  84. ******************************************************************************/  
  85. #include "stm32f10x.h"  
  86. #include "stm32f10x_gpio.h"  
  87. #include "stm32f10x_rcc.h"  
  88. #include "stm32f10x_spi.h"  
  89. #include "stm32f10x_dma.h"  
  90.   
  91. #include <string.h>  
  92. #include <stdbool.h>  
  93. #include <stdint.h>  
  94. /****************************************************************************** 
  95. ******************************* 系 统 参 数 定 义****************************** 
  96. ******************************************************************************/  
  97. /*---------------------*  
  98. *     USART优先级定义 
  99. *----------------------*/  
  100. #define W25X_DMA_TC_PRIO    2           /* 中断优先级          */  
  101.   
  102. /*---------------------*  
  103. *      参数配置定义 
  104. *----------------------*/  
  105. #define W25X_PAGE_SIZE      256         /* 定义页大小          */  
  106. #define W25X_PAGE_NUM       32768       /* 定义页的个数        */  
  107. #define W25X_SECTOR_SIZE    4096        /* 每扇区的大小        */      
  108. #define W25X_PAGES_PS       (W25X_SECTOR_SIZE/W25X_PAGE_SIZE)  /* 每扇区的页数 */  
  109.   
  110. #define W25X_BUFF_NUM       2           /* 定义SRAM中缓冲个数  */  
  111. #define W25X_DUMMY_BYTE     0xFF        /* 空读字节定义        */  
  112.   
  113. /****************************************************************************** 
  114. ********************************** 需自定义 *********************************** 
  115. ****************************** 参数配置、引脚定义  **************************** 
  116. ******************************************************************************/  
  117.   
  118. /*---------------------* 
  119. *     本地硬件连接 
  120. *----------------------*/  
  121.   
  122.   
  123. /*---------------------* 
  124. *     常用指令定义 
  125. *----------------------*/  
  126. #define W25X_ReadStatusReg      0x05    //读状态寄存器1  
  127. #define W25X_ReadStatusReg2     0x35    //读状态寄存器2  
  128. #define W25X_WriteStatusReg     0x01    //写状态寄存器1  
  129. #define W25X_ReadUniqueID       0x4B    //读取唯一ID  
  130.   
  131. #define W25X_WriteEnable        0x06    //写使能  
  132. #define W25X_WriteDisable       0x04    //写关闭  
  133.   
  134. #define W25X_ReadData           0x03    //读数据  
  135. #define W25X_PageProgram        0x02    //写FLASH  
  136.   
  137. #define W25X_ChipErase          0x60    //也可为0x60  
  138. #define W25X_SectorErase        0x20    //4KB擦除          
  139.   
  140.   
  141. #define W25X_PowerDown          0xB9    //掉电,低功耗  
  142. #define W25X_ReleasePowerDown   0xAB    //恢复上电  
  143.   
  144. /****************************************************************************** 
  145. ********************************* 参数宏定义 ********************************* 
  146. ******************************************************************************/  
  147. /*---------------------*  
  148. *       参数定义 
  149. *----------------------*/  
  150. #define W25X_WP_DIS()        (GPIOB->BRR = GPIO_Pin_0)  
  151. #define W25X_WP_EN()         (GPIOB->BSRR  = GPIO_Pin_0)  
  152. #define W25X_CS_L()          (GPIOA->BRR  = GPIO_Pin_4)  
  153. #define W25X_CS_H()          (GPIOA->BSRR = GPIO_Pin_4)  
  154. /****************************************************************************** 
  155. ********************************* 数 据 声 明 ********************************* 
  156. ******************************************************************************/  
  157. /*---------------------*  
  158. *      输出数据 
  159. *----------------------*/  
  160. extern uint8_t W25X_Buffer[W25X_SECTOR_SIZE];  
  161. extern volatile bool sem_W25X_DMA_Busy;         //用户只读  
  162. extern volatile bool sem_W25X_DMA_RxRdy;        //用户读取,清零  
  163.   
  164. /****************************************************************************** 
  165. ********************************* 函 数 声 明 ********************************* 
  166. ******************************************************************************/  
  167. /*---------------------*  
  168. *    输出函数 
  169. *----------------------*/  
  170. //初始化  
  171. extern void W25X_GPIO_Config(void);         //配置GPIO口  
  172. extern void W25X_Init(void);                //初始化SPI  
  173.   
  174. //获取状态  
  175. extern uint8_t W25X_ReadSR(void);           //读取状态寄存器  
  176. extern uint16_t W25X_ReadID(void);          //读取ID号  
  177. extern void W25X_Wait_Busy(void);           //等待W25X直到空闲  
  178. extern bool W25X_Read_BusyState(void);      //读取W25X的忙状态(不等待)  
  179.   
  180. //控制状态  
  181. extern void W25X_Write_Enable(void);        //写使能  
  182. extern void W25X_Write_Disable(void);       //写禁止  
  183. extern void SPI_Flash_PowerDown(void);      //掉电  
  184. extern void SPI_Flash_WakeUp(void);         //唤醒  
  185.   
  186. //擦除相关(有等待选择)  
  187. extern void W25X_Erase_Chip(bool bwait);    //全片擦除,要等待写完成,需要21秒  
  188. extern void W25X_Erase_Sector(uint32_t Dst_Addr,bool bwait);    //扇区擦除,实际需要65ms  
  189.   
  190. extern void W25X_Read_Data(uint8_t * pBuffer,uint32_t ReadAddr,uint16_t NumByteToRead);     //250us执行完毕  
  191. extern void W25X_DMARead_Data(uint8_t * pBuffer,uint32_t ReadAddr,uint16_t NumByteToRead);  //5us执行,75us后结束  
  192. extern void W25X_Read_Page(uint8_t * pBuffer,uint32_t PageAddr);    //读出一页,300us  
  193. extern void W25X_Write_Page(uint8_t * pBuffer,uint32_t PageAddr);   //写入一页,必先擦除,事先有些等待,600us  
  194. extern void W25X_Read_UID(uint8_t * pBuffer);   //读取W25X的唯一MAC,<5us  
  195.   
  196. /****************************************************************************** 
  197. ***********************************   END  ************************************ 
  198. ******************************************************************************/  
  199. #endif  

猜你喜欢

转载自blog.csdn.net/errorhai/article/details/79447153