RP2040 C SDK GPIO和IRQ 唤醒功能使用

RP2040 C SDK GPIO和中断功能使用


📑RP2040 中断功能简介

Each core is equipped with a standard ARM Nested Vectored Interrupt Controller (NVIC) which has 32 interrupt inputs.
Each NVIC has the same interrupts routed to it, with the exception of the GPIO interrupts: there is one GPIO interrupt per bank, per core. These are completely independent, so e.g. core 0 can be interrupted by GPIO 0 in bank 0, and core 1 by GPIO 1 in the same bank.RP2040
由于是双核,每个核心都配备了一个标准的ARM嵌套的向量中断控制器(NVIC),它有32个中断输入。每个NVIC都有相同的中断路由到它,除了GPIO中断:每个库,每个核心都有一个GPIO中断。这些都是完全独立的,例如,核心0可以被bank0中的GPIO 0中断,而核心1可以被同一银行中的GPIO 1中断。
On RP2040, only the lower 26 IRQ signals are connected on the NVIC, and IRQs 26 to 31 are tied to zero (never firing).
The core can still be forced to enter the relevant interrupt handler by writing bits 26 to 31 in the NVIC ISPR register.

  • 中断号:
    在这里插入图片描述

📗GPIO功能

Pads

Each GPIO is connected to the off-chip world via a “pad”. Pads are the electrical interface between the chip’s internal
logic and external circuitry. They translate signal voltage levels, support higher currents and offer some protection
against electrostatic discharge (ESD) events. Pad electrical behaviour can be adjusted to meet the requirements of the
external circuitry. The following adjustments are available:
• Output drive strength can be set to 2mA, 4mA, 8mA or 12mA
• Output slew rate can be set to slow or fast
• Input hysteresis (schmitt trigger mode) can be enabled
• A pull-up or pull-down can be enabled, to set the output signal level when the output driver is disabled
• The input buffer can be disabled, to reduce current consumption when the pad is unused, unconnected or
connected to an analogue signal.
在这里插入图片描述

  • 📜 GPIO引脚功能配置,枚举类型:
enum gpio_function {GPIO_FUNC_XIP = 0,GPIO_FUNC_SPI = 1,GPIO_FUNC_UART = 2,GPIO_FUNC_I2C = 3,GPIO_FUNC_PWM = 4,GPIO_FUNC_SIO = 5,GPIO_FUNC_PIO0 = 6,GPIO_FUNC_PIO1 = 7,GPIO_FUNC_GPCK = 8,GPIO_FUNC_USB = 9,GPIO_FUNC_NULL = 0x1f,
};

作为外部中断使用,gpio引脚功能配置GPIO_FUNC_SIO

  • 🌿gpio功能配置

void gpio_set_function(	uint 	gpio,enum gpio_function 	fn )	
  • 🌿gpio输入输出方式,可以配置为输入模式和输出模式。
static inline void gpio_set_dir(uint gpio, bool out)
  • 🌿gpio状态,可以配置为上拉、下拉,上下拉都使能。
void gpio_set_pulls(uint gpio, bool up, bool down);
  • 🌿gpio输出模式下,可以配置速度:慢和快。电平变化的斜率(压摆率)

void gpio_set_slew_rate	(	uint 	gpio,enum gpio_slew_rate 	slew )	
enum gpio_slew_rate {GPIO_SLEW_RATE_SLOW = 0,  ///< Slew rate limiting enabledGPIO_SLEW_RATE_FAST = 1   ///< Slew rate limiting disabled
};
  • 🌿gpio对外驱动能力,可配置驱动电流大小:
