我們已經學習了關於如何使用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。