NRF52840学习历程(五)PPI模块

时间在2021年2月2日,寒假放假在家好好学一学nRF52840

 

这几天去医院看病了,结果白跑,不过花钱买个心安也行

还有看了两三天的小说,美滋滋

 

开发板:初雪的100出头那块 NRF52840 EVAL KIT

下载工具:JINLK V11(最好是JLINK V9以上 也有人用JLINK OB也行,其他的下载器诸如STLINK,DAP不建议用)

版本号: KEIL5编程环境,CMSIS为5.3.0, NRF52840的CMSIS为8.35.0

参考资料: NRF52840-Eval-Kit-Schematic.pdf(原理图)

nRF5_SDK_17.0.2_d674dde(官方例程)

扫描二维码关注公众号,回复: 12684095 查看本文章

nRF5_SDK_17.0.0_offline_doc(官方文档)

nRF52840_PS_v1.1.pdf(官方数据手册)

 

实现功能:

 

1.PPI 介绍

  1. PPI与DMA差不多,不需要CPU干涉进行数据交换,搬完数据告诉CPU一声(产生中断)
  2. PPI需要设置两端才能用
  3. PPI的两端一端连接的是事件端点(EEP),一端连接的是任务端点(TEP)。因此 PPI 可以通过一个外设上发生的事件自动的触发另一个外设上的任务。比如定时器触发LED进行翻转
  4. PPI 一共是 32 个通道,编号为 0~31,其中通道 20~31 通道,一共12 个为固定通道,也称为预编程通道;通道 0~19 通道,一共 20 个为可编程通道,可编程通道可以通过程序配置事件终点和任务终点。

图为固定通道,不能占用,功能已被固定(定时器,2.4G,RTC为32.768K晶振的实时计数器,不是实时时钟)

 

2.fork  从任务机制:(TEP终点,比如触发作为翻转LED的)

fork 机制也称为从任务机制。每个任务终点TEP 都实现了一个 fork 机制,可以在触发任务终点TEP 中指定的任务的同时触发第二个任务。

 

3.Group  分组机制:

PPI 通道可以进行分组,多个 PPI 通道可以分为一组,那么该组内的 PPI 通道就可以统一进行管理,同时打开或者关闭 group 内所有的 PPI 通道。

 

 

 

下面为GPIOTE中断PPI应用:

PPI 作为触发通道,两端分别连接任务和事件,通过任务来触发事件的发生,可以不通过 CPU进行处理,大大的节省了系统资源。

 

添加驱动文件

大概在..\..\..\..\..\..\integration\nrfx\legacy\nrf_drv_ppi.c

 

在移植PPI的SDK_CONFIG

 

添加头文件调用PPI

#include "nrf_drv_ppi.h"

按键配置代码: (输入事件)

	nrf_drv_gpiote_in_config_t key_ex_config ; //按键中断配置用
	key_ex_config.hi_accuracy=true;  //true使用输入事件
	key_ex_config.pull = NRF_GPIO_PIN_PULLUP ; //上啦
	key_ex_config.sense = NRF_GPIOTE_POLARITY_TOGGLE ;//下降沿

	nrf_drv_gpiote_in_init(KEY0, &key_ex_config, NULL); //无中断函数
	nrf_drv_gpiote_in_event_enable(KEY0, true);//配置输入事件使能

LED配置代码:  (输出任务)

	nrf_drv_gpiote_init();//启动GPIOTE时钟,可以这么说
	nrf_drv_gpiote_out_config_t out_config ; //输出任务
	out_config.init_state = NRF_GPIOTE_INITIAL_VALUE_HIGH  ;// LED状态从1->0
	out_config.task_pin = true; // 引脚由GPIOTE控制
	out_config.action = NRF_GPIOTE_POLARITY_TOGGLE ;
	nrf_drv_gpiote_out_init(LED3, &out_config);//绑定输出端口
    nrf_drv_gpiote_out_task_enable(LED3); //使能LED任务

下面初始化PPI模块: 绑定事件输入和任务输出

来一个PPI通道配置变量

nrf_ppi_channel_t my_ppi_channel; //我的PPI通道

然后配置PPI

	nrf_drv_ppi_init();//开启PPI时钟
	nrfx_ppi_channel_alloc(&my_ppi_channel);//分配一个PPI的通道
	nrfx_ppi_channel_assign(my_ppi_channel, //绑定PPI事件输入地址, 任务输出地址
                                     nrfx_gpiote_in_event_addr_get(KEY0),
                                     nrfx_gpiote_out_task_addr_get(LED3));
	nrfx_ppi_channel_enable(my_ppi_channel);//使能PPI通道


 

 

