zedboard第二十四課(standaloneOS , BSP DEVICE DRIVER ,API模塊架構)

我們已經學習了關於如何使用SDK提供的DRIVER的API,控制zynq上的外設,本文思考API的模塊架構,以及編程思想。
首先來看SOD設計思想的幾個重要原則。

1)結構體對象抽象,數據整合,封裝。
對於我們所要描述的硬件資源, 抽象成RDB。對於所要控制的外設,抽象成RCB。

2)數據與函數分離。
函數的TEXT中,不允許直接出現硬數據,而只應該使用傳入的參數。
尤其是不能直接出現常數。
所以,需要實現,

常數符號化,常數成員化。

在函數中,不允許直接在代碼中出現硬數字,這是不可移植的。
第一級硬數字軟化,就是將常數定義成宏,即,常數符號化。
第二級硬數字軟化,就是將所需要在代碼中使用的常數,定義爲RCB的一個數據成員,使用時,通過RCB,找到這個成員,並取用成員的值。
第三級硬數字軟化,就是將所需要在代碼中使用的常數,定義爲RCB的一個數據成員,並設計對應的GET類API。使用時,利用GET類API,獲取成員的值,而不是直接尋址RCB的成員。

3)數據訪問函數化,符號化。
程序編寫時,如果涉及到訪問對象的數據成員,儘量不要使用直接尋址的方式。而應該設計對應的GET類和SET類API。
如果需要修改某個數據成員的值,就調用對應的SET類API。
如果需要獲取某個數據成員的值,就調用對應的GET類API。

4)操作函數分層。
在設計API時,應該分層設計位於不同調用層次的API,讓不同的層次的API完成更具體更清晰的任務。

主要有,
業務與操作分層,
操作與控制分層,
控制與時序分層等。

業務層,主要是面向應用程序,爲應用程序提供服務接口,它提供粒度最大的操作流程。聚焦於如何爲應用程序提供數據傳輸服務。
操作層,主要是面向業務層,爲業務層的操作函數提供接口,它聚焦於如何爲業務層提供數據IO操作。
控制層,主要是面向操作層,爲操作層的操作函數提供接口,它聚焦於如何將操作層的數據IO請求,轉化爲命令流。
時序層,主要是面向控制層,爲控制層的操作函數提供接口,它聚焦於如何將控制層的命令,轉化爲硬件寄存器訪問流。

5) 函數接口分組分隔,
爲了給應用程序提供不同的功能服務,可以設置多組不同的函數接口。
它們通常位於業務層,給應用程序提供定製化的服務,但是它們也需要使用下層,例如操作層,提供的公共服務。

下面來看看,GPIOPS這個模塊,是如何設計API的。
H文件和C文件分離。
H文件用來進行數據定義,函數接口聲明。
C文件用來進行數據實例化,函數定義。

首先來看看,最主要的H文件。xgpiops.h。
它定義了RCB和RDB。並將RCB設計爲內嵌RDB的形式。
這是對象抽象思想的體現。

typedef struct {
	u16 DeviceId;		/**< Unique ID of device */
	u32 BaseAddr;		/**< Register base address */
} XGpioPs_Config;

typedef struct {
	XGpioPs_Config GpioConfig;	/**< Device configuration */
	u32 IsReady;			/**< Device is initialized and ready */
	XGpioPs_Handler Handler;	/**< Status handlers for all banks */
	void *CallBackRef; 		/**< Callback ref for bank handlers */
	u32 Platform;			/**< Platform data */
	u32 MaxPinNum;			/**< Max pins in the GPIO device */
	u8 MaxBanks;			/**< Max banks in a GPIO device */
} XGpioPs;

typedef void (*XGpioPs_Handler) (void *CallBackRef, u32 Bank, u32 Status);

它將大量的常數定義成了宏,
這是硬數字軟件思想的體現。

#define XGPIOPS_DEVICE_MAX_PIN_NUM	(u32)118
#define XGPIOPS_BANK_MAX_PINS		(u32)32 /**< Max pins in a GPIO bank */
#define XGPIOPS_BANK0			0x00U  /**< GPIO Bank 0 */
#define XGPIOPS_BANK1			0x01U  /**< GPIO Bank 1 */
#define XGPIOPS_BANK2			0x02U  /**< GPIO Bank 2 */
#define XGPIOPS_BANK3			0x03U  /**< GPIO Bank 3 */

