S32K144入门笔记(四):GPIO的解读

目录

1.概述

2.GPIO特性

2.1引脚中断

2.2数字输入滤波器 

 2.3端口控制

2.3.GPIO全局控制寄存器

3.相关的控制函数

3.1工具配置文件解读


1.概述

        S32K144共有5个GPIO的端口实例化,从GPIOA到GPIOE。地址映射如下:

图1 GPIO的地址映射
  • 内核访问GPIO端口是零等待的,它的寄存器可以通过8位、16位、32位操作访问。
  •  不论端口配置位数字输入还是数字输出,读取端口输入寄存器都会反应引脚当前的电平状态。
  • GPIO模块的时钟来源只有BUS_CLK。

         不同模式下的GPIO的操作和行为:

图2 不同模式下GPIO的操作和行为

         相关寄存器信息:

图3 GPIO相关寄存器信息

         有关寄存器的具体信息此处不再列出,参考手册中均有描述,也是比较简单,各个单片机都差不多。

2.GPIO特性

2.1引脚中断

  • 每个引脚均有中断标志位和使能寄存器
  • 每个引脚支持边沿检测和电平检测
  • 每个引脚均支持中断和DMA请求
  • 低功耗模式下的同步唤醒功能
  • 引脚中断在所有数字引脚的复用模式下有效

2.2数字输入滤波器 

  • 每个引脚的数字输入滤波器,可供任何复用到引脚上的数字外围设备使用
  • 每个引脚都有单独的启用或旁路控制字段
  • 有五位分辨率的数字输入滤波器的可选时钟源,用于设置滤波器大小
  • 适用于所有数字引脚多路复用模式

 2.3端口控制

  •  每个引脚均可以进行上拉、下拉、无上下拉设置
  • 可以设置强弱的两级控制,在不同供电电压下(3.3V、5V)输出能力有所不同,这一点在数据手册中有官方的测试数据。拉电流能力和灌电流能力均有所不同。
  • 支持启用和禁用单个输入无源滤波器的单个输入无源滤波字段
  • 支持模拟或引脚禁用、GPIO和多达六个芯片特定数字功能的独立多路复用器控制字段
  • 引脚控制字段在所有数字引脚的复用模式下有效

        特别注意:S32K144的数字输入寄存器不支持位寻址,所以在每次读取引脚输入寄存器时都是直接读取的整个GPIOx上的电平,如果想获取具体的引脚电平需要做数据的抽取。

2.3.GPIO全局控制寄存器

        这个特性比较有意思,GPIO的每个引脚都有两个全局引脚控制和全局中断控制。笔者一直使用SDK来配置引脚初始化,并没有太关注这个特性(在SDK中的代码粗略的看了一下,貌似没有启动该功能)。下面是手册中关于这个特性的描述。

        (1)全局引脚控制:全局引脚控制寄存器允许通过一次寄存器写入,以相同的值同时更新最多16个引脚的引脚控制寄存器的低半部分(低16位)。被锁定的寄存器无法通过全局引脚控制寄存器进行写入。

        全局引脚控制寄存器的设计目的是让软件能够快速将同一端口内的多个引脚配置为相同的外设功能。该寄存器是只写寄存器,总是读为0。

        (2)全局中断控制:这两个全局中断控制寄存器允许通过一次寄存器写入操作,以相同的值同时更新最多 16 个引脚的引脚控制寄存器高半部分(高16位)。

        全局中断控制寄存器的设计目的是让软件能够快速将同一端口内的多个引脚配置为相同的中断参数(如触发方式、优先级等)。但引脚控制功能(如复用模式、上下拉等)无法通过这些全局中断控制寄存器进行配置。该寄存器是只写寄存器,总是读为0。

3.相关的控制函数

        由于在第二篇中已经算是接触过GPIO,当时是开启了时钟输出引脚的功能,当使用配置工具进行配置时,只需要初始化GPIO即可实现功能。本文主要讲解SDK库中GPIO部分代码的结构以及相关函数的功能(具体的工具配置比较简单,即在配置工具上勾选需要的功能就行,这里就略过)。

