【Nordic博文分享系列】如何在nRFConnectSDK配置和使用GPIO

原创 Nordic半导体 2023-08-25 16:00

前言

作者:Jesse Fu Nordic Semiconductor

本文介绍了如何在NCS(nRF Connect SDK)下配置和使用GPIO。内容包括以下三个部分:

  • Zephyr GPIO API配置和使用GPIO

  • DK Buttons and LEDs Library

  • PPI TRACE



使用Zephyr GPIO API配置和使用GPIO

nRF Connect SDK是基于Zephyr操作系统的,因此可以使用Zephyr的GPIO API来配置和使用GPIO。

使用Zephyr GPIO API包括以下步骤:

  1. Config中加入CONFIG_GPIO=y;

  2. 在device tree中添加GPIO节点;

  3. 在应用程序中获取GPIO Device;

  4. 配置GPIO;

  5. 读写GPIO,其中GPIO读取可以使用Polling模式和中断模式。

GPIO device的添加和获取


以下是在Device Tree中添加GPIO节点的例子,在节点中配置了两个GPIO,每个GPIO有三个参数。第一个GPIO为GPIO0.1,低电平有效;第二个GPIO为GPIO1.2,低电平有效。

n: node {

    foo-gpios = <&gpio0 1 GPIO_ACTIVE_LOW>,

                <&gpio1 2 GPIO_ACTIVE_LOW>;

 }


接下来我们可以使用gpio_dt_spec来获取device tree中定义的GPIO。

gpio_dt_spec结构体包括以下三部分,分别对应device tree中GPIO的三个参数。

  • port:GPIO 端口设备指针

  • pin:GPIO的PIN NUM

  • dt_flags:gpio在device tree中定义的配置 flags。这些flags在中定义。包括GPIO_ACTIVE_HIGH, GPIO_ACTIVE_LOW, GPIO_PULL_UP, GPIO_PULL_DOWN,GPIO_OPEN_DRAIN,GPIO_OPEN_SOURCE 等。

gpio_dt_spec可以通过以下宏由device tree在具有gpio属性的节点中获取:

  • GPIO_DT_SPEC_GET_BY_IDX

  • GPIO_DT_SPEC_GET_BY_IDX_OR

  • GPIO_DT_SPEC_GET

  • GPIO_DT_SPEC_GET_OR

其中GPIO_DT_SPEC_GET,GPIO_DT_SPEC_GET_OR是获取节点GPIO列表中的第一个GPIO(index=0)的gpio_dt_spec;而GPIO_DT_SPEC_GET_BY_IDX,GPIO_DT_SPEC_GET_BY_IDX_OR则是获取节点GPIO列表里指定index的gpio_dt_spec。相对于GPIO_DT_SPEC_GET_BY_IDX,GPIO_DT_SPEC_GET,在使用GPIO_DT_SPEC_GET_BY_IDX_OR,GPIO_DT_SPEC_GET_OR时,如果在device tree中找不到对应gpio的属性则将gpio_dt_spec赋值为一个指定的默认值。

下面的例子展示了如何在上面提到的node节点中获取第二个GPIO(index=1)的gpio_dt_spec。

const struct gpio_dt_spec spec = GPIO_DT_SPEC_GET_BY_IDX(DT_NODELABEL(n), foo_gpios, 1);

相当于给gpio_dt_spec初始化为以下值:

{

          .port = DEVICE_DT_GET(DT_NODELABEL(gpio1)),

          .pin = 2,

          .dt_flags = GPIO_ACTIVE_LOW

  }


GPIO的配置


除了gpio_dt_spec中定义的配置flags以外,GPIO还需要其他额外的配置。可以通过以下API来对GPIO进行配置:

gpio_pin_configure_dt(const struct gpio_dt_spec *spec, gpio_flags_t extra_flags)相当于gpio_pin_configure(spec->port, spec->pin, spec->dt_flags | extra_flags);

以下是一些GPIO的配置选项:

  • GPIO_INPUT:将引脚配置为输入。

  • GPIO_OUTPUT:将引脚配置为输出,不更改输出状态。

  • GPIO_DISCONNECTED:禁用输入和输出引脚。

  • GPIO_OUTPUT_LOW:将GPIO引脚配置为输出并将其初始化为低状态。

  • GPIO_OUTPUT_HIGH:将GPIO引脚配置为输出并将其初始化为高状态。

  • GPIO_OUTPUT_INACTIVE:将GPIO引脚配置为输出并将其初始化为逻辑0。

  • GPIO_OUTPUT_ACTIVE:将GPIO引脚配置为输出并将其初始化为逻辑1。