#define XGPIOPS_IRQ_TYPE_EDGE_RISING	0x00U  /**< Interrupt on Rising edge */
#define XGPIOPS_IRQ_TYPE_EDGE_FALLING	0x01U  /**< Interrupt Falling edge */
#define XGPIOPS_IRQ_TYPE_EDGE_BOTH	0x02U  /**< Interrupt on both edges */
#define XGPIOPS_IRQ_TYPE_LEVEL_HIGH	0x03U  /**< Interrupt on high level */
#define XGPIOPS_IRQ_TYPE_LEVEL_LOW	0x04U  /**< Interrupt on low level */

利用STI,對全局資源指針GRP的獲取函數,位於xgpiops_sinit.c中。
這體現了數據訪問函數化的思想。

extern XGpioPs_Config XGpioPs_ConfigTable[XPAR_XGPIOPS_NUM_INSTANCES];

XGpioPs_Config *XGpioPs_LookupConfig(u16 DeviceId)
{
	XGpioPs_Config *CfgPtr = NULL;
	u32 Index;

	for (Index = 0U; Index < (u32)XPAR_XGPIOPS_NUM_INSTANCES; Index++) {
		if (XGpioPs_ConfigTable[Index].DeviceId == DeviceId) {
			CfgPtr = &XGpioPs_ConfigTable[Index];
			break;
		}
	}

	return (XGpioPs_Config *)CfgPtr;
}

而全局資源描述塊GRDB的實例化,則位於xgpiops_g.c中。

XGpioPs_Config XGpioPs_ConfigTable[XPAR_XGPIOPS_NUM_INSTANCES] =
{
	{
		XPAR_PS7_GPIO_0_DEVICE_ID,
		XPAR_PS7_GPIO_0_BASEADDR
	}
};

它將操作函數函數進行分層,
寄存器讀寫層,位於xgpiops_hw.h中。
設備讀寫層,位於xgpiops.c中。
這是操作函數分層思想的體現。

#include "xgpiops_hw.h"
#define XGpioPs_ReadReg(BaseAddr, RegOffset)		\
		Xil_In32((BaseAddr) + (u32)(RegOffset))

#define XGpioPs_WriteReg(BaseAddr, RegOffset, Data)	\
		Xil_Out32((BaseAddr) + (u32)(RegOffset), (u32)(Data))

設備讀寫層,需要利用寄存器讀寫層提供的服務,
這體現了操作分層的思想。

u32 XGpioPs_Read(XGpioPs *InstancePtr, u8 Bank)
{
	return XGpioPs_ReadReg(InstancePtr->GpioConfig.BaseAddr,
				 ((u32)(Bank) * XGPIOPS_DATA_BANK_OFFSET) +
				 XGPIOPS_DATA_RO_OFFSET);
}

void XGpioPs_Write(XGpioPs *InstancePtr, u8 Bank, u32 Data)
{
	XGpioPs_WriteReg(InstancePtr->GpioConfig.BaseAddr,
			  ((u32)(Bank) * XGPIOPS_DATA_BANK_OFFSET) +
			  XGPIOPS_DATA_OFFSET, Data);
}

void XGpioPs_SetDirection(XGpioPs *InstancePtr, u8 Bank, u32 Direction)
{
	XGpioPs_WriteReg(InstancePtr->GpioConfig.BaseAddr,
			  ((u32)(Bank) * XGPIOPS_REG_MASK_OFFSET) +
			  XGPIOPS_DIRM_OFFSET, Direction);
}

u32 XGpioPs_GetDirection(XGpioPs *InstancePtr, u8 Bank)
{
	return XGpioPs_ReadReg(InstancePtr->GpioConfig.BaseAddr,
				((u32)(Bank) * XGPIOPS_REG_MASK_OFFSET) +
				XGPIOPS_DIRM_OFFSET);
}

void XGpioPs_SetOutputEnable(XGpioPs *InstancePtr, u8 Bank, u32 OpEnable)
{
	XGpioPs_WriteReg(InstancePtr->GpioConfig.BaseAddr,
			  ((u32)(Bank) * XGPIOPS_REG_MASK_OFFSET) +
			  XGPIOPS_OUTEN_OFFSET, OpEnable);
}

u32 XGpioPs_GetOutputEnable(XGpioPs *InstancePtr, u8 Bank)
{
	return XGpioPs_ReadReg(InstancePtr->GpioConfig.BaseAddr,
				((u32)(Bank) * XGPIOPS_REG_MASK_OFFSET) +
				XGPIOPS_OUTEN_OFFSET);
}

在寄存器讀寫層上,也可以另外封裝一套API,實現更具體,更復雜的操作功能。
這體現了函數接口分組分隔的思想。

void XGpioPs_GetBankPin(u8 PinNumber, u8 *BankNumber, u8 *PinNumberInBank)
{
	u32 XGpioPsPinTable[6] = {0};
	u32 Platform = XGetPlatform_Info();

	XGpioPsPinTable[0] = (u32)31; /* 0 - 31, Bank 0 */
	XGpioPsPinTable[1] = (u32)53; /* 32 - 53, Bank 1 */
	XGpioPsPinTable[2] = (u32)85; /* 54 - 85, Bank 2 */
	XGpioPsPinTable[3] = (u32)117; /* 86 - 117 Bank 3 */

	*BankNumber = 0U;
	while (*BankNumber < 4U) {
		if (PinNumber <= XGpioPsPinTable[*BankNumber]) {
			break;
		}
		(*BankNumber)++;
	}
		
	if (*BankNumber == (u8)0) {
		*PinNumberInBank = PinNumber;
	} else {
		*PinNumberInBank = (u8)((u32)PinNumber %
					(XGpioPsPinTable[*BankNumber - (u8)1] + (u32)1));
	}
}

u32 XGpioPs_ReadPin(XGpioPs *InstancePtr, u32 Pin)
{
	u8 Bank;
	u8 PinNumber;

	XGpioPs_GetBankPin((u8)Pin, &Bank, &PinNumber);

	return (XGpioPs_ReadReg(InstancePtr->GpioConfig.BaseAddr,
				 ((u32)(Bank) * XGPIOPS_DATA_BANK_OFFSET) +
				 XGPIOPS_DATA_RO_OFFSET) >> (u32)PinNumber) & (u32)1;

}
void XGpioPs_WritePin(XGpioPs *InstancePtr, u32 Pin, u32 Data)
{
	u32 RegOffset;
	u32 Value;
	u8 Bank;
	u8 PinNumber;
	u32 DataVar = Data;

	XGpioPs_GetBankPin((u8)Pin, &Bank, &PinNumber);

	if (PinNumber > 15U) {
		/* There are only 16 data bits in bit maskable register. */
		PinNumber -= (u8)16;
		RegOffset = XGPIOPS_DATA_MSW_OFFSET;
	} else {
		RegOffset = XGPIOPS_DATA_LSW_OFFSET;
	}

	DataVar &= (u32)0x01;
	Value = ~((u32)1 << (PinNumber + 16U)) & ((DataVar << PinNumber) | 0xFFFF0000U);
	XGpioPs_WriteReg(InstancePtr->GpioConfig.BaseAddr,
			  ((u32)(Bank) * XGPIOPS_DATA_MASK_OFFSET) +
			  RegOffset, Value);
}
void XGpioPs_SetDirectionPin(XGpioPs *InstancePtr, u32 Pin, u32 Direction)
{
	u8 Bank;
	u8 PinNumber;
	u32 DirModeReg;

	XGpioPs_GetBankPin((u8)Pin, &Bank, &PinNumber);

	DirModeReg = XGpioPs_ReadReg(InstancePtr->GpioConfig.BaseAddr,
				      ((u32)(Bank) * XGPIOPS_REG_MASK_OFFSET) +
				      XGPIOPS_DIRM_OFFSET);

	if (Direction!=(u32)0) { /*  Output Direction */
		DirModeReg |= ((u32)1 << (u32)PinNumber);
	} else { /* Input Direction */
		DirModeReg &= ~ ((u32)1 << (u32)PinNumber);
	}

	XGpioPs_WriteReg(InstancePtr->GpioConfig.BaseAddr,
			 ((u32)(Bank) * XGPIOPS_REG_MASK_OFFSET) +
			 XGPIOPS_DIRM_OFFSET, DirModeReg);
}

