前一篇分析了前十个基础实验的代码,从这里开始分析后十个~

一、PPI原理:

PPI(Programmable Peripheral Interconnect),中文翻译为可编程外设互连。

在nRF51822 内部设置了PPI 方式,可以通过任务和事件让不同外设之间进行互连,而不需要CPU 进行参与。

PPI 通过通道让任务和事件连接在一起。PPI 通道由两个端点组成:

  • 任务端点:Task End-Point (TEP)。
  • 事件端点:Event End-Point (EEP)。

所谓的互联就是将任务端点写入需要连接的任务寄存器地址,事件端点写入需要连接事件寄存器地址,之后,使能该PPI 通道,即实现了任务和事件的互联。

可以通过如下两种方式使能和关闭PPI 通道:

  • 1) 通过独立设置CHEN,CHENSET 和CHENCLR 寄存器。
  • 2) 通过PPI 通道组的使能和关闭任务。使用这种方式,在触发任务之前,需要先配置好哪些PPI 通道属于哪个组。

二、运行逻辑:

实验中,用到了3 个定时器:Timer 0、Timer 1 和Timer 2。

1) Timer 0 配置为计数器,在主循环中每100ms 被触发一次,并通过串口打印出计数值。
2) Timer 1 每个偶数秒(2、4、6、8……)产生一次比较匹配事件,该事件通过PPI通道0 和Timer 0 的STOP Task 互联,互联后通过该事件触发Timer 0 的STOP Task。
3) Timer 2 每个奇数秒(1、3、5、7……)产生一次比较匹配事件,该事件通过PPI通道1 和Timer 0 的START Task 互联,互联后通过该事件触发Timer 0 的START Task。

实验原理框图如图1 所示:

三、核心代码分析

系统运行后,在循环中Timer 0 计数器的计数值每100ms 增加一次,在偶数秒时,Timer2 产生比较匹配事件,通过PPI 触发Timer 0 的STOP Task,Timer 0 停止计数。此时,尽管主循环中每隔100ms 触发一次Timer 0 计数,但是由于Timer 0 已经停止,所以,计数值不会增加。每个奇数秒,Timer2 产生比较匹配事件,通过PPI 触发Timer 0 的START Task,Timer 0 恢复计数。

main函数部分:

 int main(void)
{
timer0_init(); // Timer used to blink the LEDs.
timer1_init(); // Timer to generate events on even number of seconds.
timer2_init(); // Timer to generate events on odd number of seconds.
ppi_init(); // PPI to redirect the event to timer start/stop tasks. 串口初始化(略) // Enabling constant latency as indicated by PAN 11 "HFCLK: Base current with HFCLK
// running is too high" found at Product Anomaly document found at
// https://www.nordicsemi.com/eng/Products/Bluetooth-R-low-energy/nRF51822/#Downloads
//
// @note This example does not go to low power mode therefore constant latency is not needed.
// However this setting will ensure correct behaviour when routing TIMER events through
// PPI (shown in this example) and low power mode simultaneously.
NRF_POWER->TASKS_CONSTLAT = ; // Start clock.
nrf_drv_timer_enable(&timer0);
nrf_drv_timer_enable(&timer1);
nrf_drv_timer_enable(&timer2); // Loop and increment the timer count value and capture value into LEDs. @note counter is only incremented between TASK_START and TASK_STOP.
while (true)
{ printf("Current cout: %d\r\n", (int)nrf_drv_timer_capture(&timer0,NRF_TIMER_CC_CHANNEL0)); /* increment the counter */
nrf_drv_timer_increment(&timer0); nrf_delay_ms();
}
}

定时器初始化部分:

 // Timer even handler. Not used since timer is used only for PPI.
void timer_event_handler(nrf_timer_event_t event_type, void * p_context){} /** @brief Function for Timer 0 initialization, which will be started and stopped by timer1 and timer2 using PPI.
*/
static void timer0_init(void)
{
ret_code_t err_code = nrf_drv_timer_init(&timer0, NULL, timer_event_handler);
APP_ERROR_CHECK(err_code);
} /** @brief Function for Timer 1 initialization.
* @details Initializes Timer 1 peripheral, creates event and interrupt every 2 seconds,
* by configuring CC[0] to timer overflow value, we create events at even number of seconds
* for example, events are created at 2,4,6 ... seconds. This event can be used to stop Timer 0
* with Timer1->Event_Compare[0] triggering Timer 0 TASK_STOP through PPI.
*/
static void timer1_init(void)
{
// Configure Timer 1 to overflow every 2 seconds. Check TIMER1 configuration for details
// The overflow occurs every 0xFFFF/(SysClk/2^PRESCALER).
// = 65535/31250 = 2.097 sec
ret_code_t err_code = nrf_drv_timer_init(&timer1, NULL, timer_event_handler);
APP_ERROR_CHECK(err_code); nrf_drv_timer_extended_compare(&timer1, NRF_TIMER_CC_CHANNEL0, 0xFFFFUL, NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK, false);//比较模式,Timer 1 每个偶数秒(2、4、6、8……)产生一次比较匹配事件,该事件通过PPI通道0 和Timer 0 的STOP Task 互联,互联后通过该事件触发Timer 0 的STOP Task。
} /** @brief Function for Timer 2 initialization.
* @details Initializes Timer 2 peripheral, creates event and interrupt every 2 seconds
* by configuring CC[0] to half of timer overflow value. Events are created at odd number of seconds.
* For example, events are created at 1,3,5,... seconds. This event can be used to start Timer 0
* with Timer2->Event_Compare[0] triggering Timer 0 TASK_START through PPI.
*/
static void timer2_init(void)
{
// Generate interrupt/event when half of time before the timer overflows has past, that is at 1,3,5,7... seconds from start.
// Check TIMER1 configuration for details
// now the overflow occurs every 0xFFFF/(SysClk/2^PRESCALER)
// = 65535/31250 = 2.097 sec */
ret_code_t err_code = nrf_drv_timer_init(&timer2, NULL, timer_event_handler);
APP_ERROR_CHECK(err_code); nrf_drv_timer_extended_compare(&timer2, NRF_TIMER_CC_CHANNEL0, 0x7FFFUL, NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK, false);//Timer 2 每个奇数秒(1、3、5、7……)产生一次比较匹配事件,该事件通过PPI通道1 和Timer 0 的START Task 互联,互联后通过该事件触发Timer 0 的START Task。
}

PPI连接事件部分:

 /** @brief Function for initializing the PPI peripheral.
*/
static void ppi_init(void)
{
uint32_t err_code = NRF_SUCCESS; err_code = nrf_drv_ppi_init();
APP_ERROR_CHECK(err_code); // Configure 1st available PPI channel to stop TIMER0 counter on TIMER1 COMPARE[0] match, which is every even number of seconds.
err_code = nrf_drv_ppi_channel_alloc(&ppi_channel1);
APP_ERROR_CHECK(err_code);
13 err_code = nrf_drv_ppi_channel_assign(ppi_channel1,//PPI连接事件
14 nrf_drv_timer_event_address_get(&timer1, NRF_TIMER_EVENT_COMPARE0),
15 nrf_drv_timer_task_address_get(&timer0, NRF_TIMER_TASK_STOP));
APP_ERROR_CHECK(err_code); // Configure 2nd available PPI channel to start timer0 counter at TIMER2 COMPARE[0] match, which is every odd number of seconds.
err_code = nrf_drv_ppi_channel_alloc(&ppi_channel2);
APP_ERROR_CHECK(err_code);
21 err_code = nrf_drv_ppi_channel_assign(ppi_channel2,
22 nrf_drv_timer_event_address_get(&timer2, NRF_TIMER_EVENT_COMPARE0),
23 nrf_drv_timer_task_address_get(&timer0, NRF_TIMER_TASK_START));
APP_ERROR_CHECK(err_code); // Enable both configured PPI channels
err_code = nrf_drv_ppi_channel_enable(ppi_channel1);
APP_ERROR_CHECK(err_code);
err_code = nrf_drv_ppi_channel_enable(ppi_channel2);
APP_ERROR_CHECK(err_code);
}

@beautifulzzzz - 物联网&普适计算实践者
e-mail:beautifulzzzz@qq.com 
i-blog:blog.beautifulzzzz.com

