时间在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(官方例程)
nRF5_SDK_17.0.0_offline_doc(官方文档)
nRF52840_PS_v1.1.pdf(官方数据手册)
实现功能:
1.PPI 介绍
- PPI与DMA差不多,不需要CPU干涉进行数据交换,搬完数据告诉CPU一声(产生中断)
- PPI需要设置两端才能用
- PPI的两端一端连接的是事件端点(EEP),一端连接的是任务端点(TEP)。因此 PPI 可以通过一个外设上发生的事件自动的触发另一个外设上的任务。比如定时器触发LED进行翻转
- 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 都没怎么用到过, 所以就不学了