【Nordic博文分享系列】PPI和DPPI的功能及应用说明

原创 Nordic半导体 2024-01-25 12:00




作者:Gao Jun, Nordic Semiconductor

1

什么是PPI和DPPI?

  • PPI,英文全称是Programmable Peripheral Interconnect;

  • DPPI,英文全称是Distributed Programmable Peripheral Interconnect。

PPI是nRF52系列芯片的一个外设,从nRF53系列开始,使用DPPI代替了PPI。PPI和DPPI的设计目的是相同的,都提供了一种机制,让某个外设的事件可以触发另一个外设的任务,让一个外设直接控制另一个外设成为可能,从而减少了CPU的参与,和DMA有异曲同工之效。

比如,我们可以用timer定时器去触发一个ADC采样,这样就不需要CPU执行指令去触发采样了。所谓编程(Programmable),就是指可以通过配置寄存器,将不同外设的事件和任务建立关联。

nRF52 DK



2

什么是事件(event)和任务(task)?

说到PPI和DPPI就绕不过事件和任务。那么这个事件和任务又是什么呢?学习过MCU的同学都知道外设(Peripheral)都会有与之对应的控制寄存器和状态寄存器,而我们Nordic的控制寄存器和状态寄存器的设计有些与众不同。

我们将控制寄存器的控制逻辑做了细分,将每一个控制逻辑都具体成了一个任务,一个任务就对应一个任务寄存器。同样,将状态寄存器的状态也做了细分,将每一个不同的状态都具体成了一个事件,一个事件就对应一个事件寄存器。

以UARTE模块为例,它的task和event寄存器如下:



3

什么是通道(Channel)?

通道可以想象成一个管道,管道的输入端关联event寄存器,管道的输出端关联task寄存器。管道上有开关,当开关被打开时(channel enable),event寄存器如果有信号,就能触发管道另一头的task寄存器,从而触发task寄存器对应的控制逻辑。

PPI和DPPI的主要区别是:通道与event寄存器和task寄存器建立关联的机制不同。PPI的机制决定了一个通道只能关联一个event和一个task,即只能一对一(一个event触发一个task),利用fork机制可以做到一对二(一个event触发两个task)。

DPPI的一个通道可以和多个task和event做关联,能做到多对多(多个event触发多个task)。另外,通道还有自己的管理机制,还可以分组管理。PPI和DPPI的通道管理机制是相同的。



4

PPI框图

  • EEP是event end point的缩写;TEP是task end point的缩写。每一个通道都有自己的EEP和TEP寄存器。

  • CH[i].EEP是一个配置寄存器,负责存储event register 地址,使外设的event与通道i(CH[i])建立关联。

  • CH[i].TEP也是一个配置寄存器,负责存储task register 地址,使外设的task与通道i (CH[i])建立关联。

  • PPI允许一个event或task和多个通道建立关联。即不同的通道里可以写入同一个event或task地址。但一个通道只能和一个event建立关联,因为某个通道i对应的CH[i].EEP里只能写入一个地址。Task比较特殊,因为有FORK[i].TEP的存在,所以CH[i].TEP和FORK[i].TEP可以写入两个不同的task register地址,实现一对二。FORK功能只存在于PPI,DPPI没有FORK功能。

  • 接入同一个通道的event和task可以形成通路,为event触发task逻辑创造条件。

  • CHEN, CHENSET, CHENCLR和CHG[m]则是用来管理这些通道(enable and disable the channels)是否使能。

  • 0-19通道可以任意配置;20-31通道的task和event是固定的,不能配置。

  • PPI的EEP和TEP寄存器:

CH[n].EEP (n=0..19)

Address offset: 0x510 + (n × 0x8)
Channel n event endpoint

CH[n].TEP (n=0..19)

Address offset: 0x514 + (n × 0x8)
Channel n task endpoint

FORK[n].TEP (n=0..19, 20..31)

Address offset: 0x910 + (n × 0x4)
Channel n task endpoint



5

DPPI框图

  • 所有外围设备都含有一系列的任务订阅寄存器和事件发布寄存器(每个task寄存器对应一个订阅( subscribe)寄存器;每个event寄存器对应一个发布(publish)寄存器)。(订阅和发布寄存器取代了PPI中EEP和TEP寄存器的功能)

  • 发布和订阅的对象是通道(channel)

  • 同一个通道可以被不同的事件发布,被不同的任务订阅,达到多对多的效果。

  • 以下是ADC模块的task,event,subscribe task,publish event寄存器。



6

通道管理和组(group)

  • PPI和DPPI对通道的管理方式基本相同

  • 通过通道管理寄存器,每一个通道可以被单独使能或是禁用,相关寄存器如下:

CHENSET

Address offset: 0x504
Channel enable set register

Note: Read: Reads value of CH[i] field in CHEN register

CHENCLR

Address offset: 0x508
Channel enable clear register

Note: Read: Reads value of CH[i] field in CHEN register
  • CHENSET和CHENCLR寄存器用于设置通道,如果要读取通道的状态,需要读取CHEN寄存器。

CHEN

Address offset: 0x500
Channel enable register

  • 不同的通道可以分配到一个组里。一共支持6个组。CHG[n](n=0..5)寄存器有32bit,每一个bit位对应一个通道号,如果相应的bit位被置“1”,那么这个通道就被分配到了当前的组中。

CHG[n] (n=0..5)

Address offset: 0x800 + (n x 0x4)
Channel group n

Note: Writes to this register are ignored if either SUBSCRIBE_CHG[n].EN or SUBSCRIBE_CHG[n].DIS are enabled
  • 每一个组都有两个task寄存器,一个task(TASKS_CHG[n].EN)控制组使能,另一个task (TASKS_CHG[n].DIS)控制组禁用。有了task,那么它们也可以通过PPI/DPPI的机制,被别的event触发。当TASKS_CHG[n].EN被触发,同一组内所有的通道被使能;当TASKS_CHG[n].DIS被触发,同一组内所有的通道被禁用。

TASKS_CHG[n].EN (n=0..5)

Address offset: 0x000 + (n x 0x8)
Enable channel group n

TASKS_CHG[n].DIS (n=0..5)

Address offset: 0x004 + (n x 0x8)
Disable channel group n



7

PPI和DPPI的驱动资源及使用流程

  • PPI 驱动位于modules\hal\nordic\nrfx\drivers\src\nrfx_ppi.c;DPPI驱动位于modules\hal\nordic\nrfx\drivers\src\nrfx_dppi.c

  • 为了兼容PPI和DPPI,还设计了辅助层(Helper layer:modules\hal\nordic\nrfx\helpers\nrfx_gppi.h) 提供 PPI 和 DPPI 驱动的通用功能。辅助层直接调用PPI和DPPI的驱动程序,使用辅助层时,需要考虑到PPI 和 DPPI 接口在应用时的明显差异。

  • PPI和DPPI的使用流程相同,都很简单:

1)分配(申请)通道

2)对于PPI,通道两端分别关联task和event;对于DPPI,task(Subscribe)和event(Publish)端关联通道

3)使能通道



8

PPI和DPPI配置代码示例

1)Timer COMPARE0 EVENT产生的时候触发ADC采样。按下button1启动timer,端口输出低电平,按下button2停止timer,端口输出高电平。下面列举了PPI多通道,以及FORK使用的配置代码。