u32 XGpioPs_GetDirectionPin(XGpioPs *InstancePtr, u32 Pin)
{
	u8 Bank;
	u8 PinNumber;

	XGpioPs_GetBankPin((u8)Pin, &Bank, &PinNumber);

	return (XGpioPs_ReadReg(InstancePtr->GpioConfig.BaseAddr,
				 ((u32)(Bank) * XGPIOPS_REG_MASK_OFFSET) +
				 XGPIOPS_DIRM_OFFSET) >> (u32)PinNumber) & (u32)1;
}

void XGpioPs_SetOutputEnablePin(XGpioPs *InstancePtr, u32 Pin, u32 OpEnable)
{
	u8 Bank;
	u8 PinNumber;
	u32 OpEnableReg;

	XGpioPs_GetBankPin((u8)Pin, &Bank, &PinNumber);

	OpEnableReg = XGpioPs_ReadReg(InstancePtr->GpioConfig.BaseAddr,
				       ((u32)(Bank) * XGPIOPS_REG_MASK_OFFSET) +
				       XGPIOPS_OUTEN_OFFSET);

	if (OpEnable != (u32)0) { /*  Enable Output Enable */
		OpEnableReg |= ((u32)1 << (u32)PinNumber);
	} else { /* Disable Output Enable */
		OpEnableReg &= ~ ((u32)1 << (u32)PinNumber);
	}

	XGpioPs_WriteReg(InstancePtr->GpioConfig.BaseAddr,
			  ((u32)(Bank) * XGPIOPS_REG_MASK_OFFSET) +
			  XGPIOPS_OUTEN_OFFSET, OpEnableReg);
}
u32 XGpioPs_GetOutputEnablePin(XGpioPs *InstancePtr, u32 Pin)
{
	u8 Bank;
	u8 PinNumber;
	
	XGpioPs_GetBankPin((u8)Pin, &Bank, &PinNumber);

	return (XGpioPs_ReadReg(InstancePtr->GpioConfig.BaseAddr,
				 ((u32)(Bank) * XGPIOPS_REG_MASK_OFFSET) +
				 XGPIOPS_OUTEN_OFFSET) >> (u32)PinNumber) & (u32)1;
}

另外,我們可以看到,
這些函數,都是以GETSET開頭的,
這也體現了數據訪問函數化的思想。

模塊提供了另一套接口,用來進行INTR的控制。位於xgpiops_intr.c中。

void XGpioPs_IntrEnable(XGpioPs *InstancePtr, u8 Bank, u32 Mask)
{
	XGpioPs_WriteReg(InstancePtr->GpioConfig.BaseAddr,
			  ((u32)(Bank) * XGPIOPS_REG_MASK_OFFSET) +
			  XGPIOPS_INTEN_OFFSET, Mask);
}
void XGpioPs_IntrDisable(XGpioPs *InstancePtr, u8 Bank, u32 Mask)
{
	XGpioPs_WriteReg(InstancePtr->GpioConfig.BaseAddr,
			  ((u32)(Bank) * XGPIOPS_REG_MASK_OFFSET) +
			  XGPIOPS_INTDIS_OFFSET, Mask);
}

u32 XGpioPs_IntrGetEnabled(XGpioPs *InstancePtr, u8 Bank)
{
	u32 IntrMask;
	IntrMask = XGpioPs_ReadReg(InstancePtr->GpioConfig.BaseAddr,
				    ((u32)(Bank) * XGPIOPS_REG_MASK_OFFSET) +
				    XGPIOPS_INTMASK_OFFSET);
	return (~IntrMask);
}

u32 XGpioPs_IntrGetStatus(XGpioPs *InstancePtr, u8 Bank)
{
	return XGpioPs_ReadReg(InstancePtr->GpioConfig.BaseAddr,
				((u32)(Bank) * XGPIOPS_REG_MASK_OFFSET) +
				XGPIOPS_INTSTS_OFFSET);
}

void XGpioPs_IntrClear(XGpioPs *InstancePtr, u8 Bank, u32 Mask)
{
	XGpioPs_WriteReg(InstancePtr->GpioConfig.BaseAddr,
			  ((u32)(Bank) * XGPIOPS_REG_MASK_OFFSET) +
			  XGPIOPS_INTSTS_OFFSET, Mask);
}

