I2C原理與配置
IIC原理超詳細(xì)講解—值得一看
【嵌入式硬件芯片開(kāi)發(fā)筆記】EEPROM芯片M24C32配置流程
STM32硬件I2C與軟件模擬I2C超詳解
M24C32芯片了解
實(shí)現(xiàn)通信功能的芯片為M24C32,對(duì)此,芯片手冊(cè)上第一頁(yè)就有對(duì)其概括描述。
Automotive 32-Kbit serial I2C bus EEPROM with 1 MHz clock
啟動(dòng)/停止條件:當(dāng)串行時(shí)鐘(SCL)位于高電平狀態(tài),串行數(shù)據(jù)(SDA)位于下降沿時(shí),M24C32開(kāi)始接收數(shù)據(jù);串行數(shù)據(jù)(SDA)位于上升沿時(shí),M24C32停止接收數(shù)據(jù)。
數(shù)據(jù)輸入:SCL上升沿時(shí)SDA進(jìn)行采樣。SDA必須在SCL的上升沿期間保持穩(wěn)定,且當(dāng)SCL被驅(qū)動(dòng)為低電平時(shí),SDA才改變電平狀態(tài)。
設(shè)備尋址:設(shè)備選擇代碼由一個(gè)4位設(shè)備類型標(biāo)識(shí)符和一個(gè)3位芯片使能地址(E2、E1、E0)組成,設(shè)備類型標(biāo)識(shí)符中,1010b為選擇存儲(chǔ)器(to select the memory),1011b為選擇標(biāo)識(shí)頁(yè)(to select the Identification page)。
在一條I2C總線上最多可連接8個(gè)存儲(chǔ)器設(shè)備。每個(gè)片上使能輸入(E2、E1、E0)上都有一個(gè)唯一的3位代碼;當(dāng)收到設(shè)備選擇代碼時(shí),只有當(dāng)芯片使能地址與E2、E1、E0輸入解碼值相同時(shí),存儲(chǔ)器設(shè)備才會(huì)響應(yīng)。
第八位是讀寫位,1=read,0=write.
讀操作
看到Current Address Read
這行,它是一次讀當(dāng)前地址數(shù)據(jù)的過(guò)程。在開(kāi)始信號(hào)發(fā)出后,主設(shè)備會(huì)發(fā)出一個(gè)7位片選信號(hào),第八位是設(shè)備讀/寫模式,ACK是從設(shè)備應(yīng)答信號(hào),當(dāng)從設(shè)備發(fā)來(lái)一個(gè)應(yīng)答信號(hào)時(shí),主設(shè)備會(huì)發(fā)送數(shù)據(jù),數(shù)據(jù)傳輸完成后,從設(shè)備不需要發(fā)應(yīng)答信號(hào),最后是主設(shè)備發(fā)送停止位結(jié)束這一次的讀操作。Random Address Read
是隨機(jī)地址讀操作,而后面的Sequential Current Read
就是按順序讀了。Random Address Read
和Sequential Random Read
模式下,需要設(shè)備發(fā)送地址才能讀,所以有兩次發(fā)送地址的序列。
讀指令后,若總線發(fā)送額外的時(shí)鐘脈沖并確認(rèn)每個(gè)傳輸?shù)臄?shù)據(jù)字節(jié),則設(shè)備可按順序輸出下一字節(jié)。若終止字節(jié)流,總線必須不確認(rèn)最后一個(gè)字節(jié),并且必須生成一個(gè)停止條件。
讀模式下確認(rèn):對(duì)于所有讀指令,設(shè)備在發(fā)送每個(gè)字節(jié)后,在第9位時(shí)間內(nèi)等待一個(gè)確認(rèn)標(biāo)識(shí)符,若總線主設(shè)備不發(fā)送確認(rèn)(主驅(qū)動(dòng)器SDA在第9位時(shí)間為高),則設(shè)備終止數(shù)據(jù)傳輸并進(jìn)入待機(jī)模式。
寫操作
看到Byte Wirte
這行,它是一次寫操作過(guò)程。在開(kāi)始信號(hào)發(fā)出后,主設(shè)備會(huì)發(fā)出一個(gè)7位片選信號(hào),第八位是設(shè)備讀/寫模式,ACK是從設(shè)備應(yīng)答信號(hào),當(dāng)從設(shè)備發(fā)來(lái)一個(gè)應(yīng)答信號(hào)時(shí),主設(shè)備會(huì)給從設(shè)備發(fā)送一個(gè)字節(jié)地址,如果從設(shè)備發(fā)來(lái)應(yīng)答信號(hào),主設(shè)備此時(shí)會(huì)再發(fā)一次字節(jié)地址,當(dāng)從設(shè)備應(yīng)答后,主設(shè)備才會(huì)發(fā)送數(shù)據(jù),數(shù)據(jù)傳輸完成后,從設(shè)備發(fā)來(lái)應(yīng)答信號(hào),最后是主設(shè)備發(fā)送停止位結(jié)束這一次的寫操作。Page Write
是連續(xù)寫操作,前面的發(fā)片選和地址和Byte Write
一樣,不一樣的是主設(shè)備會(huì)一直發(fā)數(shù)據(jù)。
HAL庫(kù)配置及初始化
根據(jù)原理圖和芯片手冊(cè)配置相關(guān)參數(shù)
配置完成后,會(huì)生成一個(gè)i2c的句柄,當(dāng)我們需要對(duì)i2c進(jìn)行讀寫等操作時(shí),對(duì)hi2c取地址,它就會(huì)調(diào)用HAL庫(kù)中的寄存器回調(diào),然后實(shí)現(xiàn)i2c規(guī)范中的功能(比如說(shuō)init、status、mode、errcode這種)。
I2C_HandleTypeDef hi2c1;
部分代碼
一開(kāi)始列出的大概框架如下。
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);
}
因?yàn)橹霸O(shè)置的是七位設(shè)備地址(第八位是讀寫位),所以在讀寫時(shí)需要左移一位,HAL庫(kù)中I2C的讀寫存儲(chǔ)器比較方便,只需要調(diào)用HAL_I2C_Mem_Write
和HAL_I2C_Mem_Read
函數(shù)即可。
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;
}
}
這兩個(gè)函數(shù)在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)
實(shí)際實(shí)現(xiàn)示例,當(dāng)i2c開(kāi)始寫的時(shí)候,因?yàn)槭且粋€(gè)字一個(gè)字地寫,所以存儲(chǔ)器地址每次加i,即0x0000+i,并且需要延遲一會(huì),否則太快了芯片來(lái)不及存數(shù)據(jù)。
讀就直接讀,從0x0000開(kāi)始讀。文章來(lái)源:http://www.zghlxwxcb.cn/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);
}
}
遇到的問(wèn)題
要了解手頭這個(gè)芯片的i2c地址位數(shù),一般都是7位,在讀寫時(shí)不能忘記移位。
在存儲(chǔ)數(shù)據(jù)時(shí)記得調(diào)用delay,否則會(huì)出現(xiàn)輸出的數(shù)據(jù)有漏掉的情況。
除了這個(gè)EEPROM芯片還有一個(gè)LP87702芯片的,在熟悉中。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-768449.html
到了這里,關(guān)于【STM32L496】使用HAL庫(kù)實(shí)現(xiàn)I2C寫入/讀取數(shù)據(jù)(M24C32)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!