[nRF51822] 8、基础实验代码解析大全 · 实验11 - PPI的更多相关文章

  1. [nRF51822] 12、基础实验代码解析大全 · 实验19 - PWM

    一.PWM概述: PWM(Pulse Width Modulation):脉冲宽度调制技术,通过对一系列脉冲的宽度进行调制,来等效地获得所需要波形. PWM 的几个基本概念: 1) 占空比:占空比是指 ...

  2. [nRF51822] 11、基础实验代码解析大全 · 实验16 - 内部FLASH读写

     一.实验内容: 通过串口发送单个字符到NRF51822,NRF51822 接收到字符后将其写入到FLASH 的最后一页,之后将其读出并通过串口打印出数据. 二.nRF51822芯片内部flash知识 ...

  3. [nRF51822] 10、基础实验代码解析大全 · 实验15 - RTC

    一.实验内容: 配置NRF51822 的RTC0 的TICK 频率为8Hz,COMPARE0 匹配事件触发周期为3 秒,并使能了TICK 和COMPARE0 中断. TICK 中断中驱动指示灯D1 翻 ...

  4. [nRF51822] 9、基础实验代码解析大全 · 实验12 - ADC

    一.本实验ADC 配置 分辨率:10 位. 输入通道:5,即使用输入通道AIN5 检测电位器的电压. ADC 基准电压:1.2V. 二.NRF51822 ADC 管脚分布 NRF51822 的ADC ...

  5. [nRF51822] 7、基础实验代码解析大全(前十)

    实验01 - GPIO输出控制LED 引脚输出配置:nrf_gpio_cfg_output(LED_1); 引脚输出置高:nrf_gpio_pin_set(LED_1); 引脚电平转换:nrf_gpi ...

  6. 基础Gan代码解析

    initializer总结: #f.constant_initializer(value) 将变量初始化为给定的常量,初始化一切所提供的值. #tf.random_normal_initializer ...

  7. MYSQL常见出错mysql_errno()代码解析

    如题,今天遇到怎么一个问题, 在理论上代码是不会有问题的,但是还是报了如上的错误,把sql打印出來放到DB中却可以正常执行.真是郁闷,在百度里面 渡 了很久没有相关的解释,到时找到几个没有人回复的 & ...

  8. 【原创】大数据基础之Spark(5)Shuffle实现原理及代码解析

    一 简介 Shuffle,简而言之,就是对数据进行重新分区,其中会涉及大量的网络io和磁盘io,为什么需要shuffle,以词频统计reduceByKey过程为例, serverA:partition ...

  9. 【原创】大数据基础之Spark(4)RDD原理及代码解析

    一 简介 spark核心是RDD,官方文档地址:https://spark.apache.org/docs/latest/rdd-programming-guide.html#resilient-di ...

随机推荐

  1. mysql忘记root密码怎么办?

    有时候忘记mysql的root密码了,怎么办? 这个时候,我们可以修改my.cnf,添加以不检查权限的方式启动,再修改root,最后重启mysql数据库. (1)service mysql stop ...

  2. Spring MVC类型转换

    类型转换器引入 为什么页面上输入"12",可以赋值给Handler方法对应的参数?这是因为框架内部帮我们做了类型转换的工作.将String转换成int 但默认类型转换器并不是可以将 ...

  3. Esri的开源JS项目杂谈

    一提到Esri大家首先想到的是庞大的ArcGIS产品大家族,其产品包含从桌面端,到服务器/云端,再到web/移动端.作为一名极客,不聊开源逼格似乎上不去啊.其实,Esri作为一个开放的平台,不仅有稳定 ...

  4. jquery的animate({})动画整理

    在网页制作的过程中少不了用到各种动画,形式多种多样,flash,css,js,canvas,等等都能实现,对于其优劣和效果只能说各有千秋. 什么是动画效果,其实网页中的渐变效果就是一种很基础的动画,动 ...

  5. Matlab中一些函数的区别

    1.fix, floor,ceil,round   都是对x取整,但取整方向不同.   fix(x):向0取整(也可以理解为向中间取整)   floor(x):向左取整(从名字看,地板,表示下面) c ...

  6. asp.net(C#)读取文件夹和子文件夹下所有文件,绑定到GRIDVIEW并排序 .

    Asp部分: <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="MyFiles ...

  7. 【转】CentOS上部署PPTP和L2TP over IPSec简要笔记

    PPTP部署 安装 PPTP 需要 MPPE 和较高版本的 ppp ( > 2.4.3 ) 支持,不过 CentOS 5.0/RHEL 5 的 2.6.18 内核已经集成了 MPPE 和高版本的 ...

  8. java中的反射简单实例

    package club.reflection.entity.User; /** * 实体类 * */ public class User { public String name; private ...

  9. R语言内存管理

    http://www.cnblogs.com/cloudtj/articles/5478281.html

  10. 关于2016.12.12——T1的反思:凸包的意义与应用

    2016.12.12 T1 给n个圆,保证圆圆相离,求将圆围起来的最小周长.n<=100 就像上图.考场上,我就想用切线的角度来做凸包.以圆心x,y排序,像点凸包一样,不过用两圆之间的下切线角度 ...