status = nrfx_ppi_channel_alloc(&m_timer_saadc_ppi_channel);NRFX_ASSERT(status == NRFX_SUCCESS);status = nrfx_ppi_channel_assign(m_timer_saadc_ppi_channel,             nrfx_timer_event_address_get(&m_sample_timer, NRF_TIMER_EVENT_COMPARE0),            nrf_saadc_task_address_get(NRF_SAADC, NRF_SAADC_TASK_SAMPLE));NRFX_ASSERT(status == NRFX_SUCCESS);
//button1 start timer and output lowstatus = nrfx_ppi_channel_alloc(&m_button0_timer_ppi_channel);NRFX_ASSERT(status == NRFX_SUCCESS);status = nrfx_ppi_channel_assign(m_button0_timer_ppi_channel,              nrfx_gpiote_in_event_addr_get(INPUT_PIN_0),              nrf_timer_task_address_get(m_sample_timer.p_reg, NRF_TIMER_TASK_START));NRFX_ASSERT(status == NRFX_SUCCESS);status = nrfx_ppi_channel_fork_assign(m_button0_timer_ppi_channel,              nrfx_gpiote_clr_task_addr_get(OUTPUT_PIN));NRFX_ASSERT(status == NRFX_SUCCESS);
//button2 stop timer and output high  status = nrfx_ppi_channel_alloc(&m_button1_timer_ppi_channel);NRFX_ASSERT(status == NRFX_SUCCESS);status = nrfx_ppi_channel_assign(m_button1_timer_ppi_channel,              nrfx_gpiote_in_event_addr_get(INPUT_PIN_1),              nrf_timer_task_address_get(m_sample_timer.p_reg, NRF_TIMER_TASK_STOP));NRFX_ASSERT(status == NRFX_SUCCESS);status = nrfx_ppi_channel_fork_assign(m_button1_timer_ppi_channel,              nrfx_gpiote_set_task_addr_get(OUTPUT_PIN));NRFX_ASSERT(status == NRFX_SUCCESS);

2)Timer COMPARE0 EVENT产生的时候触发ADC采样。按下button1启动timer,端口输出低电平,按下button2停止timer,端口输出高电平。下面列举了DPPI多通道使用的配置代码。

status = nrfx_dppi_channel_alloc(&m_timer_saadc_dppi_channel);NRFX_ASSERT(status == NRFX_SUCCESS);nrf_timer_publish_set(m_sample_timer.p_reg, NRF_TIMER_EVENT_COMPARE0,    m_timer_saadc_dppi_channel);nrf_saadc_subscribe_set(NRF_SAADC, NRF_SAADC_TASK_SAMPLE, m_timer_saadc_dppi_channel);
//button1 start timer and output lowstatus = nrfx_dppi_channel_alloc(&m_button0_timer_dppi_channel);NRFX_ASSERT(status == NRFX_SUCCESS);nrf_gpiote_publish_set(NRF_GPIOTE, nrfx_gpiote_in_event_get(INPUT_PIN_0),    m_button0_timer_dppi_channel);nrf_gpiote_subscribe_set(NRF_GPIOTE,nrfx_gpiote_clr_task_addr_get(OUTPUT_PIN),m_button0_timer_dppi_channel);      NRFX_ASSERT(status == NRFX_SUCCESS);nrf_timer_subscribe_set(m_sample_timer.p_reg, NRF_TIMER_TASK_START, m_button0_timer_dppi_channel);NRFX_ASSERT(status == NRFX_SUCCESS);
//button2 stop timer and output highstatus = nrfx_dppi_channel_alloc(&m_button1_timer_dppi_channel);NRFX_ASSERT(status == NRFX_SUCCESS);nrf_gpiote_publish_set(NRF_GPIOTE, nrfx_gpiote_in_event_get(INPUT_PIN_1),    m_button1_timer_dppi_channel);nrf_gpiote_subscribe_set(NRF_GPIOTE,nrfx_gpiote_set_task_addr_get(OUTPUT_PIN),m_button1_timer_dppi_channel);      NRFX_ASSERT(status == NRFX_SUCCESS);nrf_timer_subscribe_set(m_sample_timer.p_reg, NRF_TIMER_TASK_STOP, m_button1_timer_dppi_channel);NRFX_ASSERT(status == NRFX_SUCCESS);

3)组(group)的使用代码示例。使用timer,gpiote,dppi输出固定周期的波形。只有在COMPARE2 EVENT发生的时候,将输出电平置高;在COMPARE3 EVENT发生的时候,将输出电平置低。第一次产生COMPARE1 EVENT的时候,触发了timer clear的task, timer重新开始计数,那么COMPARE0 EVENT就不会发生了。COMPARE1 EVENT还触发了group disable task。

那么,下一个COMPARE1 EVENT就不会触发timer clear task了,因为这个channel被disable了。COMPARE1 EVENT发生后, COMPARE0 EVENT会接着发生。在COMPARE0 EVENT产生的中断处理里面,通过group的控制函数,又将channel使能了。那么,COMPARE1 EVENT,又能触发了timer clear task,循环上面的动作。输出波形如下:

  • Timer设置:

