以下文章來源于Nordic半導體,作者Smile Jiang
nRF54L15 的GPIO口分配
APB總線用于低速且低功耗的外圍設備,nRF54L15根據APB總線的標號,對外設進行命名且對GPIO口進行端口分配。AMBIX為AMBA總線互聯通道。

AMBIX0/APB00:
GPIO_P2:P2.00~P2.10
APB/AHB外設如:CCM00,UARTE00,SPIM00,SPIS00...
AMBIX1/APB10:
GPIO:None
AMBIX2/APB20:
GPIO_P1: P1.00~P1.14(包括P1.00/P1.01 XL1 XL2)
外設如:GPIOTE20,UARTE20~22,TWIM20~22,GRTC,SAADC,PWM20~22...
在nRF54L15DK原理圖上 : UART1 即APB20上的 UART20
AMBIX3/APB30:
GPIO_P0: P0.00~P0.04
外設如:GPIOTE30,UARTE30,RESET,WDT30~31...
有些外設對GPIO的引腳選擇有要求,如:

外設管腳的默認配置:
ncs/zephyr/boards/nordic/nrf54l15dk/nrf54l15dk_nrf54l15-pinctrl.dtsi
用戶可以通過在app工程中添加XXX.overlay文件對外設管腳進行重新分配。比如:


編譯完成后可以通過查看生成的zephyr.dts確認.overlay的文件是否生效,并檢查GPIO的管腳配置是否正確。比如button工程編譯后最終zephyr.dts所在目錄:
ncs/zephyr/samples/basic/button/build/button/zephyr/zephyr.dts
如何從devicetree中獲取GPIO并將其映射到軟件中?
可參考文章:
https://www.cnblogs.com/jayant97/articles/18141263
https://github.com/aiminhua/ncs_samples/blob/master/ble_comprehensive/src/io_int_thread.c
我們從兩個簡單的參考例子開始:
ncs/zephyr/samples/basic/blinky/src/main.c
ncs/zephyr/samples/basic/button/src/main.c
2.1 devicetree 中的GPIO描述
devicetree 中的GPIO描述
gpio0: gpio@10a000 {
compatible ="nordic,nrf-gpio";
gpio-controller;
reg = < 0x10a0000x300 >;
#gpio-cells = < 0x2 >;
ngpios = < 0x5 >;
status ="okay";
port = < 0x0 >;
gpiote-instance = < &gpiote30 >;
};
gpio1: gpio@d8200 {
compatible ="nordic,nrf-gpio";
gpio-controller;
reg = < 0xd82000x300 >;
#gpio-cells = < 0x2 >;
ngpios = < 0x10 >;
status ="okay";
port = < 0x1 >;
gpiote-instance = < &gpiote20 >;
phandle = < 0xd >;
};
gpio2: gpio@50400 {
...
};
參考文件:
ncs/zephyr/dts/bindings/gpio/nordic,nrf-gpio.yaml
ncs/zephyr/include/zephyr/dt-bindings/gpio/gpio.h
ncs/zephyr/include/zephyr/drivers/gpio.h
a.節點名:gpio@10a000;gpio@d8200;gpio@d8200 b.標簽:gpio0;gpio1;gpio2 c.gpio-controller: 聲明具有域控制器功能 d.reg: 外設在總線上的地址分布,需跟節點名對應 e.phandle:一個節點node1可以通過phandle被另一節點node2引用作為屬性值 f.gpiote-instance:指向外部gpiote節點的phandle屬性,表明可使用該GPIO port的gpiote實體 g.ngpios:所在GPIO Port(槽位)中最大可用GPIO口的數目。如對于nrf54L15: gpio0(port0): ngpios = < 0xb >; => P0.00~P0.10 gpio1(port1): ngpios = < 0x10 >; =>P1.00~P1.15 gpio2(port2): ngpios = < 0x5 >; =>P2.00~P2.04 h.gpio-reserved-ranges:為系統保留的gpio口,用戶不可以直接使用.比如: "gpio-reserved-ranges = [5,3]": 表明GPIO pin腳偏移為5,6,7的IO口為系統保留 "gpio-reserved-ranges = <0 2>,<10 1>": 表明GPIO pin腳偏移為0, 1,10的IO口為系統保留, 即使定義了ngpios = <0xb> i.#gpio-cells:gpio節點作為controller時的specifier參數數量。比如#gpio-cells = < 0x2 >; 意味著在其他節點中引用gpio0控制器時,specifier參數數量為2,如: led0: led_0 { gpios = < &gpio2 0x90x0 >; label ="Green LED 0"; }; &gpio2:指gpio2控制器, 對應物理上的gpio port2 0x9: 指pin腳編號是0x9,即P2.09 0x0: devicetree中定義的GPIO口配置參數,在軟件中有時被描述為flag(s),0x0等價于GPIO_ACTIVE_HIGH |GPIO_PUSH_PULL |GPIO_LINE_OPEN_SOURCE
補充說明:
GPIO_ACTIVE_HIGH: GPIO口高有效(有效指邏輯1)
GPIO_PUSH_PULL: 配置GPIO輸出為推挽模式
PIO_LINE_OPEN_SOURCE:單端開源模式(線或)
2.2 代碼中如何讓獲取&配置GPIO?
代碼中如何讓獲取&配置GPIO?
gpio及其配置更多時候是作為某個節點的屬性出現,如button節點的GPIO屬性,led節點的gpio屬性;spi的cs-gpio屬性等等
spi@abcd0001 {
cs-gpios = <&gpio0?1?GPIO_ACTIVE_LOW>;
spidev: spi-device@0 { ... };
};
buttons {
compatible ="gpio-keys";
button0: button_0{
gpios = < &gpio1?0xd0x11 >;
label ="Push button 0";
zephyr,code = 0xb?>;
};
button1: button_1 { ...};
nrf52840_reset: gpio-reset{
compatible ="nordic,nrf9160dk-nrf52840-reset";
status ="disabled";
gpios = < &interface_to_nrf52840?0x90x1 >;
};
aliases {
led00= &led0;
pwm-led0= &pwm_led1;
sw0= &button0;
};
spi@abcd0001, buttons, button_0, button_1, gpio-reset為devicetree中的節點名(node name)
button0,button1,nrf52840_reset,為節點的標簽(LABEL)
led00, pwm-led0,sw0為節點的別名(ALIAS)
對于GPIO的應用,也可以系統預留給用戶自定義的節點(zephyr,user)中將其定義為屬性:
/{
zephyr,user{
my-gpios = <&gpio0?12? ? (GPIO_ACTIVE_HIGH|GPIO_PUSH_PULL|GPIO_PULL_DOWN)>;
};
};
2.2.1.獲取節點描述符node specifier,
即node_id
參考文件:
ncs/zephyr/doc/build/dts/api-usage.rst
通過標簽獲取:DT_NODELABEL()
通過別名獲取:
DT_ALIAS(sw0);DT_ALIAS(led00) //sw0,led00分別為button0,led0的別名
通過絕對路徑獲取:
DT_PATH(zephyr_user);DT_PATH(leds);DT_PATH(soc,gpio_50400)
通過實體編號獲取:DT_INST()
通過被選取的節點chosen node獲取:
DT_CHOSEN()
通過父節點/子節點獲取:
DT_PARENT(); DT_CHILD() ;
通過node2及其phandle屬性獲取node1的節點描述符: node1=DT_PHANDLE(node2, prop)
- DT_PATH(zephyr_user, i2c_40002000) - DT_NODELABEL(i2c1) - DT_ALIAS(sensor_controller) - DT_INST(x, vnd_soc_i2c)
2.2.2通過節點將gpio配置(屬性)讀取至特定結構體中
gpio_dt_sepc my_gpio=GPIO_DT_SPEC_GET(DT_PATH(zephyr_user), my_gpios)
gpio_dt_specmyled=GPIO_DT_SPEC_GET(DT_ALIAS(led0), gpios);//節點id,屬性名
gpio_dt_specmybutton=GPIO_DT_SPEC_GET_OR(DT_ALIAS(sw0), gpios,{0});// 節點id,屬性名,默認值
以上是gpio-button作為特殊設備的直接獲取方式,對于一般的外設如uart/spi等,可以用DEVICE_DT_GET()獲取設備。
2.2.3.重新配置gpio參數
GPIO的默認配置來源于devicetree,我們可以用以下方式覆蓋默認配置:
參考文檔:
2.8.0/zephyr/include/zephyr/drivers/gpio.h
a.配置輸入輸出:
gpio_pin_configure_dt(&mybutton, GPIO_INPUT); gpio_pin_configure_dt(&myled, GPIO_OUTPUT);
b.設置/獲取IO口狀態
gpio_pin_toggle_dt(&myled); gpio_pin_get_dt(&mybutton); gpio_pin_set_dt(&myled,1);
c.配置中斷
gpio_pin_interrupt_configure_dt() gpio_init_callback(&button_cb_data, button_pressed, BIT(button.pin)); gpio_add_callback_dt() => gpio_add_callback(spec->port, callback); gpio_add_callback(button.port, &button_cb_data);
d.其他配置
gpio_remove_callback_dt() gpio_get_pending_int()
GPIO & GPIOTE Event
gpio作為通用輸入輸出端口,用來對IO口進行讀寫和清空等操作,能通過配置+檢測管腳的電平產生中斷,也可以被其他外設配置和使用。GPIO模塊的重要功能:
sense:系統進入sleep模式后(也稱system OFF模式),只能通過IO口等特殊喚醒源來喚醒并產生復位。
Detect:sense除了可以喚醒sleep模式,還可以用來產生中斷,即detect功能。DETECT類似一個中斷標志位,是每個端口所有IO口進行或操作的結果,所以DETECT信號狀態會受同一port下所有IO口的影響,只要有一個外部IO口有效,那么DETECT信號就一直為true,只有所有IO口狀態都clear時,DETECT信號才會重新變成低。
ncs底層提供了將GPIO配置成一個特殊gpio device(如button,led) ),以便而=對其進行中斷配置,通過gpio_dt_spec獲取其GPIO配置。
gpiote則是具有task/event 的外設,作用就是讓每個GPIO也具有傳統意義上的task和event的功能,gpiote外設使用GPIO后,將會覆蓋對GPIO直接的操作和配置。根據GPIO的特性,我們可以將GPIOTE的事件配置為PORT EVENT 和Pin EVENT。
PORT EVNET 是基于GPIO DETECT原理,是GPIO的sense特性,當所有外設和CPU都處于空閑狀態時,此功能可用于在System ON模式下將CPU從WFI或WFE類型睡眠中喚醒,這意味著在System ON模式下功耗最低.但可能檢測不到寬度僅為1us的脈沖(同一port上的任意pin腳都有可能使DETECT信號為高,產生PORT EVENT,,之后第二個pin上即便有SETECT信號變化也不再產生event,再次使用需要清空所有DETECT);
Pin EVENT是基于event中斷(電流相對于Port Event高),是將每個GPIO口的沿變化配置到不同的GPIOTE通道,各自觸發相應的IN EVENT,具有更高的事件精度。
GPIOTE輸入中斷,既可以是Pin Event,也可以用Port Event。FOR NRF54L15:
? GPIOTE20: 8 個channels 和 2 種中斷, 使用 GPIO port P1 ? GPIOTE30: 4 個channels 和 2 種中斷, 使用 GPIO port P0 ? 安全的GPIOTE通道可以配置安全和非安全的GPIO引腳 ? 非安全GPIOTE通道只能配置非安全GPIO引腳
3.1 GPIOTE Pin Event
GPIOTE Pin Event
ncs/zephyr/samples/basic/button展示的是GPIO Pin Event的配置方法
注意,不推薦拿這個代碼去處理button。因為這個是最底層的GPIO中斷,并沒有按鍵消抖功能,有button的應用需求可以用lbs里的button模塊來做,一般只需要簡單的引腳替換和硬件上細微改動。
3.2 GPIOTE PORT EVENT
GPIOTE PORT EVENT
Port Event的響應速度稍慢,但功耗會低15uA。如果要使用更低功耗的Port Event,可以作如下擇一選擇
3.2.1.在DeviceTree Overlay文件中,在對應的GPIO Port的節點中,設置一個`sense-edge-mask`屬性,把所有需要使用Port Event的引腳的對應bit設為1即可,例如:
如果是nRF54L15中button0和button1分別使用P1.13(0xd)和P1.09(0x9),可以在app.overlay中加如下配置將這兩個引腳配置為port event,其余gpio button為Pin EVENT:
&gpio1 {
sense-edge-mask = <(BIT(13)|BIT(9))>;
};
二進制展開為0010 0010 0000 0000,十六進制為0x2200,因此也可以表達為:
&gpio1 {
sense-edge-mask = <0x2200>;
};
*BIT(13)的意思就是`0x00000001<<13`。
3.2.2.參考lbs的例程中app_button的用法對GPIO口進行配置
app_button/lbs檢測button信號分為兩個階段
a.掃描模式
Module starts in scanning mode and will switch to callback mode if no button is pressed.
模塊以掃描模式啟動,如果掃描模式期間沒約發現button GPIO口電平變化(即按下按鈕),軟件將切換到事件中斷(回調)模式。
b.事件中斷模式,
app_button進入事件中斷模式后,功耗也會隨之降下來,并低于15uA。
參考app_button/lbs的配置,即使我們不修改devicetree, 也能將GPIO button功能模塊配置成port event狀態,如:
gpio_flags_tflags = button.dt_flags & GPIO_ACTIVE_LOW ? GPIO_PULL_UP : GPIO_PULL_DOWN; ret= gpio_pin_configure_dt(&button, GPIO_INPUT | flags); ret= gpio_pin_interrupt_configure_dt(&button,GPIO_INT_LEVEL_ACTIVE);
3.3
nRF54L15 GPIO休眠功耗
(Power Monitor for nRF54L15 GPIO event Wake UP)
3.3.1.Pin Event ppk2波形圖