void XGpioPs_SetIntrType(XGpioPs *InstancePtr, u8 Bank, u32 IntrType,
			  u32 IntrPolarity, u32 IntrOnAny)
{
	XGpioPs_WriteReg(InstancePtr->GpioConfig.BaseAddr,
			  ((u32)(Bank) * XGPIOPS_REG_MASK_OFFSET) +
			  XGPIOPS_INTTYPE_OFFSET, IntrType);

	XGpioPs_WriteReg(InstancePtr->GpioConfig.BaseAddr,
			  ((u32)(Bank) * XGPIOPS_REG_MASK_OFFSET) +
			  XGPIOPS_INTPOL_OFFSET, IntrPolarity);

	XGpioPs_WriteReg(InstancePtr->GpioConfig.BaseAddr,
			  ((u32)(Bank) * XGPIOPS_REG_MASK_OFFSET) +
			  XGPIOPS_INTANY_OFFSET, IntrOnAny);
}

void XGpioPs_GetIntrType(XGpioPs *InstancePtr, u8 Bank, u32 *IntrType,
			  u32 *IntrPolarity, u32 *IntrOnAny)
{
	*IntrType = XGpioPs_ReadReg(InstancePtr->GpioConfig.BaseAddr,
				     ((u32)(Bank) * XGPIOPS_REG_MASK_OFFSET) +
				     XGPIOPS_INTTYPE_OFFSET);

	*IntrPolarity = XGpioPs_ReadReg(InstancePtr->GpioConfig.BaseAddr,
					 ((u32)(Bank) * XGPIOPS_REG_MASK_OFFSET) +
					 XGPIOPS_INTPOL_OFFSET);

	*IntrOnAny = XGpioPs_ReadReg(InstancePtr->GpioConfig.BaseAddr,
				      ((u32)(Bank) * XGPIOPS_REG_MASK_OFFSET) +
				      XGPIOPS_INTANY_OFFSET);
}

當然,模塊也提供了另一套對應於PIN操作的API,

void XGpioPs_IntrEnablePin(XGpioPs *InstancePtr, u32 Pin)
{
	u8 Bank;
	u8 PinNumber;
	u32 IntrReg = 0U;

	XGpioPs_GetBankPin((u8)Pin, &Bank, &PinNumber);

	IntrReg = ((u32)1 << (u32)PinNumber);
	XGpioPs_WriteReg(InstancePtr->GpioConfig.BaseAddr,
			  ((u32)(Bank) * XGPIOPS_REG_MASK_OFFSET) +
			  XGPIOPS_INTEN_OFFSET, IntrReg);
}

void XGpioPs_IntrDisablePin(XGpioPs *InstancePtr, u32 Pin)
{
	u8 Bank;
	u8 PinNumber;
	u32 IntrReg = 0U;

	XGpioPs_GetBankPin((u8)Pin, &Bank, &PinNumber);

	IntrReg =  ((u32)1 << (u32)PinNumber);
	XGpioPs_WriteReg(InstancePtr->GpioConfig.BaseAddr,
			  ((u32)(Bank) * XGPIOPS_REG_MASK_OFFSET) +
			  XGPIOPS_INTDIS_OFFSET, IntrReg);
}

u32 XGpioPs_IntrGetEnabledPin(XGpioPs *InstancePtr, u32 Pin)
{
	u8 Bank;
	u8 PinNumber;
	u32 IntrReg;

	XGpioPs_GetBankPin((u8)Pin, &Bank, &PinNumber);

	IntrReg  = XGpioPs_ReadReg(InstancePtr->GpioConfig.BaseAddr,
				    ((u32)(Bank) * XGPIOPS_REG_MASK_OFFSET) +
				    XGPIOPS_INTMASK_OFFSET);

	return (((IntrReg & ((u32)1 << PinNumber)) != (u32)0)? FALSE : TRUE);
}

u32 XGpioPs_IntrGetStatusPin(XGpioPs *InstancePtr, u32 Pin)
{
	u8 Bank;
	u8 PinNumber;
	u32 IntrReg;

	XGpioPs_GetBankPin((u8)Pin, &Bank, &PinNumber);

	IntrReg = XGpioPs_ReadReg(InstancePtr->GpioConfig.BaseAddr,
				   ((u32)(Bank) * XGPIOPS_REG_MASK_OFFSET) +
				   XGPIOPS_INTSTS_OFFSET);

	return (((IntrReg & ((u32)1 << PinNumber)) != (u32)0)? TRUE : FALSE);
}