另外还有一些配置选项是Nordic独有的,比如Drive strength(bit8,bit9),它通常与GPIO_OPEN_DRAIN,GPIO_OPEN_SOURCE配合使用。具体代码如下:

static int get_drive(gpio_flags_t flags, nrf_gpio_pin_drive_t *drive)

{

    switch (flags & (NRF_GPIO_DRIVE_MSK | GPIO_OPEN_DRAIN)) {

    case NRF_GPIO_DRIVE_S0S1:

        *drive = NRF_GPIO_PIN_S0S1;

        break;

    case NRF_GPIO_DRIVE_S0H1:

        *drive = NRF_GPIO_PIN_S0H1;

        break;

    case NRF_GPIO_DRIVE_H0S1:

        *drive = NRF_GPIO_PIN_H0S1;

        break;

    case NRF_GPIO_DRIVE_H0H1:

        *drive = NRF_GPIO_PIN_H0H1;

        break;

    case NRF_GPIO_DRIVE_S0 | GPIO_OPEN_DRAIN:

        *drive = NRF_GPIO_PIN_S0D1;

        break;

    case NRF_GPIO_DRIVE_H0 | GPIO_OPEN_DRAIN:

        *drive = NRF_GPIO_PIN_H0D1;

        break;

    case NRF_GPIO_DRIVE_S1 | GPIO_OPEN_SOURCE:

        *drive = NRF_GPIO_PIN_D0S1;

        break;

    case NRF_GPIO_DRIVE_H1 | GPIO_OPEN_SOURCE:

        *drive = NRF_GPIO_PIN_D0H1;

        break;

    default:

        return -EINVAL;

    }


    return 0;

}

gpio_pin_interrupt_configure_dt(const struct gpio_dt_spec *spec, gpio_flags_t flags)可以将中断配置到指定GPIO。以下是GPIO中断的配置选项:

  • GPIO_INT_DISABLE:禁用GPIO引脚中断。

  • GPIO_INT_EDGE_RISING:将GPIO中断配置为在引脚上升沿触发并启用它。

  • GPIO_INT_EDGE_FALLING:将GPIO中断配置为在引脚下降沿触发并启用它。

  • GPIO_INT_EDGE_BOTH:将GPIO中断配置为在引脚上升或下降沿触发并启用它。

  • GPIO_INT_LEVEL_LOW:将GPIO中断配置为在物理电平低时触发并启用它。

  • GPIO_INT_LEVEL_HIGH:将GPIO中断配置为在物理电平高时触发并启用它。

  • GPIO_INT_EDGE_TO_INACTIVE:将GPIO中断配置为在状态更改到逻辑0时触发并启用它。

  • GPIO_INT_EDGE_TO_ACTIVE:将GPIO中断配置为在状态更改到逻辑1时触发并启用它。

  • GPIO_INT_LEVEL_INACTIVE:将GPIO中断配置为在逻辑电平0时触发并启用它。

  • GPIO_INT_LEVEL_ACTIVE:将GPIO中断配置为在逻辑电平1时触发并启用它。

Polling模式下读写GPIO


可以使用以下API对GPIO进行读写操作:

  • static inline int gpio_pin_set_dt(const struct gpio_dt_spec *spec, int value) 相当于 gpio_pin_set(spec->port, spec->pin, value);

对指定输出引脚设置逻辑电平。

  • static inline int gpio_pin_set_raw(const struct device *port, gpio_pin_t pin, int value)

对指定输出引脚设置物理电平。

  • static inline int gpio_pin_toggle_dt(const struct gpio_dt_spec *spec) 相当于 gpio_pin_toggle (spec->port, spec->pin)

翻转指定输出引脚电平。

  • static inline int gpio_pin_get_dt(const struct gpio_dt_spec *spec)相当于 gpio_pin_get(spec->port, spec->pin)

读取指定输入引脚逻辑电平。

  • static inline int gpio_pin_get_raw(const struct device *port, gpio_pin_t pin)

读取指定输入引脚物理电平。

另外,还可以使用gpio_port_XXXX API对GPIO端口进行操作。

中断模式读取GPIO


中断模式读取GPIO包括以下步骤:

1. 使用下面API给指定PIN配置中断触发方式

  • static inline int gpio_pin_interrupt_configure_dt(const struct gpio_dt_spec *spec, gpio_flags_t flags) 相当于gpio_pin_interrupt_configure(spec->port, spec->pin, flags); 

示例代码如下

  • gpio_pin_interrupt_configure_dt(&gpio_spec, GPIO_INT_EDGE_TO_ACTIVE);