3.3.2.Port Event ppk2波形圖

3.3.3.System OFF ppk2波形圖

nRF54L15 進入system off前需要關閉不使用的RAM
#ifdefCONFIG_SOC_NRF54L15_CPUAPP /* Disable RAM retention in System OFF as it is not utilized by this sample. */ uint32_tram_sections =8; nrf_memconf_ramblock_ret_mask_enable_set(NRF_MEMCONF,0,BIT_MASK(ram_sections),false); nrf_memconf_ramblock_ret2_mask_enable_set(NRF_MEMCONF,0, BIT_MASK(ram_sections),false); #endif sys_poweroff();
將特殊GPIOs 配置為通用 GPIOs
4.1
NFC pin 作為通用 GPIO
在NCSv2.8.0,在device tree overlay中修改UICR配置:
&uicr {
nfct-pins-as-gpios;
};
添加后,系統啟動時會自動擦寫、配置UICR。
4.2
RESET PIN 作為通用 GPIO
對于nRF54L15,nRESET是Pin Reset專用pin. 查datasheet上可知,芯片并未為其分配作為通用GPIO口的Port和Pin number,nrf5340也是如此。
對于nrf52系列,可以通過ncs代碼將nReset配置為通用GPIO口。其中:
nRF52805/52810/52811/52832對應GPIO口P0.21
nRF52820/52833/52840對應GPIO口P0.18
拿nrf52840 nreset舉例,PSELRESET[0]和PSELREET[1]的值都是PIN=18,PORT=0,CONNECT=0的情況下,P0.18才會作為Reset引腳使用。否則,P0.18作為普通GPIO使用。Reset信號無法映射到其他GPIO。將nrf52的NReset pin配置為通用GPIO只需在devicetree中加如下代碼:
&uicr{
/delete-property/gpio-as-nreset;
};
VS Code默認的燒錄(west flash 燒錄)會將pin reset打開導致程序里面刪掉的UICR pin reset失效(相當于寫了值到UICR)
4.3
低頻晶振引腳XL1 XL2
作為通用 GPIO
4.3.1 對于 nrf52840/nrf53,P0.00/P0.01為XL1 XL2
a. CONFIG_CLOCK_CONTROL_NRF_K32SRC_RC=y
b.devicetree 修改
&gpio1 {
gpio-reserved-ranges = < 0x60x1 >, < 0x80x3 >, < 0x110x7 >;
/*去除XL1,XL2描述,可選項*/
gpio-line-names ="AREF","A0","A1","RTS","TXD","CTS","RXD","NFC1","NFC2","BUTTON1","BUTTON2","LED1","LED2","LED3","LED4","QSPI CS","RESET","QSPI CLK","QSPI DIO0","QSPI DIO1","QSPI DIO2","QSPI DIO3","BUTTON3","BUTTON4","SDA","SCL","A2","A3","A4","A5";
};
4.3.2 對于nRF54L15,P1.00/P1.01 為XL1 XL2
CONFIG_CLOCK_CONTROL_NRF_K32SRC_RC=y
其他外設對GPIO的復用
A. Nordic nRF54L15給外設配置GPIO時,原則上是使用自己域內的IO口,同時需參考datasheet和nRF54L15DK的配置。外設的gpio配置可以自動覆蓋(Override)GPIO的原來的輸入輸出方向、輸出值等配置。