void XGpioPs_IntrClearPin(XGpioPs *InstancePtr, u32 Pin)
{
	u8 Bank;
	u8 PinNumber;
	u32 IntrReg;

	XGpioPs_GetBankPin((u8)Pin, &Bank, &PinNumber);

	/* Clear the specified pending interrupts. */
	IntrReg = XGpioPs_ReadReg(InstancePtr->GpioConfig.BaseAddr,
				   ((u32)(Bank) * XGPIOPS_REG_MASK_OFFSET) +
				   XGPIOPS_INTSTS_OFFSET);

	IntrReg &= ((u32)1 << PinNumber);
	XGpioPs_WriteReg(InstancePtr->GpioConfig.BaseAddr,
			  ((u32)(Bank) * XGPIOPS_REG_MASK_OFFSET) +
			  XGPIOPS_INTSTS_OFFSET, IntrReg);
}

void XGpioPs_SetIntrTypePin(XGpioPs *InstancePtr, u32 Pin, u8 IrqType)
{
	u32 IntrTypeReg;
	u32 IntrPolReg;
	u32 IntrOnAnyReg;
	u8 Bank;
	u8 PinNumber;

	XGpioPs_GetBankPin((u8)Pin, &Bank, &PinNumber);

	IntrTypeReg = XGpioPs_ReadReg(InstancePtr->GpioConfig.BaseAddr,
				       ((u32)(Bank) * XGPIOPS_REG_MASK_OFFSET) +
				       XGPIOPS_INTTYPE_OFFSET);

	IntrPolReg = XGpioPs_ReadReg(InstancePtr->GpioConfig.BaseAddr,
				      ((u32)(Bank) * XGPIOPS_REG_MASK_OFFSET) +
				      XGPIOPS_INTPOL_OFFSET);

	IntrOnAnyReg = XGpioPs_ReadReg(InstancePtr->GpioConfig.BaseAddr,
					((u32)(Bank) * XGPIOPS_REG_MASK_OFFSET) +
					XGPIOPS_INTANY_OFFSET);

	switch (IrqType) {
		case XGPIOPS_IRQ_TYPE_EDGE_RISING:
			IntrTypeReg |= ((u32)1 << (u32)PinNumber);
			IntrPolReg |= ((u32)1 << (u32)PinNumber);
			IntrOnAnyReg &= ~((u32)1 << (u32)PinNumber);
			break;
		case XGPIOPS_IRQ_TYPE_EDGE_FALLING:
			IntrTypeReg |= ((u32)1 << (u32)PinNumber);
			IntrPolReg &= ~((u32)1 << (u32)PinNumber);
			IntrOnAnyReg &= ~((u32)1 << (u32)PinNumber);
			break;
		case XGPIOPS_IRQ_TYPE_EDGE_BOTH:
			IntrTypeReg |= ((u32)1 << (u32)PinNumber);
			IntrOnAnyReg |= ((u32)1 << (u32)PinNumber);
			break;
		case XGPIOPS_IRQ_TYPE_LEVEL_HIGH:
			IntrTypeReg &= ~((u32)1 << (u32)PinNumber);
			IntrPolReg |= ((u32)1 << (u32)PinNumber);
			break;
		case XGPIOPS_IRQ_TYPE_LEVEL_LOW:
			IntrTypeReg &= ~((u32)1 << (u32)PinNumber);
			IntrPolReg &= ~((u32)1 << (u32)PinNumber);
			break;
		default:
			/**< Default statement is added for MISRA C compliance. */
			break;
	}

	XGpioPs_WriteReg(InstancePtr->GpioConfig.BaseAddr,
			  ((u32)(Bank) * XGPIOPS_REG_MASK_OFFSET) +
			  XGPIOPS_INTTYPE_OFFSET, IntrTypeReg);

	XGpioPs_WriteReg(InstancePtr->GpioConfig.BaseAddr,
			  ((u32)(Bank) * XGPIOPS_REG_MASK_OFFSET) +
			  XGPIOPS_INTPOL_OFFSET, IntrPolReg);

	XGpioPs_WriteReg(InstancePtr->GpioConfig.BaseAddr,
			  ((u32)(Bank) * XGPIOPS_REG_MASK_OFFSET) +
			  XGPIOPS_INTANY_OFFSET, IntrOnAnyReg);
}

