项目中需要用到Silicon Labs的ERF32BG22系列的芯片,接收从机的I2C数据并且通过蓝牙BLE发送到手机端。
一.引脚配置
1.首先通过SSV5的pintool工具配置芯片引脚,例如将PC0配置为SCL,PC1配置为SDA。
2.需要先在SOFEWARE COMPONENTS中开启I2C相关外设和驱动
3.接着给引脚添加Software Component功能
4.I2C的基本设置,例如使用EFR32BG22的I2C0,速度设置为100kbit/s
完成配置后在sl_driver_init(void)中,SSV5会自动生成I2C初始化函数
void sl_driver_init(void)
{
sl_i2cspm_init_instances();
}
二.I2C接收和发送函数
//发送函数
static sl_status_t user_i2c_send_data(sl_i2cspm_t *i2cspm, uint8_t addr, uint8_t *command,
uint8_t command_len)
{
I2C_TransferSeq_TypeDef seq;
I2C_TransferReturn_TypeDef ret;
uint8_t i2c_write_data[8];
uint8_t i;
seq.addr = addr<<1;
seq.flags = I2C_FLAG_WRITE;
/* Select command to issue */
for(i=0;i<command_len;i++)
{
i2c_write_data[i] = command[i];
}
seq.buf[0].data = i2c_write_data;
seq.buf[0].len = command_len;
ret = I2CSPM_Transfer(i2cspm, &seq);
return SL_STATUS_OK;
}
//接收函数
static sl_status_t user_i2c_read_data(sl_i2cspm_t *i2cspm, uint8_t addr, uint8_t *data,uint8_t data_len)
{
I2C_TransferSeq_TypeDef seq;
I2C_TransferReturn_TypeDef ret;
uint8_t i2c_read_data[8];
uint8_t i;
seq.addr = addr<<1;
seq.flags = I2C_FLAG_READ;
/* Select command to issue */
seq.buf[0].data = i2c_read_data;
seq.buf[0].len = data_len;
ret = I2CSPM_Transfer(i2cspm, &seq);
for(i=0;i<I2C_BUFFER_SIZE;i++)
{
data[i] = i2c_read_data[i];
}
return SL_STATUS_OK;
}
发送和接收主要通过对I2C_TransferSeq_TypeDef这个结构体进行相应操作
typedef struct {
/**
* @brief
* Address to use after (repeated) start.
* @details
* Layout details, A = Address bit, X = don't care bit (set to 0):
* @li 7 bit address - Use format AAAA AAAX
* @li 10 bit address - Use format XXXX XAAX AAAA AAAA
*/
uint16_t addr;//I2C从机地址
/** Flags defining sequence type and details, see I2C_FLAG_ defines. */
uint16_t flags;//需要I2C进行的操作
/**
* Buffers used to hold data to send from or receive into, depending
* on sequence type.
*/
struct {
/** Buffer used for data to transmit/receive, must be @p len long. */
uint8_t *data;//发送或者接收的数据
/**
* Number of bytes in @p data to send or receive. Notice that when
* receiving data to this buffer, at least 1 byte must be received.
* Setting @p len to 0 in the receive case is considered a usage fault.
* Transmitting 0 bytes is legal, in which case only the address
* is transmitted after the start condition.
*/
uint16_t len;//数据长度
} buf[2];
} I2C_TransferSeq_TypeDef;
其中flags可以设置为以下几种状态
#define I2C_FLAG_WRITE 0x0001//I2C进行写数据操作
/**
* @brief
* Indicate plain read sequence: S+ADDR(R)+DATA0+P.
* @details
* @li S - Start
* @li ADDR(R) - Address with W/R bit set
* @li DATA0 - Data read into buffer with index 0
* @li P - Stop
*/
#define I2C_FLAG_READ 0x0002//I2C进行读数据操作
/**
* @brief
* Indicate combined write/read sequence: S+ADDR(W)+DATA0+Sr+ADDR(R)+DATA1+P.
* @details
* @li S - Start
* @li Sr - Repeated start
* @li ADDR(W) - Address with W/R bit cleared
* @li ADDR(R) - Address with W/R bit set
* @li DATAn - Data written from/read into buffer with index n
* @li P - Stop
*/
#define I2C_FLAG_WRITE_READ 0x0004
//I2C进行写数据操作之后读取数据,I2C_TransferSeq_TypeDef中有两个buf,例如可以将buf[0]中的data作为需要写入的数据,将buf[1]中的data设置为接收的数据
/**
* @brief
* Indicate write sequence using two buffers: S+ADDR(W)+DATA0+DATA1+P.
* @details
* @li S - Start
* @li ADDR(W) - Address with W/R bit cleared
* @li DATAn - Data written from buffer with index n
* @li P - Stop
*/
#define I2C_FLAG_WRITE_WRITE 0x0008
/** Use 10 bit address. */
#define I2C_FLAG_10BIT_ADDR 0x0010
设置完成后通过自带的I2CSPM_Transfer函数启动I2C发送或者接收。
三.与从机通讯验证
使用上述函数发送0xAC,0x78,0x01,0x52命令使从机开始发送数据并接受从机发回的数据,从机地址为0x7D,发送命令之后成功接收到从机发回的{1,2,3,6,6,6,0,0}.
四.蓝牙GATT Configuratior
新建自己的Services,新建自己的Characteristics Data用于显示接收到的I2C数据
Data中的ID一定要勾选并且取名之后可以在gatt_db.h文件中找到自己新建Characteristics,例如我这里自动生成的#define gattdb_Sensor_data 21
五.蓝牙事件代码
static void i2c_char_config_changed_cb(sl_bt_evt_gatt_server_characteristic_status_t *data)
{
bool enable = sl_bt_gatt_disable != data->client_config_flags;
i2c_connection = data->connection;
// update notification status
switch (data->characteristic) {
case gattdb_Sensor_data:
i2c__notification = enable;
break;
default:
//app_assert(false, "Unexpected characteristic\n");
break;
}
}
有了上面的ID,当触发相关事件时,才能将数据正常传入到我们需要的Characteristics中。
static void i2c_notify(void)//接收I2C数据,并且将其链接到Sensor_data中
{
sl_status_t sc;
uint8_t i;
for(i=0;i<I2C_BUFFER_SIZE;i++)
{
i2c_buf[i] = i2c_Buffer[i];
}
sc = sl_bt_gatt_server_send_notification(
i2c_connection,
gattdb_Sensor_data,
sizeof(i2c_buf),
(uint8_t*)i2c_buf);
}
void sl_gatt_service_i2c_step(void)//gatt服务
{
if (i2c__notification)
{
i2c_notify();
}
}
在void sl_bt_on_event(sl_bt_msg_t *evt)中添加事件相应代码
case sl_bt_evt_gatt_server_characteristic_status_id:
if ((sl_bt_gatt_server_client_config ==
(sl_bt_gatt_server_characteristic_status_flag_t)evt->data.evt_gatt_server_characteristic_status.status_flags)
&& (gattdb_Sensor_data == evt->data.evt_gatt_server_user_read_request.characteristic))
{
// client characteristic configuration changed by remote GATT client
i2c_char_config_changed_cb(&evt->data.evt_gatt_server_characteristic_status);
}
break;
将sl_gatt_service_i2c_step()放入sl_internal_app_process_action中使得在触发相应时间后能执行相应操作
void sl_internal_app_process_action(void)
{
sl_gatt_service_i2c_step();
}
当手机端的notify被打开始,将会显示I2C接收到的数据
初值显示为Data
打开notify之后显示I2C接收到的数据