B.peripheral 域(APB10,APB20,APB30)內的串行數據接口外設可以自由使用自己域內通用GPIO口
C. Port2(APB00)上的dedicated pins可以被peripheral 域內的串行數據接口如SPIM/SPIS/UARTE使用,但是僅限于P2內的dedicated Pin(參考Pin Assignment Table),比如:
a.Peripheral域內的SPI PSEL.MOSI可以使用P2 MOSI,但不能使用其他P2的其他GPIO
b.由于P2上沒有TWI 的dedicated pin,所以periperal 區域的TWI不能跨域使用P2 GPIO
D. Nordic54L給外設配置GPIO時,外設時鐘有專用GPIO口:

下圖中紅色GPIO口可用于時鐘。

-
總線
+關注
關注
10文章
3047瀏覽量
91756 -
端口
+關注
關注
4文章
1107瀏覽量
34004 -
GPIO
+關注
關注
16文章
1330瀏覽量
56329
原文標題:【儒卓力為您帶來Nordic博文分享系列】簡化設計,提升性能:nRF54L15 GPIO解析
文章出處:【微信號:儒卓力,微信公眾號:儒卓力】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
基于nRF54L15為核心的模組方案PTR5415
深入比較nRF52832和Nordic新的產品nRF54L15參數對比
NRF54L15藍牙模組性能與場景應用
深入比較nRF52832和Nordic新的產品nRF54L15參數對比
Nordic最新開發工具nRF54L15 DK
NRF54L15的NORDIC芯片,adc的內部參考電壓
使用nrf54L15的NORDIC藍牙芯片,通過串口發送一幀數據包時,會出現分包發送分析
NORDIC藍牙芯片NRF54l15的dsp庫支持分享
突破性能邊界,重塑物聯網未來——NRF54L15芯片全面解析
超低功耗藍牙多協議模塊NRF54L15手冊
nRF54L15 # 超低功耗無線 SoC
nRF54L15 如何自動管理電源狀態
藍牙 SoC 選型看這篇!nRF52832/nRF54L15 各適配什么場景?
【深度解析】nRF54L15:低功耗藍牙5.3 SoC的破局之道與應用創新
Nordic nRF54L15 GPIO深度解析
評論