/**
********************************************************************
* 文件名 EEPROM_24LC256.c
* 作 者 ChipON_AE/FAE_Group
* 版 本 V2.1
* 日 期 2019-11-16
* 描 述 该文件提供了EERPOM读写功能函数等相关函数。
*
*********************************************************************
*/
#include "system_init.h"
#include "EEPROM_24LC256.h"
#define I2C_Buffer_Addr 0x40000D08 //I2C0 Buffer 地址
I2C_SFRmap* I2C_Choose; //定义I2C变量,取值 为I2C0_SFR~I2C3_SFR
//延时函数 局部变量用volatile声明,否则可能会被优化
void Delay(volatile uint32_t cnt)
{
while(cnt--);
}
void delay_ms(volatile uint32_t nms)
{
volatile uint32_t i,j;
for(i=0;i<nms;i++)
{
j=800;
while(j--);
}
}
/**
* 描述 eeprom 写入单字节数据。
* 输入 write_address:eeprom 16位寄存器地址
* p_buffer: 写入数据,取值为10位数据。
* 返回 无。
*/
void eeprom_byte_write(uint16_t write_address,uint32_t p_buffer)
{
I2C_Choose=I2C0_SFR;//选择I2C0_SFR I2C1_SFR I2C2_SFR I2C3_SFR
static uint8_t EEPROM_AddH=0;
static uint8_t EEPROM_AddL=0;
EEPROM_AddL=write_address& 0xff; //低8位寄存器地址
EEPROM_AddH=(write_address>>8)& 0xff; //高8位寄存器地址
I2C_Clear_INTERRUPT_Flag(I2C_Choose); //清I2C中断标志位ISIF位
I2C_Cmd(I2C_Choose,TRUE); //使能I2C模块
/*起始位*/
I2C_Generate_START(I2C_Choose,TRUE); //使能起始信号
while(!I2C_Get_INTERRUPT_Flag(I2C_Choose)); //等待起始位稳定
/*发送I2C从机地址*/
I2C_SendData(I2C_Choose,EEPROM_I2C_ADDRESS); //发送从机I2C地址
I2C_Clear_INTERRUPT_Flag(I2C_Choose); //清I2C中断标志位ISIF位
while(!I2C_Get_INTERRUPT_Flag(I2C_Choose)); //等待发送完成
/*发送高位地址*/
I2C_SendData(I2C_Choose,EEPROM_AddH); //发送从机高位寄存器地址
I2C_Clear_INTERRUPT_Flag(I2C_Choose); //清I2C中断标志位ISIF位
while(!I2C_Get_INTERRUPT_Flag(I2C_Choose)); //等待发送完成
/*发送低位地址*/
I2C_SendData(I2C_Choose,EEPROM_AddL); //发送从机低位寄存器地址
I2C_Clear_INTERRUPT_Flag(I2C_Choose); //清I2C中断标志位ISIF位
while(!I2C_Get_INTERRUPT_Flag(I2C_Choose)); //等待发送完成
/*发送数据*/
I2C_SendData(I2C_Choose, p_buffer); //发送8位数据
I2C_Clear_INTERRUPT_Flag(I2C_Choose); //清I2C中断标志位ISIF位
while(!I2C_Get_INTERRUPT_Flag(I2C_Choose)); //等待发送完成
/*停止位*/
I2C_Generate_STOP(I2C_Choose,TRUE); //使能停止信号
I2C_Clear_INTERRUPT_Flag(I2C_Choose); //清I2C中断标志位ISIF位
while(!I2C_Get_INTERRUPT_Flag(I2C_Choose)); //等待停止完成
I2C_Clear_INTERRUPT_Flag(I2C_Choose); //清I2C中断标志位ISIF位
I2C_Clear_Stop_Flag(I2C_Choose); //清I2C停止标志位PIF位
I2C_Cmd(I2C_Choose,FALSE); //关闭I2C模块
}
/**
* 描述 eeprom 写入多字节数据。
* 输入 write_address:eeprom 16位寄存器地址
* p_buffer: 写入数据指针
* number_of_byte:写入数据长度
* 返回 无。
*/
void eeprom_buffer_write(uint16_t Write_address,uint8_t *p_buffer,uint16_t number_of_byte)
{
I2C_Choose=I2C0_SFR;//选择I2C0_SFR I2C1_SFR I2C2_SFR I2C3_SFR
static uint8_t EEPROM_AddH=0;
static uint8_t EEPROM_AddL=0;
EEPROM_AddL=Write_address& 0xff; //低8位寄存器地址
EEPROM_AddH=(Write_address>>8)& 0xff; //高8位寄存器地址
I2C_Clear_INTERRUPT_Flag(I2C_Choose); //清I2C中断标志位ISIF位
I2C_Cmd(I2C_Choose,TRUE); //使能I2C模块
/*起始位*/
I2C_Generate_START(I2C_Choose,TRUE); //使能起始信号
while(!I2C_Get_INTERRUPT_Flag(I2C_Choose));
/*发送I2C从机地址*/
I2C_SendData8(I2C_Choose,EEPROM_I2C_ADDRESS); //发送从机I2C地址
I2C_Clear_INTERRUPT_Flag(I2C_Choose); //清I2C中断标志位ISIF位
while(!I2C_Get_INTERRUPT_Flag(I2C_Choose)); //等待发送完成
while(I2C_Get_Ack_Fail_Flag(I2C_Choose)); //判断是否有ACK应答,如没有则停止,如果有则继续发
/*发送高位地址*/
I2C_SendData8(I2C_Choose,EEPROM_AddH); //发送从机高位寄存器地址
I2C_Clear_INTERRUPT_Flag(I2C_Choose); //清I2C中断标志位ISIF位
while(!I2C_Get_INTERRUPT_Flag(I2C_Choose)); //等待发送完成
/*发送低位地址*/
I2C_SendData8(I2C_Choose,EEPROM_AddL); //发送从机低位寄存器地址
I2C_Clear_INTERRUPT_Flag(I2C_Choose); //清I2C中断标志位ISIF位
while(!I2C_Get_INTERRUPT_Flag(I2C_Choose)); //等待发送完成
/* 循环写数据操作 */
while(number_of_byte--){
I2C_SendData8(I2C_Choose, *p_buffer); //发送8位数据
I2C_Clear_INTERRUPT_Flag(I2C_Choose); //清I2C中断标志位ISIF位
/* 指向下一个所要写的字节 */
p_buffer++;
while(!I2C_Get_INTERRUPT_Flag(I2C_Choose)); //等待发送完成
}
/*停止位*/
I2C_Generate_STOP(I2C_Choose,TRUE); //使能停止信号
I2C_Clear_INTERRUPT_Flag(I2C_Choose); //清I2C中断标志位ISIF位
while(!I2C_Get_INTERRUPT_Flag(I2C_Choose)); //等待停止完成
I2C_Clear_INTERRUPT_Flag(I2C_Choose); //清I2C中断标志位ISIF位
I2C_Clear_Stop_Flag(I2C_Choose); //清I2C停止标志位PIF位
I2C_Cmd(I2C_Choose,FALSE); //关闭I2C模组
}
/**
* 描述 eeprom 读出单字节数据。
* 输入 write_address:eeprom 16位寄存器地址
* p_buffer: 读出数据,取值为8位数据。
* 返回 无。
*/
void eeprom_byte_read(uint16_t Write_address,uint8_t p_buffer)
{
I2C_Choose=I2C0_SFR;//选择I2C0_SFR I2C1_SFR I2C2_SFR I2C3_SFR
static uint8_t EEPROM_AddH=0;
static uint8_t EEPROM_AddL=0;
EEPROM_AddL=Write_address& 0xff;//低8位寄存器地址
EEPROM_AddH=(Write_address>>8)& 0xff; //高8位寄存器地址
I2C_Cmd(I2C_Choose,TRUE);
/*起始位*/
I2C_Clear_INTERRUPT_Flag(I2C_Choose); //清I2C中断标志位ISIF位
I2C_Generate_START(I2C_Choose,TRUE); //使能起始信号
while(!I2C_Get_INTERRUPT_Flag(I2C_Choose)); //等待起始位稳定
/*发送I2C从机地址*/
I2C_SendData8(I2C_Choose,EEPROM_I2C_ADDRESS); //发送从机I2C地址
I2C_Clear_INTERRUPT_Flag(I2C_Choose); //清I2C中断标志位ISIF位
while(!I2C_Get_INTERRUPT_Flag(I2C_Choose)); //等待发送完成
while(I2C_Get_Ack_Fail_Flag(I2C_Choose)); //判断是否有ACK应答,如没有则停止,如果有则继续发
/*发送要读寄存器高位地址*/
I2C_SendData8(I2C_Choose,EEPROM_AddH); //发送从机高位寄存器地址
I2C_Clear_INTERRUPT_Flag(I2C_Choose); //清I2C中断标志位ISIF位
while(!I2C_Get_INTERRUPT_Flag(I2C_Choose)); //等待发送完成
/*发送要读寄存器低位地址*/
I2C_SendData8(I2C_Choose,EEPROM_AddL); //发送从机低位寄存器地址
I2C_Clear_INTERRUPT_Flag(I2C_Choose); //清I2C中断标志位ISIF位
while(!I2C_Get_INTERRUPT_Flag(I2C_Choose)); //等待发送完成
I2C_Cmd(I2C_Choose,FALSE); //关I2C模块
I2C_Clear_Start_Flag(I2C_Choose); //清I2C起始标志位SIF位
I2C_Clear_INTERRUPT_Flag(I2C_Choose); //清I2C中断标志位ISIF位
I2C_Cmd(I2C_Choose,TRUE); //使能I2C模块
/*起始位*/
I2C_Clear_INTERRUPT_Flag(I2C_Choose); //清I2C中断标志位ISIF
I2C_Generate_START(I2C_Choose,TRUE); //使能起始信号
while(!I2C_Get_INTERRUPT_Flag(I2C_Choose)); //等待起始信号稳定
/*发送读指令*/
I2C_SendData8(I2C_Choose,EEPROM_I2C_ADDRESS|0x01);//发送从机地址及读操作
I2C_Clear_INTERRUPT_Flag(I2C_Choose); //清标志位ISIF位
while(!I2C_Get_INTERRUPT_Flag(I2C_Choose)); //等待发送完成ISIF会置1
I2C_Clear_INTERRUPT_Flag(I2C_Choose); //然后完成清标志位ISIF位
while(!I2C_Get_INTERRUPT_Flag(I2C_Choose)); //等待读取Buff完成ISIF会置1
if(I2C_Get_Receive_Buff_Flag(I2C_Choose)) //判断Buff是否为满
{
I2C_Ack_DATA_Config(I2C_Choose,I2C_ACKDATA_ACK);//回复ACK
p_buffer = I2C_ReceiveData(I2C_Choose);
I2C_Clear_INTERRUPT_Flag(I2C_Choose); //然后读完后清标志位ISIF位
}
while(!I2C_Get_INTERRUPT_Flag(I2C_Choose));
/*停止位*/
I2C_Generate_STOP(I2C_Choose,TRUE); //使能停止信号
I2C_Clear_INTERRUPT_Flag(I2C_Choose); //清I2C中断标志位ISIF位
while(!I2C_Get_INTERRUPT_Flag(I2C_Choose)); //等待停止完成
I2C_Clear_INTERRUPT_Flag(I2C_Choose); //清I2C中断标志位ISIF位
I2C_Clear_Stop_Flag(I2C_Choose); //清I2C停止标志位PIF位
I2C_Cmd(I2C_Choose,FALSE); //关闭I2C模组
}
/**
* 描述 eeprom 读出多字节数据。
* 输入 write_address:eeprom 16位寄存器地址
* p_buffer: 读出数据指针
* number_of_byte:读出数据长度
* 返回 无。
*/
void eeprom_buffer_read(uint16_t Write_address,uint8_t *p_buffer,uint16_t number_of_byte)
{
I2C_Choose=I2C0_SFR;//选择I2C0_SFR I2C1_SFR I2C2_SFR I2C3_SFR
static uint8_t EEPROM_AddH=0;
static uint8_t EEPROM_AddL=0;
EEPROM_AddL=Write_address& 0xff; //低8位寄存器地址
EEPROM_AddH=(Write_address>>8)& 0xff; //高8位寄存器地址
I2C_Cmd(I2C_Choose,TRUE); //使能I2C3模块
/*起始位*/
I2C_Clear_INTERRUPT_Flag(I2C_Choose); //清I2C中断标志位ISIF位
I2C_Generate_START(I2C_Choose,TRUE); //使能起始信号
while(!I2C_Get_INTERRUPT_Flag(I2C_Choose)); //等待起始位稳定
/*发送I2C从机地址*/
I2C_SendData8(I2C_Choose,EEPROM_I2C_ADDRESS); //发送从机I2C地址
I2C_Clear_INTERRUPT_Flag(I2C_Choose); //清I2C中断标志位ISIF位
while(!I2C_Get_INTERRUPT_Flag(I2C_Choose)); //等待发送完成
while(I2C_Get_Ack_Fail_Flag(I2C_Choose)); //判断是否有ACK应答,如没有则停止,如果有则继续发
/*发送要读寄存器高位地址*/
I2C_SendData8(I2C_Choose,EEPROM_AddH); //发送从机高位寄存器地址
I2C_Clear_INTERRUPT_Flag(I2C_Choose); //清I2C中断标志位ISIF位
while(!I2C_Get_INTERRUPT_Flag(I2C_Choose)); //等待发送完成
/*发送要读寄存器低位地址*/
I2C_SendData8(I2C_Choose,EEPROM_AddL); //发送从机低位寄存器地址
I2C_Clear_INTERRUPT_Flag(I2C_Choose); //清I2C中断标志位ISIF位
while(!I2C_Get_INTERRUPT_Flag(I2C_Choose)); //等待发送完成
I2C_Cmd(I2C_Choose,FALSE); //关I2C模块
I2C_Clear_Start_Flag(I2C_Choose); //清I2C起始标志位SIF位
I2C_Clear_INTERRUPT_Flag(I2C_Choose); //清标志位ISIF位
I2C_Cmd(I2C_Choose,TRUE); //打开I2C模块
/*起始位*/
I2C_Clear_INTERRUPT_Flag(I2C_Choose); //清中断标志位ISIF位
I2C_Generate_START(I2C_Choose,TRUE); //起始信号
while(!I2C_Get_INTERRUPT_Flag(I2C_Choose)); //等待起始位稳定
/*发送读指令*/
I2C_SendData8(I2C_Choose,EEPROM_I2C_ADDRESS|0x01);//发送从机地址及读操作
I2C_Clear_INTERRUPT_Flag(I2C_Choose); //清标志位ISIF位
while(!I2C_Get_INTERRUPT_Flag(I2C_Choose)); //等待发送完成ISIF会置1
while(I2C_Get_Ack_Fail_Flag(I2C_Choose)); //判断是否有ACK应答,如没有则停止,如果有则继续发
I2C_Clear_INTERRUPT_Flag(I2C_Choose); //然后完成清标志位ISIF位
while(number_of_byte)
{
while(!I2C_Get_INTERRUPT_Flag(I2C_Choose)); //等待读取Buff完成ISIF会置1
if(I2C_Get_Receive_Buff_Flag(I2C_Choose)) //判断Buff是否为满
{
*p_buffer = I2C_ReceiveData(I2C_Choose);
I2C_Ack_DATA_Config(I2C_Choose,I2C_ACKDATA_ACK);//回复ACK
I2C_Clear_INTERRUPT_Flag(I2C_Choose); //然后读完后清标志位ISIF位
p_buffer++; /* 指向下一个被读取的字节将被保存的位置 */
/* 递减读取字节计数*/
number_of_byte--;
}
// if(number_of_byte==1)
// {
// I2C_Generate_STOP(I2C_Choose,TRUE); //使能停止信号
// I2C_Clear_INTERRUPT_Flag(I2C_Choose); //然后读完后清标志位ISIF位
// }
}
/*停止位*/
I2C_Generate_STOP(I2C_Choose,TRUE); //使能停止信号
I2C_Clear_INTERRUPT_Flag(I2C_Choose); //清I2C中断标志位ISIF位
while(!I2C_Get_INTERRUPT_Flag(I2C_Choose)); //等待停止完成
I2C_Clear_INTERRUPT_Flag(I2C_Choose); //清I2C中断标志位ISIF位
I2C_Clear_Stop_Flag(I2C_Choose); //清I2C停止标志位PIF位
I2C_Cmd(I2C_Choose,FALSE); //关闭I2C模组
}
/**
* 描述 I2C_DMA 初始化。
* 输入 无
*
* 返回 无。
*/
void I2C_DMA_Init(void)
{
uint32_t *I2C_write_ADDR=&i2c_buffer_write[0];
DMA_InitTypeDef I2C_DMAStruct;
//注意:DMA传感完成标志产生是在传输完成倒数第一个时就会置位
I2C_DMAStruct.m_Number = WRITE_BUFFER_SIZE+1;/* 配置 传输数据个数: WRITE_BUFFER_SIZE+1 */
I2C_DMAStruct.m_Direction = DMA_MEMORY_TO_PERIPHERAL;/* 配置 DMA传输方向: 内存到外设*/
I2C_DMAStruct.m_Priority = DMA_CHANNEL_LOWER;/* 配置 DMA通道优先级:低优先级 */
I2C_DMAStruct.m_PeripheralDataSize = DMA_DATA_WIDTH_8_BITS;/* 配置 外设数据位宽:8位宽 */
I2C_DMAStruct.m_MemoryDataSize = DMA_DATA_WIDTH_8_BITS;/* 配置 存储器数据位宽:8位宽 */
I2C_DMAStruct.m_PeripheralInc = FALSE;/* 配置 外设地址增量模式使能: 不使能 */
I2C_DMAStruct.m_MemoryInc = TRUE;/* 配置 存储器地址增量模式使能: 使能 */
I2C_DMAStruct.m_Channel = DMA_CHANNEL_4;/* 配置 DMA通道选择:通道4 */
I2C_DMAStruct.m_BlockMode = DMA_TRANSFER_BYTE; /* 配置 数据块传输模式: */
I2C_DMAStruct.m_LoopMode = TRUE;/* 配置 循环模式使能: 禁止 */
I2C_DMAStruct.m_PeriphAddr = I2C_Buffer_Addr;/* 配置 外设起始地址:等待发送的数据的起始地址 */
I2C_DMAStruct.m_MemoryAddr = I2C_write_ADDR;/* 配置 内存起始地址:接收数据的内存空间的起始地址 */
DMA_Reset(DMA0_SFR);
DMA_Configuration(DMA0_SFR, &I2C_DMAStruct);
}
void DMA_I2C_Enable(FunctionalState NewState)
{
I2C_Choose=I2C0_SFR;//选择I2C0_SFR I2C1_SFR I2C2_SFR I2C3_SFR
I2C_Transmit_DMA_INT_Enable(I2C_Choose,NewState); //使能 I2C0发送DMA中断
DMA_Channel_Enable(DMA0_SFR,DMA_CHANNEL_4,NewState); //配置使能DMA0 通道4
/*发送*/
I2C_Cmd(I2C_Choose,TRUE); //使能I2C模块
I2C_Clear_INTERRUPT_Flag(I2C_Choose); //清中断标志ISIF
I2C_Generate_START(I2C_Choose,TRUE); //开起始信号
while(!DMA_Get_Finish_Transfer_INT_Flag(DMA0_SFR,DMA_CHANNEL_4)); //等待DMA传输完成
if(!I2C_Get_Transmit_Buff_Flag(I2C_Choose)) //读取Buff状态,为空则释放总线
{
/*停止位*/
I2C_Generate_STOP(I2C_Choose,TRUE); //使能停止信号
I2C_Clear_INTERRUPT_Flag(I2C_Choose); ////清中断标志ISIF
}
I2C_Clear_INTERRUPT_Flag(I2C_Choose); //清I2C中断标志位ISIF位
while(!I2C_Get_INTERRUPT_Flag(I2C_Choose)); //等待停止完成
I2C_Clear_INTERRUPT_Flag(I2C_Choose); //清I2C中断标志位ISIF位
I2C_Clear_Stop_Flag(I2C_Choose); //清I2C停止标志位PIF位
I2C_Cmd(I2C_Choose,FALSE); //使能I2C模块
}
/**
* 描述 先写64个字节数据并读出64个字节数据进行比较。
* 输入 无
* 返回 1 :数据对比匹配。
* 0 :数据对比不匹配。
*/
uint8_t AT24LC256_TEST_DMA(void)
{
volatile uint16_t i;
i2c_buffer_write[0]=EEPROM_I2C_ADDRESS; // EEPROM I2C 地址定义
i2c_buffer_write[1]=EEPROM_ADDH; // EEPROM I2C 高8位寄存器地址定义
i2c_buffer_write[2]=EEPROM_ADDL; // EEPROM I2C 低8位寄存器地址定义
/* 初始化i2c写缓冲区 */
for(i = 3;i < WRITE_BUFFER_SIZE;i++)
{
i2c_buffer_write[i]=i-3; //0~0X3F
}
Delay(0XFFFF);
Delay(0XFFFF);
/* 使用DMA 写EERPOM 数据*/
I2C_DMA_Init(); //初始化I2C DMA
DMA_I2C_Enable(TRUE); //使能DMA 通道及I2C触发DMA
Delay(0XFFFF);
Delay(0XFFFF);
Delay(0XFFFF);
I2C_Transmit_DMA_INT_Enable(I2C0_SFR,FALSE); //关 I2C0发送DMA中断
DMA_Channel_Enable(DMA0_SFR,DMA_CHANNEL_4,FALSE); //关DMA0 通道4
Delay(0XFFFF);
Delay(0XFFFF);
Delay(0XFFFF);
Delay(0XFFFF);
Delay(0XFFFF);
/* 读取EEPROM 数据 */
eeprom_buffer_read(EEP_FIRST_PAGE,i2c_buffer_read,sizeof(i2c_buffer_read));
Delay(0XFFFF);
Delay(0XFFFF);
Delay(0XFFFF);
Delay(0XFFFF);
Delay(0XFFFF);
///写入的EEPROM数据和读出的EERPOM数据对比
for(i = 0;i < READ_BUFFER_SIZE;i++)
{
if(i2c_buffer_read[i] != i2c_buffer_write[i+3])
{
return I2C_FAIL;
}
}
return I2C_OK;
}