u8 XGpioPs_GetIntrTypePin(XGpioPs *InstancePtr, u32 Pin)
{
	u32 IntrType;
	u32 IntrPol;
	u32 IntrOnAny;
	u8 Bank;
	u8 PinNumber;
	u8 IrqType;

	XGpioPs_GetBankPin((u8)Pin, &Bank, &PinNumber);

	IntrType = XGpioPs_ReadReg(InstancePtr->GpioConfig.BaseAddr,
				    ((u32)(Bank) * XGPIOPS_REG_MASK_OFFSET) +
				    XGPIOPS_INTTYPE_OFFSET) & ((u32)1 << PinNumber);

	if (IntrType == ((u32)1 << PinNumber)) {
		IntrOnAny = XGpioPs_ReadReg(InstancePtr->GpioConfig.BaseAddr,
				     ((u32)(Bank) * XGPIOPS_REG_MASK_OFFSET) +
				     XGPIOPS_INTANY_OFFSET) & ((u32)1 << PinNumber);

		IntrPol = XGpioPs_ReadReg(InstancePtr->GpioConfig.BaseAddr,
				   ((u32)(Bank) * XGPIOPS_REG_MASK_OFFSET) +
				   XGPIOPS_INTPOL_OFFSET) & ((u32)1 << PinNumber);

		if (IntrOnAny == ((u32)1 << PinNumber)) {
			IrqType = XGPIOPS_IRQ_TYPE_EDGE_BOTH;
		} else if (IntrPol == ((u32)1 << PinNumber)) {
			IrqType = XGPIOPS_IRQ_TYPE_EDGE_RISING;
		} else {
			IrqType = XGPIOPS_IRQ_TYPE_EDGE_FALLING;
		}
	} else {
		IntrPol = XGpioPs_ReadReg(InstancePtr->GpioConfig.BaseAddr,
				   ((u32)(Bank) * XGPIOPS_REG_MASK_OFFSET) +
				   XGPIOPS_INTPOL_OFFSET) & ((u32)1 << PinNumber);

		if (IntrPol == ((u32)1 << PinNumber)) {
			IrqType = XGPIOPS_IRQ_TYPE_LEVEL_HIGH;
		} else {
			IrqType = XGPIOPS_IRQ_TYPE_LEVEL_LOW;
		}
	}

	return IrqType;
}

模塊提供了另外一套API,用來與ISR系統進行掛接。
這體現了函數接口分組分隔的思想。

void StubHandler(void *CallBackRef, u32 Bank, u32 Status)
{
	(void) CallBackRef;
	(void) Bank;
	(void) Status;

	Xil_AssertVoidAlways();
}
void XGpioPs_IntrHandler(XGpioPs *InstancePtr)
{
	u8 Bank;
	u32 IntrStatus;
	u32 IntrEnabled;

	for (Bank = 0U; Bank < InstancePtr->MaxBanks; Bank++) {
		IntrStatus = XGpioPs_IntrGetStatus(InstancePtr, Bank);
		if (IntrStatus != (u32)0) {
			IntrEnabled = XGpioPs_IntrGetEnabled(InstancePtr,
							      Bank);
			XGpioPs_IntrClear((XGpioPs *)InstancePtr, Bank,
							(IntrStatus & IntrEnabled));
			InstancePtr->Handler(InstancePtr->
					     CallBackRef, Bank,
					     (IntrStatus & IntrEnabled));
		}
	}
}

void XGpioPs_SetCallbackHandler(XGpioPs *InstancePtr, void *CallBackRef,
				 XGpioPs_Handler FuncPointer)
{
	InstancePtr->Handler = FuncPointer;
	InstancePtr->CallBackRef = CallBackRef;
}

ISR系統是基於Callback機制運行的,即,API提供將Callback掛接到ISR的服務,而Callback函數則是由應用程序編寫。
整個ISR系統是一個多級控制面板的架構,以VectorTable的形式,設置了多個函數入口彈射器。而API所提供的服務,就是將Callback掛接到某個函數入口彈射器上。
當IRQ被觸發時,經過multi-stage的處理,最終會調用合適的Callback。

本例中,操作函數的分層,被簡化爲兩層,即,
寄存器讀寫層,
設備讀寫層。
而設備讀寫層,就是我們說的業務層了。
在業務層,提供了多套API,用來提供不同的服務。應用程序可以根據需要,選用不同分組中的API。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章