STM32F103的W25Q64的DMA高效数据访问实现
1. 关于DMA
首先任何FLASH的写操作都是非常耗时的,体现在擦除FLASH上,且写操作不能太频繁,故而用DMA方式实现写操作程序逻辑会非常复杂,程序逻辑在各种中断处理中容易乱,与之相反采用DMA读大批量数据时及具有优势.
比如36MHzSPI时种,采用轮询方式读一页数据需要花费250us时间,二用了DMA后只需要80us时间,提高了三倍还多,且启动DMA只需要5us,节省了245us时间.
2. W25Q64实用的函数
① 读ID号,用于确定芯片是否能正常访问
② 轮询方式读数据
③ 擦除指令
④ 写一页数据指令,(事先要擦除)
⑤ DMA方式读取一块数据
3. 程序正文W25Q64.c
- /*********************************Copyright (c)*********************************
- **
- ** FIVE工作组
- **
- **---------------------------------File Info------------------------------------
- ** File Name: w25q64.c
- ** Last modified Date: 2013/9/10 9:32:33
- ** Last Version: V1.2
- ** Description: none
- **
- **------------------------------------------------------------------------------
- ** Created By: wanxuncpx
- ** Created date: 2013/8/6 21:12:35
- ** Version: V1.2
- ** Descriptions: none
- **------------------------------------------------------------------------------
- ** HW_CMU: STM32F103ZET6
- ** Libraries: STM32F10x_StdPeriph_Driver
- ** version V3.5
- *******************************************************************************/
- /******************************************************************************
- 更新说明:
- ******************************************************************************/
- /******************************************************************************
- ********************************* 应 用 资 料 ********************************
- ******************************************************************************/
- /******************************************************************************
- ********************************* 文件引用部分 ********************************
- ******************************************************************************/
- #include "w25q64.h"
- /******************************************************************************
- ********************************* 数 据 声 明 *********************************
- ******************************************************************************/
- /*---------------------*
- * 数据定义(输出)
- *----------------------*/
- uint8_t W25X_Buffer[W25X_SECTOR_SIZE];
- volatile bool sem_W25X_DMA_Busy = true;
- volatile bool sem_W25X_DMA_RxRdy= false;
- /*---------------------*
- * 数据定义(内部用)
- *----------------------*/
- static uint8_t W25X_TX_Byte=0xFF;
- /******************************************************************************
- ********************************* 函 数 声 明 *********************************
- ******************************************************************************/
- /******************************************************************************
- / 函数功能:初始化W25Q64的GPIO口连接
- / 修改日期:2013/9/10 19:04:15
- / 输入参数:none
- / 输出参数:none
- / 使用说明:none
- ******************************************************************************/
- void W25X_GPIO_Config(void)
- {
- /* Private typedef ---------------------------------------------------------*/
- GPIO_InitTypeDef GPIO_InitStruct;
- /** SPI1 GPIO Configuration
- PA5 ------> SPI1_SCK
- PA6 ------> SPI1_MISO
- PA7 ------> SPI1_MOSI
- */
- /*Enable or disable APB2 peripheral clock */
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
- /*Configure GPIO pin */
- GPIO_InitStruct.GPIO_Pin = GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7;
- GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
- GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
- GPIO_Init(GPIOA, &GPIO_InitStruct);
- /** Configure pins as GPIO
- PA4 ------> GPIO_Output
- PB0 ------> GPIO_Output
- */
- /*Enable or disable APB2 peripheral clock */
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB, ENABLE);
- W25X_WP_EN();
- W25X_CS_H();
- /*Configure GPIO pin */
- GPIO_InitStruct.GPIO_Pin = GPIO_Pin_4;
- GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
- GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
- GPIO_Init(GPIOA, &GPIO_InitStruct);
- /*Configure GPIO pin */
- GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0;
- GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
- GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
- GPIO_Init(GPIOB, &GPIO_InitStruct);
- /*Lock of the gpio */
- GPIO_PinLockConfig(GPIOA,GPIO_Pin_4);
- GPIO_PinLockConfig(GPIOB,GPIO_Pin_0);
- }
- /******************************************************************************
- / 函数功能:初始化W25Q64
- / 修改日期:2013/9/10 19:04:16
- / 输入参数:none
- / 输出参数:none
- / 使用说明:none
- ******************************************************************************/
- void W25X_Init(void)
- {
- SPI_InitTypeDef SPI_InitStructure ;
- DMA_InitTypeDef DMA_InitStructure;
- NVIC_InitTypeDef NVIC_InitStructure;
- //配置DMA通道,DMA1_CH2收
- //读取SPI FLASH时多数为空数据故而数据地址无需增加
- //启动DMA1的时钟
- RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
- DMA_DeInit(DMA1_Channel2);
- DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(&SPI1->DR);
- DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)W25X_Buffer;
- DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
- DMA_InitStructure.DMA_BufferSize = 0;
- DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
- DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
- DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
- DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
- DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
- DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
- DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
- DMA_Init(DMA1_Channel2, &DMA_InitStructure);
- //配置DMA通道,DMA1_CH3发送
- DMA_DeInit(DMA1_Channel3);
- DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(&SPI1->DR);
- DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)(&W25X_TX_Byte);
- DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
- DMA_InitStructure.DMA_BufferSize = 0;
- DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
- DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable;
- DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
- DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
- DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
- DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;
- DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
- DMA_Init(DMA1_Channel3, &DMA_InitStructure);
- //关闭DMA,清DMA标记,使能DMA1_CH2的传输完成中断
- DMA_Cmd(DMA1_Channel3, DISABLE); //关闭发送DMA
- DMA_Cmd(DMA1_Channel2, DISABLE); //关闭接收DMA
- DMA_ClearFlag(DMA1_FLAG_GL3|DMA1_FLAG_TC3|DMA1_FLAG_HT3|DMA1_FLAG_TE3);
- DMA_ClearFlag(DMA1_FLAG_GL2|DMA1_FLAG_TC2|DMA1_FLAG_HT2|DMA1_FLAG_TE2);
- DMA_ITConfig(DMA1_Channel2,DMA_IT_TC,ENABLE);
- //初始化SPI时钟
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1,ENABLE);
- // SPI配置
- SPI_Cmd(SPI1,DISABLE);
- SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex ;
- SPI_InitStructure.SPI_Mode = SPI_Mode_Master ;
- SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b ;
- SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low ;
- SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge ;
- SPI_InitStructure.SPI_NSS = SPI_NSS_Soft ;
- SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2 ; //72MHz分频
- SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB ; //SPI设置成LSB模式
- SPI_InitStructure.SPI_CRCPolynomial = 7 ;
- SPI_Init( SPI1, &SPI_InitStructure ) ;
- SPI_Cmd(SPI1,ENABLE); //启动SPI
- //打开SPI1的DMA发送接收请求
- SPI_I2S_DMACmd(SPI1, SPI_I2S_DMAReq_Rx, ENABLE);
- SPI_I2S_DMACmd(SPI1, SPI_I2S_DMAReq_Tx, ENABLE);
- //清DMA忙信号
- sem_W25X_DMA_Busy = false;
- //使能NVIC中断
- NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel2_IRQn;
- NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
- NVIC_InitStructure.NVIC_IRQChannelSubPriority = W25X_DMA_TC_PRIO;
- NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
- NVIC_Init(&NVIC_InitStructure);
- }
- /******************************************************************************
- / 函数功能:SPI发送一个字节的数据
- / 修改日期:2013/9/10 19:04:16
- / 输入参数:none
- / 输出参数:none
- / 使用说明:none
- ******************************************************************************/
- uint8_t W25X_ReadWriteByte(uint8_t dat)
- {
- while ((SPI1->SR & SPI_I2S_FLAG_TXE) == (uint16_t)RESET);
- SPI1->DR = dat;
- while ((SPI1->SR & SPI_I2S_FLAG_RXNE) == (uint16_t)RESET);
- return (SPI1->DR);
- }
- /******************************************************************************
- / 函数功能:读取SPI_FLASH的状态寄存器
- / 修改日期:2013/9/10 20:38:48
- / 输入参数:none
- / 输出参数:none
- / 使用说明:none
- / BIT7 6 5 4 3 2 1 0
- / SPR RV TB BP2 BP1 BP0 WEL BUSY
- /
- / SPR:默认0,状态寄存器保护位,配合WP使用
- / TB,BP2,BP1,BP0:FLASH区域写保护设置
- / WEL:写使能锁定, 1
- / BUSY:忙标记位(1,忙;0,空闲)
- / 默认:0x00
- ******************************************************************************/
- uint8_t W25X_ReadSR(void)
- {
- uint8_t byte=0;
- W25X_CS_L(); //使能器件
- W25X_ReadWriteByte(W25X_ReadStatusReg); //发送读取状态寄存器命令
- byte=W25X_ReadWriteByte(0Xff); //读取一个字节
- W25X_CS_H(); //使能器件
- return byte;
- }
- /******************************************************************************
- / 函数功能:读取芯片ID
- / 修改日期:2013/9/10 20:43:20
- / 输入参数:none
- / 输出参数:
- / 返回值如下:
- / 0XEF13,表示芯片型号为W25Q80
- / 0XEF14,表示芯片型号为W25Q16
- / 0XEF15,表示芯片型号为W25Q32
- / 0XEF16,表示芯片型号为W25Q64
- / 使用说明:none
- ******************************************************************************/
- uint16_t W25X_ReadID(void)
- {
- uint16_t Temp = 0;
- W25X_CS_L();
- W25X_ReadWriteByte(0x90); //发送读取ID命令
- W25X_ReadWriteByte(0x00);
- W25X_ReadWriteByte(0x00);
- W25X_ReadWriteByte(0x00);
- Temp|=W25X_ReadWriteByte(0xFF)<<8;
- Temp|=W25X_ReadWriteByte(0xFF);
- W25X_CS_H();
- return Temp;
- }
- /******************************************************************************
- / 函数功能:等待芯片执行完毕
- / 修改日期:2013/9/10 20:43:20
- / 输入参数:none
- / 输出参数:none
- / 使用说明:none
- ******************************************************************************/
- void W25X_Wait_Busy(void)
- {
- while((W25X_ReadSR()&0x01)==0x01); // 等待BUSY位清空
- }
- /******************************************************************************
- / 函数功能:读取芯片看是否为忙
- / 修改日期:2013/9/10 20:43:20
- / 输入参数:none
- / 输出参数:none
- / 使用说明:none
- ******************************************************************************/
- bool W25X_Read_BusyState(void)
- {
- if((W25X_ReadSR()&0x01))return true;
- else return false;
- }
- /******************************************************************************
- / 函数功能:SPI_FLASH写使能
- / 修改日期:2013/9/10 20:43:20
- / 输入参数:none
- / 输出参数:none
- / 使用说明:none
- ******************************************************************************/
- void W25X_Write_Enable(void)
- {
- W25X_WP_EN(); //打开硬件写使能
- W25X_CS_L(); //使能器件
- W25X_ReadWriteByte(W25X_WriteEnable); //发送写使能
- W25X_CS_H(); //取消片选
- }
- /******************************************************************************
- / 函数功能:SPI_FLASH写禁止
- / 修改日期:2013/9/10 20:43:20
- / 输入参数:none
- / 输出参数:none
- / 使用说明:none
- ******************************************************************************/
- void W25X_Write_Disable(void)
- {
- W25X_WP_DIS(); //关闭硬件写使能
- W25X_CS_L(); //使能器件
- W25X_ReadWriteByte(W25X_WriteDisable); //发送写禁止指令
- W25X_CS_H(); //取消片选
- }
- /******************************************************************************
- / 函数功能:使SPI FLASH掉电
- / 修改日期:2013/9/10 20:43:20
- / 输入参数:none
- / 输出参数:none
- / 使用说明:none
- ******************************************************************************/
- void SPI_Flash_PowerDown(void)
- {
- uint16_t i;
- W25X_CS_L(); //使能器件
- W25X_ReadWriteByte(W25X_PowerDown); //发送掉电命令
- W25X_CS_H(); //取消片选
- i= (72)*3;while(i--); //等待约3us
- }
- /******************************************************************************
- / 函数功能:唤醒SPI FLASH
- / 修改日期:2013/9/10 20:43:20
- / 输入参数:none
- / 输出参数:none
- / 使用说明:none
- ******************************************************************************/
- void SPI_Flash_WakeUp(void)
- {
- uint16_t i;
- W25X_CS_L(); //使能器件
- W25X_ReadWriteByte(W25X_ReleasePowerDown); //发送掉电命令
- W25X_CS_H(); //取消片选
- i= (72)*3;while(i--); //等待约3us
- }
- /******************************************************************************
- / 函数功能:擦除整个芯片 ,等待时间超长...
- / 修改日期:2013/9/10 20:43:20
- / 输入参数:none
- / 输出参数:none
- / 使用说明:none
- ******************************************************************************/
- void W25X_Erase_Chip(bool bwait)
- {
- W25X_Write_Enable(); //SET WEL
- W25X_Wait_Busy();
- W25X_CS_L(); //使能器件
- W25X_ReadWriteByte(W25X_ChipErase); //发送片擦除命令
- W25X_CS_H(); //取消片选
- if(bwait)W25X_Wait_Busy(); //等待芯片擦除结束
- }
- /******************************************************************************
- / 函数功能:擦除一个扇区
- / 修改日期:2013/9/10 20:43:20
- / 输入参数:Dst_Addr:扇区地址 根据实际容量设置
- / 输出参数:none
- / 使用说明:none擦除一个扇区的最少时间:65ms
- ******************************************************************************/
- void W25X_Erase_Sector(uint32_t Dst_Addr,bool bwait)
- {
- W25X_Write_Enable(); //SET WEL
- W25X_Wait_Busy();
- W25X_CS_L(); //使能器件
- W25X_ReadWriteByte(W25X_SectorErase); //发送扇区擦除指令
- W25X_ReadWriteByte((uint8_t)((Dst_Addr)>>16)); //发送24bit地址
- W25X_ReadWriteByte((uint8_t)((Dst_Addr)>>8));
- W25X_ReadWriteByte((uint8_t)Dst_Addr);
- W25X_CS_H(); //取消片选
- if(bwait)W25X_Wait_Busy(); //等待擦除完成
- }
- /******************************************************************************
- / 函数功能:读出一页数据,无限制
- / 修改日期:2013/9/10 20:43:20
- / 输入参数:none
- / 输出参数:none
- / 使用说明:none
- ******************************************************************************/
- void W25X_Read_Page(uint8_t * pBuffer,uint32_t PageAddr)
- {
- uint32_t ReadAddr;
- uint16_t i;
- if(PageAddr < W25X_PAGE_NUM)
- {
- ReadAddr = PageAddr *W25X_PAGE_SIZE;
- W25X_CS_L();
- W25X_ReadWriteByte(W25X_ReadData); //发送读取命令
- W25X_ReadWriteByte((uint8_t)((ReadAddr)>>16)); //发送24bit地址
- W25X_ReadWriteByte((uint8_t)((ReadAddr)>>8));
- W25X_ReadWriteByte((uint8_t)ReadAddr);
- for(i=0;i<W25X_PAGE_SIZE;i++)
- {
- pBuffer[i]=W25X_ReadWriteByte(0XFF); //循环读数
- }
- W25X_CS_H();
- }
- }
- /******************************************************************************
- / 函数功能:写一页数据到指定的页,必须该页已被擦除!!!
- / 修改日期:2013/9/10 20:43:20
- / 输入参数:none
- / 输出参数:none
- / 使用说明:none
- ******************************************************************************/
- void W25X_Write_Page(uint8_t * pBuffer,uint32_t PageAddr)
- {
- uint16_t i;
- uint32_t WriteAddr;
- //打开写状态,并等待上次写操作完成
- W25X_Write_Enable();
- W25X_Wait_Busy(); //等待擦除完成
- //将数据写入FLASH
- WriteAddr =PageAddr* W25X_PAGE_SIZE;
- W25X_CS_L();
- W25X_ReadWriteByte(W25X_PageProgram); //发送写页命令
- W25X_ReadWriteByte((uint8_t)((WriteAddr)>>16)); //发送24bit地址
- W25X_ReadWriteByte((uint8_t)((WriteAddr)>>8));
- W25X_ReadWriteByte((uint8_t)WriteAddr);
- for(i=0;i<W25X_PAGE_SIZE;i++)W25X_ReadWriteByte(pBuffer[i]);//循环写数
- W25X_CS_H();
- //W25X_Wait_Busy(); //等待擦除完成
- }
- /******************************************************************************
- / 函数功能:在指定地址开始读取指定长度的数据(最大64KB字节),连续读取模式
- / 修改日期:2013/9/10 20:43:20
- / 输入参数:
- / pBuffer:数据存储区
- / ReadAddr:开始读取的地址(24bit)
- / NumByteToRead:要读取的字节数(最大65535)
- / 输出参数:none
- / 使用说明:none
- ******************************************************************************/
- void W25X_Read_Data(uint8_t * pBuffer,uint32_t ReadAddr,uint16_t NumByteToRead)
- {
- uint16_t i;
- W25X_CS_L();
- W25X_ReadWriteByte(W25X_ReadData); //发送读取命令
- W25X_ReadWriteByte((uint8_t)((ReadAddr)>>16)); //发送24bit地址
- W25X_ReadWriteByte((uint8_t)((ReadAddr)>>8));
- W25X_ReadWriteByte((uint8_t)ReadAddr);
- for(i=0;i<NumByteToRead;i++)
- {
- pBuffer[i]=W25X_ReadWriteByte(0XFF); //循环读数
- }
- W25X_CS_H();
- }
- /******************************************************************************
- / 函数功能:DMA方式高效读取一批数据,小余64KB即可
- / 修改日期:2013/9/11 9:06:27
- / 输入参数:none
- / 输出参数:none
- / 使用说明:none
- ******************************************************************************/
- void W25X_DMARead_Data(uint8_t * pBuffer,uint32_t ReadAddr,uint16_t NumByteToRead)
- {
- //判断DMA是否仍处于工作状态,若是则等待传输完成,
- if( (DMA1_Channel2->CCR & DMA_CCR1_EN) || (DMA1_Channel3->CCR & DMA_CCR1_EN) )
- {
- //while( !DMA_GetFlagStatus(DMA1_FLAG_TC2));//高效写法如下
- while( !(DMA1->ISR & DMA1_FLAG_TC2)); //等待传送完成
- sem_W25X_DMA_RxRdy = true; //标记DMA接收数据信号
- W25X_CS_H(); //结束片选
- __NOP();__NOP();__NOP();__NOP(); //短延时,使CS有足够的拉高时间
- }
- //设置DMA数据载荷,并清DMA标记
- sem_W25X_DMA_Busy = true; //标记为DMA忙
- DMA1_Channel3->CMAR = (uint32_t)(&W25X_TX_Byte); //设置发送数据的源SRAM地址
- DMA1_Channel3->CNDTR= NumByteToRead; //设置发送字节长度,发送SRAM地址不增加
- DMA1_Channel2->CMAR =(uint32_t)pBuffer; //设置接收数据个数
- DMA1_Channel2->CNDTR= NumByteToRead; //设置接收数据的目标SRAM地址
- //发送前导字节
- W25X_CS_L();
- W25X_ReadWriteByte(W25X_ReadData); //发送读取命令
- W25X_ReadWriteByte((uint8_t)((ReadAddr)>>16)); //发送24bit地址
- W25X_ReadWriteByte((uint8_t)((ReadAddr)>>8));
- W25X_ReadWriteByte((uint8_t)ReadAddr);
- SPI1->DR ; //接送前读一次SPI1->DR,保证接收缓冲区为空
- //清DMA标记
- DMA_ClearFlag(DMA1_FLAG_GL3|DMA1_FLAG_TC3|DMA1_FLAG_HT3|DMA1_FLAG_TE2);
- DMA_ClearFlag(DMA1_FLAG_GL2|DMA1_FLAG_TC2|DMA1_FLAG_HT2|DMA1_FLAG_TE2);
- //启动DMA发送数据
- while ((SPI1->SR & SPI_I2S_FLAG_TXE) == (uint16_t)RESET);
- DMA_Cmd(DMA1_Channel3, ENABLE);
- DMA_Cmd(DMA1_Channel2, ENABLE);
- //等待DMA传送数据完毕
- /*
- while( !DMA_GetFlagStatus(DMA1_FLAG_TC2)); //等待接收DMA的传输完成
- DMA_Cmd(DMA1_Channel3, DISABLE); //关闭发送DMA
- DMA_Cmd(DMA1_Channel2, DISABLE); //关闭接收DMA
- sem_W25X_DMA_RxRdy = true; //标记DMA接收数据信号
- W25X_CS_H();
- */
- }
- /******************************************************************************
- / 函数功能:读唯一ID号,8个字节
- / 修改日期:2013/9/11 9:38:49
- / 输入参数:none
- / 输出参数:none
- / 使用说明:none
- ******************************************************************************/
- void W25X_Read_UID(uint8_t * pBuffer)
- {
- uint8_t i;
- W25X_CS_L();
- W25X_ReadWriteByte(W25X_ReadUniqueID);
- W25X_ReadWriteByte(0x00);
- W25X_ReadWriteByte(0x00);
- W25X_ReadWriteByte(0x00);
- W25X_ReadWriteByte(0x00);
- for(i=0;i<8;i++)
- pBuffer[i]=W25X_ReadWriteByte(0XFF); //循环读数
- W25X_CS_H();
- }
- /******************************************************************************
- / 函数功能:DMA数据接收完毕中断
- / 修改日期:2013/9/11 9:38:47
- / 输入参数:none
- / 输出参数:none
- / 使用说明:none
- ******************************************************************************/
- void DMA1_Channel2_IRQHandler(void)
- {
- //空读ISR状态
- DMA1->ISR;
- //关闭DMA通道
- //DMA_Cmd(DMA1_Channel2, DISABLE);//以下为等效写法
- //DMA_Cmd(DMA1_Channel3, DISABLE);//以下为等效写法
- DMA1_Channel2->CCR &= ~DMA_CCR1_EN; //关闭DMA1_CH2
- DMA1_Channel3->CCR &= ~DMA_CCR1_EN; //关闭DMA1_CH2
- //清DMA中断标记
- //DMA_ClearITPendingBit(DMA1_IT_GL2|DMA1_IT_TC2|DMA1_IT_HT2|DMA1_IT_TE2);//以下为等待模式
- DMA1->IFCR = DMA1_IT_GL2|DMA1_IT_TC2|DMA1_IT_HT2|DMA1_IT_TE2;
- //置信号量
- DMA_Cmd(DMA1_Channel3, DISABLE); //关闭发送DMA
- DMA_Cmd(DMA1_Channel2, DISABLE); //关闭接收DMA
- sem_W25X_DMA_Busy = false; //标记为DMA空闲
- sem_W25X_DMA_RxRdy = true; //标记DMA接收数据信号
- W25X_CS_H(); //结束片选
- }
4. 头文件W25Q64.h
- /*********************************Copyright (c)*********************************
- **
- ** FIVE工作组
- **
- **---------------------------------File Info------------------------------------
- ** File Name: w25q64.h
- ** Last modified Date: 2013/9/10 9:32:33
- ** Last Version: V1.2
- ** Description: none
- **
- **------------------------------------------------------------------------------
- ** Created By: wanxuncpx
- ** Created date: 2013/8/6 21:12:35
- ** Version: V1.2
- ** Descriptions: none
- **------------------------------------------------------------------------------
- ** HW_CMU: STM32F103ZET6
- ** Libraries: STM32F10x_StdPeriph_Driver
- ** version V3.5
- *******************************************************************************/
- /******************************************************************************
- 更新说明:
- ******************************************************************************/
- /******************************************************************************
- ********************************* 应 用 资 料 ********************************
- *******************************************************************************
- 1. W25Q64 拥有32 768个页,每页256个字节故有8MB的容量
- 2. W25Q64 16个页为一个扇区
- 3. W25Q64 256个页为一个Block
- 2. 指令表
- ┌-----------------------┬--------┬-----------┬-----------┬-----------┬-----------┬-----------┐
- | 令名 | BYTE1 | BYTE2 | BYTE3 | BYTE4 | BYTE5 | BYTE6 |
- | | (CODE) | | | | | |
- ├-----------------------┼--------┼-----------┼-----------┼-----------┼-----------┼-----------┤
- | Write Enable | 06h | | | | | |
- | 允许写状态寄存器 | 50h | | | | | |
- | Write Disable | 04h | | | | | |
- | Read Status Register-1 | 05h | S7–S0 | | | | |
- | Read Status Register-2 | 35h | S15–S8 | | | | |
- | Write Status Register | 01h | S7–S0 | S15-S8 | | | |
- | Page Program | 02h | A23–A16 | A15–A8 | A7–A0 |D7–D0 | |
- | Quad Page Program | 32h | A23–A16 | A15–A8 | A7–A0 |D7–D0,..(3)| |
- | Sector Erase (4KB) | 20h | A23–A16 | A15–A8 | A7–A0 | | |
- | Block Erase (32KB) | 52h | A23–A16 | A15–A8 | A7–A0 | | |
- | Block Erase (64KB) | D8h | A23–A16 | A15–A8 | A7–A0 | | |
- | Chip Erase | C7h/60h | | | | | |
- | Erase / Program Suspend| 75h | | | | | |
- | Erase / Program Resume | 7Ah | | | | | |
- | Power-down | B9h | | | | | |
- | 复位连续读模式 | FFh | FFh | | | | |
- ├-----------------------┼--------┼-----------┼-----------┼-----------┼-----------┼-----------┤
- | Read Data | 03h | A23-A16 | A15-A8 | A7-A0 | (D7-D0) | |
- | Fast Read | 0Bh | A23-A16 | A15-A8 | A7-A0 | dummy |(D7-D0) |
- | Fast Read Dual Output | 3Bh | A23-A16 | A15-A8 | A7-A0 | dummy |(D7-D0, …) |
- | Fast Read Quad Output | 6Bh | A23-A16 | A15-A8 | A7-A0 | dummy |(D7-D0, …) |
- | Fast Read Dual I/O | BBh | A23-A8(2) | A7-A0, | M7-M0(2) | (D7-D0,..) | |
- | Fast Read Quad I/O | EBh |A23-A0,M7-M0|xxxx,D7-D0,.|(D7-D0,..) | | |
- | Word Read Quad I/O | E7h |A23-A0,M7-M0|xx,D7-D0,. |(D7-D0,..) | | |
- |Octal Word Read Quad I/O| E3h |A23-A0,M7-M0|(D7-D0,.) | | | |
- | Set Burst with Wrap | 77h |xxxxxx,W6-W4| | | | |
- ├-----------------------┼--------┼-----------┼-----------┼-----------┼-----------┼-----------┤
- |Release Device ID | ABh | dummy | dummy | dummy | (ID7-ID0) | |
- |ID | 90h | dummy | dummy | 00h | (MF7-MF0) | (ID7-ID0) |
- |ID by Dual I/O | 92h | A23-A8 |A7-A0,M[7:0]|MF[7:0],ID[7:0] | | |
- |ID by Quad I/O | 94h | A23-A0,M[7:0]| xxxx,(MF[7:0],ID[7:0])|(MF[7:0], ID[7:0], …)| ||
- |JEDEC ID | 9Fh | (MF7-MF0) | (ID15-ID8) | (ID7-ID0) | | |
- |Read Unique ID | 4Bh | dummy | dummy | dummy | dummy | (ID63-ID0) |
- |Erase Security Registers| 44h | A23–A16 | A15–A8 | A7–A0 | | |
- |Program Security Registers|42h | A23–A16 | A15–A8 | A7–A0 | D7-D0 | D7-D0 |
- |Read Security Registers | 48h | A23–A16 | A15–A8 | A7–A0 | dummy | (D7-0) |
- └-----------------------┴--------┴-----------┴-----------┴-----------┴-----------┴-----------┘
- ******************************************************************************/
- #ifndef _W25Q64_H_
- #define _W25Q64_H_
- /******************************************************************************
- ********************************* 文件引用部分 ********************************
- ******************************************************************************/
- #include "stm32f10x.h"
- #include "stm32f10x_gpio.h"
- #include "stm32f10x_rcc.h"
- #include "stm32f10x_spi.h"
- #include "stm32f10x_dma.h"
- #include <string.h>
- #include <stdbool.h>
- #include <stdint.h>
- /******************************************************************************
- ******************************* 系 统 参 数 定 义******************************
- ******************************************************************************/
- /*---------------------*
- * USART优先级定义
- *----------------------*/
- #define W25X_DMA_TC_PRIO 2 /* 中断优先级 */
- /*---------------------*
- * 参数配置定义
- *----------------------*/
- #define W25X_PAGE_SIZE 256 /* 定义页大小 */
- #define W25X_PAGE_NUM 32768 /* 定义页的个数 */
- #define W25X_SECTOR_SIZE 4096 /* 每扇区的大小 */
- #define W25X_PAGES_PS (W25X_SECTOR_SIZE/W25X_PAGE_SIZE) /* 每扇区的页数 */
- #define W25X_BUFF_NUM 2 /* 定义SRAM中缓冲个数 */
- #define W25X_DUMMY_BYTE 0xFF /* 空读字节定义 */
- /******************************************************************************
- ********************************** 需自定义 ***********************************
- ****************************** 参数配置、引脚定义 ****************************
- ******************************************************************************/
- /*---------------------*
- * 本地硬件连接
- *----------------------*/
- /*---------------------*
- * 常用指令定义
- *----------------------*/
- #define W25X_ReadStatusReg 0x05 //读状态寄存器1
- #define W25X_ReadStatusReg2 0x35 //读状态寄存器2
- #define W25X_WriteStatusReg 0x01 //写状态寄存器1
- #define W25X_ReadUniqueID 0x4B //读取唯一ID
- #define W25X_WriteEnable 0x06 //写使能
- #define W25X_WriteDisable 0x04 //写关闭
- #define W25X_ReadData 0x03 //读数据
- #define W25X_PageProgram 0x02 //写FLASH
- #define W25X_ChipErase 0x60 //也可为0x60
- #define W25X_SectorErase 0x20 //4KB擦除
- #define W25X_PowerDown 0xB9 //掉电,低功耗
- #define W25X_ReleasePowerDown 0xAB //恢复上电
- /******************************************************************************
- ********************************* 参数宏定义 *********************************
- ******************************************************************************/
- /*---------------------*
- * 参数定义
- *----------------------*/
- #define W25X_WP_DIS() (GPIOB->BRR = GPIO_Pin_0)
- #define W25X_WP_EN() (GPIOB->BSRR = GPIO_Pin_0)
- #define W25X_CS_L() (GPIOA->BRR = GPIO_Pin_4)
- #define W25X_CS_H() (GPIOA->BSRR = GPIO_Pin_4)
- /******************************************************************************
- ********************************* 数 据 声 明 *********************************
- ******************************************************************************/
- /*---------------------*
- * 输出数据
- *----------------------*/
- extern uint8_t W25X_Buffer[W25X_SECTOR_SIZE];
- extern volatile bool sem_W25X_DMA_Busy; //用户只读
- extern volatile bool sem_W25X_DMA_RxRdy; //用户读取,清零
- /******************************************************************************
- ********************************* 函 数 声 明 *********************************
- ******************************************************************************/
- /*---------------------*
- * 输出函数
- *----------------------*/
- //初始化
- extern void W25X_GPIO_Config(void); //配置GPIO口
- extern void W25X_Init(void); //初始化SPI
- //获取状态
- extern uint8_t W25X_ReadSR(void); //读取状态寄存器
- extern uint16_t W25X_ReadID(void); //读取ID号
- extern void W25X_Wait_Busy(void); //等待W25X直到空闲
- extern bool W25X_Read_BusyState(void); //读取W25X的忙状态(不等待)
- //控制状态
- extern void W25X_Write_Enable(void); //写使能
- extern void W25X_Write_Disable(void); //写禁止
- extern void SPI_Flash_PowerDown(void); //掉电
- extern void SPI_Flash_WakeUp(void); //唤醒
- //擦除相关(有等待选择)
- extern void W25X_Erase_Chip(bool bwait); //全片擦除,要等待写完成,需要21秒
- extern void W25X_Erase_Sector(uint32_t Dst_Addr,bool bwait); //扇区擦除,实际需要65ms
- extern void W25X_Read_Data(uint8_t * pBuffer,uint32_t ReadAddr,uint16_t NumByteToRead); //250us执行完毕
- extern void W25X_DMARead_Data(uint8_t * pBuffer,uint32_t ReadAddr,uint16_t NumByteToRead); //5us执行,75us后结束
- extern void W25X_Read_Page(uint8_t * pBuffer,uint32_t PageAddr); //读出一页,300us
- extern void W25X_Write_Page(uint8_t * pBuffer,uint32_t PageAddr); //写入一页,必先擦除,事先有些等待,600us
- extern void W25X_Read_UID(uint8_t * pBuffer); //读取W25X的唯一MAC,<5us
- /******************************************************************************
- *********************************** END ************************************
- ******************************************************************************/
- #endif