CC2541 硬件I2C读取寄存器返回值错误
做的项目需要用到CC2541的硬件I2C功能,使用的是TI的I2C驱动。但是调试时读取不同寄存器的数据全都一样,用示波器监控信号时发现:
读取寄存器地址时发送的从机地址和寄存器地址都正确,而且从机也应答了并且返回从机地址+数据,当读取不同寄存器数据时返回的却都是从机地址+固定的一串数据。。猜测硬件的I2C可能读取数据时错误
所以试了下用SDA、SCL的引脚做模拟I2C的功能,能正常返回读取各寄存器的数据
直接用SDA、SCL引脚做模拟I2C功能代码
.c文件
#include "sw_i2c.h"
/**
* 初始化I2C数据引脚
*/
void SW_I2C_Init(void)
{
I2C_GPIO;
SDA_OUT;
SCL_OUT;
SDA_1; //SDA = 1;
SCL_1; //SCL = 1;
}
/********************************************
* 名称:i2c_send_noack()
* 功能:无应答I2C总线
* 参数:无
* 返回:1 有NOACK信号 0 无NOACK信号
*/
void send_noack(){
SDA_OUT;
SDA_1; //SDA = 1; NO ACK
DELAY_I2C;
SCL_1; //SCL = 1;
DELAY_I2C;
SCL_0; //SCL = 0; //START
DELAY_I2C;
}
// iic 应答 for slaver
void send_ack() {
SDA_OUT;
SDA_0; //OUT 0 ACK
DELAY_I2C;
SCL_1;
DELAY_I2C;
SCL_0;
DELAY_I2C;
}
/*
* 起始位
*/
static void start(){
SDA_OUT;
SCL_OUT;
SDA_1; //SDA = 1;
DELAY_I2C;
SCL_1; //SCL = 1;
DELAY_I2C;
SDA_0; //SDA = 0;
}
/*
*停止位
*/
static void stop(){
SDA_OUT;
SCL_OUT;
SDA_0; //SDA = 0;
DELAY_I2C;
SCL_1; //SCL = 1; STOP
DELAY_I2C;
SDA_1; //SDA = 1;
}
/**
* 向从机写一个字节
*/
void iic_write_byte(uint8 datIn) {
uint8 data, j;
data = datIn;
SDA_OUT;
for (j = 0; j < 8; j++) {
SCL_0;
DELAY_I2C;
if((data & 0x80)) SDA_1;
else SDA_0;
SCL_1; //write TDOS_SDA begin
DELAY_I2C;
data <<= 1;
}
SCL_0;
DELAY_I2C;
}
bool check_ack() {
bool ack_flag;
SDA_IN; //开路输入,
SCL_1; //read ask begin
DELAY_I2C;
if((I2CIO & I2C_SDAD) ==1){ //if (SDA==1)
ack_flag = 0; //1: err
}else{
ack_flag = 1; //0: ok
}
SCL_0; //read ask end
return ack_flag;
}
/*
* 读一个字节
*/
uint8 iic_read() {
uint8 j, data = 0;
SCL_OUT;
SDA_IN; //输入
DELAY_I2C;
for (j = 0; j < 8; j++) {
SCL_1; //read TDOS_SDA begin. delay 0.7us
DELAY_I2C;
data <<= 1;
if((I2CIO & I2C_SDAD) ==1){ //if (SDA==1)
data |= 0x01; //input TDOS_SDA
}
SCL_0; //read TDOS_SDA end. delay 1.4us
DELAY_I2C;
}
return data;
}
/*
* 通过I2C总线向某一寄存器写入一个字节数据
*/
void I2C_write_byte(uint8 I2C_addr, uint8 reg, uint8 data)
{
start(); //发启动信号
iic_write_byte((I2C_addr << 1) | 0x00); //从机地址
if (check_ack()==0) {
goto err;
}
iic_write_byte(reg); //发送寄存器地址
if (check_ack()==0) {
goto err;
}
iic_write_byte(data); //发送数据字节
if (check_ack()==0) {
goto err;
}
err:
stop();
}
/*
* 通过I2C总线读出某一寄存器的数据
*/
uint8 I2C_read_byte(uint8 I2C_addr, uint8 reg)
{
uint8 data;
start();
iic_write_byte((I2C_addr << 1) | 0X00); //WRITE i2c
if (check_ack()==0) {
goto err;
}
iic_write_byte(reg); //TDOS'register
if (check_ack()==0) {
goto err;
}
start(); //重发起动信号
iic_write_byte((I2C_addr << 1) | 0X01); //READ
if (check_ack()==0) {
goto err;
}
data = iic_read(); //接收读出的数据
send_noack();
err:
stop();
return data;
}
/*
* 通过I2C总线读出某一寄存器的数据
*/
uint16 I2C_read_2byte(uint8 I2C_addr, uint8 reg)
{
uint8 data1,data2;
start();
iic_write_byte((I2C_addr << 1) | 0X00); //WRITE i2c
if (check_ack()==0) {
goto err;
}
iic_write_byte(reg); //TDOS'register
if (check_ack()==0) {
goto err;
}
start(); //重发起动信号
iic_write_byte((I2C_addr << 1) | 0X01); //READ
if (check_ack()==0) {
goto err;
}
data1 = iic_read(); //接收读出的数据
send_ack();
data2 = iic_read(); //接收读出的数据
send_noack();
err:
stop();
return data1 | (data2 << 8) ;
}
头文件.h
#ifndef _SW_IIC_H_
#define _SW_IIC_H_
#include <ioCC2541.h>
#include "hal_types.h"
#include "hal_defs.h"
/* Ative delay: 125 cycles ~1 msec */
#define ST_HAL_DELAY(n) st( { volatile uint32 i; for (i=0; i<(n); i++) { }; } )
#define DELAY_I2C ST_HAL_DELAY(1) //125KHz~8us
/* ------------------------------------------------------------------------------------------------
* Constants
* ------------------------------------------------------------------------------------------------
*/
// I2CWC
#define I2C_OVR BV(7) // 1: GPIO functionality.0: I2C functionality
#define I2C_SCLPUE BV(3) //SCL pin pullup enable
#define I2C_SDAPUE BV(2) //SDA pin pullup enable.
#define I2C_SCLOE BV(1) //SCL pin output enable
#define I2C_SDAOE BV(0) //SDA pin output enable
// I2CIO
#define I2C_SCLD BV(1) //SCL data value
#define I2C_SDAD BV(0) //SDA data value
#define SDA_0 I2CIO &= ~I2C_SDAD //SDA=0
#define SDA_1 I2CIO |= I2C_SDAD //SDA=1
#define SCL_0 I2CIO &= ~I2C_SCLD //SCL=0
#define SCL_1 I2CIO |= I2C_SCLD //SCL=1
#define SDA_IN I2CWC &= ~I2C_SDAOE //SDA INPUT
#define SDA_OUT I2CWC |= I2C_SDAOE //SDA OUTPUT
#define SCL_IN I2CWC &= ~I2C_SCLOE //SCL INPUT
#define SCL_OUT I2CWC |= I2C_SCLOE //SCL OUTPUT
#define I2C_GPIO st(I2CWC = 0x80;) //1: I2C GPIO
/**
* 软件I2C初始化
*/
void SW_I2C_Init(void);
/**
* 写一个字节的数据
* @param
* I2C_addr 从机地址
Raddr 寄存器地址
dat 8bit数据
*/
void I2C_write_byte(uint8 I2C_addr, uint8 reg, uint8 dat);
/**
* 读寄存器数据,16bit
* @param
* I2C_addr 从机地址
Raddr 寄存器地址
* @return 16bit数据
*/
uint16 I2C_read_2byte(uint8 I2C_addr, uint8 reg) ;
#endif