首先要设置相关的管脚信号:MISO,MOSI,SPCK以及片选信号NPCS(CS0)
void InitSpiBus_MsIO(void)
{
*AT91C_PMC_PCER = 0xFFffffFF;
*AT91C_PIOA_PER = PA12_MISO|PA13_MOSI|PA14_SPCK|PA11_CS0;
*AT91C_PIOA_OER = PA13_MOSI|PA14_SPCK|PA11_CS0;//PA12_MISO|PA13_MOSI|
*AT91C_PIOA_SODR = PA11_CS0;//PA12_MISO|PA11_CS0;
*AT91C_PIOA_CODR = PA14_SPCK;
}
然后使用下面几个函数操作:
void BufferWrite(UINT16 buffer_addr,BYTE *target,UINT16 size,CS_NO cs_no);
void BufferRead(UINT16 buffer_addr,BYTE *target,UINT16 size,CS_NO cs_no_mode);
void MainPageRead(UINT16 page_addr,UINT16 buffer_addr,BYTE *target,UINT16 size,PAGE_SIZE_TYPE page_size_mode);
void MainPageProgThroughBuffer(UINT16 page_addr,UINT16 buffer_addr,BYTE *target,UINT16 size,CS_NO cs_no,PAGE_SIZE_TYPE page_size_mode);
其中BufferWrite是对SDRAM写入,所以掉电后不能保存BufferWrite设置的值。
具体可以参考:AT91SAM7S64 驱动 AT45DB321D DataFlash的程序 使用模拟SPI总线完成- http://www.pudn.com/downloads263/sourcecode/embed/detail1209624.html
下面是实现函数:
//#include<AT91SAM7S64.H>
#include "..\header\AT91SAM7X256.h"
#ifndef __MACRO_H__
#include"macro.h"
#endif
#include"spi.h"
#ifndef __AT45DB321D_MACRO_H__
#include"AT45DB321D_MACRO.H"
#endif
#define DONT_CARE_ADDR 0x00
typedef enum _PAGE_SIZE_TYPE
{
STANDARD_PAGE_SIZE=0,
BINARY_PAGE_SIZE=1
}PAGE_SIZE_TYPE;
#define BUFFER_SIZE 528
BYTE DB321_buf[528]={0};
BYTE ReadStateRegister()
{
BYTE state=0,busy;
CLR_CS0; //拉低片选信号
SpiSendByte(0xD7);//
state = SpiReadByte();
state = SpiReadByte();
SET_CS0;
#if 1
if(state&0x80) //^7=0:busy; =1:ready
busy =0;
else busy =1;
#endif
return busy;
}
// read manufacturer Device ID
UINT32 ManufacturerDeviceRead()
{
UINT32 temp =0;
BYTE state;
while(ReadStateRegister());
CLR_CS0; //拉低片选信号
SpiSendByte(0x9F);//
state = SpiReadByte();
temp = state;
state = SpiReadByte();
temp += ((UINT32)state <<8);
state = SpiReadByte();
temp += ((UINT32)state <<16);
state = SpiReadByte();
temp += ((UINT32)state <<24);
SET_CS0;
return temp;
}
// Write data to AT45DB321D's RAM buffer
void BufferWrite(UINT16 buffer_addr,BYTE *target,UINT16 size,CS_NO cs_no)
{
while(ReadStateRegister());
CLR_CS0; //拉低片选信号
if(!cs_no)//cs_no=0 :buffer 1 ; cs_no=1 :buffer 2
SpiSendByte(Buffer1_Write);//
else
SpiSendByte(Buffer2_Write);//
//send 3 bytes buffer addr (512:15don't care bit 528:14don't care bit)
SpiSendByte(DONT_CARE_ADDR);//
SpiSendByte((BYTE)(buffer_addr>>8));
SpiSendByte((BYTE)buffer_addr);
//send size bytes data to buffer
while(size--)
{
SpiSendByte(*target++);//
}
SET_CS0; //拉高片选信号
}
// Read data from AT45DB321D's RAM buffer to target array
void BufferRead(UINT16 buffer_addr,BYTE *target,UINT16 size,CS_NO cs_no_mode)
{
//FLAG ready = 0;
while(ReadStateRegister());
CLR_CS0; //拉低片选信号
//send cmd opcode
switch(cs_no_mode)
{
case 0: SpiSendByte(Buffer1_Read);break;//0xD4
case 1: SpiSendByte(Buffer2_Read);break;//0xD6
case 4: SpiSendByte(Buffer1_Read_Low_Frequency);break;//0xD1
case 5: SpiSendByte(Buffer2_Read_Low_Frequency);break;//0xD3
case 8: SpiSendByte(Legacy_Buf1_Read);break;//0x54
case 9: SpiSendByte(Legacy_Buf2_Read);break;//0x54
}
//send 3 bytes buffer addr (512:15don't care bit 528:14don't care bit)
SpiSendByte(DONT_CARE_ADDR);//
SpiSendByte((BYTE)(buffer_addr>>8));
SpiSendByte((BYTE)buffer_addr);
SpiSendByte(DONT_CARE_ADDR);//
//read n size bytes data to buffer
while(size--)
{
*target++ = SpiReadByte();
}
SET_CS0; //拉高片选信号
}
// buffer data write to the AT45DB321D's main memory page
void BufferToMainPageProg(UINT16 page_addr,CS_NO cs_no_mode,PAGE_SIZE_TYPE page_size_mode)
{
while(ReadStateRegister());
CLR_CS0; //拉低片选信号
//send cmd opcode
switch(cs_no_mode)
{
case 0: SpiSendByte(Buf1_toMainPageProg_With_Erase);break;//0x83
case 1: SpiSendByte(Buf2_toMainPageProg_With_Erase);break;//0x86
case 8: SpiSendByte(Buf1_toMainPageProg_Without_Erase);break;//0x88
case 9: SpiSendByte(Buf2_toMainPageProg_Without_Erase);break;//0x89
}
//send 3 bytes buffer addr (512:15don't care bit 528:14don't care bit)
if(page_size_mode == STANDARD_PAGE_SIZE)
{
SpiSendByte((BYTE)(page_addr>>6));//X.PA12-6 &(A21-A9)
SpiSendByte((BYTE)(page_addr<<2));//PA5-0 .xx
}
else //BINARY_PAGE_SIZE=1 (A21-A9)
{
SpiSendByte((BYTE)(page_addr>>7));//XX.(A21-A16)
SpiSendByte((BYTE)(page_addr<<1));//(A15-A9).X
}
SpiSendByte(DONT_CARE_ADDR);
SET_CS0; //拉高片选信号 执行片内写操作开始
}
// Data read from main memory page to buffer
void MainPageToBufferTransfer(UINT16 page_addr,CS_NO cs_no,PAGE_SIZE_TYPE page_size_mode)
{
while(ReadStateRegister());
CLR_CS0; //拉低片选信号
//send cmd opcode
if(!cs_no)
SpiSendByte(MainMemPageTo_Buf1_Transfer);// 0x53
else
SpiSendByte(MainMemPageTo_Buf2_Transfer);// 0x55
//send 3 bytes buffer addr (512:15don't care bit 528:14don't care bit)
if(page_size_mode == STANDARD_PAGE_SIZE)
{
SpiSendByte((BYTE)(page_addr>>6));//X.PA12-6 &(A21-A9)
SpiSendByte((BYTE)(page_addr<<2));//PA5-0 .xx
}
else //BINARY_PAGE_SIZE=1 (A21-A9)
{
SpiSendByte((BYTE)(page_addr>>7));//XX.(A21-A16)
SpiSendByte((BYTE)(page_addr<<1));//(A15-A9).X
}
SpiSendByte(DONT_CARE_ADDR);
SET_CS0; //拉高片选信号 执行片内写操作开始
}
/* Program flash(AT45DB) through buffer
need buffer_addr and page_addr
*/
void MainPageProgThroughBuffer(UINT16 page_addr,UINT16 buffer_addr,BYTE *target,UINT16 size,CS_NO cs_no,PAGE_SIZE_TYPE page_size_mode)
{
BYTE temp_addr;
while(ReadStateRegister());
CLR_CS0; //拉低片选信号
//send 1 byte cmd opcode
if(!cs_no)//cs_no=0 :buffer 1 ; cs_no=1 :buffer 2
SpiSendByte(MainPageProg_Through_Buf1);// 0x82
else
SpiSendByte(MainPageProg_Through_Buf2);// 0x85
//send 3 bytes buffer addr (512:15don't care bit 528:14don't care bit)
if(page_size_mode == STANDARD_PAGE_SIZE)//528 bytes per page
{
SpiSendByte((BYTE)(page_addr>>6)); //X.PA12-6 &(A21-A9)
temp_addr = (BYTE)( (page_addr<<2)|(buffer_addr>>8) );
SpiSendByte(temp_addr); //PA5-0 .BA9-BA8
SpiSendByte((BYTE)buffer_addr); //BA7-BA0
}
else //BINARY_PAGE_SIZE=1 //512 bytes per page
{
SpiSendByte((BYTE)(page_addr>>7)); //XX.(A21-A16)
temp_addr = (BYTE)( (page_addr<<1)|(buffer_addr>>8) );
SpiSendByte(temp_addr); //(A15-A9).A8
SpiSendByte((BYTE)buffer_addr); //(A7-A0)
}
//send size bytes data to buffer
while(size--)
{
SpiSendByte(*target++);
}
SET_CS0; //拉高片选信号 start inself-time program
}
/* Main Memory page read to use array
可选择 page中的地址 不必从addr=0 开始读,超过end_page_addr 则回绕到该页的起始地址开始继续读操作
主存储器页读绕过这两个数据缓冲器和叶缓冲区的内容不变。
*/
void MainPageRead(UINT16 page_addr,UINT16 buffer_addr,BYTE *target,UINT16 size,PAGE_SIZE_TYPE page_size_mode)
{
BYTE temp_addr,i;
while(ReadStateRegister());
CLR_CS0; //拉低片选信号
//send 1 byte cmd opcode
SpiSendByte(Main_Memory_Page_Read); // 0xD2
//send 3 bytes buffer addr (512:15don't care bit 528:14don't care bit)
if(page_size_mode == STANDARD_PAGE_SIZE)//528 bytes per page
{
SpiSendByte((BYTE)(page_addr>>6)); //X.PA12-6 &(A21-A9)
temp_addr = (BYTE)( (page_addr<<2)|(buffer_addr>>8) );
SpiSendByte(temp_addr); //PA5-0 .BA9-BA8
SpiSendByte((BYTE)buffer_addr); //BA7-BA0
}
else //BINARY_PAGE_SIZE=1 //512 bytes per page
{
SpiSendByte((BYTE)(page_addr>>7)); //XX.(A21-A16)
temp_addr = (BYTE)( (page_addr<<1)|(buffer_addr>>8) );
SpiSendByte(temp_addr); //(A15-A9).A8
SpiSendByte((BYTE)buffer_addr); //(A7-A0)
}
//send 4 bytes don't care addr
for(i=0;i<4;i++) SpiSendByte(DONT_CARE_ADDR);
//read n size bytes data to buffer
while(size--)
{
*target++ = SpiReadByte();
}
SET_CS0; //拉高片选信号
}
// continuous Array read 可以读多个连续的page -------------------------------------------//
void ArrayRead(UINT16 page_addr,UINT16 buffer_addr,BYTE *target,UINT16 size,CS_NO cs_no_mode,PAGE_SIZE_TYPE page_size_mode)
{
BYTE temp_addr,i;
while(ReadStateRegister());
CLR_CS0; //拉低片选信号
//send 1 byte cmd opcode
switch(cs_no_mode)
{
case 0:SpiSendByte(ARRAY_READ);break;
case 1:SpiSendByte(Low_Frequency_Array_Read);break;
case 2:SpiSendByte(High_Frequency_Array_Read);break;
case 5:SpiSendByte(Legacy_Array_Read);break; //没有时序图
}
//send 3 bytes buffer addr (512:15don't care bit 528:14don't care bit)
if(page_size_mode == STANDARD_PAGE_SIZE)//528 bytes per page
{
SpiSendByte((BYTE)(page_addr>>6)); //X.PA12-6 &(A21-A9)
temp_addr = (BYTE)( (page_addr<<2)|(buffer_addr>>8) );
SpiSendByte(temp_addr); //PA5-0 .BA9-BA8
SpiSendByte((BYTE)buffer_addr); //BA7-BA0
}
else //BINARY_PAGE_SIZE=1 //512 bytes per page
{
SpiSendByte((BYTE)(page_addr>>7)); //XX.(A21-A16)
temp_addr = (BYTE)( (page_addr<<1)|(buffer_addr>>8) );
SpiSendByte(temp_addr); //(A15-A9).A8
SpiSendByte((BYTE)buffer_addr); //(A7-A0)
}
//send n bytes don't care addr (n<=4)
switch(cs_no_mode)
{
case 0:for(i=0;i<4;i++) SpiSendByte(DONT_CARE_ADDR);break;
case 1:break;
case 2:SpiSendByte(DONT_CARE_ADDR);break;
case 5:break; //没有时序图
}
//read n size bytes data to buffer
while(size--)
{
*target++ = SpiReadByte();
}
SET_CS0; //拉高片选信号 结束 Array Read
}
//------------------------------------------------------------------------//
void DeepPowerDown(void)
{
while(ReadStateRegister());
CLR_CS0; //拉低片选信号
SpiSendByte(DEEP_POWER_DOWN);
SET_CS0; //拉高片选信号
}
void ResumeFromDeepPowerDown(void)
{
while(ReadStateRegister());
CLR_CS0; //拉低片选信号
SpiSendByte(Resume_From_DeepPowerDown);
SET_CS0; //拉高片选信号
}
/*
对“2的幂”页面大小是一个一次性可编程(OTP)寄存器,一旦设备被配置为“2的幂”页面大小,不能再重新配置。
*/
void PowerofTwoPageSize(void) //建议不修改原有FLash存储结构,1但修改为512Bytes/page 则不能重新配置
{
while(ReadStateRegister());
CLR_CS0; //拉低片选信号 0x3D ,0x2A ,0x80 ,0xA6
SpiSendByte(0x3D);
SpiSendByte(0x2A);
SpiSendByte(0x80);
SpiSendByte(0xA6);
SET_CS0; //拉高片选信号
}
// page erase operation
void PageErase(UINT16 page_addr,PAGE_SIZE_TYPE page_size_mode)
{
while(ReadStateRegister());
CLR_CS0; //拉低片选信号
SpiSendByte(PAGE_ERASE);
if(page_size_mode == STANDARD_PAGE_SIZE)//528 bytes per page
{
SpiSendByte((BYTE)(page_addr>>6)); //X.PA12-6 &(A21-A9)
SpiSendByte((BYTE)(page_addr<<2)); //PA5-0 .BA9-BA8
}
else //BINARY_PAGE_SIZE=1 //512 bytes per page
{
SpiSendByte((BYTE)(page_addr>>7)); //XX.(A21-A16)
SpiSendByte((BYTE)(page_addr<<1)); //(A15-A9).A8
}
SpiSendByte(DONT_CARE_ADDR);//
SET_CS0; //拉高片选信号
}
//Block Erase 8 page per block total:1024 blocks
void BlockErase(UINT16 block_addr,PAGE_SIZE_TYPE page_size_mode)
{
while(ReadStateRegister());
CLR_CS0; //拉低片选信号
//send 1 byte cmd opcode
SpiSendByte(BLOCK_ERASE);
if(page_size_mode == STANDARD_PAGE_SIZE)//528 bytes per page
{
SpiSendByte((BYTE)(block_addr>>3)); //X.PA12-6
SpiSendByte((BYTE)(block_addr<<5)); //PA5-3 .xxxxx
}
else //BINARY_PAGE_SIZE=1 //512 bytes per page
{
SpiSendByte((BYTE)(block_addr>>4)); //XX.(A21-A16)
SpiSendByte((BYTE)(block_addr<<4)); //(A15-A12).xxxx
}
SpiSendByte(DONT_CARE_ADDR);//
SET_CS0; //拉高片选信号
}
//Sector Erase 16 block per sector total:64 sectors
void SectorErase(UINT16 sector_addr,PAGE_SIZE_TYPE page_size_mode)
{
while(ReadStateRegister());
CLR_CS0; //拉低片选信号
//send 1 byte cmd opcode
SpiSendByte(BLOCK_ERASE);
if(page_size_mode == STANDARD_PAGE_SIZE)//528 bytes per page
{
SpiSendByte((BYTE)(sector_addr>>3)); //X.PA12-9
SpiSendByte(DONT_CARE_ADDR);//
SpiSendByte(DONT_CARE_ADDR);//
}
else //BINARY_PAGE_SIZE=1 //512 bytes per page
{
SpiSendByte((BYTE)(sector_addr>>4));
SpiSendByte((BYTE)(sector_addr<<4));
SpiSendByte(DONT_CARE_ADDR);//
}
SET_CS0; //拉高片选信号 内部擦出开始
}
// chip earse
void ChipErase(void)
{
while(ReadStateRegister());
CLR_CS0; //拉低片选信号 0xC7,0x94,0x80,0x9A
SpiSendByte(0xC7);//
SpiSendByte(0x94);//
SpiSendByte(0x80);//
SpiSendByte(0x9A);//
SET_CS0; //拉高片选信号 内部擦出开始
}