完整代码

#include <stdbool.h>
#include <stdint.h>
#include "nrf_delay.h"
#include "nrf_gpio.h"
#include "nrf_drv_gpiote.h"

#include "nrf_uart.h"
#include "app_uart.h"
#include "nrf_drv_timer.h"

#include "nrf_drv_ppi.h"
#include "nrfx_ppi.h"

uint32_t LED0,LED1,LED2,LED3;
uint32_t KEY0,KEY1,KEY2,KEY3;

nrf_ppi_channel_t my_ppi_channel; //我的PPI通道


int main(void)
{

	LED0 =  NRF_GPIO_PIN_MAP(0,13);
	LED1 =  NRF_GPIO_PIN_MAP(0,14);
	LED2 =  NRF_GPIO_PIN_MAP(1,9);
	LED3 =  NRF_GPIO_PIN_MAP(0,16);

	KEY0 =  NRF_GPIO_PIN_MAP(0,11);
	KEY1 =  NRF_GPIO_PIN_MAP(0,24);
	KEY2 =  NRF_GPIO_PIN_MAP(0,20);
	KEY3 =  NRF_GPIO_PIN_MAP(0,17);

//	nrf_gpio_cfg_output(LED0);
//	nrf_gpio_cfg_output(LED1);
//	nrf_gpio_cfg_output(LED2);
//	nrf_gpio_cfg_output(LED3);

//	nrf_gpio_pin_set(LED0);
//	nrf_gpio_pin_set(LED1);
//	nrf_gpio_pin_set(LED2);
//	nrf_gpio_pin_set(LED3);
//	
//	nrf_gpio_cfg_input(KEY0,NRF_GPIO_PIN_PULLUP );
//	nrf_gpio_cfg_input(KEY1,NRF_GPIO_PIN_PULLUP );
//	nrf_gpio_cfg_input(KEY2,NRF_GPIO_PIN_PULLUP );
//	nrf_gpio_cfg_input(KEY3,NRF_GPIO_PIN_PULLUP );
	
	nrf_drv_gpiote_init();//启动GPIOTE时钟,可以这么说
	
	nrf_drv_gpiote_out_config_t out_config ; //输出任务
	out_config.init_state = NRF_GPIOTE_INITIAL_VALUE_HIGH  ;// LED状态从1->0
	out_config.task_pin = true; // 引脚由GPIOTE控制
	out_config.action = NRF_GPIOTE_POLARITY_TOGGLE ;
	nrf_drv_gpiote_out_init(LED3, &out_config);//绑定输出端口
    nrf_drv_gpiote_out_task_enable(LED3); //使能LED任务


	
	nrf_drv_gpiote_in_config_t key_ex_config ; //按键中断配置用
	key_ex_config.hi_accuracy=true;  //true使用输入事件
	key_ex_config.pull = NRF_GPIO_PIN_PULLUP ; //上啦
	key_ex_config.sense = NRF_GPIOTE_POLARITY_TOGGLE ;//下降沿

	nrf_drv_gpiote_in_init(KEY0, &key_ex_config, NULL); //无中断函数
	nrf_drv_gpiote_in_event_enable(KEY0, true);//配置输入事件使能


//	nrf_drv_gpiote_in_init(KEY1, &key_ex_config, KEY_Interrupt);
//	nrf_drv_gpiote_in_init(KEY2, &key_ex_config, KEY_Interrupt);
//	nrf_drv_gpiote_in_init(KEY3, &key_ex_config, KEY_Interrupt);


//	nrf_drv_gpiote_in_event_enable(KEY1, true);//启动KEY1中断
//	nrf_drv_gpiote_in_event_enable(KEY2, true);//启动KEY2中断
//	nrf_drv_gpiote_in_event_enable(KEY3, true);//启动KEY3中断


	
	nrf_drv_ppi_init();//开启PPI时钟
	
	nrfx_ppi_channel_alloc(&my_ppi_channel);//分配一个PPI的通道

	nrfx_ppi_channel_assign(my_ppi_channel, //绑定PPI事件输入地址, 任务输出地址
							 nrfx_gpiote_in_event_addr_get(KEY0),
							 nrfx_gpiote_out_task_addr_get(LED3));

	nrfx_ppi_channel_enable(my_ppi_channel);//使能PPI通道


	while(1)
	{				

	}
	
}

 

后面看了一下 fork 和 group 都没怎么用到过, 所以就不学了

猜你喜欢

转载自blog.csdn.net/jwdeng1995/article/details/113541110