void gpio_set_drive_strength(uint gpio, enum gpio_drive_strength drive) 
/*! \brief Drive strength levels for GPIO outputs*  \ingroup hardware_gpio** Drive strength levels for GPIO outputs.* \sa gpio_set_drive_strength*/
enum gpio_drive_strength {GPIO_DRIVE_STRENGTH_2MA = 0, ///< 2 mA nominal drive strengthGPIO_DRIVE_STRENGTH_4MA = 1, ///< 4 mA nominal drive strengthGPIO_DRIVE_STRENGTH_8MA = 2, ///< 8 mA nominal drive strengthGPIO_DRIVE_STRENGTH_12MA = 3 ///< 12 mA nominal drive strength
};
blink点灯程序
#include "pico/stdlib.h"int main() {
#ifndef PICO_DEFAULT_LED_PIN
#warning blink example requires a board with a regular LED
#elseconst uint LED_PIN = PICO_DEFAULT_LED_PIN;gpio_init(LED_PIN);//gpio_set_dir(LED_PIN, GPIO_OUT);while (true) {gpio_put(LED_PIN, 1);sleep_ms(250);gpio_put(LED_PIN, 0);sleep_ms(250);}
#endif
}
  • 🌿gpio初始化:void gpio_init(uint gpio)
void gpio_init(uint gpio) {gpio_set_dir(gpio, GPIO_IN);//输入模式gpio_put(gpio, 0);//设置为低电平gpio_set_function(gpio, GPIO_FUNC_SIO);//SIO模式
}
  • 多个gpio初始化操作:void gpio_init_mask(uint gpio_mask)
  • gpio位操作函数:
static inline void gpio_put(uint gpio, bool value);
  • 多个gpio位操作 static inline void gpio_put_masked(uint32_t mask, uint32_t value)
gpio_set_mask(1ul << gpio);//置位
sio_hw->gpio_set = 1ul << gpio;//原子操作
gpio_clr_mask(1ul << gpio);//清零
sio_hw->gpio_clr = 1ul << gpio;//原子操作
gpio_xor_mask(1ul << BUILTIN_LED); // Toggle the LED
sio_hw->gpio_togl = 1ul << gpio;//状态翻转

从上面的函数可以看出,SDK给出了不同封装层的gpio操作方式。

📘GPIO 中断

GPIO中断函数介绍
  • void gpio_set_irq_enabled_with_callback(uint gpio, uint32_t events, bool enabled, gpio_irq_callback_t callback)
  • 第一个形参,引脚号
  • 第二个形参事件可以是设定为下面的一种或多种信号作为触发事件:
enum gpio_irq_level {GPIO_IRQ_LEVEL_LOW = 0x1u,GPIO_IRQ_LEVEL_HIGH = 0x2u,GPIO_IRQ_EDGE_FALL = 0x4u,GPIO_IRQ_EDGE_RISE = 0x8u,
};
  • 形参三,是irq使能:irq_set_enabled(IO_IRQ_BANK0, true);
  • 形参四,是要执行的回调函数,✨需要注意:该回调函数可以是默认带2个形参的typedef void (*gpio_irq_callback_t)(uint gpio, uint32_t event_mask);这2个形参是gpio中断发生时,传递过来的返回值,记录了gpio中断发生的引脚和触发响应事件,如果传递过来的形参,用不到的话,自己写也可以不带任何形参作为回调函数填进去。形参不可以是void类型,如果是void类型那么就相当于带了一个形参,无法通过编译语法✨

👉该gpio中断配置函数的好处就是,在发生gpio中断事件后,不需要手动再去清除中断事件标志位。类似的函数还有 gpio_set_irq_callback;另外该gpio中断配置函数的好处就是,会自动使能gpio中断配置函数 irq_set_enabled(IO_IRQ_BANK0, true);(具体看函数方法实现)

  • static inline void gpio_add_raw_irq_handler(uint gpio, irq_handler_t handler) :gpio中断回调,在发生gpio中断事件后,需要手动清除标志事件。
  • 形参一,配置gpio引脚
  • 形参二,回调函数,typedef void (*irq_handler_t)(void);✨需要注意形参是void类型,形参可以是void类型或者无形参。

