?? mx25l1605drv.c
字號:
/****************************************Copyright (c)**************************************************
** Guangzou ZLG-MCU Development Co.,LTD.
** graduate school
** http://www.zlgmcu.com
**
**--------------File Info-------------------------------------------------------------------------------
** File name: MX25L1602.c
** Descriptions: SPI下的SST25VF016B操作函數庫
**
**------------------------------------------------------------------------------------------------------
** Created by: Litiantian
** Created date: 2007-04-16
** Version: 1.0
** Descriptions: The original version
**
**------------------------------------------------------------------------------------------------------
** Modified by:
** Modified date:
** Version:
** Descriptions:
********************************************************************************************************/
#include <stdio.h>
#include "LPC11xx.h" /* LPC11xx 外設寄存器 */
#include "MX25L1605Drv.h"
/* 移植本軟件包時需要修改以下的函數或宏 */
#define CE_Low() LPC_GPIO0->DATA &= ~(0x1<<7) //P0.7=0
#define CE_High() LPC_GPIO0->DATA |= (0x1<<7); //P0.7=0
/* SPI初始化 */
/*******************************************************************************************
** 函數名稱:SPIInit
** 功能說明:初始化SPI。
** 入口參數:無
** 出口參數:無
*******************************************************************************************/
void SPIInit(void)
{
LPC_SYSCON->PRESETCTRL|=0x01; //取消SSP0復位
LPC_SYSCON->SYSAHBCLKCTRL|=(1<<11); //打開SSP外設
LPC_SYSCON->SYSAHBCLKCTRL|=(1<<16); //使能IO配置塊時鐘
LPC_SYSCON->SSP0CLKDIV =0x01; //時鐘不分頻
// LPC_IOCON->PIO0_7=0x01; //設置CS 片選
LPC_IOCON->PIO0_7=0x00; //設置GPIO
LPC_GPIO0->DIR |=0x080; //設置P0_7為輸出
LPC_SSP0->CR0 =(0x01<<8)| //SCR時鐘分頻 f=PCLK/(CPSDVSRX[SCR+1])
(0x00<<7)| //時鐘輸出相位
(0x00<<6)| //時鐘輸出極性
(0x00<<4)| // FRF幀格式 00=SPI,01=SSI 10=Microwire,11=保留
(0x07<<0); //0111=8bit,0011=4bit,1111=16bit
LPC_SSP0->CR1 =(0x00<<3)| //從機輸出禁能,1=禁止
(0x00<<2)| //MS選擇,0=主機;1=從機;
(0x01<<1)| //SSP使能
(0x00<<0); //正常模式
LPC_SSP0->CPSR=0x02; //PCLK分頻值
LPC_SSP0->ICR=0x03; //中斷清除
}
/************************************************************************
** 函數名稱: Send_Byte
** 函數功能:通過硬件SPI發送一個字節到MX25L1602
** 入口參數:data
** 出口參數:無
************************************************************************/
void Send_Byte(uint8_t data)
{
LPC_SSP0->DR = data;
while (LPC_SSP0->SR&0x010!=0); // 等待BSY=0,即等待數據發送
}
/************************************************************************
** 函數名稱:Get_Byte
** 函數功能:通過硬件SPI接口接收一個字節到處理器
** 入口參數:無
** 出口參數:無
************************************************************************/
uint8_t Get_Byte(void)
{
LPC_SSP0->DR = 0xff; // 發送該數據用以產生時鐘,數據本身沒有用處
while (LPC_SSP0->SR&0x010!=0); // 等待BSY=0,即等待數據發送
return (LPC_SSP0->DR); // 返回接收到的數據
}
/* 以下函數在移植時無需修改 */
/************************************************************************
** 函數名稱:MX25L1602_RD
** 函數功能:MX25L1602的讀函數,可選擇讀ID和讀數據操作
** 入口參數:
** INT32U Dst:目標地址,范圍 0x0 - MAX_ADDR(MAX_ADDR = 0x1FFFFF)
** INT32U NByte: 要讀取的數據字節數
** INT8U* RcvBufPt:接收緩存的指針
** 出口參數:操作成功則返回OK,失敗則返回ERROR
** 注 意:若某功能下,某一入口參數無效,可在該入口參數處填Invalid,該參數將被忽略
************************************************************************/
uint8_t MX25L1602_RD(uint32_t Dst, uint32_t NByte,uint8_t* RcvBufPt)
{
uint32_t i = 0;
if ((Dst+NByte > MAX_ADDR)||(NByte == 0)) return (ERROR); // 檢查入口參數
CE_Low();
Send_Byte(0x0B); // 發送讀命令
Send_Byte(((Dst & 0xFFFFFF) >> 16)); // 發送地址信息:該地址由3個字節組成
Send_Byte(((Dst & 0xFFFF) >> 8));
Send_Byte(Dst & 0xFF);
Send_Byte(0xFF); // 發送一個啞字節以讀取數據
for (i = 0; i < NByte; i++)
{
RcvBufPt[i] = Get_Byte();
}
CE_High();
return (OK);
}
/************************************************************************
** 函數名稱:MX25L1602_RdID
** 函數功能:MX25L1602的讀ID函數,可選擇讀ID和讀數據操作
** 入口參數:
** idtype IDType:ID類型。用戶可在Jedec_ID,Dev_ID,Manu_ID三者里選擇
** INT32U* RcvbufPt:存儲ID變量的指針
** 出口參數:操作成功則返回OK,失敗則返回ERROR
** 注 意:若填入的參數不符合要求,則返回ERROR
************************************************************************/
uint8_t MX25L1602_RdID(idtype IDType, uint32_t* RcvbufPt)
{
uint32_t temp = 0;
if (IDType == Jedec_ID)
{
CE_Low();
Send_Byte(0x9F); // 發送讀JEDEC ID命令(9Fh)
temp = (temp | Get_Byte()) << 8;// 接收數據
temp = (temp | Get_Byte()) << 8;
temp = (temp | Get_Byte()); // 在本例中,temp的值應為0xBF2541
CE_High();
*RcvbufPt = temp;
return (OK);
}
if ((IDType == Manu_ID) || (IDType == Dev_ID) )
{
CE_Low();
Send_Byte(0x90); // 發送讀ID命令 (90h or ABh)
Send_Byte(0x00); // 發送地址
Send_Byte(0x00); // 發送地址
Send_Byte(IDType); // 發送地址 - 不是00H就是01H
temp = Get_Byte(); // 接收獲取的數據字節
CE_High();
*RcvbufPt = temp;
return (OK);
}
else
{
return (ERROR);
}
}
/************************************************************************
** 函數名稱:MX25L1602_WR
** 函數功能:MX25L1602的寫函數,可寫1個和多個數據到指定地址
** 入口參數:
** INT32U Dst:目標地址,范圍 0x0 - MAX_ADDR(MAX_ADDR = 0x1FFFFF)
** INT8U* SndbufPt:發送緩存區指針
** INT32U NByte:要寫的數據字節數
** 出口參數:操作成功則返回OK,失敗則返回ERROR
** 注 意:若某功能下,某一入口參數無效,可在該入口參數處填Invalid,該參數將被忽略
************************************************************************/
uint8_t MX25L1602_WR(uint32_t Dst, uint8_t* SndbufPt, uint32_t NByte)
{
uint32_t temp = 0,i = 0,StatRgVal = 0;
if (( (Dst+NByte-1 > MAX_ADDR)||(NByte == 0) ))
{
return (ERROR); // 檢查入口參數
}
CE_Low();
Send_Byte(0x05); // 發送讀狀態寄存器命令
temp = Get_Byte(); // 保存讀得的狀態寄存器值
CE_High();
CE_Low();
Send_Byte(0x50); // 使狀態寄存器可寫
CE_High();
CE_Low();
Send_Byte(0x01); // 發送寫狀態寄存器指令
Send_Byte(0); // 清0BPx位,使Flash芯片全區可寫
CE_High();
for(i = 0; i < NByte; i++)
{
CE_Low();
Send_Byte(0x06); // 發送寫使能命令
CE_High();
CE_Low();
Send_Byte(0x02); // 發送字節數據燒寫命令
Send_Byte((((Dst+i) & 0xFFFFFF) >> 16));// 發送3個字節的地址信息
Send_Byte((((Dst+i) & 0xFFFF) >> 8));
Send_Byte((Dst+i) & 0xFF);
Send_Byte(SndbufPt[i]); // 發送被燒寫的數據
CE_High();
do
{
CE_Low();
Send_Byte(0x05); // 發送讀狀態寄存器命令
StatRgVal = Get_Byte(); // 保存讀得的狀態寄存器值
CE_High();
}
while (StatRgVal == 0x03); // 一直等待,直到芯片空閑
}
CE_Low();
Send_Byte(0x06); // 發送寫使能命令
CE_High();
CE_Low();
Send_Byte(0x50); // 使狀態寄存器可寫
CE_High();
CE_Low();
Send_Byte(0x01); // 發送寫狀態寄存器指令
Send_Byte(temp); // 恢復狀態寄存器設置信息
CE_High();
return (OK);
}
/************************************************************************
** 函數名稱:MX25L1602_Erase
** 函數功能:根據指定的扇區號選取最高效的算法擦除
** 入口參數:
** INT32U sec1:起始扇區號,范圍(0~499)
** INT32U sec2:終止扇區號,范圍(0~499)
** 出口參數:操作成功則返回OK,失敗則返回ERROR
************************************************************************/
uint8_t MX25L1605_Erase(uint32_t uiStartSect, uint32_t uiEndSect)
{
uint32_t temp=0;
uint32_t ucStatus = 0;
/* 檢查入口參數 */
if ((uiStartSect > SEC_MAX)||(uiEndSect > SEC_MAX))
{
return (ERROR);
}
if(uiStartSect>uiEndSect)
{
temp=uiEndSect;
uiEndSect=uiStartSect;
uiStartSect=temp;
}
ucStatus=_MX25L1605_RDStat();
__MX25L1605_WrStat(0);
if(uiStartSect==uiEndSect)
{
}
CE_Low();
Send_Byte(0x05); // 發送讀狀態寄存器命令
temp1 = Get_Byte(); // 保存讀得的狀態寄存器值
CE_High();
CE_Low();
Send_Byte(0x50); // 使狀態寄存器可寫
CE_High();
CE_Low();
Send_Byte(0x01); // 發送寫狀態寄存器指令
Send_Byte(0); // 清0BPx位,使Flash芯片全區可寫
CE_High();
CE_Low();
Send_Byte(0x06); // 發送寫使能命令
CE_High();
/* 如果用戶輸入的起始扇區號大于終止扇區號,則在內部作出調整 */
if (sec1 > sec2)
{
temp2 = sec1;
sec1 = sec2;
sec2 = temp2;
}
/* 若起止扇區號相等則擦除單個扇區 */
if (sec1 == sec2)
{
SecnHdAddr = SEC_SIZE * sec1; // 計算扇區的起始地址
CE_Low();
Send_Byte(0x20); // 發送扇區擦除指令
Send_Byte(((SecnHdAddr & 0xFFFFFF) >> 16)); // 發送3個字節的地址信息
Send_Byte(((SecnHdAddr & 0xFFFF) >> 8));
Send_Byte(SecnHdAddr & 0xFF);
CE_High();
do
{
CE_Low();
Send_Byte(0x05); // 發送讀狀態寄存器命令
StatRgVal = Get_Byte(); // 保存讀得的狀態寄存器值
CE_High();
}
while (StatRgVal == 0x03); // 一直等待,直到芯片空閑
return (OK);
}
/* 根據起始扇區和終止扇區間距調用最快速的擦除功能 */
if (sec2 - sec1 == SEC_MAX)
{
CE_Low();
Send_Byte(0x60); // 發送芯片擦除指令(60h or C7h)
CE_High();
do
{
CE_Low();
Send_Byte(0x05); // 發送讀狀態寄存器命令
StatRgVal = Get_Byte(); // 保存讀得的狀態寄存器值
CE_High();
}
while (StatRgVal == 0x03); // 一直等待,直到芯片空閑
return (OK);
}
no_SecsToEr = sec2 - sec1 +1; // 獲取要擦除的扇區數目
CurSecToEr = sec1; // 從起始扇區開始擦除
/* 若兩個扇區之間的間隔夠大,則采取16扇區擦除算法 */
while (no_SecsToEr >= 16)
{
SecnHdAddr = SEC_SIZE * CurSecToEr; // 計算扇區的起始地址
CE_Low();
Send_Byte(0xD8); // 發送64KB塊擦除指令
Send_Byte(((SecnHdAddr & 0xFFFFFF) >> 16)); // 發送3個字節的地址信息
Send_Byte(((SecnHdAddr & 0xFFFF) >> 8));
Send_Byte(SecnHdAddr & 0xFF);
CE_High();
do
{
CE_Low();
Send_Byte(0x05); // 發送讀狀態寄存器命令
StatRgVal = Get_Byte(); // 保存讀得的狀態寄存器值
CE_High();
}
while (StatRgVal == 0x03); // 一直等待,直到芯片空閑
CurSecToEr += 16; // 計算擦除了16個扇區后,和擦除區域相鄰的待擦除扇區號
no_SecsToEr -= 16; // 對需擦除的扇區總數作出調整
}
/* 若兩個扇區之間的間隔夠大,則采取8扇區擦除算法 */
while (no_SecsToEr >= 8)
{
SecnHdAddr = SEC_SIZE * CurSecToEr; // 計算扇區的起始地址
CE_Low();
Send_Byte(0x52); // 發送32KB擦除指令
Send_Byte(((SecnHdAddr & 0xFFFFFF) >> 16)); // 發送3個字節的地址信息
Send_Byte(((SecnHdAddr & 0xFFFF) >> 8));
Send_Byte(SecnHdAddr & 0xFF);
CE_High();
do
{
CE_Low();
Send_Byte(0x05); // 發送讀狀態寄存器命令
StatRgVal = Get_Byte(); // 保存讀得的狀態寄存器值
CE_High();
}
while (StatRgVal == 0x03); // 一直等待,直到芯片空閑
CurSecToEr += 8;
no_SecsToEr -= 8;
}
/* 采用扇區擦除算法擦除剩余的扇區 */
while (no_SecsToEr >= 1)
{
SecnHdAddr = SEC_SIZE * CurSecToEr; // 計算扇區的起始地址
CE_Low();
Send_Byte(0x20); // 發送扇區擦除指令
Send_Byte(((SecnHdAddr & 0xFFFFFF) >> 16)); // 發送3個字節的地址信息
Send_Byte(((SecnHdAddr & 0xFFFF) >> 8));
Send_Byte(SecnHdAddr & 0xFF);
CE_High();
do
{
CE_Low();
Send_Byte(0x05); // 發送讀狀態寄存器命令
StatRgVal = Get_Byte(); // 保存讀得的狀態寄存器值
CE_High();
}
while (StatRgVal == 0x03); // 一直等待,直到芯片空閑
CurSecToEr += 1;
no_SecsToEr -= 1;
}
/* 擦除結束,恢復狀態寄存器信息 */
CE_Low();
Send_Byte(0x06); // 發送寫使能命令
CE_High();
CE_Low();
Send_Byte(0x50); // 使狀態寄存器可寫
CE_High();
CE_Low();
Send_Byte(0x01); // 發送寫狀態寄存器指令
Send_Byte(temp1); // 恢復狀態寄存器設置信息
CE_High();
return (OK);
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -