为了实现两块蓝牙开发板之间的通信,本文着重分析I2C程序。
1、打开twi_master_with_twis_slave文件下的程序,编译运行,下载。
2、在串口工具中,我们看到了如下结果:
3、想要搞清楚p,w,c,x,分别式什么意思,以p为例,从主函数看起,主循环里有个
case ‘p‘:
do_print_data();
break;
4、看do_print_data(),我们在虚拟串口工具(参考上一篇)我们输入p发送数据,看到出现了如下图:
5、为了分析为什么出现Communication error1,我们在do_print_data()里面发现了如下语句:
if(NRF_SUCCESS != err_code)
{
printf("Communication error1\n\r");
return;
}
6、很明显的可以看出if语句式成立,也就是说NRF_SUCCESS 和err_code不相等,我们可以查出NRF_SUCCESS =0,那么我们就要证明err_code不等于0.
7、为了看err_code的值,我们右击第二个选项,
选择option,打开如下图的c/c++标签,将optimization改为level 0(因为level 3压缩了一些数据),如下图:
8、再次编译下载,按debug,在printf处定定点
在串口工具里发送p,点击运行
可以在call stack+locals或者鼠标放在变量error_code上可以看到当前数值为3,如下图
9、为了找出error_code为什么是3,我们找到如下程序err_code = eeprom_read(addr, buff, IN_LINE_PRINT_CNT)
点eeprom_read进去,发现:
static ret_code_t eeprom_read(size_t addr, uint8_t * pdata, size_t size)
{
ret_code_t ret;
if(size > (EEPROM_SIM_SIZE))
{
return NRF_ERROR_INVALID_LENGTH;
}
do
{
uint8_t addr8 = (uint8_t)addr;
ret = nrf_drv_twi_tx(&m_twi_master, EEPROM_SIM_ADDR, &addr8, 1, true);
if(NRF_SUCCESS != ret)
{
break;
}
ret = nrf_drv_twi_rx(&m_twi_master, EEPROM_SIM_ADDR, pdata, size);
}while(0);
return ret;
}
可以看出里面有两个return,我们现在就是要找它的返回值。
10、可以找出NRF_ERROR_INVALID_LENGTH的值为9,排除。
那就说明return的是ret,我们可以看出在do while里有两个ret,下面就看break能否执行。
如果bresk执行的话,return的是第一个ret,反之是第二个ret
11、注意:在每次调试或者设置断点时,必须在串口工具重新发送p!!!!!!!!!
12、在break处设置断点,发送p,运行,当它执行到break,单步运行,发现程序跳过第二个ret,所以说明执行的是第一个ret,开始研究第一个ret
ret = nrf_drv_twi_tx(&m_twi_master, EEPROM_SIM_ADDR, &addr8, 1, true);
13、点进第一个ret的调用函数,看到
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_xfer_desc_t xfer = NRF_DRV_TWI_XFER_DESC_TX(address, (uint8_t*)p_data, length);
return nrf_drv_twi_xfer(p_instance, &xfer, no_stop ? NRF_DRV_TWI_FLAG_TX_NO_STOP : 0);
}
14、发现有一个return的值,继续进入它的调用函数nrf_drv_twi_xfer(p_instance, &xfer, no_stop ? NRF_DRV_TWI_FLAG_TX_NO_STOP : 0)发现,
ret_code_t nrf_drv_twi_xfer(nrf_drv_twi_t const * p_instance,
nrf_drv_twi_xfer_desc_t const * p_xfer_desc,
uint32_t flags)
{
ret_code_t ret = NRF_SUCCESS;
twi_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
// TXRX and TXTX transfers are support only in non-blocking mode.
ASSERT( !((p_cb->handler == NULL) && (p_xfer_desc->type == NRF_DRV_TWI_XFER_TXRX)));
ASSERT( !((p_cb->handler == NULL) && (p_xfer_desc->type == NRF_DRV_TWI_XFER_TXTX)));
CODE_FOR_TWIM
(
ret = twim_xfer(p_cb, (NRF_TWIM_Type *)p_instance->reg.p_twim, p_xfer_desc, flags);
)
CODE_FOR_TWI
(
if ( (NRF_DRV_TWI_FLAG_TX_POSTINC | NRF_DRV_TWI_FLAG_RX_POSTINC) & flags)
{
return NRF_ERROR_NOT_SUPPORTED;
}
ret = twi_xfer(p_cb, (NRF_TWI_Type *)p_instance->reg.p_twi, p_xfer_desc, flags);
)
return ret;
}
15、在debug模式下,程序前面不是灰色的不能设断点,也就是意味着该段程序不执行!!!!!
16、 可以看出代码做参数,相当于执行()里的程序不执行
CODE_FOR_TWIM
(
ret = twim_xfer(p_cb, (NRF_TWIM_Type *)p_instance->reg.p_twim, p_xfer_desc, flags);
)
17、下面就看
CODE_FOR_TWI
(
if ( (NRF_DRV_TWI_FLAG_TX_POSTINC | NRF_DRV_TWI_FLAG_RX_POSTINC) & flags)
{
return NRF_ERROR_NOT_SUPPORTED;
}
ret = twi_xfer(p_cb, (NRF_TWI_Type *)p_instance->reg.p_twi, p_xfer_desc, flags);
)
return ret;
这里面有两个return,可以看出NRF_ERROR_NOT_SUPPORTED为6,显然不是。
所以执行的是 ret = twi_xfer(p_cb, (NRF_TWI_Type *)p_instance->reg.p_twi, p_xfer_desc, flags);
18、进入 ret = twi_xfer(p_cb, (NRF_TWI_Type *)p_instance->reg.p_twi, p_xfer_desc, flags);,看到
__STATIC_INLINE ret_code_t twi_xfer(twi_control_block_t * p_cb,
NRF_TWI_Type * p_twi,
nrf_drv_twi_xfer_desc_t const * p_xfer_desc,
uint32_t flags)
{
ret_code_t ret = NRF_SUCCESS;
/* Block TWI interrupts to ensure that function is not interrupted by TWI interrupt. */
nrf_twi_int_disable(p_twi, DISABLE_ALL);
if (p_cb->busy)
{
nrf_twi_int_enable(p_twi, p_cb->int_mask);
return NRF_ERROR_BUSY;
}
else
{
p_cb->busy = (NRF_DRV_TWI_FLAG_NO_XFER_EVT_HANDLER & flags) ? false : true;
}
if (flags & NRF_DRV_TWI_FLAG_HOLD_XFER)
{
return NRF_ERROR_NOT_SUPPORTED;
}
p_cb->flags = flags;
p_cb->xfer_desc = *p_xfer_desc;
p_cb->curr_length = p_xfer_desc->primary_length;
p_cb->p_curr_buf = p_xfer_desc->p_primary_buf;
nrf_twi_address_set(p_twi, p_xfer_desc->address);
if (p_xfer_desc->type != NRF_DRV_TWI_XFER_RX)
{
p_cb->curr_no_stop = ((p_xfer_desc->type == NRF_DRV_TWI_XFER_TX) &&
!(flags & NRF_DRV_TWI_FLAG_TX_NO_STOP)) ? false : true;
ret = twi_tx_start_transfer(p_cb, p_twi, p_xfer_desc->p_primary_buf, p_xfer_desc->primary_length, p_cb->curr_no_stop);
}
else
{
p_cb->curr_no_stop = false;
ret = twi_rx_start_transfer(p_cb, p_twi, p_xfer_desc->p_primary_buf, p_xfer_desc->primary_length);
}
if (p_cb->handler == NULL)
{
p_cb->busy = false;
}
return ret;
}
可以看出有3个return,其中两个return:NRF_ERROR_BUSY=17,NRF_ERROR_NOT_SUPPORTED=6,可以排除,那么返回的是第3个return,ret
19、可以看出ret有两个
if (p_xfer_desc->type != NRF_DRV_TWI_XFER_RX)
{
p_cb->curr_no_stop = ((p_xfer_desc->type == NRF_DRV_TWI_XFER_TX) &&
!(flags & NRF_DRV_TWI_FLAG_TX_NO_STOP)) ? false : true;
ret = twi_tx_start_transfer(p_cb, p_twi, p_xfer_desc->p_primary_buf, p_xfer_desc->primary_length, p_cb->curr_no_stop);
}
else
{
p_cb->curr_no_stop = false;
ret = twi_rx_start_transfer(p_cb, p_twi, p_xfer_desc->p_primary_buf, p_xfer_desc->primary_length);
}
if (p_cb->handler == NULL)
{
p_cb->busy = false;
}
return ret;
20、在两个ret前设断点,点击运行,运行到第一个断点后直接跳过了第二个断点,由此我们可以判断,返回的是第一个ret
21、看 ret = twi_tx_start_transfer(p_cb, p_twi, p_xfer_desc->p_primary_buf, p_xfer_desc->primary_length, p_cb->curr_no_stop);可以看到
static ret_code_t twi_rx_start_transfer(twi_control_block_t * p_cb,
NRF_TWI_Type * p_twi,
uint8_t const * p_data,
uint8_t length)
{
ret_code_t ret_code = NRF_SUCCESS;
nrf_twi_event_clear(p_twi, NRF_TWI_EVENT_STOPPED);
nrf_twi_event_clear(p_twi, NRF_TWI_EVENT_ERROR);
nrf_twi_event_clear(p_twi, NRF_TWI_EVENT_TXDSENT);
nrf_twi_event_clear(p_twi, NRF_TWI_EVENT_RXDREADY);
p_cb->bytes_transferred = 0;
p_cb->error = false;
if (length == 1)
{
nrf_twi_shorts_set(p_twi, NRF_TWI_SHORT_BB_STOP_MASK);
}
else
{
nrf_twi_shorts_set(p_twi, NRF_TWI_SHORT_BB_SUSPEND_MASK);
}
// In case TWI is suspended resume its operation.
nrf_twi_task_trigger(p_twi, NRF_TWI_TASK_RESUME);
nrf_twi_task_trigger(p_twi, NRF_TWI_TASK_STARTRX);
if (p_cb->handler)
{
p_cb->int_mask = NRF_TWI_INT_STOPPED_MASK |
NRF_TWI_INT_ERROR_MASK |
NRF_TWI_INT_TXDSENT_MASK |
NRF_TWI_INT_RXDREADY_MASK;
nrf_twi_int_enable(p_twi, p_cb->int_mask);
}
else
{
while (twi_transfer(p_twi, &p_cb->error, &p_cb->bytes_transferred, (uint8_t*)p_data, length, false))
{}
if (p_cb->error)
{
ret_code = NRF_ERROR_INTERNAL;
}
}
return ret_code;
}
可以发现返回的是ret_code,
22、可以找到
if (p_cb->error)
{
ret_code = NRF_ERROR_INTERNAL;
}
里面的NRF_ERROR_INTERNAL=3,就可以找到为什么出现了最开始的Communication error1
23、后来发现两块蓝牙开发板共地,再发送p,就不会出现最开始的Communication error1,成功的画面如下: