KV58 Note 01 有关GPIO

GPIO "Chapter 55 General-Purpose Input/Output (GPIO)" 通用输入/输出接口

在官方库<MKV58F42.h>中,对于GPIO寄存器的定义:

/* ----------------------------------------------------------------------------
   -- GPIO Peripheral Access Layer
   ---------------------------------------------------------------------------- */
/*!
 * @addtogroup GPIO_Peripheral_Access_Layer GPIO Peripheral Access Layer
 */
/**GPIO - Register Layout Typedef */
typedef struct {
  __IO uint32_t PDOR;                              /**< Port Data Output Register, offset: 0x0 */
  __O  uint32_t PSOR;                              /**< Port Set Output Register, offset: 0x4 */
  __O  uint32_t PCOR;                              /**< Port Clear Output Register, offset: 0x8 */
  __O  uint32_t PTOR;                              /**< Port Toggle Output Register, offset: 0xC */
  __I  uint32_t PDIR;                              /**< Port Data Input Register, offset: 0x10 */
  __IO uint32_t PDDR;                              /**< Port Data Direction Register, offset: 0x14 */
} GPIO_Type;

GPIO分多个通道,GPIOA~GPIOE。
根据KV5x系列参考手册 "55.3 Memory map and register definition"(P1837)。
GPIO每个通道按顺序有寄存器PDOR,PSOR,PCOR,PTOR,PDIR,PDDR,每个寄存器长度为32bits,且地址连续。
其中PDOR的地址即为该通道的基址。

/* GPIO - Peripheral instance base addresses */
/** Peripheral GPIOA base address */
#define GPIOA_BASE                               (0x400FF000u)
/** Peripheral GPIOA base pointer */
#define GPIOA                                    ((GPIO_Type *)GPIOA_BASE)

将GPIOx的基址直接强制类型转换为GPIO寄存器结构体的首地址,即为PDOR的地址。
该宏定义方式,将宏GPIOx变为一种指向对应GPIO通道寄存器内存空间的方式。
因此在点亮PTC0管脚的LED时,将GPIO设置为输出低电平的程序中:

<pin_mux.h>
#define BOARD_INITPINS_LED0_PIN 0U                             /*!<@brief PORTC pin index: 0 */
#define BOARD_INITPINS_LED0_PORT PORTC                         /*!<@brief PORT device name: PORTC */
<main.c>
#define LED(output)\
	GPIO_PinWrite(BOARD_INITPINS_LED0_PORT, BOARD_INITPINS_LED0_PIN,output);\
	GPIOC->PDDR |= (1U << BOARD_INITPINS_LED0_PIN);
<fsl_gpio.h>
/*!
 * @brief Sets the output level of the multiple GPIO pins to the logic 1 or 0.
 *
 * @param base    GPIO peripheral base pointer (GPIOA, GPIOB, GPIOC, and so on.)
 * @param pin     GPIO pin number
 * @param output  GPIO pin output logic level.
 *        - 0: corresponding pin output low-logic level.
 *        - 1: corresponding pin output high-logic level.
 */
static inline void GPIO_PinWrite(GPIO_Type *base, uint32_t pin, uint8_t output)
{
	if (output == 0U)
	{
		base->PCOR = 1U << pin;
	}
	else
	{
		base->PSOR = 1U << pin;
	}
}

PDOR "55.3.1 Port Data Output Register (GPIOx_PDOR)" 定义的是GPIO整个通道的输出。
PSOR "55.3.2 Port Set Output Register (GPIOx_PSOR)" 置0不变,置1输出高电平。
PCOR "55.3.3 Port Clear Output Register (GPIOx_PCOR)" 置0不变,置1输出低电平。
一般来说操作PDOR比较复杂,因此通过PSOR和PCOR来控制输出更加高效。
PDDR "55.3.6 Port Data Direction Register (GPIOx_PDDR)" 置0则为GPI,置1则为GPO。

龙邱给出的库将寄存器结构体重新定义为共用体(union),以实现更加便捷的GPIO宏:

