CC2541对AT24CXX系列存储器的支持
?首先,需要強調的是CC2541具有I2C外設,而CC2540不具備,這也是它們的區別之一。所以,CC2451可以完美驅動帶I2C的設備。
?如果CC2541的程序是跑OSAL架構的,那么可以可以將它提供的i2c的源碼直接拿來用,而不需做任何修改。下面就是基于OSAL架構的來講的。
?支持i2c的代碼可以在BLE協議棧安裝目錄下的BLE-CC254x-1.3.2\Components\hal\target\CC2541ST目錄下找到。在這個目錄下,找到hal_i2c.c、hal_i2c.h、hal_sensor.c和hal_sensor.h這4個文件,拷貝到你的工程目錄下,然后天添加到工程中。其中hal_i2c.c與hal_i2c.h兩個文件支持了CC2541的i2c的基本實現函數,hal_sensor.c與hal_sensor.h這兩個文件則是為具體的i2c設備提供了讀寫接口。下面就來仔細講講。
1、hal_i2c.c與hal_i2c.h的代碼實現
?要想使用i2c,當然要對i2c協議有一定的了解。如下圖說所示,可以總結出來i2c必須要的幾部分是:起始信號、設備地址、讀寫選擇位,應答信號,以及停止位。
?在使用i2c之前,當然需要先配置下i2c。在hal_i2c.c下,有?HalI2CInit()函數,用來配置CC2541的i2c,代碼如下:?????static?uint8?i2cAddr;
void?HalI2CInit(uint8?address,?i2cClock_t?clockRate)
{
?i2cAddr?=?address?<<?1;
?I2C_WRAPPER_DISABLE();
?I2CADDR?=?0;?//?no?multi?master?support?at?this?time
?I2C_CLOCK_RATE(clockRate);
?I2C_ENABLE();
}
上面代碼中看起來像函數的語句其實是宏定義,用來配置相關的寄存器,他們在hal_i2c.c的最開始就宏定義過,這里就不細講,自己看代碼。這里定義了一個i2cAddr變量,用于保存i2c設備的地址。I2C_WRAPPER_DISABLE()關閉寫保護,這樣的話就可以支持讀寫操作了,I2C_CLOCK_RATE()則設置i2c的時鐘速率,最后I2C_ENABLE()使能i2c。這樣的話,i2c就初始化完成了。
?i2c的起始信號和停止信號以及讀寫數據都是通過操作寄存器操作的。hal_i2c.c中給出了他們的宏定義:
#define?I2C_STRT()?st?(?\
?I2CCFG?&=?~I2C_SI;?\
?I2CCFG?|=?I2C_STA;?\
?while?((I2CCFG?&?I2C_SI)?==?0);?\
?I2CCFG?&=?~I2C_STA;?\
)
//?Must?set?STO?before?clearing?SI.
#define?I2C_STOP()?st?(?\
?I2CCFG?|=?I2C_STO;?\
?I2CCFG?&=?~I2C_SI;?\
?while?((I2CCFG?&?I2C_STO)?!=?0);?\
)
//?Stop?clock-stretching?and?then?read?when?it?arrives.
#define?I2C_READ(_X_)?st?(?\
?I2CCFG?&=?~I2C_SI;?\
?while?((I2CCFG?&?I2C_SI)?==?0);?\
?(_X_)?=?I2CDATA;?\
)
//?First?write?new?data?and?then?stop?clock-stretching.
#define?I2C_WRITE(_X_)?st?(?\
?I2CDATA?=?(_X_);?\
?I2CCFG?&=?~I2C_SI;?\
?while?((I2CCFG?&?I2C_SI)?==?0);?\
)
?hal_i2c.c中還給出了發送起始信號與設備地址以及控制讀寫的函數:i2cMstStrt(),如下:
static?uint8?i2cMstStrt(uint8?RD_WRn)
{
?I2C_STRT();
?if?(I2CSTAT?==?mstStarted)?/*?A?start?condition?has?been?transmitted?*/
?{
?I2C_WRITE(i2cAddr?|?RD_WRn);
?}
?return?I2CSTAT;
}
?為了從i2c總線上讀取數據,hal_i2c.c中給出了HalI2CRead()函數,代碼如下:
uint8?HalI2CRead(uint8?len,?uint8?*pBuf)
{
?uint8?cnt?=?0;
?if?(i2cMstStrt(I2C_MST_RD_BIT)?!=?mstAddrAckR)
?{
?len?=?0;
?}
?if?(len?>?1)
?{
?I2C_SET_ACK();
?}
?while?(len?>?0)
?{
?//?slave?devices?require?NACK?to?be?sent?after?reading?last?byte
?if?(len?==?1)
?{
?I2C_SET_NACK();
?}
?//?read?a?byte?from?the?I2C?interface
?I2C_READ(*pBuf++);
?cnt++;
?len--;
?if?(I2CSTAT?!=?mstDataAckR)
?{
?if?(I2CSTAT?!=?mstDataNackR)
?{
?//?something?went?wrong,?so?don't?count?last?byte
?cnt--;
?}
?break;
?}
?}
?I2C_STOP();
?return?cnt;
}
?為了向i2c總線上寫數據,hal_i2c.c給出了HalI2CWrite()函數,代碼如下:
uint8?HalI2CWrite(uint8?len,?uint8?*pBuf)
{
?if?(i2cMstStrt(0)?!=?mstAddrAckW)
?{
?len?=?0;
?}
?for?(uint8?cnt?=?0;?cnt?<?len;?cnt++)
?{
?I2C_WRITE(*pBuf++);
?if?(I2CSTAT?!=?mstDataAckW)
?{
?if?(I2CSTAT?==?mstDataNackW)
?{
?len?=?cnt?+?1;
?}
?else
?{
?len?=?cnt;
?}
?break;
?}
?}
?I2C_STOP();
?return?len;
}
2、hal_sensor.c與hal_sensor.h文件
?如果對于AT24CXX系列中的AT2401、AT2402、AT2404、AT2408、AT2416這幾種存儲器,hal_sensor.c和hal_sensor.h可以不做任何修改就可以完全支持。但是如果對于大于16K的AT24CXX些列存儲器則需要對這兩個文件進行修改。為什么會存在這樣的差別呢?原因在于他們的片內地址的范圍。對于1K位,2K位,4K位,8K位,16K位芯片采用一個8位長的字節地址碼,對于32K位以上的采用2個8位長的字節地址碼直接尋址,而4K位,8K位,16K位配合頁面地址來尋址的。hal_sensor給出的代碼用的就是支持8為地址的。所以對于16k以上的存儲器需要將hal_sensor的代碼修改成支持2個8位地址。下面就分成上面兩種情況進行說明。
?對于AT2401、AT2402、AT2404、AT2408、AT2416這幾種存儲器,hal_sensor的代碼可以不做任何修改,但是可以將除了HalSensorReadReg()和HalSensorWriteReg()這兩個函數之外的其他函數全部去掉,因為都是不相關的代碼。HalSensorReadReg()與HalSensorWriteReg()分別用向AT24CXX存儲器指定的地址上讀寫指定的數數據。代碼如下:
bool?HalSensorReadReg(uint8?addr,?uint8?*pBuf,?uint8?nBytes)
{
?uint8?i?=?0;
?/*?Send?address?we're?reading?from?*/
?if?(HalI2CWrite(1,&addr)?==?1)
?{
?/*?Now?read?data?*/
?i?=?HalI2CRead(nBytes,pBuf);
?}
?return?i?==?nBytes;
}
bool?HalSensorWriteReg(uint8?addr,?uint8?*pBuf,?uint8?nBytes)
{
?uint8?i;
?uint8?*p?=?buffer;
?/*?Copy?address?and?data?to?local?buffer?for?burst?write?*/
?*p++?=?addr;
?for?(i?=?0;?i?<?nBytes;?i++)
?{
?*p++?=?*pBuf++;
?}
?nBytes++;
?/*?Send?address?and?data?*/
?i?=?HalI2CWrite(nBytes,?buffer);
?if?(?i!=?nBytes)
?HAL_TOGGLE_LED2();
?return?(i?==?nBytes);
}
?對于AT2432、AT2464、AT24128、AT24256這幾種存在器的片內地址需要2個8為字節的數據需要將上面給出的HalSensorReadReg()與HalSensorWriteReg()修改成支持16為地址,代碼如下:
bool?HalSensorReadReg(uint16?addr,?uint8?*pBuf,?uint8?nBytes)
{
?uint8?i?=?0;
?uint8?addrH,?addrL;
?
?addrL?=?addr?&?0xff;
?addrH?=?addr?>>?8;
?/*?Send?address?we're?reading?from?*/
?if?(HalI2CWrite(1,?&addrH)?==?1)
?if?(HalI2CWrite(1,?&addrL)?==?1)
?{
?/*?Now?read?data?*/
?i?=?HalI2CRead(nBytes,pBuf);
?}
?return?i?==?nBytes;
}
bool?HalSensorWriteReg(uint16?addr,?uint8?*pBuf,?uint8?nBytes)
{
?uint8?i;
?uint8?*p?=?buffer;
?uint8?addrL?=?0,?addrH?=?0;
?
?addrL?=?(uint8)(addr?&?0xff);
?addrH?=?(uint8)(addr?>>?8);
?/*?Copy?address?and?data?to?local?buffer?for?burst?write?*/
?*p++?=?addrH;
?*p++?=?addrL;
?for?(i?=?0;?i?<?nBytes;?i++)
?{
?*p++?=?*pBuf++;
?}
?nBytes?+=?2;
?/*?Send?address?and?data?*/
?i?=?HalI2CWrite(nBytes,?buffer);
?if?(?i!=?nBytes)
?HAL_TOGGLE_LED2();
?return?(i?==?nBytes);
}
void?halSensorInit(void)
{
?HalI2CInit(0x50,?i2cClock_533KHZ);?
}
3、AT24CXX的讀寫
?在應用代碼中,調用上面給出的halSensorInit()函數初始化CC2541的i2c外設,然后調用HalSensorWriteReg()指定地址寫入數據,然后再調用HalSensorReadReg()函數將該地址數據的上的值讀取出來,實例代碼如下:
static?uint8?buffer[32]?=?{0};
halSensorinit();//初始化CC2541的i2c
halWriteReg(0x0000,?"abcdefghij",?10);//向AT24C256的0x0000地址處寫入數據
halReadReg(0x0000,?buffer,?10);//從AT24C256的0x0000地址處讀取10個字節數據
HalLcdWriteString(buffer,?HAL_LCD_LINE_4);//將讀取到的數據顯示在LCD上
轉載自 http://ziye334.lofter.com/post/2435a3_2a2e1b4
總結
以上是生活随笔為你收集整理的CC2541对AT24CXX系列存储器的支持的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: STM32 GPIO与 EXTI的映射关
- 下一篇: PID算法-温度控制