✨另外需要注意的是,使用该函数,在产生gpio中断事件时,需要手动清gpio中断事件标志位,void gpio_acknowledge_irq(uint gpio, uint32_t events);在配置时,还需要手动使能gpio中断,才能响应gpio中断。手动使能gpio中断: irq_set_enabled(IO_IRQ_BANK0, true);

  • 📝SDK给出的例程:
/*** Copyright (c) 2020 Raspberry Pi (Trading) Ltd.** SPDX-License-Identifier: BSD-3-Clause*/#include <stdio.h>
#include "pico/stdlib.h"
#include "hardware/gpio.h"static char event_str[128];void gpio_event_string(char *buf, uint32_t events);void gpio_callback(uint gpio, uint32_t events) {//带2个形参// Put the GPIO event(s) that just happened into event_str// so we can print itgpio_event_string(event_str, events);printf("GPIO %d %s\n", gpio, event_str);
}int main() {stdio_init_all();printf("Hello GPIO IRQ\n");gpio_set_irq_enabled_with_callback(2, GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL, true, &gpio_callback);// Wait foreverwhile (1);
}static const char *gpio_irq_str[] = {"LEVEL_LOW",  // 0x1"LEVEL_HIGH", // 0x2"EDGE_FALL",  // 0x4"EDGE_RISE"   // 0x8
};void gpio_event_string(char *buf, uint32_t events) {for (uint i = 0; i < 4; i++) {uint mask = (1 << i);if (events & mask) {// Copy this event string into the user stringconst char *event_str = gpio_irq_str[i];while (*event_str != '\0') {*buf++ = *event_str++;}events &= ~mask;// If more events add ", "if (events) {*buf++ = ',';*buf++ = ' ';}}}*buf++ = '\0';
}

🛠需要手动清除gpio中断标志位配置使用方法

    gpio_init(EXT_INT_PIN);// gpio_set_dir(EXT_INT_PIN, GPIO_IN);// sio_hw->gpio_oe_set = mask;gpio_set_input_enabled(EXT_INT_PIN, true);// 单独中断gpio_set_irq_enabled(EXT_INT_PIN, GPIO_IRQ_EDGE_RISE, true);gpio_add_raw_irq_handler(EXT_INT_PIN, my_irq_handler);  irq_set_enabled(IO_IRQ_BANK0, true); // 使能中断控制器......void my_irq_handler()
{if (gpio_get_irq_event_mask(EXT_INT_PIN) & GPIO_IRQ_EDGE_RISE|GPIO_IRQ_EDGE_FALL){gpio_acknowledge_irq(EXT_INT_PIN, GPIO_IRQ_EDGE_RISE|GPIO_IRQ_EDGE_FALL);  //clear irq flag//  gpio_xor_mask(1<<LED_PIN); // Toggle the LEDprintf("GPIO %d\n", EXT_INT_PIN);}}

📒GPIO中断清标志位自动配置使用

    gpio_set_irq_enabled_with_callback(EXT_INT_PIN, GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL, true, &my_irq_handler); // 复用中断gpio_set_irq_enabled_with_callback(EXT_INT_PIN2, GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL, true, &my_irq_handler);//gpio_set_irq_callback(&my_irq_handler);
......void my_irq_handler()
{if (gpio_get_irq_event_mask(EXT_INT_PIN) & GPIO_IRQ_EDGE_RISE|GPIO_IRQ_EDGE_FALL){//  gpio_xor_mask(1<<LED_PIN); // Toggle the LEDprintf("GPIO %d\n", EXT_INT_PIN);//    gpio_clear_irq(EXT_INT_PIN);}if (gpio_get_irq_event_mask(EXT_INT_PIN2) & GPIO_IRQ_EDGE_RISE|GPIO_IRQ_EDGE_FALL){//  gpio_xor_mask(1<<LED_PIN); // Toggle the LEDprintf("GPIO %d \n", EXT_INT_PIN2);}
}
  • 👉一般情况下推荐使用gpio_set_irq_enabled_with_callback来配置需要的gpio中断,比较省事。在SDK给出的多种API接口函数,需要熟悉各功能函数的使用差异以及注意事项。

📗GPIO 唤醒功能使用

在芯片进入睡眠模式(DORMANT State)下,gpio可以用作唤醒。


/*CMSIS-DAP烧录命令:openocd -f interface/cmsis-dap.cfg -f target/rp2040.cfg -c  "adapter speed 5000"-c "program RP2040_Deep_Sleep_Wake.elf verify reset exit"jlink命令: openocd -f interface/jlink.cfg -f target/rp2040.cfg  -c  "adapter speed 2000" -c  "program RP2040_Deep_Sleep_Wake.elf verify reset exit"*/
#include <stdio.h>
#include "pico/stdlib.h"
#include "hardware/clocks.h"
#include "hardware/gpio.h"
#include "hardware/xosc.h"
#include "pico/multicore.h"
#include "pico/stdio.h"
#include "pico/time.h"#define LED_PIN 25
#define EXT_INT_PIN 5static void measure_freqs(void);void disable_pll() {clock_configure(clk_sys,CLOCKS_CLK_SYS_CTRL_SRC_VALUE_CLK_REF,0,12 * MHZ,12 * MHZ);
}void enable_pll() {clock_configure(clk_sys,CLOCKS_CLK_SYS_CTRL_SRC_VALUE_CLKSRC_CLK_SYS_AUX,CLOCKS_CLK_SYS_CTRL_AUXSRC_VALUE_CLKSRC_PLL_SYS,125 * MHZ,125 * MHZ);
}int main() {// stdio_init_all();gpio_init(PICO_DEFAULT_LED_PIN);gpio_set_dir(PICO_DEFAULT_LED_PIN, GPIO_OUT);gpio_put(PICO_DEFAULT_LED_PIN, true);gpio_init(EXT_INT_PIN);gpio_set_dir(EXT_INT_PIN, GPIO_IN);// sio_hw->gpio_oe_set = mask;gpio_set_pulls(EXT_INT_PIN, false, true); // 下拉gpio_set_dormant_irq_enabled(EXT_INT_PIN, IO_BANK0_DORMANT_WAKE_INTE0_GPIO0_LEVEL_HIGH_BITS, true);disable_pll();xosc_dormant(); // WARNING: This stops the xosc until woken up by an irq
//   gpio_acknowledge_irq(EXT_INT_PIN, IO_BANK0_DORMANT_WAKE_INTE0_GPIO0_LEVEL_HIGH_BITS);enable_pll();stdio_init_all();while (true)  {measure_freqs();gpio_xor_mask(1ul << PICO_DEFAULT_LED_PIN); // Toggle the LEDsleep_ms(1000);// for (uint32_t i=0; i<3; i++) {//     gpio_put(PICO_DEFAULT_LED_PIN, false);//     sleep_ms(100);//     gpio_put(PICO_DEFAULT_LED_PIN, true);//     sleep_ms(100);// }}
}static void measure_freqs(void)
{uint f_pll_sys = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_PLL_SYS_CLKSRC_PRIMARY);uint f_pll_usb = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_PLL_USB_CLKSRC_PRIMARY);uint f_rosc = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_ROSC_CLKSRC);uint f_clk_sys = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_CLK_SYS);uint f_clk_peri = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_CLK_PERI);uint f_clk_usb = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_CLK_USB);uint f_clk_adc = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_CLK_ADC);uint f_clk_rtc = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_CLK_RTC);printf("pll_sys  = %dkHz\n", f_pll_sys);printf("pll_usb  = %dkHz\n", f_pll_usb);printf("rosc     = %dkHz\n", f_rosc);printf("clk_sys  = %dkHz\n", f_clk_sys);printf("clk_peri = %dkHz\n", f_clk_peri);printf("clk_usb  = %dkHz\n", f_clk_usb);printf("clk_adc  = %dkHz\n", f_clk_adc);printf("clk_rtc  = %dkHz\n", f_clk_rtc);// Can't measure clk_ref / xosc as it is the ref
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/1542249.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

