STM32驱动AT45DB161D代码
//SPI初始化部分:
void SPI2_Init(void)
{
RCC->APB2ENR|=1<<3; //PORTB时钟使能
RCC->APB1ENR|=1<<14; //SPI2时钟使能
//这里只针对SPI口初始化
GPIOB->CRH&=0X000FFFFF;
GPIOB->CRH|=0XBBB00000; //PB13/14/15复用
GPIOB->ODR|=0X7<<13; //PB13/14/15上拉
SPI2->CR1|=0<<10; //全双工模式
SPI2->CR1|=1<<9; //软件nss管理
SPI2->CR1|=1<<8;
SPI2->CR1|=1<<2; //SPI主机
SPI2->CR1|=0<<11; //8bit数据格式
SPI2->CR1|=1<<1; //空闲模式下SCK为1 CPOL=1
SPI2->CR1|=1<<0; //数据采样从第二个时间边沿开始,CPHA=1 //对SPI2属于APB1的外设.时钟频率最大为36M.
SPI2->CR1|=7<<3; //Fsck=Fpclk1/256
SPI2->CR1|=0<<7; //MSBfirst
SPI2->CR1|=1<<6; //SPI设备使能
SPI2_ReadWriteByte(0xff);//启动传输
}
//SPI2 读写一个字节
//TxData:要写入的字节
//返回值:读取到的字节
u8 SPI2_ReadWriteByte(u8 TxData)
{
u16 retry=0;
while((SPI2->SR&1<<1)==0) //等待发送区空
{
retry++;
if(retry>=0XFFFE)return 0; //超时退出
}
SPI2->DR=TxData; //发送一个byte
retry=0;
while((SPI2->SR&1<<0)==0) //等待接收完一个byte
{
retry++;
if(retry>=0XFFFE)return 0; //超时退出
}
return SPI2->DR; //返回收到的数据
}
//以下对存储器的操作都是针对AT45DB161D的,
//AT45DB161D:16Mbit=2M字节
//
void FLASH_Init(void)
{
RCC->APB2ENR|=1<<3; //使能PORTB时钟
RCC->APB2ENR|=1<<8; //使能PORTG时钟
GPIOB->CRH&=0XFFF0FFFF;
GPIOB->CRH|=0X00030000; //PB12 推挽
GPIOB->ODR|=1<<12; //PB12上拉
GPIOG->CRH&=0XFFFFFFF0;
GPIOG->CRH|=0X00000003; //PG8 推挽
GPIOG->ODR|=1<<8; //PG8 上拉
SPI2_Init(); //初始化SPI2
}
//读取AT45DB161D的状态寄存器(查看数据手册P23)
//返回:读取的状态
//bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0
//RDY/BUSY COMP 1 0 1 1 PROTECT PAGESIZE u8 Flash_ReadStatus(void)
{
u8 rd;
FLASH_CS_L; //使能操作
SPI2_ReadWriteByte(STATUS_REG_READ); //发送读状态寄存器命令"D7H”
rd=SPI2_ReadWriteByte(0XFF); //读回状态
FLASH_CS_H; //失能操作
return rd;
}
//FLASH判忙函数
//不断读取外部FLASH的状态寄存器的bit7为判断是否为0
//bit7:0,忙;1,不忙
static void Flash_CheckBusy(void)
{
u8 st;
st=SPI2_ReadWriteByte(0XFF);
while( (st&BUSY_BIT_MASK)== BUSY_STATUS )
{
st=SPI2_ReadWriteByte(0XFF);
}
}
//读FLASH函数,调用者需保证所读取的数据不能超过范围
//page:指定页地址(0~4095页)
//offset:页内偏移地址(0~527字节)
//nBytes:读取的字节数
//*data:读到的数组首地址
//-----连续读到达一个页的结尾时,芯片会从下个页的开头继续读取,
//-----页间的跨越是没有延时的。当主存储器的最后一个位被读出后,
//-----芯片会自动返回到第一页的开头继续读取。与页间跨越相同的,
//------从存储器阵列结尾转到开头也是无延时的。
void Flash_Read(u16 page,u16 offset,u16 nBytes,u8 *data)
{
u32 addr; //绝对地址变量,注意528字节每页与512字节每页的绝对地址计算不一样,//这里用默认(264字节每页模式)
addr=((u32)page<<10)+offset; //24根地址线,PA11~PA0为页地址,BA9~BA0为页内//地址,详情请查看数据手册A T45DB161D第31页Table15-7
Flash_CheckBusy(); //判忙
FLASH_CS_L;
SPI2_ReadWriteByte(CONTINUE_ARRAY_READ); //发送连续读命令"0BH"
SPI2_ReadWriteByte( (u8)(addr>>16) ); //发送地址,从高到低
SPI2_ReadWriteByte( (u8)(addr>>8) );
SPI2_ReadWriteByte( (u8)(addr) );
SPI2_ReadWriteByte( 0 ); //a dummy byte
while( (nBytes--)>0 )
{
*data++=SPI2_ReadWriteByte(0XFF); //循环读取字节
}
FLASH_CS_H;
Flash_CheckBusy();
}
//写FLASH函数,调用者需保证所写入的数据不能超过范围
//page:指定页地址(0~4095页)整页直接写入主存储器
//*data:待写入的数组首地址
void Flash_PageWrite(u16 page,u8 *data)
{
u16 i;
u32 addr=0;
Flash_CheckBusy(); //判忙
addr=( (u32)page<<10); //页首地址
FLASH_CS_L;
SPI2_ReadWriteByte(MAIN_MEM_PAGE_PROGRAM); //发送主存储器编程命令"82H"
SPI2_ReadWriteByte( (u8)(addr>>16) );
SPI2_ReadWriteByte( (u8)(addr>>8) );
SPI2_ReadWriteByte( (u8)(addr) );
for(i=0;i<264;i++)
{
SPI2_ReadWriteByte( *data++ ); //循环写入字节数据
}
FLASH_CS_H;
Flash_CheckBusy(); //等待写完
}
//写入BUFF1函数,调用者需保证所写入的数据不能超过范围
//offset: 页内偏移地址(0~527字节)
//nBytes:写入的字节数(最大528)
//*data:待写入的数组首地址
void Flash_WriteBuf(u16 offset,u16 nBytes,u8 *data)
{
Flash_CheckBusy();
FLASH_CS_L;
SPI2_ReadWriteByte(BUFFER1_WRITE);//发送写BUFF1命令“84H”
SPI2_ReadWriteByte( 0x00 );
SPI2_ReadWriteByte( (u8)(offset>>8) );
SPI2_ReadWriteByte( (u8)offset );
while( (nBytes--)>0 )
{
SPI2_ReadWriteByte( *data++ );
}
FLASH_CS_H;
Flash_CheckBusy();
}
//从BUFF1写入到主存储器函数,BUFF1刚好是1页大小的缓存
//page:页地址(0~4095)
void Flash_BufToMemory(u16 page)
{
u32 addr=0;
addr=((u32)page<<10);
Flash_CheckBusy();
FLASH_CS_L;
SPI2_ReadWriteByte( BUFFER1_TO_MEMORY_WITH_ERASE);//发送从BUFF1到
//FLASH的写入操作命令"83H"
SPI2_ReadWriteByte( (u8)(addr>>16) );
SPI2_ReadWriteByte( (u8)(addr>>8) );
SPI2_ReadWriteByte( (u8)(addr) );
FLASH_CS_H;
Flash_CheckBusy();
}
//页擦除函数,整页进行擦除
//page:页地址(0~4095)
void Flash_PageErase(u16 page)
{
u32 addr=0;
addr=( (u32)page<<10);//计算页的绝对地址
Flash_CheckBusy();
FLASH_CS_L;
SPI2_ReadWriteByte(PAGE_ERASE); //发送页擦除命令“81H”
SPI2_ReadWriteByte( (u8)(addr>>16) );
SPI2_ReadWriteByte( (u8)(addr>>8) );
SPI2_ReadWriteByte( (u8)(addr) );
FLASH_CS_H;
}