typedef struct GPIO_MemMap
{
	union
	{
		uint32_t PDOR;                                   /**< Port Data Output Register, offset: 0x0 */
		struct                                           
		{
			uint32_t PDOR0 : 1;
			uint32_t PDOR1: 1;
			uint32_t PDOR2 : 1;
			uint32_t PDOR3 : 1;
			uint32_t PDOR4 : 1;
			uint32_t PDOR5 : 1;
			uint32_t PDOR6 : 1;
			uint32_t PDOR7 : 1;
			uint32_t PDOR8 : 1;
			uint32_t PDOR9 : 1;
			uint32_t PDOR10: 1;
			uint32_t PDOR11: 1;
			uint32_t PDOR12: 1;
			uint32_t PDOR13: 1;
			uint32_t PDOR14: 1;
			uint32_t PDOR15: 1;
			uint32_t PDOR16: 1;
			uint32_t PDOR17: 1;
			uint32_t PDOR18: 1;
			uint32_t PDOR19: 1;
			uint32_t PDOR20: 1;
			uint32_t PDOR21: 1;
			uint32_t PDOR22: 1;
			uint32_t PDOR23: 1;
			uint32_t PDOR24: 1;
			uint32_t PDOR25: 1;
			uint32_t PDOR26: 1;
			uint32_t PDOR27: 1;
			uint32_t PDOR28: 1;
			uint32_t PDOR29: 1;
			uint32_t PDOR30: 1;
			uint32_t PDOR31: 1;
		} PDORs;
		struct                                            
		{
			uint8_t Byte0;
			uint8_t Byte1;
			uint8_t Byte2;
			uint8_t Byte3;
		} PDORByte;
		struct                                            
		{
			uint16_t Word0;
			uint16_t Word1;
		} PDORWord;
	};
	uint32_t PSOR;                                   /**< Port Set Output Register, offset: 0x4 */
	uint32_t PCOR;                                   /**< Port Clear Output Register, offset: 0x8 */
	uint32_t PTOR;                                   /**< Port Toggle Output Register, offset: 0xC */
	union
	{
		uint32_t PDIR;                                   /**< Port Data Input Register, offset: 0x10 */
		struct                                            
		{
			uint32_t PDIR0 : 1;
			uint32_t PDIR1: 1;
			uint32_t PDIR2 : 1;
			uint32_t PDIR3 : 1;
			uint32_t PDIR4 : 1;
			uint32_t PDIR5 : 1;
			uint32_t PDIR6 : 1;
			uint32_t PDIR7 : 1;
			uint32_t PDIR8 : 1;
			uint32_t PDIR9 : 1;
			uint32_t PDIR10: 1;
			uint32_t PDIR11: 1;
			uint32_t PDIR12: 1;
			uint32_t PDIR13: 1;
			uint32_t PDIR14: 1;
			uint32_t PDIR15: 1;
			uint32_t PDIR16: 1;
			uint32_t PDIR17: 1;
			uint32_t PDIR18: 1;
			uint32_t PDIR19: 1;
			uint32_t PDIR20: 1;
			uint32_t PDIR21: 1;
			uint32_t PDIR22: 1;
			uint32_t PDIR23: 1;
			uint32_t PDIR24: 1;
			uint32_t PDIR25: 1;
			uint32_t PDIR26: 1;
			uint32_t PDIR27: 1;
			uint32_t PDIR28: 1;
			uint32_t PDIR29: 1;
			uint32_t PDIR30: 1;
			uint32_t PDIR31: 1;
		} PDIRs;
		struct                                           
		{
			uint8_t Byte0;
			uint8_t Byte1;
			uint8_t Byte2;
			uint8_t Byte3;
		} PDIRByte;
		struct                                           
		{
			uint16_t Word0;
			uint16_t Word1;
		} PDIRWord;
	};
	union
	{
		uint32_t PDDR;                                   /**< Port Data Direction Register, offset: 0x14 */
		struct                                            
		{
			uint32_t DDR0 : 1;
			uint32_t DDR1: 1;
			uint32_t DDR2 : 1;
			uint32_t DDR3 : 1;
			uint32_t DDR4 : 1;
			uint32_t DDR5 : 1;
			uint32_t DDR6 : 1;
			uint32_t DDR7 : 1;
			uint32_t DDR8 : 1;
			uint32_t DDR9 : 1;
			uint32_t DDR10: 1;
			uint32_t DDR11: 1;
			uint32_t DDR12: 1;
			uint32_t DDR13: 1;
			uint32_t DDR14: 1;
			uint32_t DDR15: 1;
			uint32_t DDR16: 1;
			uint32_t DDR17: 1;
			uint32_t DDR18: 1;
			uint32_t DDR19: 1;
			uint32_t DDR20: 1;
			uint32_t DDR21: 1;
			uint32_t DDR22: 1;
			uint32_t DDR23: 1;
			uint32_t DDR24: 1;
			uint32_t DDR25: 1;
			uint32_t DDR26: 1;
			uint32_t DDR27: 1;
			uint32_t DDR28: 1;
			uint32_t DDR29: 1;
			uint32_t DDR30: 1;
			uint32_t DDR31: 1;
		} DDRs;
		struct                                           
		{
			uint8_t Byte0;
			uint8_t Byte1;
			uint8_t Byte2;
			uint8_t Byte3;
		} DDRByte;
		struct                                           
		{
			uint16_t Word0;
			uint16_t Word1;
		} DDRWord;
	};
} volatile GPIO_Type,*GPIO_MemMapPtr;

