Nordic--nrf52832--GPIOTE

 Nordic 的 NRF51 和 NRF52 系列芯片在 GPIO 的基础上引入了任务和事件(GPIOTE)
的概念。GPIOTE 能让我们更方便地去操作 GPIO,同时,他还能有效地减少程序的参与、
降低 CPU 的负担。

nRF52832 寄存器类型

说到 GPIOTE ,就需要先了解一下 nRF52832 的寄存器类型,和一般的单片机有所差别,
nRF52832 的寄存器分为下面的三种类型。

  • Task :任务寄存器,可以由程序或事件触发。
  • Event:事件寄存器,事件可以产生中断或触发任务。
  • Register:普通寄存器,和一般单片机的寄存器一样。

 Task 和 event 使得操作片上外设十分方便简洁,只需进行少量的配置,即可轻松运用各
种外设。同时,Task 和 event 能有效减少 CPU 的占用时间,降低 CPU 的负荷。

 Task 和 Event 更多的是用来和 PPI(可编程外设互连)配合使用,通过 PPI 将某个 Event
和 Task 连接起来,连接后,该 Event 即可触发对应的 Task 执行相应的功能。

  • 示例:实现每隔 1S 翻转一次指示灯的状态。
    一般的做法:配置定时器定时时间为 1S,每秒产生一次中断,在中断服务程序中通过软件操作翻转指示灯的状态。在这个过程中,必须要通过软件操作才能实现。
    通过 Task 和 Event 实现:配置定时器的相关参数,配置 GPIOTE 的 Task 为翻转管脚状态,配置 PPI 的一个通道用于连接定时器的匹配事件和 GPIOTE 的 Task。这样,当定时器产生匹配事件时,会自动触发 GPIOTE 的 Task,在无需任何软件干预的情况下实现指示灯状态的翻转。

GPIOTE (GPIO Task and Events)功能

 nRF52832 的 GPIOTE 共有 8 个通道,每个通道都可以选择一个管脚,选择的管脚可以
配置为 Task mode 或 Event mode。需要注意的是:不能将某个管脚同时分配给多个 GPIOTE
通道,否则会导致无法预料的错误。

GPIOTE 每个通道可以使用的 Task 有 3 个:

  • 设置(Set)
  • 清除(Clear)
  • 切换(Toggle)

GPIOTE 每个通道的事件可以由以下的输入状态产生:

  • 上升边缘(Rising edge)
  • 下降边缘(Falling edge)
  • 任何改变(Any change)

引脚Tasks和Events

 Tasks 和 Events 通过 CONFIGn 寄存器配置,每个 CONFIG[n]寄存器对应一组OUT[n] 任务寄存器和 IN[n]事件寄存器。OUT[n]用于写引脚,IN[n]由引脚状态变化触发。

 当把某个引脚分配给OUT[n]任务或IN[n]事件后,该引脚就只能被GPIOTE模块写操作,
正常的 GPIO 写入无效。

 一旦配置 OUT[n]任务或 IN[n]事件控制某个引脚,那么该管脚的输出值只能通过 GPIOTE 模块操作,使用 GPIO 的寄存器操作会被忽略。

 当 GPIOTE 通道被配置用于操作一个任务引脚时,CONFIG[n]寄存器中的 OUTINIT 决定了该引脚的初始值。可以通过配置 OUTINIT 来设置引脚初始化状态为高电平或是低电平。

 当在同一个 GPIOTE 通道中同时触发了有冲突的任务(即同一个时钟周期内),那么任务按照下表所示的优先级执行。

优先级 任务
1 OUT
2 CLEAR
3 SET

PORT 事件

 GPIOTE 除了 8 个通道外,还包含一个 PORT 事件。PORT 事件由使用 GPIO DETECT 信号的多个引脚触发,PORT 中的任意一个引脚上的上升沿都会触发 PORT 事件。即使外设处于空闲状态,PORT 事件也能使能,此功能不需要任何时钟或其他电源相关的外设。当CPU 和所有外设处于 IDLE 状态时,PORT 事件可以将 CPU 从 WFI 或 WFE 类型休眠中,以及 CPU 空闲模式下唤醒,即在系统 ON 模式下实现最低的功耗。

可以设置一个或多个 GPIO DETECT 用来产生 PORT 事件,PORT 事件可以作为唤醒源,也可以作为中断源产生中断。

GPIOTE 基址:0x40006000

GPIOTE 操作

