PPI,英文全称Programmable Peripheral Interconnect,是Nordic独有的外设,其设计目的是让CPU处于idle模式下外设与外设之间也能完成相应通信,从而降低系统功耗。为此,很多人会把PPI类比成DMA,的确PPI和DMA两者在设计最终目的上有一定的相似性,但两者的功能和原理完全不相同。讲解PPI原理之前,先大概阐述一下Nordic芯片一个独特的设计理念。

Nordic芯片每个外设都可以看做一个状态机,所以每个外设都有输入(task),输出(event)以及状态。比较常见的task比如启动外设,清0寄存器等,常见的event比如数据发送完毕,外设关闭等。实现上,每个task和event都是一个独立的32-bit寄存器,这跟传统的芯片不一样,传统的芯片都是用寄存器的某一个bit来启动,或者某一个bit来显示状态。换句话说,Nordic把传统芯片1bit要做的事情换成一个完整的32-bit寄存器来实现。这样做的好处是,每个task和event都是一个寄存器,他们都可以用一个独立而唯一的地址来标识,这就为PPI打下了坚实的基础。比如Timer模块的寄存器列表如下所示,里面就包含了各种task和event寄存器:

再比如ADC模块的寄存器列表如下所示,里面也包含了各种task和event寄存器:

现在开始讲PPI,首先PPI也是一个外设,因此PPI也有自己的寄存器定义,如下图所示,其主要用来配置PPI通道等。简言之,PPI就是一个数字逻辑系统,它可以通过某一个PPI通道把外设1的event跟外设2的task相连,这样一旦外设1的event置起(相关寄存器为1),将会自动触发外设2的task(将相关寄存器自动置1)。

下面以一个实际例子来加深大家对PPI的理解,假设我们要实现如下功能:启动timer,定时10ms,10ms到后启动ADC模块。这里我们以两种方式来实现该例子要求:传统方式和PPI方式,大家仔细比较两者的区别,以理解PPI的积极作用。

传统方式

传统方式大致需要如下步骤:

  1. 初始化Timer模块和ADC模块——(CPU工作)
  2. 启动Timer——(CPU工作)
  3. 等待Timer中断——(CPU不工作)
  4. 10ms到,进入Timer timeout handler,启动ADC——(CPU工作)

PPI方式

PPI方式大致需要如下步骤:

  1. 初始化Timer模块,ADC模块,以及PPI模块,将Timer模块的timeout event和ADC模块的start task相连——(CPU工作)
  2. 启动Timer——(CPU工作)
  3. 等待Timer timeout,10ms到,PPI将自动启动ADC——(CPU不工作)

通过比较传统方式和PPI方式,PPI方式可以少进入一次timeout handler,从而减少CPU工作时间,降低系统功耗。由于不需要进入timeout handler,因此启动ADC的操作就不存在被其他高优先级中断打断的可能,这是PPI带来的第二个好处:系统实时性更好。

除了一个event对应一个task,PPI通过fork机制可以让一个event同时启动2个task,即把一个event同时和一个task以及task对应的fork相连,以实现一个event到来,2个task同时启动的目的。

大家可以参考SDK自带例子(Keil5工程):

SDK安装目录\examples\peripheral\ppi\pca10040\blank\arm5_no_packs

或者

SDK安装目录\examples\peripheral\gpiote\pca10040\blank\arm5_no_packs

来进一步理解PPI的工作原理和编程注意事项。

下面为一段PPI使用代码示例,它实现的功能是:当定时时间到,通过PPI自动去操作IO口

err_code = nrf_drv_ppi_init();

APP_ERROR_CHECK(err_code);

err_code = nrf_drv_ppi_channel_alloc(&ppi_channel);

APP_ERROR_CHECK(err_code);

compare_evt_addr = nrf_drv_timer_event_address_get(&timer, NRF_TIMER_EVENT_COMPARE0);

gpiote_task_addr = nrf_drv_gpiote_out_task_addr_get(GPIO_OUTPUT_PIN_NUMBER);

err_code = nrf_drv_ppi_channel_assign(ppi_channel, compare_evt_addr, gpiote_task_addr);

APP_ERROR_CHECK(err_code);

err_code = nrf_drv_ppi_channel_enable(ppi_channel);

APP_ERROR_CHECK(err_code);