Python办公自动化教程(002):PDF的拆分与合并

1、PyPDF2 介绍 介绍&#xff1a; PyPDF2是一个用于处理PDF文件的Python库&#xff0c;它提供了丰富的功能来读取、编辑、合并、拆分PDF文档&#xff0c;以及提取文本、图像和其他内容。 功能&#xff1a; 读取PDF&#xff1a;PyPDF2可以轻松地打开和读取PDF文件&#xff0c;获…

计算机丢失mfc110.dll是什么原因与有哪些解决方法详解

丢失动态链接库文件&#xff08;DLL&#xff09;是比较常见的一种情况&#xff0c;其中之一就是“计算机丢失mfc110.dll”。这个问题通常是由于系统文件损坏或缺失引起的&#xff0c;给计算机的正常运行带来了困扰。为了解决这个问题&#xff0c;我总结了以下几种方法&#xff…

1512. 好数对的数目

目录 一&#xff1a;题目&#xff1a; 二&#xff1a;代码&#xff1a; 三&#xff1a;结果&#xff1a; 一&#xff1a;题目&#xff1a; 给你一个整数数组 nums 。 如果一组数字 (i,j) 满足 nums[i] nums[j] 且 i < j &#xff0c;就可以认为这是一组 好数对 。 返…

状态模式:将对象行为与状态解耦