1、GPIOTE输出

 GPIOTE 输出一般不单独使用,因为单独使用时,操作和普通 GPIO 差不多,同样需要程序来操作他,不同的是普通 GPIO 通过 GPIO 的寄存器操作,GPIOTE 通过任务寄存器触发,单独使用时和普通 GPIO 一样同样需要软件干预,体现不了他的优势。GPIOTE 应用的时候一般和 PPI(可编程外设互联)一起用,通过其他外设的事件来触发 GPIOTE 的任务,如使用定时器比较事件等等,这样,整个过程就可以由硬件自动完成,无需软件干预,从而简化程序的流程、降低 CPU 的负担。

 GPIOTE 输出的操作流程如下图所示,其中初始化 GPIOTE 模块和初始化 GPIOTE 输出引脚是必须要有的,接下来可以选择是否使能该引脚的 GPIOTE 功能,使能之后,只能通过 GPIOTE 任务触发输出,如果不使能 GPIOTE 功能,则通过写 GPIO 寄存器控制其输出。
Nordic--nrf52832--GPIOTE_第1张图片

1. 初始化 GPIOTE 模块

 Nordic 的 SDK 是模块化设计的,使用 GPIOTE 模块时,先要初始化 GPIOTE 模块,初
始化很简单,调用初始化函数 nrf_drv_gpiote_init 即可。

 需要注意的是:GPIOTE 模块在一个应用程序中和很多其他的程序模块共享资源,所以
在一个应用程序中 GPIOTE 模块只能初始化一次

2. 初始化 GPIOTE 输出引脚

 初始化 GPIOTE 输出引脚通过调用 nrf_drv_gpiote_out_init 函数来完成,该函数接收两个输入参数:引脚号和 GPIOTE 输出初始化结构体,引脚号指定将要配置的引脚的编号(0~31),GPIOTE 输出初始化结构体 nrf_drv_gpiote_out_config_t 包含下面的三项内容:

  1. 引脚的初始状态:高电平或是低电平。
    • 高电平:NRF_GPIOTE_INITIAL_VALUE_HIGH
    • 低电平 NRF_GPIOTE_INITIAL_VALUE_LOW
  2. 引脚动作:任务触发后引脚执行的动作。
    • 置位(高电平):NRF_GPIOTE_POLARITY_LOTOHI
    • 清除(低电平):NRF_GPIOTE_POLARITY_HITOLO
    • 翻转:NRF_GPIOTE_POLARITY_TOGGLE
  3. 是否为 GPIOTE 任务引脚:如果设置成 GPIOTE 任务引脚,驱动程序才会去配置前面
    两项(初始状态和引脚动作)并且为该引脚分配 GPIOTE 通道,否则,将该引脚按照普通
    GPIO 处理。需要注意,即使将引脚配置为 GPIOTE 任务引脚,也需要使能该引脚的任
    务触发功能,触发任务对该引脚无效。

3. 使能任务触发

 初始化GPIOTE输出引脚(配置为任务引脚)为指定的引脚分配了GPIOTE通道并且配置了引脚的初始值和动作,但是并没有配置该引脚的模式即没有配置 CONFIG[n].MODE,使能任务触发就是设置 CONFIG[n].MODE = 3,即将其配置为任务模式。

 使能任务触通过调用 nrf_drv_gpiote_out_task_enable 函数实现,只有使能任务触发后,我们才能通过触发 GPIOTE 的任务让引脚执行动作。

4. 触发任务驱动引脚

可以通过下面是三个函数触发 GPIOTE 任务,驱动引脚动作:

  1. nrf_drv_gpiote_out_task_trigger:触发 GPIOTE 的 TASKS_OUT 任务,每触发一次,引
    脚状态翻转一次。
  2. nrf_drv_gpiote_set_task_trigger:触发 GPIOTE 的 TASKS_SET 任务,触发后,引脚输出
    高电平。
  3. nrf_drv_gpiote_clr_task_trigger:触发 GPIOTE 的 TASKS_CLR 任务,触发后,引脚输出
    低电平。
#define LED_1 17
/**********************************************************************
* 描 述 : main 函数
* 入 参 : 无
* 返回值 : 无
*********************************************************************/
int main(void)
{
	ret_code_t err_code;
	//初始化 GPIOTE 程序模块
	err_code = nrf_drv_gpiote_init();
	APP_ERROR_CHECK(err_code);
	//定义 GPIOTE 输出初始化结构体,并对其成员变量赋值
	nrf_drv_gpiote_out_config_t config = GPIOTE_CONFIG_OUT_TASK_TOGGLE(true);
	//初始化 GPIOTE 输出引脚
	err_code = nrf_drv_gpiote_out_init(LED_1, &config);
	APP_ERROR_CHECK(err_code);
	//使能引脚 LED_1(P0.17)所在 GPIOTE 通道的任务触发
	nrf_drv_gpiote_out_task_enable(LED_1);
	while (true)
	{
		//任务触发驱动引脚 P0.17 状态翻转,即指示灯 D1 翻转状态
		nrf_drv_gpiote_out_task_trigger(LED_1);
		//任务触发驱动引脚 P0.17 输出高电平,即指示灯 D1 熄灭
		//nrf_drv_gpiote_clr_task_trigger(LED_1);
		//任务触发驱动引脚 P0.17 输出低电平,即指示灯 D1 电亮
		//nrf_drv_gpiote_set_task_trigger(LED_1);
		nrf_delay_ms(150);
	}
}