如何理解nRF5芯片外设PPI的更多相关文章

  1. nRF5芯片外设GPIO和GPIOTE介绍

    nRF51/nRF52同时包含GPIO和GPIOTE两种外设,经常有人将两者搞混,今天我们就来介绍一下这2种外设有什么不同,及使用注意事项. GPIO和GPIOTE都属于芯片外设,但两者功能完全不一样 ...

  2. Nordic nRF5 SDK和softdevice介绍

    SDK和Softdevice的区别是什么?怎么选择SDK和softdevice版本?芯片,SDK和softdevice有没有版本兼容问题?怎么理解SDK目录结构?SDK帮助文档在哪里?Softdevi ...

  3. 如何调试nRF5 SDK

    本文将讲述Nordic nRF5 SDK的主要调试手段,以帮助大家快速定位问题,并解决问题.一般来说,你可以通过打log方式,IDE的debug模式,SDK自带的app_error_check函数,以 ...

  4. 【STM32学习笔记1】基于固件库的STM32_MDK工程模版

    文章包含STM32固件库介绍和工程模板搭建两方面内容. 一.STM32固件库介绍 要建立工程模板,首先要对STM32的固件库有所了解.STM32的固件可以从ST官网下载,网址为:http://www. ...

  5. 豹哥嵌入式讲堂:ARM开发中有用的文件(1)- source文件

    大家好,我是豹哥,猎豹的豹,犀利哥的哥.今天豹哥给大家讲的是嵌入式开发里的source文件种类. 众所周知,嵌入式开发属于偏底层的开发,主要编程语言是C和汇编.所以本文要讲的source文件主要指的就 ...

  6. 痞子衡嵌入式:ARM Cortex-M文件那些事(1)- 源文件(.c/.h/.s)

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家讲的是嵌入式开发里的source文件. 众所周知,嵌入式开发属于偏底层的开发,主要编程语言是C和汇编.所以本文要讲的source文件主要指的就是 ...

  7. 手把手教你开发BLE数据透传应用程序

    如何开发BLE数据透传应用程序?什么是BLE service和characteristic?如何开发自己的service和characteristic?如何区分ATT和GATT?有没有什么工具可以对B ...

  8. Raw-OS源代码分析之同优先级任务切换

    分析的内核版本号截止到2014-04-15,基于1.05正式版,blogs会及时跟进最新版本号的内核开发进度,若源代码凝视出现"???"字样,则是未深究理解部分. Raw-OS官方 ...

  9. Android Bluetooth模块学习笔记

    一.蓝牙基础知识 1.蓝牙( Bluetooth )是一种无线技术标准,可实现固定设备.移动设备和楼宇个人域网之间的短距离数据交换.蓝牙基于设备低成本的收发器芯片,传输距离近.低功耗. 2.微波频段: ...

随机推荐

  1. CentOS yum 安装node.js

    第一步: curl --silent --location https://rpm.nodesource.com/setup_10.x | sudo bash - 第二步: sudo yum -y i ...

  2. MySQL DBA的修炼与未来(参考篇)

    转自:https://blog.csdn.net/xielingshao/article/details/77840101 MySQL DBA的修炼与未来 随着MySQL地位爆炸式的提升, MySQL ...

  3. spring MVC学习(一)---前端控制器

    1.spring MVC中的前段控制器就是DsipatcherServlet,它在spring MVC框架中的结构图如下: 2.DispatcherServlet其实就是一个Servlet,它继承了H ...

  4. des/3des

    一.python 1. des3 python平台的DES3 + base64 加密解密, 有两个常用的库pycrypto和pyDes 1)pycrypto des3.py #coding=utf-8 ...

  5. Spark2.0机器学习系列之4:Logistic回归及Binary分类(二分问题)结果评估

    参数设置 α: 梯度上升算法迭代时候权重更新公式中包含 α :  http://blog.csdn.net/lu597203933/article/details/38468303 为了更好理解 α和 ...

  6. 新建虚拟机与本机ping不通(一招解决)

    初始新建虚拟机或者复制虚拟机后,发现虚拟机能ping通内外网,但是本机无法ping通虚拟机,xshell也无法连接虚拟机 这时候就很头疼了,因为要上传很多文件到虚拟机上面 解决办法: 1.关闭虚拟机后 ...

  7. C++实现去掉string字符串前后的空白字符

    C++标准库提供的字符串类string没有提供类似CString中Trim方法,该方法功能为去除字符串前后的空白字符.利用string自身一些方法可以很容易实现该功能. 如下: void Trim(s ...

  8. 关于在MFC的视图类里面添加各种控件 以及给这些控件添加对用的函数。2015-03-24 13:46:00

    首先我们把题目所示的要求分为两个问题: 问题一:如何给基于MFC的单文档视图类里面添加 控件.就是那种类似工具箱里面的控件. 问题二:如何给已经添加的控件 定义一些消息的响应函数. ××××××××× ...

  9. 基于java的网络爬虫框架(实现京东数据的爬取,并将插入数据库)

    原文地址http://blog.csdn.net/qy20115549/article/details/52203722 本文为原创博客,仅供技术学习使用.未经允许,禁止将其复制下来上传到百度文库等平 ...

  10. 元类 metaclass

    metaclass 类由Type创建 对象由创建 MetaClass作用 用来指定当前类由谁来创建(默认type创建). MetaClass 会被继承,如果父类指定了元类,那么子类也是由这个元类创建 ...