状态模式&#xff08;State Pattern&#xff09;是一种行为设计模式&#xff0c;它允许对象在其内部状态改变时改变其行为&#xff0c;使对象看起来好像修改了其类。 状态模式的核心思想是将对象的行为封装在不同的状态对象中&#xff0c;每个状态对象都代表了对象在某一特定状…

校园美食探索者:Spring Boot开发的分享平台

第二章 系统分析 2.1 可行性分析 可行性分析的目的是确定一个系统是否有必要开发、确定系统是否能以最小的代价实现。其工作主要有三个方面&#xff0c;分别是技术、经济和社会三方面的可行性。我会从这三个方面对网上校园周边美食探索及分享平台进行详细的分析。 2.1.1技术可行…

Redis数据结构之list列表

一.list列表 列表相当于数组或者顺序表 它里面的元素是有序的&#xff0c;也就是可以通过下标进行访问。这里的有序的含义是要根据上下文区分的&#xff0c;有的时候&#xff0c;有序指的是升序/降序&#xff0c;有的时候有序指的是顺序很关键&#xff0c;俩个元素交换后就不…

<<编码>> 第 16 章 存储器组织(4)--内存 示例电路

内存内部结构 info::操作说明 译码器用于写入, 操作同上 选择器用于输出, 操作同上 地址信号同时控制译码器和选择器, 注意地址的高位在右(比如 001 实际是 100, 选择的是 Q6 和 I6) 缺省情况下, 内部数据全是 0. 读者可先通过译码器写入, 再通过选择器输出 primary::在线交…

YOLO原理实现

YOLO&#xff08;You Only Look Once&#xff09;是一个标志性的目标检测模型&#xff0c;可以快速分类并定位图像中的多个对象。本文总结了YOLO模型中所有关键的数学操作。 第一步&#xff1a;定义输入 要使用YOLO模型&#xff0c;首先必须将RGB图像转换为448 x 448 x 3的张…

再看Java-笔试

放在前面的话 最近确实有些空闲&#xff0c;分配的功能从一开始的两眼一黑到现在的一上午就能完成&#xff0c;这何尝不是一种进步呢。 该说不说&#xff0c;海康的API问题相比较其他第三方的API还是蛮多的&#xff0c;而且10月份人工客服还会停运&#xff0c;不过到那个时候…

