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