2. 定义回调函数,比如 void pin_isr(const struct device *dev, struct gpio_callback *cb, gpio_port_pins_t pins);

这个回调函数会在中断触发时调用。

3. 定义数据类型为 struct gpio_callback 的变量,这个变量保存了pin num和回调函数的信息。下面是个示例:

  • static struct gpio_callback pin_cb_data;

4. 使用gpio_init_callback()初始化gpio_callback 变量,下面是一个示例

  • gpio_init_callback(& pin_cb_data ,pin_isr ,BIT(gpio_spec.pin));

5. 使用gpio_add_callback()添加callback, 示例代码如下:

  • gpio_add_callback(gpio_spec.port, & pin_cb_data);

Zephyr GPIO API的实现


Zephyr gpio API最终会调用到nrfx gpiote, nrfx gpio驱动。它是由文件gpio_nrf.c以及头文件gpio.h里的内联函数实现的。下面以gpio_pin_interrupt_configure_dt()为例说明这个函数是如何实现的。

在gpio.h定义了内联函数gpio_pin_interrupt_configure_dt();

里面调用的函数关系如下

gpio_pin_interrupt_configure_dt() =>

gpio_pin_interrupt_configure() =>

z_impl_gpio_pnrfxin_interrupt_configure() =>

(api->pin_interrupt_configure()); 也就是 gpio_nrfx_pin_interrupt_configure()

而gpio_nrfx_pin_interrupt_configure()会调用nrfx gpiote, nrf gpio的驱动。

因为大部分函数都是内联函数,所以实际使用中只多增加了一个调用层级。

接下来,我们看一下gpio_nrfx_pin_interrupt_configure()是如何实现的。

从上面我们可以看到如果中断使用边沿触发模式而且该pin没有配置成sense模式则使用nrfx gpiote的IN EVT。如果使用电平触发模式或者pin被配置为sense模式则使用PORT EVT。

Zephyr中GPIO的例子


Zephyr中关于GPIO有Blinky和Button两个例子。下面是Blinky的例子,位于zephyr\samples\basic\blinky

Button例子代码如下,位于zephyr\samples\basic\button



DK Buttons and LEDs Library

DK Buttons and LEDs Library是Nordic提供的用于与按键和LED交互的模块。它是在Zephyr GPIO API之上实现的API。

  • 支持读取4个以内的按键或者控制4个以内的LEDs

  • 支持按键防抖功能。相对于直接调用Zephyr GPIO API, 不需要用户额外实现按键防抖功能。

  • 相对于Zephyr GPIO API,调用更加简单方便。

DK Buttons and LEDs Library的使用方法如下:

  1. 在proj conf中加入CONFIG_DK_LIB=y。

  2. 在device tree中加入LEDs和Buttons的节点。

  3. 在应用程序中添加代码

    #include

  4. 调用dk_leds_init(),接下来就可以设置单个LED的值或者将他们通过掩码设置到指定的状态。

  5. 调用dk_buttons_init(),在初始化时可以传递回调函数,当每次按键更改时都会调用此回调函数。也可以通过polling模式读取按键的值。

LEDs和Buttons设备树节点的定义


LEDs和Buttons的节点Binddings定义在../bindings/gpio/gpio-leds.yaml 和 ../bindings/gpio/gpio-keys.yaml。

Leds节点的例子如下:

/ {       

        leds {               

                compatible = "gpio-leds";

                led_0 {                       

                        /* LED 0 on P0.13, LED on when pin is high */

                        gpios = < &gpio0 13 GPIO_ACTIVE_HIGH >;

                        label = "LED 0";               

                };

                led_1 {

                        /* LED 1 on P0.14, LED on when pin is low */

                        gpios = < &gpio0 14 GPIO_ACTIVE_LOW >;

                        label = "LED 1";               

                };               

                led_2 {                       

                        /* LED 2 on P1.0, on when low */

                        gpios = < &gpio1 0 GPIO_ACTIVE_LOW >;

                        label = "LED 2";

                };

                led_3 {

                        /* LED 3 on P1.1, on when high */

                        gpios = < &gpio1 1 GPIO_ACTIVE_HIGH >;

                        label = "LED 3";

                };

     };

};

这个例子中定义了四个LED。LED_0和LED_3为高电平点亮;LED_1和LED_2低电平点亮。

以下例子为Buttons的例子:

