I2C原理与配置
IIC原理超详细讲解—值得一看
【嵌入式硬件芯片开发笔记】EEPROM芯片M24C32配置流程
STM32硬件I2C与软件模拟I2C超详解
M24C32芯片了解
实现通信功能的芯片为M24C32,对此,芯片手册上第一页就有对其概括描述。
Automotive 32-Kbit serial I²C bus EEPROM with 1 MHz clock
启动/停止条件:当串行时钟(SCL)位于高电平状态,串行数据(SDA)位于下降沿时,M24C32开始接收数据;串行数据(SDA)位于上升沿时,M24C32停止接收数据。
数据输入:SCL上升沿时SDA进行采样。SDA必须在SCL的上升沿期间保持稳定,且当SCL被驱动为低电平时,SDA才改变电平状态。
设备寻址:设备选择代码由一个4位设备类型标识符和一个3位芯片使能地址(E2、E1、E0)组成,设备类型标识符中,1010b为选择存储器(to select the memory),1011b为选择标识页(to select the Identification page)。
在一条I2C总线上最多可连接8个存储器设备。每个片上使能输入(E2、E1、E0)上都有一个唯一的3位代码;当收到设备选择代码时,只有当芯片使能地址与E2、E1、E0输入解码值相同时,存储器设备才会响应。
第八位是读写位,1=read,0=write.
读操作
看到Current Address Read
这行,它是一次读当前地址数据的过程。在开始信号发出后,主设备会发出一个7位片选信号,第八位是设备读/写模式,ACK是从设备应答信号,当从设备发来一个应答信号时,主设备会发送数据,数据传输完成后,从设备不需要发应答信号,最后是主设备发送停止位结束这一次的读操作。Random Address Read
是随机地址读操作,而后面的Sequential Current Read
就是按顺序读了。Random Address Read
和Sequential Random Read
模式下,需要设备发送地址才能读,所以有两次发送地址的序列。
读指令后,若总线发送额外的时钟脉冲并确认每个传输的数据字节,则设备可按顺序输出下一字节。若终止字节流,总线必须不确认最后一个字节,并且必须生成一个停止条件。
读模式下确认:对于所有读指令,设备在发送每个字节后,在第9位时间内等待一个确认标识符,若总线主设备不发送确认(主驱动器SDA在第9位时间为高),则设备终止数据传输并进入待机模式。
写操作
看到Byte Wirte
这行,它是一次写操作过程。在开始信号发出后,主设备会发出一个7位片选信号,第八位是设备读/写模式,ACK是从设备应答信号,当从设备发来一个应答信号时,主设备会给从设备发送一个字节地址,如果从设备发来应答信号,主设备此时会再发一次字节地址,当从设备应答后,主设备才会发送数据,数据传输完成后,从设备发来应答信号,最后是主设备发送停止位结束这一次的写操作。Page Write
是连续写操作,前面的发片选和地址和Byte Write
一样,不一样的是主设备会一直发数据。
HAL库配置及初始化
根据原理图和芯片手册配置相关参数
配置完成后,会生成一个i2c的句柄,当我们需要对i2c进行读写等操作时,对hi2c取地址,它就会调用HAL库中的寄存器回调,然后实现i2c规范中的功能(比如说init、status、mode、errcode这种)。
I2C_HandleTypeDef hi2c1;
部分代码
一开始列出的大概框架如下。
int i2c_write(const unsigned char *pwbuf, const unsigned short wbuflen);
int i2c_read(unsigned char *prBuf, const unsigned short *rbuflen);
void main(void)
{
//write
unsigned short wBuflen = 128;
unsigned char wBuf[wBuflen] = {0};
for(unsigned char i =0 ;i<wBuflen;i++)
{
wBuf[i] = i;
}
int wret = i2c_write(wBuf, wBuflen);
//read
unsigned char rBuf[128] = {0};
unsigned short rlen = 128;
int rret = i2c_read(rBuf, rlen);
}
因为之前设置的是七位设备地址(第八位是读写位),所以在读写时需要左移一位,HAL库中I2C的读写存储器比较方便,只需要调用HAL_I2C_Mem_Write
和HAL_I2C_Mem_Read
函数即可。
int i2c_write(uint8_t devadd,uint16_t memadd,uint16_t memsize,uint8_t *pwbuf, const unsigned short wbuflen)
{
devadd = (devadd<<1)&0xFF;
if(pwbuf != NULL || wbuflen != 0)
{
if(HAL_I2C_Mem_Write(&hi2c1,devadd,memadd,memsize,pwbuf, wbuflen,0xFFFF)==HAL_OK)
{
return 1;
}
}
else
{
return 0;
}
}
int i2c_read(uint8_t devadd,uint16_t memadd,uint16_t memsize,uint8_t *prbuf, const unsigned short rbuflen)
{
devadd = (devadd<<1)&0xFF;
if(prbuf != NULL || rbuflen != 0)
{
if(HAL_I2C_Mem_Read(&hi2c1, devadd, memadd,memsize, prbuf,rbuflen,0xFFFF)==HAL_OK)
{
return 1;
}
}
else
{
return 0;
}
}
这两个函数在stm32l4xx_hal_i2c.c文件下
HAL_StatusTypeDef HAL_I2C_Mem_Write(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress,
uint16_t MemAddSize, uint8_t *pData, uint16_t Size, uint32_t Timeout)
HAL_StatusTypeDef HAL_I2C_Mem_Read(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress,
uint16_t MemAddSize, uint8_t *pData, uint16_t Size, uint32_t Timeout)
实际实现示例,当i2c开始写的时候,因为是一个字一个字地写,所以存储器地址每次加i,即0x0000+i,并且需要延迟一会,否则太快了芯片来不及存数据。
读就直接读,从0x0000开始读。文章来源:https://www.toymoban.com/news/detail-768449.html
void I2C_ReadorWrite(uint8_t flag)
{
if(flag == 1)
{
//write
unsigned char i;
uint8_t dat=0;
if(HAL_I2C_IsDeviceReady(&hi2c1,M24C32_ADD<<1,2,0x00ff)==HAL_OK)
{
i=0;
}
unsigned short wBuflen = 128;
for(i = 0;i<wBuflen;i++)//i2c clear
{
dat=0;
i2c_write(M24C32_ADD,0x0000+i,I2C_MEMADD_SIZE_16BIT,&dat,1);
delay_ms(10);
}
for(i = 0;i<wBuflen;i++)//i2c write
{
dat=i;
i2c_write(M24C32_ADD,0x0000+i,I2C_MEMADD_SIZE_16BIT,&dat,1);
delay_ms(10);
}
}
else if(flag == 0)
{
//read
unsigned char rBuf[128] = {0};
unsigned short rlen = 128;
i2c_read(M24C32_ADD,0x0000,I2C_MEMADD_SIZE_16BIT,rBuf,rlen);
// for(i=0;i<rlen;i++)
// {
// printf("rBuf[%d] = %02X \n",i,rBuf[i]);
// }
//uint16_t re_dat=0;
//i2c_write(M24C32_ADD,0x0000,I2C_MEMADD_SIZE_16BIT,&dat,1);
//delay_ms(55);
//i2c_write(M24C32_ADD,0x0000,I2C_MEMADD_SIZE_16BIT,&dat,1);
//delay_ms(50);
//i2c_read(M24C32_ADD,0x0000,I2C_MEMADD_SIZE_16BIT,&re_dat,1);
}
}
遇到的问题
要了解手头这个芯片的i2c地址位数,一般都是7位,在读写时不能忘记移位。
在存储数据时记得调用delay,否则会出现输出的数据有漏掉的情况。
除了这个EEPROM芯片还有一个LP87702芯片的,在熟悉中。文章来源地址https://www.toymoban.com/news/detail-768449.html
到了这里,关于【STM32L496】使用HAL库实现I2C写入/读取数据(M24C32)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!