【CTF】Nginx日志注入

Nginx日志注入&#xff1a; 日志包含漏洞的成因还是服务器没有进行严格的过滤 &#xff0c;导致用户可以进行任意文件读取&#xff0c;但是前提是服务器需要开启了记录日志的功能才可以利用这个漏洞。 对于Apache&#xff0c;日志存放路径&#xff1a;/var/log/apache/access.l…

华为HarmonyOS灵活高效的消息推送服务(Push Kit) - 5 发送通知消息

场景介绍 通知消息通过Push Kit通道直接下发&#xff0c;可在终端设备的通知中心、锁屏、横幅等展示&#xff0c;用户点击后拉起应用。您可以通过设置通知消息样式来吸引用户。 开通权益 Push Kit根据消息内容&#xff0c;将通知消息分类为服务与通讯、资讯营销两大类别&…

【Qt】QSS的设置方式

QSS的设置方式 QWidget 中包含了 setStyleSheet ⽅法, 可以直接设置样式. 上述代码我们已经演⽰了上述设置⽅式 还可以通过 QApplication 的 setStyleSheet ⽅法设置整个程序的全局样式. 设置全局样式&#xff0c;可以将界面上所有的样式都集中到一起来组织。 全局样式优点:…

图神经网络的新篇章:通用、强大、可扩展的图变换器

人工智能咨询培训老师叶梓 转载标明出处 图变换器&#xff08;Graph Transformers, GTs&#xff09;因其在处理节点间全局依赖关系方面的能力而受到广泛关注。然而&#xff0c;现有的GTs模型在处理大规模图时面临着计算复杂度高、泛化能力有限等问题。为了解决这些问题&#x…

UnLua扩展接口

一、在蓝图中创建接口 1、创建BlueprintInterface 2、声明接口函数 3、继承接口 注意&#xff0c;接口不需要绑定Lua&#xff0c;也没有Bind按钮 二、在Lua中实现接口函数 1、实现接口函数 BP_Player.lua function BP_Player_C:UpdateAiming(IsAiming)if IsAiming thensel…

maven手动导入本地仓库

maven手动导入本地仓库 1.在maven仓库下载对应的依赖 一定要把jar包下载到maven仓库的bin下 2.找到自己仓库的maven仓库下的bin目录cmd进去 在cmd窗口中输入以下命令&#xff1a;&#xff08;这里根据你的groupId、artifactId、version修改即可&#xff09; <!-- https:…

gpu scene cull

(1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) LaunchComputeRelevanceTask 调用堆栈 (1) (1)

12k star,这可能是我见过最强的国产开源支付系统!(附源码)

最近有读者问到支付系统相关的问题&#xff0c;这里推荐两个总体完成度还不错的国产开源支付系统&#xff0c;可以拿来学习&#xff0c;也可以根据项目需求直接拿来用。 01 Jeepay 项目介绍 &#xff1a; 一套适合互联网企业使用的开源支付系统&#xff0c;提供了交易、退款、…

IO流中的异常捕获

Java简化 接口AutoCloseable

【深入学习Redis丨第六篇】Redis哨兵模式与操作详解

〇、前言 哨兵是一个分布式系统&#xff0c;你可以在一个架构中运行多个哨兵进程&#xff0c;这些进程使用流言协议来接收关于Master主服务器是否下线的信息&#xff0c;并使用投票协议来决定是否执行自动故障迁移&#xff0c;以及选择哪个Slave作为新的Master。 文章目录 〇、…

vue3扩展echart封装为组件库-快速复用

ECharts ECharts&#xff0c;全称Enterprise Charts&#xff0c;是一款由百度团队开发并开源&#xff0c;后捐赠给Apache基金会的纯JavaScript图表库。它提供了直观、生动、可交互、可个性化定制的数据可视化图表&#xff0c;广泛应用于数据分析、商业智能、网页开发等领域。以…