1.
TX表示传送数据,为输出。
RX表示接收数据,为输入。
通信上的RX和TX代表的意思:
TXD 发送数据 Transmit(tx) Data 的简写形式
RXD 接收数据 Receive(rx) Data 的简写形式
2.platform_write 和I2C_WriteData 关系。platform_read和 I2C_ReadData关系:
static int32_t platform_write(void *handle, uint8_t reg, const uint8_t *bufp,
uint16_t len)
{
I2C_WriteData(0x6a,reg,(uint8_t*)bufp,len);
return 0;
}
static int32_t platform_read(void *handle, uint8_t reg, uint8_t *bufp,
uint16_t len)
{
I2C_ReadData(0x6a,reg,(uint8_t*)bufp,len);
return 0;
}
- 功能: 该函数从I2C从设备(地址为
0x6a)的寄存器reg读取len字节的数据,并将数据存放到bufp指向的缓冲区中。 - 参数:
handle: 指向某种处理句柄的指针,但在此函数中未使用。reg: 要读取的寄存器地址。bufp: 数据将被读取到此缓冲区。len: 读取的数据长度。
- 调用
I2C_ReadData: 实际的I2C数据读取操作是通过调用I2C_ReadData函数完成的。 - 3.
I2C_ReadData函数详细解释如下:
/**
@brief TWI(I2C)读数据函数
@param slaveAddr -[in] 从设备地址
@param regAddr -[in] 寄存器地址
@param pData -[in] 读出数据
@param dataLen -[in] 读出数据长度
@return 错误码
*/
uint16_t I2C_ReadData(uint8_t slaveAddr, uint8_t regAddr, uint8_t *pData, uint16_t dataLen)
{
uint32_t errCode; //变量声明:errCode:用于存储操作的返回码。
uint32_t timeout = TWI_TIMEOUT; // timeout:用于定义操作超时的计时器,TWI_TIMEOUT 是预定义的超时时间。
errCode = nrf_drv_twi_tx(&s_twiHandle, slaveAddr, ®Addr, 1, false);
if(errCode != NRF_SUCCESS)
{
return errCode;
}
- 发送寄存器地址:
nrf_drv_twi_tx:这是 Nordic 的驱动函数,用于发送数据到 I2C 从设备。&s_twiHandle:指向 TWI(I2C)的句柄,用于识别 I2C 实例。slaveAddr:从设备的地址。®Addr:寄存器地址的指针。1:要发送的数据字节数(这里是寄存器地址的字节数)。false:表示这是一个写操作,不需要重复开始。- 错误检查:如果
nrf_drv_twi_tx返回NRF_SUCCESS,说明发送成功,否则返回错误码。
while((!s_twiTxDone) && --timeout);
if(!timeout)
{
return NRF_ERROR_TIMEOUT;
}
s_twiTxDone = false;
- 等待传输完成:
s_twiTxDone:一个全局标志,指示传输是否完成。- 循环等待:通过减少
timeout计数器来实现超时机制,如果s_twiTxDone没有被设置,循环继续。 - 如果超时 (
timeout变为 0),返回NRF_ERROR_TIMEOUT,表示操作超时。 - 重置标志:传输完成后,重置
s_twiTxDone为false,以便下一次使用。
errCode = nrf_drv_twi_rx(&s_twiHandle, slaveAddr, pData, dataLen);
if(errCode != NRF_SUCCESS)
{
return errCode;
}
nrf_drv_twi_rx:Nordic 的驱动函数,用于从 I2C 从设备接收数据。pData:指向存储接收数据的缓冲区的指针。dataLen:要接收的数据字节数。- 错误检查:如果
nrf_drv_twi_rx返回NRF_SUCCESS,说明读取成功,否则返回错误码。
timeout = TWI_TIMEOUT;
while((!s_twiRxDone) && --timeout);
if(!timeout)
{
return NRF_ERROR_TIMEOUT;
}
s_twiRxDone = false;
- 等待接收完成:
- 循环等待:通过减少
timeout计数器来实现超时机制,如果s_twiRxDone没有被设置,循环继续。 - 如果超时 (
timeout变为 0),返回NRF_ERROR_TIMEOUT,表示操作超时。 - 重置标志:接收完成后,重置
s_twiRxDone为false,以便下一次使用。
- 循环等待:通过减少
return errCode;
- 返回结果:返回最终的错误码(如果有),或者
NRF_SUCCESS以表示操作成功。
}
- 整体功能,整体来说: 该函数负责从指定的I2C从设备读取数据。
- 参数:
slaveAddr: I2C从设备的地址。regAddr: 要读取的寄存器地址。pData: 指向数据缓冲区的指针,用于存放读取到的数据。dataLen: 需要读取的数据长度。
- 过程:
- 发送写命令来指定要读取的寄存器地址(
nrf_drv_twi_tx)。 - 等待发送完成,超时返回错误(
NRF_ERROR_TIMEOUT)。 - 发送读取命令并接收数据(
nrf_drv_twi_rx)。 - 等待接收完成,超时返回错误(
NRF_ERROR_TIMEOUT)。
- 发送写命令来指定要读取的寄存器地址(
4.I2C_ReadData里面调用的nrf_drv_twi_tx和nrf_drv_twi_tx本人的关系:
errCode = nrf_drv_twi_tx(&s_twiHandle, slaveAddr, ®Addr, 1, false);
nrf_drv_twi_tx本人:
ret_code_t nrf_drv_twi_tx(nrf_drv_twi_t const * p_instance,
uint8_t address,
uint8_t const * p_data,
uint8_t length,
bool no_stop)
小小补充:
nrf_drv_twi_t const * p_instance,
- 解释:这是一个指向
nrf_drv_twi_t结构体的常量指针。nrf_drv_twi_t是一个数据结构,用来保存 TWI (I2C) 实例的状态和配置信息。通过这个指针,函数可以访问和操作指定的 TWI 实例。 const:表示指针指向的内容(即nrf_drv_twi_t结构体)在函数内部不会被修改。指针本身可以改变,但指针所指向的内容保持不变。
- uint8_t const * p_data,解释:这是一个指向
uint8_t类型常量的指针。p_data是一个指向数据缓冲区的指针,用于传递要发送的数据。const表示函数内部不会修改数据缓冲区的内容。 -
bool no_stop:- 解释:这是一个布尔值(
true或false),用于控制 I2C 传输结束时是否发送停止信号。true表示不发送停止信号(即使用重复开始条件),false表示发送停止信号。 p_instance是一个指向 TWI 实例的常量指针,允许函数读取 TWI 实例的状态但不能修改它。address是要访问的 I2C 从设备的地址。p_data是指向待发送数据的缓冲区的指针,const表示数据在函数内部不会被修改。length是要发送的数据的字节数。no_stop控制是否发送停止信号的布尔值。- 这些参数共同决定了函数如何进行 I2C 数据传输,具体操作包括设置目标设备地址、数据缓冲区、传输数据的长度以及是否在传输结束后发送停止信号。
- 解释:这是一个布尔值(
{
ret_code_t result = 0;
if (NRF_DRV_TWI_USE_TWIM)
{
result = nrfx_twim_tx(&p_instance->u.twim,
address, p_data, length, no_stop);
}
else if (NRF_DRV_TWI_USE_TWI)
{
result = nrfx_twi_tx(&p_instance->u.twi,
address, p_data, length, no_stop);
}
return result;
}
buffer:缓冲区。
I2C_ReadData里面调用的nrf_drv_twi_rx和nrf_drv_twi_rx本人的关系:
-
nrf_drv_twi_rx的调用:在I2C_ReadData函数中,nrf_drv_twi_rx被调用来执行从 I2C 从设备读取数据的操作。它将从设备的地址slaveAddr和接收缓冲区pData以及数据长度dataLen传递给nrf_drv_twi_rx函数。 -
nrf_drv_twi_rx的作用:这个函数根据使用的 TWI 驱动(TWIM或TWI)选择合适的实现来执行接收操作。nrf_drv_twi_rx函数实际执行的是具体的硬件操作或者中间件操作,它会返回操作结果(成功或失败的代码)。 -
nrf_drv_twi_rx函数负责从 I2C 从设备接收数据,并将数据存储到提供的缓冲区p_data中。它根据具体的硬件驱动(TWIM或TWI)选择合适的实现来完成这个任务。I2C_ReadData函数通过调用nrf_drv_twi_rx实现了从 I2C 从设备读取数据的功能,确保数据能够正确地被读取并存储在指定的缓冲区中。
errCode = nrf_drv_twi_rx(&s_twiHandle, slaveAddr, pData, dataLen);
ret_code_t nrf_drv_twi_rx(nrf_drv_twi_t const * p_instance,
uint8_t address,
uint8_t * p_data,
uint8_t length)
{
ret_code_t result = 0;
if (NRF_DRV_TWI_USE_TWIM)
{
result = nrfx_twim_rx(&p_instance->u.twim,
address, p_data, length);
}
else if (NRF_DRV_TWI_USE_TWI)
{
result = nrfx_twi_rx(&p_instance->u.twi,
address, p_data, length);
}
return result;
}
5.nrf_drv_twi_rx 函数
nrf_drv_twi_rx 是 Nordic Semiconductor 提供的用于 I2C 数据接收的函数。其主要功能是从 I2C 从设备读取指定长度的数据。
-
参数:
s_twiHandle: I2C 实例的句柄。slaveAddr: 从设备地址。pData: 数据接收缓冲区。dataLen: 要接收的数据长度。
-
功能: 向I2C从设备发送读取命令,并将读取的数据存放到提供的缓冲区中。
s_twiHandle是一个I2C实例的句柄。
在嵌入式系统中,通常一个微控制器或处理器会有多个外设接口,比如UART、SPI、I2C等。为了管理和控制这些外设接口,通常会为每个外设创建一个"实例"(instance)。这个实例就相当于是一个对象,它包含了该外设的所有相关信息和状态。
在使用这些外设时,我们需要先获取对应外设的实例句柄,然后通过这个句柄来操作和控制该外设。这个句柄通常是一个指向外设实例结构体的指针。
对于I2C外设来说,s_twiHandle就是指向I2C实例的句柄。它包含了I2C总线的配置信息、当前状态等,可以通过这个句柄来发送和接收I2C数据。
在上面的代码中,nrf_drv_twi_tx和nrf_drv_twi_rx函数都需要使用I2C实例的句柄作为参数,来指明应该在哪个I2C总线上执行读写操作。这样做可以方便地在同一个系统中管理和使用多个I2C外设。
句柄:handle。
简单来说,句柄(Handle)是一个用来标识和操作计算机资源的标识符。它可以是一个整数值、内存地址或其他类型的标识符,主要用于访问或管理各种系统资源,例如文件、窗口、网络连接或数据库连接。句柄的作用是使程序能够通过一个简单的标识符来进行复杂的资源操作,而不需要直接处理底层的细节。
6.I2C_Init();
/**
@brief TWI(I2C)驱动初始化
@param 无
@return 无
*/
void I2C_Init(void)
{
uint32_t errCode; //uint32_t 是一种标准的 32 位无符号整型,用于存储无符号整数。在代码中,uint32_t errCode; 声明了一个变量 errCode,它用来保存函数调用后的错误码或状态码。通过这种方式,可以检测操作是否成功并进行相应的错误处理。
// 初始化TWI配置结构体
const nrf_drv_twi_config_t twiConfig =
{
.scl = BOARD_TWI_SCL_IO, // 配置TWI SCL引脚
.sda = BOARD_TWI_SDA_IO, // 配置TWI SDA引脚
.frequency = NRF_DRV_TWI_FREQ_400K, // 配置TWI时钟频率
.interrupt_priority = APP_IRQ_PRIORITY_HIGH // TWI中断优先级设置
};
// 初始化TWI
errCode = nrf_drv_twi_init(&s_twiHandle, &twiConfig, twi_handleEvent, NULL);
APP_ERROR_CHECK(errCode);
// 使能TWI
nrf_drv_twi_enable(&s_twiHandle);
}
相当于是调用了nrf_drv_twi_init
ret_code_t nrf_drv_twi_init(nrf_drv_twi_t const * p_instance,
nrf_drv_twi_config_t const * p_config,
nrf_drv_twi_evt_handler_t event_handler,
void * p_context)
{
uint32_t inst_idx = p_instance->inst_idx;
m_handlers[inst_idx] = event_handler;
m_contexts[inst_idx] = p_context;
if(p_config->clear_bus_init)
{
/* Send clocks (max 9) until slave device back from stuck mode */
twi_clear_bus(p_config);
}
ret_code_t result = 0;
if (NRF_DRV_TWI_USE_TWIM)
{
result = nrfx_twim_init(&p_instance->u.twim,
(nrfx_twim_config_t const *)p_config,
event_handler ? twim_evt_handler : NULL,
(void *)inst_idx);
}
else if (NRF_DRV_TWI_USE_TWI)
{
result = nrfx_twi_init(&p_instance->u.twi,
(nrfx_twi_config_t const *)p_config,
event_handler ? twi_evt_handler : NULL,
(void *)inst_idx);
}
return result;
}
相当于是调用了nrf_drv_twi_enable
void nrf_drv_twi_enable(nrf_drv_twi_t const * p_instance)
{
if (NRF_DRV_TWI_USE_TWIM)
{
nrfx_twim_enable(&p_instance->u.twim);
}
else if (NRF_DRV_TWI_USE_TWI)
{
nrfx_twi_enable(&p_instance->u.twi);
}
}
7.I2C_Enable();
@brief 开启TWI(I2C)
@param 无
@return 无
*/
void I2C_Enable(void)
{
nrf_drv_twi_enable(&s_twiHandle);
}
/**
@brief 禁用TWI(I2C)
@param 无
@return 无
*/
void I2C_Disable(void)
{
nrf_drv_twi_disable(&s_twiHandle);
}
8..Check_LSM6DSR_ID();
bool Check_LSM6DSR_ID()
{
printf("LSM6DSR_ID is %02x\r\n", LSM6DSR_Read_Reg(LSM6DSR_WHO_AM_I) );
return (LSM6DSR_Read_Reg(LSM6DSR_WHO_AM_I) == LSM6DSR_ID);
}
9.if (whoamI != LSM6DSV_ID)
while (1);
- 如果
whoamI的值与LSM6DSV_ID不匹配,则进入一个无限循环。 - 这意味着如果传感器的型号与预期不符,程序将永远卡在这里,不会继续执行后续的代码。
10..

4265

被折叠的 条评论
为什么被折叠?