3.1工具配置文件解读

        在工具生成的文件中,配置代码全部放在pin_mux.c和pin_mux.h中,笔者举例一个配置文件如下:

#ifndef _PIN_MUX_H_
#define _PIN_MUX_H_

#include "pins_driver.h"

/***********************************************************************************************************************
 * Definitions
 **********************************************************************************************************************/

/*!
 * @addtogroup pin_mux
 * @{
 */

/***********************************************************************************************************************
 * API
 **********************************************************************************************************************/

#if defined(__cplusplus)
extern "C" {
#endif


/*! @brief Definitions/Declarations for BOARD_InitPins Functional Group */
/*! @brief User definition pins */
#define LED_RED_PORT    PTD
#define LED_RED_PIN     15U
#define BTN1_PORT    PTC
#define BTN1_PIN     13U
/*! @brief User number of configured pins */
#define NUM_OF_CONFIGURED_PINS0 2
/*! @brief User configuration structure */
extern pin_settings_config_t g_pin_mux_InitConfigArr0[NUM_OF_CONFIGURED_PINS0];


#if defined(__cplusplus)
}
#endif

/*!
 * @}
 */
#endif /* _PIN_MUX_H_ */

/***********************************************************************************************************************
 * EOF
 **********************************************************************************************************************/

        在上述代码中,笔者配置了两个GPIO,分别位PTD15和PTC13,配置代码会以宏定义的方式重新定义GPIO的端口和引脚,笔者这里是LED_RED_PORT、LED_RED_PIN和BTN1_PORT、BTN1_PIN。

        GPIO的具体寄存器的配置是使用了结构体数组的方式来定义,上述代码中是

extern pin_settings_config_t g_pin_mux_InitConfigArr0[NUM_OF_CONFIGURED_PINS0];

        这个结构体数据在.h文件中声明位全局变量,在.c文件中定义具体的内容,结构体数组的大小NUM_OF_CONFIGURED_PINS0是用户具体配置多少个PIN,每个PIN的配置都是独立的配置结构体,.c中的代码如下:

#include "pin_mux.h"

/* clang-format off */
/*
 * TEXT BELOW IS USED AS SETTING FOR TOOLS *************************************
BOARD_InitPins:
- options: {callFromInitBoot: 'true', coreID: core0}
- pin_list:
  - {pin_num: '22', peripheral: PORTD, signal: 'port, 15', pin_signal: PTD15, direction: OUTPUT, initValue: state_1}
  - {pin_num: '49', peripheral: PORTC, signal: 'port, 13', pin_signal: PTC13, identifier: BTN1, direction: INPUT, initValue: state_1}
 * BE CAREFUL MODIFYING THIS COMMENT - IT IS YAML SETTINGS FOR TOOLS ***********
 */
/* clang-format on */

/* Generate array of configured pin structures */
pin_settings_config_t g_pin_mux_InitConfigArr0[NUM_OF_CONFIGURED_PINS0] = {
    {
        .base            = PORTC,
        .pinPortIdx      = 13U,
        .pullConfig      = PORT_INTERNAL_PULL_NOT_ENABLED,
        .driveSelect     = PORT_LOW_DRIVE_STRENGTH,
        .passiveFilter   = false,
        .mux             = PORT_MUX_AS_GPIO,
        .pinLock         = false,
        .intConfig       = PORT_DMA_INT_DISABLED,
        .clearIntFlag    = false,
        .gpioBase        = PTC,
        .direction       = GPIO_INPUT_DIRECTION,
        .digitalFilter   = false,
        .initValue       = 1U,
    },
    {
        .base            = PORTD,
        .pinPortIdx      = 15U,
        .pullConfig      = PORT_INTERNAL_PULL_NOT_ENABLED,
        .driveSelect     = PORT_LOW_DRIVE_STRENGTH,
        .passiveFilter   = false,
        .mux             = PORT_MUX_AS_GPIO,
        .pinLock         = false,
        .intConfig       = PORT_DMA_INT_DISABLED,
        .clearIntFlag    = false,
        .gpioBase        = PTD,
        .direction       = GPIO_OUTPUT_DIRECTION,
        .digitalFilter   = false,
        .initValue       = 1U,
    },
};

        配置参数有了,要想使用GPIO的功能就需要使用函数来驱动,GPIO的操作函数哎pin_driver.h文件中声明,常用到的函数如下:

