nordic 52832 例程I2C解析

为了实现两块蓝牙开发板之间的通信,本文着重分析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,成功的画面如下:

时间: 2024-11-08 10:40:46

nordic 52832 例程I2C解析的相关文章

linux之I2C解析(转)

1      硬件特性 1.1 概述 I2C总线是由Philips公司开发的两线式串行总线,这两根线为时钟线(SCL)和双向数据线(SDA).由于I2C总线仅需要两根线,因此在电路板上占用的空间更少,带来的问题是带宽较窄.I2C在标准模式下传输速率最高100Kb/s,在快速模式下最高可达400kb/s.属于半双工. 在嵌入式系统中,I2C应用非常广泛,大多数微控制器中集成了I2C总线,一般用于和RTC,EEPROM,智能电池电路,传感器,LCD以及其他类似设备之间的通信. 1.2 I2C总线传输

nordic DFU固件升级

一:测试固件芯片类型: nordic 52832 二:下载升级源码 1>nRF Toolbox App 源码  https://github.com/NordicSemiconductor/IOS-nRF-Toolbox 2>IOS-DFU-Library 源码  https://github.com/NordicSemiconductor/IOS-DFU-Library PS:建议使用后者,针对性强,集成性高,容易进行相关的代码抽取 三:实际应用: 1>使用cocoapods集成 iO

开发你的第一个BLE应用程序—Blinky

本文将和大家一起编写我们的第一个BLE应用程序:Blinky(闪灯程序),哪怕你之前没有任何BLE开发经验,也不用担心,只要跟着文中所述步骤,你就可以一步步搭建自己的第一个BLE应用程序.通过这个Blinky程序的搭建,你将体会到BLE的一些基本概念,对BLE将会有一个非常直观的认识,为后续自己的BLE应用程序开发打下一个坚实的基础. 1. 开发准备 1)     nRF52或者nRF51开发板1块.请参考"Nordic nRF51/nRF52开发流程说明",购买相应开发板(DK).

[转]RPC 编程

简介 任何 RPC 客户机-服务器程序的重要实体都包括 IDL 文件(接口定义文件).客户机 stub.服务器 stub 以及由客户机和服务器程序共用的头文件.客户机和服务器 stub 使用 RPC 运行时库通信.RPC 运行时库提供一套标准的运行时例程来支持 RPC 应用程序.了解运行时例程的内部情况有助于进一步了解 RPC 编程. 在一般的应用程序中,被调用的过程在相同的地址空间中运行,并把结果返回给发出调用的过程.在分布式环境中,客户机和服务器在不同的机器上运行,客户端调用在服务器端运行的

BulkLoop例程の初始化函数and重复调度函数の解析

//----------------------------------------------------------------------------- // File: bulkloop.c // Contents: Hooks required to implement USB peripheral function. // // $Archive: /USB/Examples/FX2LP/bulkloop/bulkloop.c $ // $Date: 3/23/05 2:55p $

I2C驱动实例解析

简单的说,i2c驱动也就三步吧,注册i2c设备,注册i2c设备驱动,创建sysfs文件供上层调用. 1. 注册i2c设备. 先定义一个i2c_board_info static struct i2c_board_info __initdata xxxx_i2c_info[] = { { I2C_BOARD_INFO("XXXX", 0x1D), .platform_data = &xxxx_platform_data, }, }; 再注册,一般会注册一个client. i2c_

i2c知识总结及协议解析

知识总结部分: 一. 技术性能: 工作速率有100K和400K两种: 支持多机通讯: 支持多主控模块,但同一时刻只允许有一个主控: 由数据线SDA和时钟SCL构成的串行总线: 每个电路和模块都有唯一的地址: 每个器件可以使用独立电源 二. 基本工作原理: 以启动信号START来掌管总线,以停止信号STOP来释放总线: 每次通讯以START开始,以STOP结束: 启动信号START后紧接着发送一个地址字节,其中7位为被控器件的地址码,一位为读/写控制位R/W,R. /W位为0表示由主控向被控器件写

STM32 I2C 總線佔用問題解析

这几天解决 STM32 MCU的I2C 总线占用(bus BUSY) 问题,觉得是不错的学习,从文中可得知I2C问题的思考逻辑逻,文末并指出经常出错的问题点,在此分享给大家. 问题描述 STM32F207 MCU有三组I2C,I2C1~I2C3,此项目的初版硬件使用I2C1接三颗chip (DSP/Codec/EEPROM),运作良好. 但新硬件把Codec/EEPROM移到I2C3,DSP还是留在I2C1,发现I2C3有机会传输失败,失败時log打总线占用(Bus BUSY) 查MCU dat

i2c 协议解析【转】

转自:http://blog.csdn.net/g_salamander/article/details/8016698 版权声明:本文为博主原创文章,未经博主允许不得转载. 1.基本概念 主机            初始化发送,产生时钟信号和终止发送的器件 从机            被主机寻址的器件 发送器        发送数据到总线的器件 接收器        从总线接收数据的器件 多主机        同时有多于一个主机尝试控制总线 但不破坏报文 仲裁           是一个在有多