2、GPIOTE输入

 GPIOTE 输入的操作流程如下图所示,包含初始化 GPIOTE 程序模块、初始化 GPIOTE
输入引脚、使能事件模式。

Nordic--nrf52832--GPIOTE_第2张图片

1. 初始化 GPIOTE

 和 GPIOTE 输入时一样,调用初始化函数 nrf_drv_gpiote_init 即可。

2. 初始化 GPIOTE 输 输 入 引脚

 初始化 GPIOTE 输入引脚通过调用 nrf_drv_gpiote_in_init 函数来完成,该函数接收三个
输入参数:引脚号、GPIOTE 输入初始化结构体和事件句柄,相对于 GPIOTE 输出引脚的初
始化,函数参数多了一个事件句柄,当 GPIOTE 检测到引脚电平变化后,会产生事件,这
时会自动调用这个注册的事件句柄来处理事件。

 引 脚 号 指 定 将 要 配 置 的 引 脚 的 编 号 (0~31) , GPIOTE 输 入 初 始 化 结 构 体
nrf_drv_gpiote_in_config_t 包含下面的 4 项内容:

  1. Sense:配置引脚的 Sense 功能,可配置为下面。
    • 高电平到低电平的变化产生事件:NRF_GPIOTE_POLARITY_HITOLO
    • 低电平到高电平的变化产生事件:NRF_GPIOTE_POLARITY_LOTOHI
    • 任意电平变化产生事件:NRF_GPIOTE_POLARITY_TOGGLE
  2. is_watcher:是否连接输入缓冲器,设置为“true”表示连接输入缓冲器。
  3. pull:是否开启引脚的上拉电阻,设置为“true”表示打开上拉。
  4. hi_accuracy:是否为高精度模式,设置为“true”表示使用高精度模式。

3. 使能 事件模式

 初始化 GPIOTE 输入引脚时为指定的引脚分配了 GPIOTE 通道,但是并没有配置该引脚的模式即没有配置 CONFIG[n].MODE,使能事件模式就是设置 CONFIG[n].MODE = 1,即将其配置为事件模式,当其检测到引脚电平变化时(初始化 GPIOTE 输入引脚时 Sense 项配置了哪种变化可以产生事件)即产生事件。

#define LED_1 17
#define BUTTON_0 13
void in_pin_handler(nrf_drv_gpiote_pin_t pin, nrf_gpiote_polarity_t action)
{
nrf_drv_gpiote_out_toggle(LED_1);
}
/**********************************************************************
* 描 述 : main 函数
* 入 参 : 无
* 返回值 : 无
**********************************************************************/
int main(void)
{
	ret_code_t err_code;
	//初始化 GPIOTE 程序模块
	err_code = nrf_drv_gpiote_init();
	APP_ERROR_CHECK(err_code);
	//定义 GPIOTE 输出初始化结构体,并对其成员变量赋值
	nrf_drv_gpiote_out_config_t out_config =
	GPIOTE_CONFIG_OUT_SIMPLE(true);
	//初始化 GPIOTE 输出引脚
	err_code = nrf_drv_gpiote_out_init(LED_1, &out_config);
	APP_ERROR_CHECK(err_code);
	
	//高电平到低电平变化产生事件
	nrf_drv_gpiote_in_config_t in_config = GPIOTE_CONFIG_IN_SENSE_HITOLO(true);
	
	//低电平到高电平变化产生事件
	//nrf_drv_gpiote_in_config_t in_config = GPIOTE_CONFIG_IN_SENSE_LOTOHI(true);
	
	//任意电平变化产生事件
	//nrf_drv_gpiote_in_config_t in_config = GPIOTE_CONFIG_IN_SENSE_TOGGLE(true);
	
	//开启 P0.13 引脚的上拉电阻
	in_config.pull = NRF_GPIO_PIN_PULLUP;
	//配置该引脚为 GPIOTE 输入
	err_code = nrf_drv_gpiote_in_init(BUTTON_0, &in_config, in_pin_handler);
	APP_ERROR_CHECK(err_code);
	//使能该引脚所在 GPIOTE 通道的事件模式
	nrf_drv_gpiote_in_event_enable(BUTTON_0, true);
	while (true)
	{
	}
}
Sense 配置电平变化产生事件
//高电平到低电平变化产生事件
nrf_drv_gpiote_in_config_t in_config = GPIOTE_CONFIG_IN_SENSE_HITOLO(true);

//低电平到高电平变化产生事件
nrf_drv_gpiote_in_config_t in_config = GPIOTE_CONFIG_IN_SENSE_LOTOHI(true);

//任意电平变化产生事件
nrf_drv_gpiote_in_config_t in_config = GPIOTE_CONFIG_IN_SENSE_TOGGLE(true);

3、GPIOTE唤醒系统

你可能感兴趣的:(C,Nordic,nrf52832学习应用之路)