//此函数用于初始化所有的GPIO配置,参数是引脚数和配置参数结构体数据的首地址
status_t PINS_DRV_Init(uint32_t pinCount,
                       const pin_settings_config_t config[]);
//向一个PIN写入电平值
void PINS_DRV_WritePin(GPIO_Type * const base,
                       pins_channel_type_t pin,
                       pins_level_type_t value);
//读取一个端口的所有引脚电平
pins_channel_type_t PINS_DRV_ReadPins(const GPIO_Type * const base);
//反转引脚电平(可以多个)
void PINS_DRV_TogglePins(GPIO_Type * const base,
                         pins_channel_type_t pins);
//置位引脚电平
void PINS_DRV_SetPins(GPIO_Type * const base,
                      pins_channel_type_t pins);
//清零引脚电平
void PINS_DRV_ClearPins(GPIO_Type * const base,
                        pins_channel_type_t pins);

        其他更多的函数可以在pin_driver.h文件中找到函数声明,NXP的SDK命名规则还是很容易理解的。

### S32K 微控制器 GPIO 唤醒实现方法 对于S32K系列微控制器而言,在低功耗模式下通过外部事件触发唤醒是一项重要功能。为了使能并配置GPIO作为唤醒源,开发者需遵循特定流程来设置相应的寄存器和初始化外设。 #### 配置步骤概述 在进入等待中断状态之前,应当先设定好哪些引脚可以用来产生唤醒信号。这涉及到修改端口控制模块中的相应位以允许指定的输入引脚响应边沿变化而引发系统退出待机模式[^1]。 具体来说: - **启用时钟供应给相关外围设备** 确认PORTE时钟已开启以便访问其下的各个子部件。 - **选择合适的上拉/下拉电阻** 对于那些用于检测电平跳变从而引起唤醒动作的目标管脚,合理配置内部上下拉有助于提高抗干扰能力以及确保正常运作。 - **定义边缘敏感特性** 设置PTX_PCRy[ISF]字段决定是上升沿还是下降沿能够激活唤醒机制;同时清除任何现存的状态标志以防误操作。 - **注册回调函数处理程序** 当发生由选定IO线引起的事件后,应用程序层面上应有对应的逻辑去应对这种情形的发生。 以下是基于上述原则编写的一段C语言示范代码片段展示如何完成这些任务: ```c #include "fsl_port.h" #include "fsl_gpio.h" void setupGpioWakeUp(void){ /* Enable clock for PORT and configure pin as input */ CLOCK_EnableClock(kCLOCK_PortE); port_pin_config_t config = {0}; config.pullSelect = kPORT_PullDown; // Set pull-down resistor PORT_SetPinConfig(PORTE, 7U, &config); // Configure PE7 as wakeup source with pulldown enabled. /* Select the edge that triggers wake-up event */ GPIO_PinInit(GPIOE, 7U, &(gpio_pin_config_t){kGPIO_DigitalInput}); GPIO_WritePinOutput(GPIOE, 7U, 0U); /* Clear any existing flag before enabling interrupts */ GPIO_ClearPinsInterruptFlags(GPIOE, 1U << 7U); } ``` 此部分实现了基本的功能需求——即让PE7成为有效的唤醒源之一,并且当该针脚经历一次高到低的变化过程时就会促使MCU脱离休眠态回到活动周期内继续执行后续指令序列。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值