/ {

        buttons {

                compatible = "gpio-keys";

                /*

                 * Add up to 4 total buttons in child nodes as shown here.

                 */

                button0: button_0 {

                        /* Button 0 on P0.11. Enable internal SoC pull-up

                         * resistor and treat low level as pressed button. */

                        gpios = <&gpio0 11 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>;

                        label = "Button 0";

                };

                button1: button_1 {

                        /* Button 1 on P0.12. Enable internal pull-down resistor.

                         * Treat high level as pressed button. */

                        gpios = <&gpio0 12 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)>;

                        label = "Button 1";

                };

                button2: button_2 {

                        /* Button 2 on P1.12, enable internal pull-up,

                         * low level is pressed. */

                        gpios = <&gpio1 12 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>;

                        label = "Button 2";

                };

                button3: button_3 {

                        /* Button 3 on P1.15, no internal pull resistor,

                         * low is pressed. */

                        gpios = <&gpio1 15 GPIO_ACTIVE_LOW>;

                        label = "Button 3";

                };

        };

};

在这个例子中定义了四个Buttons。Button0,Button2,Button3按键按下去时为低电平并且Button0和Button2配置为内部上拉,Button1按键按下去时为高电平且配置为内部下拉。

LEDs控制


LEDs控制的API包括以下:

  • int dk_leds_init(void) : 初始化LEDs library

  • int dk_set_led_on(uint8_t led_idx : 打开单个LED

  • int dk_set_led_off(uint8_t led_idx) : 关闭单个LED

  •  int dk_set_led(uint8_t led_idx, uint32_t val) :打开或者关闭单个LED

  • int dk_set_leds(uint32_t leds) :通过LEDs的掩码来设置LEDs

  • int dk_set_leds_state(uint32_t leds_on_mask, uint32_t leds_off_mask) :通过LEDs on/off掩码来设置LEDs状态

Buttons读取


DK Buttons and LEDs Library 为Buttons的读取提供了以下API:

  • int dk_buttons_init(button_handler_t button_handler):初始化Buttons并传入回调函数,回调函数在按键状态发生改变时调用。

    typedef void (*button_handler_t)(uint32_t button_state, uint32_t has_changed)

    button_state:  按键的状态掩码值

    has_changed:  指示哪些按键状态发生了改变

  • uint32_t dk_get_buttons(void):读取按键的掩码

  • void dk_read_buttons(uint32_t *button_state, uint32_t *has_changed):读取按键的状态和状态改变的按键掩码值

Buttons读取实现过程


DK Buttons and LEDs Library是在文件dk_buttons_leds.c中实现的,下面重点介绍下Buttons读取的实现过程。

  • Buttons lib采用中断和扫描相结合的方式。

  • Buttons lib有两种状态

    STATE_WAITING:等待按键中断触发事件

    STATE_SCANNING :关闭中断,启动可延迟的工作队列进行定时扫描,扫描由 buttons_scan_fn(struct k_work *work)实现,默认扫描间隔为10ms。

  • Buttons lib状态转换

    当Buttons初始化时或者Button中断被触发时会关闭中断并启动可延迟的工作队进行定时扫描。

    在扫描状态下,当发现按键状态发生改变时,调用用户回调函数;当按键掩码值为0时,即所有按键都处于release状态,程序退出扫描状态并启动中断进入等待状态;当按键掩码值不为0时,继续启动可延迟的工作队列,过一段时间进行下一次扫描。

  • 因为按键采用定时扫描,所以过滤掉了按键抖动。

  • 在没有按键发生时,程序处于等待状态进入睡眠,从而降低了功耗。

  • 中断通常采用电平触发模式,使用PORT EVT。

配置选项


DK Buttons and LEDs Library包括以下配置选项:

  • menuconfig DK_LIBRARY

      bool "Button and LED Library for Nordic DKs"

      select GPIO

    开启DK_LIBRARY

  • config DK_LIBRARY_BUTTON_SCAN_INTERVAL

          int "Scanning interval of buttons in milliseconds"

      default 10

    按健的扫描间隔(毫秒)

  • config DK_LIBRARY_DYNAMIC_BUTTON_HANDLERS

      bool "Enable the runtime assignable button handler API"

      default y

    除了传递给 dk_buttons_init 的按健处理程序函数之外,还可以在运行时添加和删除任意数量的按健处理程序。使用的API如下:

    void dk_button_handler_add(struct button_handler *handler)添加回调函数;                 

    int dk_button_handler_remove(struct button_handler *handler)动态删除回调函数。

Peripheral LBS Sample


接下来,我们以Peripheral LBS Sample为例说明这个例子是如何使用DK Buttons and LEDs Library的。这个例子位于nrf\samples\bluetooth\peripheral_lbs

以下是这个例子中初始化LEDs和Buttons的代码:

 err = dk_leds_init();

 if (err) {

     printk("LEDs init failed (err %d)\n", err);

     return 0;

 }


 err = init_button();

 if (err) {

     printk("Button init failed (err %d)\n", err);

     return 0;

 }


static int init_button(void)

{

    int err;


    err = dk_buttons_init(button_changed);

    if (err) {

        printk("Cannot init buttons (err: %d)\n", err);

    }


    return err;

}

接下来是LEDs的控制BEL连接时,点亮连接指示灯。

dk_set_led_on(CON_STATUS_LED);

BLE断开时,关闭连接指示灯

dk_set_led_off(CON_STATUS_LED);

app_led_cb():根据BLE传入命令设置用户灯状态。

static void app_led_cb(bool led_state)

{

    dk_set_led(USER_LED, led_state);

}

在main()主函数里闪烁运行状态灯

for (;;) {

    dk_set_led(RUN_STATUS_LED, (++blink_status) % 2);

    k_sleep(K_MSEC(RUN_LED_BLINK_INTERVAL));

}

最后是按键的回调函数,当按键状态发生改变时,通过BLE把按键状态发送出去。

tatic void button_changed(uint32_t button_state, uint32_t has_changed)

{

    if (has_changed & USER_BUTTON) {

        uint32_t user_button_state = button_state & USER_BUTTON;


        bt_lbs_send_button_state(user_button_state);

        app_button_state = user_button_state ? true : false;

    }

}



PPI TRACE

Nordic除了提供DK Buttons and LEDs Library这个与GPIO相关模块以外,还提供了PPI trace。

  • PPI trace是使用GPIO跟踪硬件事件的软件模块。

  • 因为 PPI 用于将事件与 GPIOTE 中的任务连接起来,所以跟踪是在没有 CPU 干预的情况下进行的,非常适用于DEBUG。

  • PPI trace 可用于跟踪单个事件或一对互补事件。

    当跟踪单个事件时,事件的每次发生都会切换引脚的状态(请参见 ppi_trace_config())。

    当跟踪一对互补事件时(例如,传输的开始和结束),当其中一个事件发生时,引脚被设置为1,而当另一个事件发生时,引脚被清除(请参见 ppi_trace_pair_config())

需要注意的是,这个模块并没有调用Zephyr GPIO API,而是直接调用了nrfx gpiote的驱动。这是因为这样不但效率更高而且可以实现更加丰富的功能。

关于nrfx gpiote以及nrfx gpio的API请参阅以下在线文档:

https://developer.nordicsemi.com/nRF_Connect_SDK/doc/latest/nrfx/drivers/gpiote/driver.html

https://developer.nordicsemi.com/nRF_Connect_SDK/doc/latest/nrfx/drivers/gpio/index.html

PPI trace API


PPI trace 提供了以下四个API:

  • void *ppi_trace_config(uint32_t pin, uint32_t evt) :配置 PPI trace 引脚以跟踪单个事件

  • void *ppi_trace_pair_config(uint32_t pin, uint32_t start_evt, uint32_t stop_evt) :配置 PPI trace 引脚以跟踪一对互补事件

  • void ppi_trace_enable(void *handle) :启用 PPI trace 引脚

  • void ppi_trace_disable(void *handle):禁用 PPI trace 引脚

PPI trace API的实现


PPI trace API是在nrfx gpiote和nrfx ppi驱动之上实现的API,下面以ppi_trace_config() 为例看一下它是如何实现的。

PPI trace Sample


在nRF Connect SDK中,Nordic还提供了PPI trace的例子,这个例子位于nrf\samples\debug\ppi_trace。

此sample中使用了四个PIN来trace以下事件。

  • RTC 比较事件(NRF_RTC_EVENT_COMPARE_0),每50ms触发一次。

ppi_trace_pin_setup(CONFIG_PPI_TRACE_PIN_RTC_COMPARE_EVT,

    nrf_rtc_event_address_get(RTC, NRF_RTC_EVENT_COMPARE_0));

  • RTC Tick 事件(NRF_RTC_EVENT_TICK),开始使用内部RC震荡器,然后无缝切换到外部晶振低频时钟。

ppi_trace_pin_setup(CONFIG_PPI_TRACE_PIN_RTC_TICK_EVT,

    nrf_rtc_event_address_get(RTC, NRF_RTC_EVENT_TICK));

  • 低频时钟 (LFCLK) 开始事件 (NRF_CLOCK_EVENT_LFCLKSTARTED),RTC外部晶振时钟ready时产生

ppi_trace_pin_setup(CONFIG_PPI_TRACE_PIN_LFCLOCK_STARTED_EVT,

    nrf_clock_event_address_get(NRF_CLOCK,

        NRF_CLOCK_EVENT_LFCLKSTARTED));

  • 在蓝牙广播中Radio active 事件(radio ready和radio disable互补事件)

start_evt = nrf_radio_event_address_get(NRF_RADIO,

         NRF_RADIO_EVENT_READY);

stop_evt = nrf_radio_event_address_get(NRF_RADIO,

         NRF_RADIO_EVENT_DISABLED);

handle = ppi_trace_pair_config(CONFIG_PPI_TRACE_PIN_RADIO_ACTIVE,

         start_evt, stop_evt);

例子中使用了Zephyr’s链路层而不是SoftDevice链路层,这是因为SoftDevice链路层在初始化期间被阻塞,直到低频晶振启动并且时钟稳定。因此,SoftDevice 链路层不能用于显示引脚上的LFCLK开始事件。

接下来我们选择nrf52840dk编译这个例子。四个PIN的默认定义在Kconfig中,分别为:

  • PPI_TRACE_PIN_RTC_COMPARE_EVT => 3 即A0.3。

  • PPI_TRACE_PIN_RTC_TICK_EVT => 4 即A0.4。

  • PPI_TRACE_PIN_LFCLOCK_STARTED_EVT => 28 即A0.28。

  • PPI_TRACE_PIN_RADIO_ACTIVE =>29 即A0.29。

接下来我们把这四个管脚接入逻辑分析仪,打开nRF52840DK并捕获到以下波形。

通道0对应RTC 比较事件,通道1对应RTC Tick时间, 通道2对应低频时钟 (LFCLK) 开始事件,通道3对应Radio active 事件。从中我们可以看到RTC比较事件约50ms触发一次,打开PPI trace后377ms左右低频时钟被触发。大约每隔100ms 会有一组Radio Active事件。

下面的图是放大的低频时钟被触发前后的波形,通道2低电平时RTC使用内部RC振荡器,高电平时使用外部低频晶振。我们可以看到RTC tick事件频率大约为32768Hz:

接下来的图形是放大的Radio Active事件,该事件在通道3中,高电平时表示Radio Active(Radio Ready EVT开始-->Radio Disable EVT结束)。



总结

nRF Connect SDK下可以使用以下三种方法对GPIO进行配置和使用。

  1. 使用DK Buttons and LEDs Library

    这种方法最简单易用。

  2. 使用Zephyr GPIO API

    这种方法调用标准的Zephyr GPIO驱动,因此对于基于Zephyr的工程易于移植和维护。

  3. 直接调用nrfx gpiote, nrfx gpio驱动

    无论使用方法1还是方法2最终都会调用到nrfx gpiote, nrfx gpio 驱动。因此用户直接调用nrfx gpiote, nrfx gpio 驱动效率最高,也最灵活,比如ppi trace模块就是直接调用nrfx gpiote的驱动。如果用户已有nrf5 sdk基于nrfx gtiote,nrfx gpio驱动的程序,可以使用这种方法快速移植到nRF Connect SDK上面来。

【联系我们】

中文官网:www.nordicsemi.cn

英文官网:www.nordicsemi.com

微信公众号:nordicsemi


【Nordic 开发者论坛】

https://devzone.nordicsemi.com


【销售接洽】

北京分公司: +86 10 6410 8596

上海分公司: +86 21 6330 0620

深圳分公司: +86 755 8322 0147

sales.cn@nordicsemi.no


按下方提示星标 Nordic🌟

以免错过半导体行业深度好文👇




点击阅读原文” 进入Nordic半导体中文官网

Nordic半导体 Nordic 半导体开发支持蓝牙智能、ANT+和2.4GHz应用的超低功耗短距无线通信技术,用于物联网 、可穿戴产品、智能家居、玩具等应用。Nordic 提供现成可用的设计框架、世界级文档资料和支持,以加快专业工程师和业余爱好者的开发速度。
评论
  • 遇到部分串口工具不支持1500000波特率,这时候就需要进行修改,本文以触觉智能RK3562开发板修改系统波特率为115200为例,介绍瑞芯微方案主板Linux修改系统串口波特率教程。温馨提示:瑞芯微方案主板/开发板串口波特率只支持115200或1500000。修改Loader打印波特率查看对应芯片的MINIALL.ini确定要修改的bin文件#查看对应芯片的MINIALL.ini cat rkbin/RKBOOT/RK3562MINIALL.ini修改uart baudrate参数修改以下目
    Industio_触觉智能 2024-12-03 11:28 45浏览
  • 作为优秀工程师的你,已身经百战、阅板无数!请先醒醒,新的项目来了,这是一个既要、又要、还要的产品需求,ARM核心板中一个处理器怎么能实现这么丰富的外围接口?踌躇之际,你偶阅此文。于是,“潘多拉”的魔盒打开了!没错,USB资源就是你打开新世界得钥匙,它能做哪些扩展呢?1.1  USB扩网口通用ARM处理器大多带两路网口,如果项目中有多路网路接口的需求,一般会选择在主板外部加交换机/路由器。当然,出于成本考虑,也可以将Switch芯片集成到ARM核心板或底板上,如KSZ9897、
    万象奥科 2024-12-03 10:24 41浏览
  • 11-29学习笔记11-29学习笔记习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习笔记&记录学习习笔记&记学习学习笔记&记录学习学习笔记&记录学习习笔记&记录学习学习笔记&记录学习学习笔记记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&学习学习笔记&记录学习学习笔记&记录学习学习笔记&记
    youyeye 2024-12-02 23:58 52浏览
  •         温度传感器的精度受哪些因素影响,要先看所用的温度传感器输出哪种信号,不同信号输出的温度传感器影响精度的因素也不同。        现在常用的温度传感器输出信号有以下几种:电阻信号、电流信号、电压信号、数字信号等。以输出电阻信号的温度传感器为例,还细分为正温度系数温度传感器和负温度系数温度传感器,常用的铂电阻PT100/1000温度传感器就是正温度系数,就是说随着温度的升高,输出的电阻值会增大。对于输出
    锦正茂科技 2024-12-03 11:50 70浏览
  • 戴上XR眼镜去“追龙”是种什么体验?2024年11月30日,由上海自然博物馆(上海科技馆分馆)与三湘印象联合出品、三湘印象旗下观印象艺术发展有限公司(下简称“观印象”)承制的《又见恐龙》XR嘉年华在上海自然博物馆重磅开幕。该体验项目将于12月1日正式对公众开放,持续至2025年3月30日。双向奔赴,恐龙IP撞上元宇宙不久前,上海市经济和信息化委员会等部门联合印发了《上海市超高清视听产业发展行动方案》,特别提到“支持博物馆、主题乐园等场所推动超高清视听技术应用,丰富线下文旅消费体验”。作为上海自然
    电子与消费 2024-11-30 22:03 86浏览
  • 当前,智能汽车产业迎来重大变局,随着人工智能、5G、大数据等新一代信息技术的迅猛发展,智能网联汽车正呈现强劲发展势头。11月26日,在2024紫光展锐全球合作伙伴大会汽车电子生态论坛上,紫光展锐与上汽海外出行联合发布搭载紫光展锐A7870的上汽海外MG量产车型,并发布A7710系列UWB数字钥匙解决方案平台,可应用于数字钥匙、活体检测、脚踢雷达、自动泊车等多种智能汽车场景。 联合发布量产车型,推动汽车智能化出海紫光展锐与上汽海外出行达成战略合作,联合发布搭载紫光展锐A7870的量产车型
    紫光展锐 2024-12-03 11:38 71浏览
  • 学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习笔记&记录学习习笔记&记学习学习笔记&记录学习学习笔记&记录学习习笔记&记录学习学习笔记&记录学习学习笔记记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&
    youyeye 2024-11-30 14:30 73浏览
  • 光伏逆变器是一种高效的能量转换设备,它能够将光伏太阳能板(PV)产生的不稳定的直流电压转换成与市电频率同步的交流电。这种转换后的电能不仅可以回馈至商用输电网络,还能供独立电网系统使用。光伏逆变器在商业光伏储能电站和家庭独立储能系统等应用领域中得到了广泛的应用。光耦合器,以其高速信号传输、出色的共模抑制比以及单向信号传输和光电隔离的特性,在光伏逆变器中扮演着至关重要的角色。它确保了系统的安全隔离、干扰的有效隔离以及通信信号的精准传输。光耦合器的使用不仅提高了系统的稳定性和安全性,而且由于其低功耗的
    晶台光耦 2024-12-02 10:40 105浏览
  • 艾迈斯欧司朗全新“样片申请”小程序,逾160种LED、传感器、多芯片组合等产品样片一触即达。轻松3步完成申请,境内免费包邮到家!本期热荐性能显著提升的OSLON® Optimal,GF CSSRML.24ams OSRAM 基于最新芯片技术推出全新LED产品OSLON® Optimal系列,实现了显著的性能升级。该系列提供五种不同颜色的光源选项,包括Hyper Red(660 nm,PDN)、Red(640 nm)、Deep Blue(450 nm,PDN)、Far Red(730 nm)及Ho
    艾迈斯欧司朗 2024-11-29 16:55 171浏览
  • 国产光耦合器正以其创新性和多样性引领行业发展。凭借强大的研发能力,国内制造商推出了适应汽车、电信等领域独特需求的专业化光耦合器,为各行业的技术进步提供了重要支持。本文将重点探讨国产光耦合器的技术创新与产品多样性,以及它们在推动产业升级中的重要作用。国产光耦合器创新的作用满足现代需求的创新模式新设计正在满足不断变化的市场需求。例如,高速光耦合器满足了电信和数据处理系统中快速信号传输的需求。同时,栅极驱动光耦合器支持电动汽车(EV)和工业电机驱动器等大功率应用中的精确高效控制。先进材料和设计将碳化硅
    克里雅半导体科技 2024-11-29 16:18 170浏览
  • 概述 说明(三)探讨的是比较器一般带有滞回(Hysteresis)功能,为了解决输入信号转换速率不够的问题。前文还提到,即便使能滞回(Hysteresis)功能,还是无法解决SiPM读出测试系统需要解决的问题。本文在说明(三)的基础上,继续探讨为SiPM读出测试系统寻求合适的模拟脉冲检出方案。前四代SiPM使用的高速比较器指标缺陷 由于前端模拟信号属于典型的指数脉冲,所以下降沿转换速率(Slew Rate)过慢,导致比较器检出出现不必要的问题。尽管比较器可以使能滞回(Hysteresis)模块功
    coyoo 2024-12-03 12:20 71浏览
  • 《高速PCB设计经验规则应用实践》+PCB绘制学习与验证读书首先看目录,我感兴趣的是这一节;作者在书中列举了一条经典规则,然后进行详细分析,通过公式推导图表列举说明了传统的这一规则是受到电容加工特点影响的,在使用了MLCC陶瓷电容后这一条规则已经不再实用了。图书还列举了高速PCB设计需要的专业工具和仿真软件,当然由于篇幅所限,只是介绍了一点点设计步骤;我最感兴趣的部分还是元件布局的经验规则,在这里列举如下:在这里,演示一下,我根据书本知识进行电机驱动的布局:这也算知行合一吧。对于布局书中有一句:
    wuyu2009 2024-11-30 20:30 106浏览
  • 在电子技术快速发展的今天,KLV15002光耦固态继电器以高性能和强可靠性完美解决行业需求。该光继电器旨在提供无与伦比的电气隔离和无缝切换,是现代系统的终极选择。无论是在电信、工业自动化还是测试环境中,KLV15002光耦合器固态继电器都完美融合了效率和耐用性,可满足当今苛刻的应用需求。为什么选择KLV15002光耦合器固态继电器?不妥协的电压隔离从本质上讲,KLV15002优先考虑安全性。输入到输出隔离达到3750Vrms(后缀为V的型号为5000Vrms),确保即使在高压情况下,敏感的低功耗
    克里雅半导体科技 2024-11-29 16:15 128浏览
  • 最近几年,新能源汽车愈发受到消费者的青睐,其销量也是一路走高。据中汽协公布的数据显示,2024年10月,新能源汽车产销分别完成146.3万辆和143万辆,同比分别增长48%和49.6%。而结合各家新能源车企所公布的销量数据来看,比亚迪再度夺得了销冠宝座,其10月新能源汽车销量达到了502657辆,同比增长66.53%。众所周知,比亚迪是新能源汽车领域的重要参与者,其一举一动向来为外界所关注。日前,比亚迪汽车旗下品牌方程豹汽车推出了新车方程豹豹8,该款车型一上市就迅速吸引了消费者的目光,成为SUV
    刘旷 2024-12-02 09:32 101浏览
  • RDDI-DAP错误通常与调试接口相关,特别是在使用CMSIS-DAP协议进行嵌入式系统开发时。以下是一些可能的原因和解决方法: 1. 硬件连接问题:     检查调试器(如ST-Link)与目标板之间的连接是否牢固。     确保所有必要的引脚都已正确连接,没有松动或短路。 2. 电源问题:     确保目标板和调试器都有足够的电源供应。     检查电源电压是否符合目标板的规格要求。 3. 固件问题: &n
    丙丁先生 2024-12-01 17:37 86浏览
我要评论
0
点击右上角,分享到朋友圈 我知道啦
请使用浏览器分享功能 我知道啦