#define PERIOD       (20*16000)   //compare0  (duty=25%)#define SHORT_PERIOD (10*16000)   //compare1 (duty=50%)#define OFFSET       1            //compare2#define PULSE_WIDTH  (5*16000)    //compare3/*//2 3 1 2 3 1 0 2 3 1 2 3 1 0  __   __       __   __       __   __       __   __    _| |__| |______| |__| |______| |__| |______| |__| |______  2 3  1 3   1  0 3  1 3   1  0 3  1 3   1  0 3  1 3  1  0       2        2    2        2    2        2    2*/
static void timer_init(void){    nrfx_timer_config_t timer_config = NRFX_TIMER_DEFAULT_CONFIG;    timer_config.frequency = NRF_TIMER_FREQ_125kHz;    timer_config.bit_width = NRF_TIMER_BIT_WIDTH_32;    nrfx_timer_init(&timer, &timer_config, timer_handler);    nrfx_timer_compare(&timer, NRF_TIMER_CC_CHANNEL0, PERIOD, true);    nrf_timer_shorts_enable(timer.p_reg, NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK);    nrfx_timer_compare(&timer, NRF_TIMER_CC_CHANNEL1, SHORT_PERIOD, true);    nrfx_timer_compare(&timer, NRF_TIMER_CC_CHANNEL2, OFFSET, false);    nrfx_timer_compare(&timer, NRF_TIMER_CC_CHANNEL3, OFFSET + PULSE_WIDTH, false);
   IRQ_CONNECT(TIMER0_IRQn, NRFX_TIMER_DEFAULT_CONFIG_IRQ_PRIORITY - 1,        nrfx_timer_0_irq_handler, NULL, 0);
   configure_one_time_clear();    nrfx_timer_enable(&timer);
}
//NRF_TIMER_EVENT_COMPARE1触发中断,每次会发生;//触发task,则是一次不允许,一次允许。触发task的时候,会清timer//timer清了COMPARE0就不会发生了。下次,task不触发时,compare0就会发生,然后使能task触发。
static void timer_handler(nrf_timer_event_t event_type, void *p_context){  if (event_type == NRF_TIMER_EVENT_COMPARE0) {      printk("0");      //group里面只有一个通道的情况下,下面两个函数的功能是等价的。      nrfx_dppi_group_enable(group_ch);      //nrfx_dppi_channel_enable(channel_ch);  }  if (event_type == NRF_TIMER_EVENT_COMPARE1) {      printk("1");  }}
  • DPPI分配组,分配通道,关联通道配置COMPARE1 EVENT触发timer clear,加入组,配置COMPARE1 EVENT触发group disable task。然后使能通道。

static void configure_one_time_clear(void){  nrfx_dppi_group_alloc(&group_ch);  nrfx_dppi_channel_alloc(&channel_ch);  nrf_timer_publish_set(timer.p_reg, NRF_TIMER_EVENT_COMPARE1, channel_ch);  nrf_timer_subscribe_set(timer.p_reg, NRF_TIMER_TASK_CLEAR, channel_ch);  nrfx_dppi_channel_include_in_group(channel_ch, group_ch);
 //影响下次event触发task,把通道disable了。  nrf_dppi_subscribe_set(NRF_DPPIC, nrf_dppi_group_disable_task_get(group_ch), channel_ch);  nrfx_dppi_channel_enable(channel_ch);}
  • DPPI分配通道,配置COMPARE2 EVENT触发output ‘H’,使能通道;DPPI分配通道,配置COMPARE3 EVENT触发output ‘L’,使能通道。

nrfx_gpiote_out_init(OUTPUT_PIN, &out_config);nrfx_gpiote_out_task_enable(OUTPUT_PIN);
uint8_t channel;nrfx_dppi_channel_alloc(&channel);nrf_timer_publish_set(timer.p_reg, NRF_TIMER_EVENT_COMPARE2, channel);nrf_gpiote_subscribe_set(        NRF_GPIOTE,        nrfx_gpiote_set_task_get(OUTPUT_PIN),        channel);nrfx_dppi_channel_enable(channel);
nrfx_dppi_channel_alloc(&channel);nrf_timer_publish_set(timer.p_reg, NRF_TIMER_EVENT_COMPARE3, channel);nrf_gpiote_subscribe_set(        NRF_GPIOTE,        nrfx_gpiote_clr_task_get(OUTPUT_PIN),        channel);nrfx_dppi_channel_enable(channel);

本文相关链接

① 上述完整代码可在百度网盘下载

https://www.nordicsemi.cn/static/misc/ppi&dppi-sample.rar

② nRF52

https://www.nordicsemi.cn/tag/nrf52/

③ nRF53

https://www.nordicsemi.cn/tag/nrf53/

【联系我们】

中文官网:www.nordicsemi.cn

英文官网:www.nordicsemi.com

微信公众号:nordicsemi


【Nordic 开发者论坛】

https://devzone.nordicsemi.com


【销售接洽】

北京分公司: +86 010 8438 2767

上海分公司: +86 21 6330 0620

深圳分公司: +86 755 8322 0147

sales.cn@nordicsemi.no

 点击“阅读原文”进入Nordic半导体中文官网

Nordic半导体 Nordic 半导体开发支持蓝牙智能、ANT+和2.4GHz应用的超低功耗短距无线通信技术,用于物联网 、可穿戴产品、智能家居、玩具等应用。Nordic 提供现成可用的设计框架、世界级文档资料和支持,以加快专业工程师和业余爱好者的开发速度。
评论
  •     IPC-2581是基于ODB++标准、结合PCB行业特点而指定的PCB加工文件规范。    IPC-2581旨在替代CAM350格式,成为PCB加工行业的新的工业规范。    有一些免费软件,可以查看(不可修改)IPC-2581数据文件。这些软件典型用途是工艺校核。    1. Vu2581        出品:Downstream     
    电子知识打边炉 2025-01-22 11:12 81浏览
  • Ubuntu20.04默认情况下为root账号自动登录,本文介绍如何取消root账号自动登录,改为通过输入账号密码登录,使用触觉智能EVB3568鸿蒙开发板演示,搭载瑞芯微RK3568,四核A55处理器,主频2.0Ghz,1T算力NPU;支持OpenHarmony5.0及Linux、Android等操作系统,接口丰富,开发评估快人一步!添加新账号1、使用adduser命令来添加新用户,用户名以industio为例,系统会提示设置密码以及其他信息,您可以根据需要填写或跳过,命令如下:root@id
    Industio_触觉智能 2025-01-17 14:14 125浏览
  • 数字隔离芯片是一种实现电气隔离功能的集成电路,在工业自动化、汽车电子、光伏储能与电力通信等领域的电气系统中发挥着至关重要的作用。其不仅可令高、低压系统之间相互独立,提高低压系统的抗干扰能力,同时还可确保高、低压系统之间的安全交互,使系统稳定工作,并避免操作者遭受来自高压系统的电击伤害。典型数字隔离芯片的简化原理图值得一提的是,数字隔离芯片历经多年发展,其应用范围已十分广泛,凡涉及到在高、低压系统之间进行信号传输的场景中基本都需要应用到此种芯片。那么,电气工程师在进行电路设计时到底该如何评估选择一
    华普微HOPERF 2025-01-20 16:50 76浏览
  • 2024年是很平淡的一年,能保住饭碗就是万幸了,公司业绩不好,跳槽又不敢跳,还有一个原因就是老板对我们这些员工还是很好的,碍于人情也不能在公司困难时去雪上加霜。在工作其间遇到的大问题没有,小问题还是有不少,这里就举一两个来说一下。第一个就是,先看下下面的这个封装,你能猜出它的引脚间距是多少吗?这种排线座比较常规的是0.6mm间距(即排线是0.3mm间距)的,而这个规格也是我们用得最多的,所以我们按惯性思维来看的话,就会认为这个座子就是0.6mm间距的,这样往往就不会去细看规格书了,所以这次的运气
    wuliangu 2025-01-21 00:15 201浏览
  • 高速先生成员--黄刚这不马上就要过年了嘛,高速先生就不打算给大家上难度了,整一篇简单但很实用的文章给大伙瞧瞧好了。相信这个标题一出来,尤其对于PCB设计工程师来说,心就立马凉了半截。他们辛辛苦苦进行PCB的过孔设计,高速先生居然说设计多大的过孔他们不关心!另外估计这时候就跳出很多“挑刺”的粉丝了哈,因为翻看很多以往的文章,高速先生都表达了过孔孔径对高速性能的影响是很大的哦!咋滴,今天居然说孔径不关心了?别,别急哈,听高速先生在这篇文章中娓娓道来。首先还是要对各位设计工程师的设计表示肯定,毕竟像我
    一博科技 2025-01-21 16:17 105浏览
  •  万万没想到!科幻电影中的人形机器人,正在一步步走进我们人类的日常生活中来了。1月17日,乐聚将第100台全尺寸人形机器人交付北汽越野车,再次吹响了人形机器人疯狂进厂打工的号角。无独有尔,银河通用机器人作为一家成立不到两年时间的创业公司,在短短一年多时间内推出革命性的第一代产品Galbot G1,这是一款轮式、双臂、身体可折叠的人形机器人,得到了美团战投、经纬创投、IDG资本等众多投资方的认可。作为一家成立仅仅只有两年多时间的企业,智元机器人也把机器人从梦想带进了现实。2024年8月1
    刘旷 2025-01-21 11:15 521浏览
  • 本文介绍瑞芯微开发板/主板Android配置APK默认开启性能模式方法,开启性能模式后,APK的CPU使用优先级会有所提高。触觉智能RK3562开发板演示,搭载4核A53处理器,主频高达2.0GHz;内置独立1Tops算力NPU,可应用于物联网网关、平板电脑、智能家居、教育电子、工业显示与控制等行业。源码修改修改源码根目录下文件device/rockchip/rk3562/package_performance.xml并添加以下内容,注意"+"号为添加内容,"com.tencent.mm"为AP
    Industio_触觉智能 2025-01-17 14:09 167浏览
  • 临近春节,各方社交及应酬也变得多起来了,甚至一月份就排满了各式约见。有的是关系好的专业朋友的周末“恳谈会”,基本是关于2025年经济预判的话题,以及如何稳定工作等话题;但更多的预约是来自几个客户老板及副总裁们的见面,他们为今年的经济预判与企业发展焦虑而来。在聊天过程中,我发现今年的聊天有个很有意思的“点”,挺多人尤其关心我到底是怎么成长成现在的多领域风格的,还能掌握一些经济趋势的分析能力,到底学过哪些专业、在企业管过哪些具体事情?单单就这个一个月内,我就重复了数次“为什么”,再辅以我上次写的:《
    牛言喵语 2025-01-22 17:10 68浏览
  • 嘿,咱来聊聊RISC-V MCU技术哈。 这RISC-V MCU技术呢,简单来说就是基于一个叫RISC-V的指令集架构做出的微控制器技术。RISC-V这个啊,2010年的时候,是加州大学伯克利分校的研究团队弄出来的,目的就是想搞个新的、开放的指令集架构,能跟上现代计算的需要。到了2015年,专门成立了个RISC-V基金会,让这个架构更标准,也更好地推广开了。这几年啊,这个RISC-V的生态系统发展得可快了,好多公司和机构都加入了RISC-V International,还推出了不少RISC-V
    丙丁先生 2025-01-21 12:10 125浏览
  • 现在为止,我们已经完成了Purple Pi OH主板的串口调试和部分配件的连接,接下来,让我们趁热打铁,完成剩余配件的连接!注:配件连接前请断开主板所有供电,避免敏感电路损坏!1.1 耳机接口主板有一路OTMP 标准四节耳机座J6,具备进行音频输出及录音功能,接入耳机后声音将优先从耳机输出,如下图所示:1.21.2 相机接口MIPI CSI 接口如上图所示,支持OV5648 和OV8858 摄像头模组。接入摄像头模组后,使用系统相机软件打开相机拍照和录像,如下图所示:1.3 以太网接口主板有一路
    Industio_触觉智能 2025-01-20 11:04 159浏览
我要评论
0
点击右上角,分享到朋友圈 我知道啦
请使用浏览器分享功能 我知道啦