PDOR、PDIR和PDDR均使用union声明了一个32bits的空间,支持按位、八位一组、十六位一组的寄存器操作。
另外结构体声明中例如:

uint32_t DDR31: 1;

冒号表示位域,意味着DDR31虽然定义为uint32_t,但实际内存空间只占1bit,DDR0~DDR31恰好32位。
注意位域的具体使用方式。
龙邱的宏具体实现:

<MKV58F42.h>
/** Peripheral GPIOA base address */
#define GPIOA_BASE                               (0x400FF000u)
/** Peripheral GPIOA base pointer */
#define GPIOA                                    ((GPIO_Type *)GPIOA_BASE)
#define GPIOA_BASE_PTR                           (GPIOA)
<gpio_cfg.h>
//定义PTA的输出
#define PTA0_OUT     GPIOA_BASE_PTR->PDORs.PDOR0
//定义PTA的输出输入方向 
#define DDRA0       GPIOA_BASE_PTR->DDRs.DDR0
//定义PTA的输入端口  
#define PTA0_IN     GPIOA_BASE_PTR->PDIRs.PDIR0
//定义PTA的8位端口  
#define PTA_BYTE0_OUT   GPIOA_BASE_PTR->PDORByte.Byte0
//定义PTA的8位输出输入方向  
#define DDRA_BYTE0   GPIOA_BASE_PTR->DDRByte.Byte0
//定义PTA的8位输入端口  
#define PTA_BYTE0_IN   GPIOA_BASE_PTR->PDIRByte.Byte0
//定义PTA的16位端口  
#define PTA_WORD0_OUT   GPIOA_BASE_PTR->PDORWord.Word0
//定义PTA的16位输出输入方向  
#define DDRA_WORD0   GPIOA_BASE_PTR->DDRWord.Word0
//定义PTA的16位输入端口  
#define PTA_WORD0_IN   GPIOA_BASE_PTR->PDIRWord.Word0

龙邱GPIO库中:

void GPIO_Init (GPIO_Type* port, int index, GPIO_CFG dir,int data)
if(dir == 1)//output
{
	GPIO_PDDR_REG(port) |= (1<<index);
	if(data == 1)//output
		GPIO_PDOR_REG(port) |= (1<<index);
	else
		GPIO_PDOR_REG(port) &= ~(1<<index);
}
else
	GPIO_PDDR_REG(port) &= ~(1<<index);

用的是直接控制PDOR的方式操作输出

相关:
<1>GPIO模块以及其他模块使用前都需要开启该模块时钟,详见SIM
<2>管脚启用GPIO同样需要为其设置管脚复用,详见PORT