转载请标明是引用于 http://blog.csdn.net/chenyujing1234
对于文章中有什么意见或是需要代码的可以留言联系我。
// DDM控制器能服务的外围设备配置信息的结构体 typedef struct { BOOL Valid; // 表明此逻辑设备是否可用 ULONG ChanCfg; // DDMA 通道配置 (每个通道特有的) ULONG DescCmd; // 描述符 cmd,即 dsr_cmd0的设置 ULONG DescSrc1; // 描述符 source1, striding / burst sizes etc. ULONG DescDest1; // 描述符 dest1, striding / burst sizes etc. ULONG FifoAddr; // FIFO 地址 for peripheral BOOL DevIsRead; // 它是一个读事务吗 ? WCHAR *Name; // 设备名 } DDMA_DEVICE_CONFIG;
static DDMA_DEVICE_CONFIG DdmaConfig[MAX_DMA_LOGICAL_DEVICES];
/*++ Routine Description: 这个函数在BCEDDK为每个进程加载时调用. 它表现了初始化来让BCEDDK的DMA portion 不可用 performs initialization to make the DMA portion of the BCEDDK usable. Arguments: None. Return Value: None. --*/ VOID DmaEntry( VOID ) { //为每个要用DMA的设备 初始化数据,通过DdmaConfig管理这些设备 // 下面以SPI设备为例 // SPI (PSC0) Transmit DdmaConfig[DMA_SPI_TX].Valid = TRUE; DdmaConfig[DMA_SPI_TX].Name = TEXT("SPI TX"); DdmaConfig[DMA_SPI_TX].ChanCfg = DDMA_CHANCFG_DFN; DdmaConfig[DMA_SPI_TX].DescCmd = DDMA_DESCCMD_SID_N(DDMA_ALWAYS_HIGH_ID) | DDMA_DESCCMD_DW_HWORD | DDMA_DESCCMD_SW_WORD | DDMA_DESCCMD_DN | DDMA_DESCCMD_SN; DdmaConfig[DMA_SPI_TX].DescSrc1 = DDMA_DESCSRC_STRIDE_STS_1 | DDMA_DESCSRC_STRIDE_SAM_INC; DdmaConfig[DMA_SPI_TX].DescDest1 = DDMA_DESCDST_STRIDE_DTS_8 | DDMA_DESCDST_STRIDE_DAM_STATIC; DdmaConfig[DMA_SPI_TX].DevIsRead = FALSE; // SPI (PSC0) Receive DdmaConfig[DMA_SPI_RX].Valid = TRUE; DdmaConfig[DMA_SPI_RX].Name = TEXT("SPI RX"); DdmaConfig[DMA_SPI_RX].ChanCfg = DDMA_CHANCFG_DFN; DdmaConfig[DMA_SPI_RX].DescCmd = DDMA_DESCCMD_DID_N(DDMA_ALWAYS_HIGH_ID) | DDMA_DESCCMD_DW_WORD | DDMA_DESCCMD_SW_WORD | DDMA_DESCCMD_DN | DDMA_DESCCMD_SN; DdmaConfig[DMA_SPI_RX].DescSrc1 = DDMA_DESCSRC_STRIDE_STS_8 | DDMA_DESCSRC_STRIDE_SAM_STATIC; DdmaConfig[DMA_SPI_RX].DescDest1 = DDMA_DESCDST_STRIDE_DTS_1 | DDMA_DESCDST_STRIDE_DAM_INC; DdmaConfig[DMA_SPI_RX].DevIsRead = TRUE; DdmaConfig[DMA_SPI_TX].DescCmd |= DDMA_DESCCMD_DID_N(DDMA_PSC0_TX_ID); DdmaConfig[DMA_SPI_TX].FifoAddr = DDMA_PSC0_TX_ADDR; DdmaConfig[DMA_SPI_RX].DescCmd |= DDMA_DESCCMD_SID_N(DDMA_PSC0_RX_ID); DdmaConfig[DMA_SPI_RX].FifoAddr = DDMA_PSC0_RX_ADDR; ........ }
以上最重要的是参数是Physical Address,它是我们告诉DDMA从哪里接收数据,把数据发往哪里的根据。
从以上代码可以看出Physical Address给了FifoAddr变量。在接下文的2、3中会讲到怎么把它赋给DDMA寄存器。
ULONG XXX_Init( IN ULONG RegistryPath ) { PDEVICE_INSTANCE DeviceInstance; DeviceInstance = LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, sizeof(*DeviceInstance)); 。。。。 // // Setup DMA operations // DeviceInstance->DmaBufferSize = 512; // 为接收与发送分配DMA对象 DeviceInstance->TxDma = HalAllocateDMAChannel(); DeviceInstance->RxDma = HalAllocateDMAChannel(); // 初始化DMA对象 HalInitDmaChannel(DeviceInstance->TxDma, DMA_SPI_TX, DeviceInstance->DmaBufferSize, TRUE); HalInitDmaChannel(DeviceInstance->RxDma, DMA_SPI_RX, DeviceInstance->DmaBufferSize, FALSE); HalSetDMAForReceive(DeviceInstance->RxDma); // 启动DMA HalStartDMA(DeviceInstance->RxDma); HalStartDMA(DeviceInstance->TxDma); // 为Tx DMA完成设备中断 HwIntr = HalGetDMAHwIntr(DeviceInstance->TxDma); // 监视得到的中断 DeviceInstance->SysIntr = InterruptConnect(Internal,0,HwIntr,0); DeviceInstance->hIsrEvent = CreateEvent(NULL,FALSE,FALSE,NULL); if (!InterruptInitialize(DeviceInstance->SysIntr,DeviceInstance->hIsrEvent,NULL,0)) { RETAILMSG(1,(TEXT("SPI: Failed InterruptInitialize\r\n"))); goto ErrorReturn; } InterruptDone(DeviceInstance->SysIntr); }
第二个步骤主要由两个函数实现:
HalAllocateDMAChannel: 分配DAM对象较为简单,先判断是不是对全局管理DMA的对象进行了初始化,没有就做初始化;
得到的DDMA对象是:
PDMA_CHANNEL_OBJECT
typedef PVOID PDMA_CHANNEL_OBJECT;
可以看到它只是一个指针而已,但传到下面讲到的重要函数HalInitDmaChannel 时就转化成
PCHANNEL_OBJECT
typedef struct _CHANNEL_OBJECT CHANNEL_OBJECT, *PCHANNEL_OBJECT;
// // CHANNEL_OBJECT structure definition. A forward declaration for this // structure is in bceddk.h. This is the real definition. // struct _CHANNEL_OBJECT { // These are the parts from ceddk.h USHORT ObjectSize; // Size of structure (versioning). INTERFACE_TYPE InterfaceType; // Adapter bus interface. ULONG BusNumber; // Adapter bus number. // Au1550 specific bits ULONG DmaChannel; ULONG BufferSize; HANDLE hChannelMutex; DDMA_DEVICE_CONFIG *pDevCfg; BOOL InterruptsEnabled; DMA_LOGICAL_DEVICE DeviceID; DDMA_CHANNEL* DmaRegPtr; PVOID pBufferA; PVOID pBufferB; PHYSICAL_ADDRESS BufferAPhys; PHYSICAL_ADDRESS BufferBPhys; DDMA_DESCRIPTOR_STD* pDescA; DDMA_DESCRIPTOR_STD* pDescB; PHYSICAL_ADDRESS DescAPhys; PHYSICAL_ADDRESS DescBPhys; BUFFER_STATE BufferStateA; BUFFER_STATE BufferStateB; WCHAR *Name; // Device name // Entries for MDL DMA DDMA_DESCRIPTOR_STD *pDescriptors; PHYSICAL_ADDRESS DescriptorsPhysAddr; ULONG AllocatedDescriptors; PVOID pAlignedBuffer; PHYSICAL_ADDRESS AlignedPhysAddr; ULONG AlignedByteCount; ULONG NextDMABuffer; // The Next DMA Buffer to be serviced by interrupt // Added to remove hardware state dependencies // DWORD dwGet, dwPut, dwCur; };
// // BCEDDK Routines // PDMA_CHANNEL_OBJECT HalAllocateDMAChannel() /*++ Routine Description: 此函数分配一个DMA通道. Arguments: None. Return Value: 指向一个新的DMA通道对象,如果失败就返回NULL --*/ { PCHANNEL_OBJECT pNewChannel; int i; BOOL bIsInitialized=FALSE; if (!bIsInitialized) { bIsInitialized = TRUE; DmaEntry(); } // 分配对象 pNewChannel = LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, sizeof(*pNewChannel)); if (pNewChannel == NULL) { goto ErrorReturn; } // 找一个空的通道 for (i=0;i<DDMA_NUM_CHANNELS;i++) { pNewChannel->hChannelMutex = CreateMutex(NULL, FALSE, DmaChannelMutexNames[i]); if (pNewChannel->hChannelMutex == NULL) { goto ErrorReturn; } if(GetLastError()==ERROR_ALREADY_EXISTS) { CloseHandle(pNewChannel->hChannelMutex); } else { RETAILMSG(MSGS,(L"DDMA channel %d is not in use, create new Mutex\r\n",i)); pNewChannel->DmaChannel = i; break; } } if (i==DDMA_NUM_CHANNELS) { RETAILMSG(1,(L"No DDMA Channels available\r\n")); goto ErrorReturn; } // // 等待通道变成可用的 WaitForSingleObject(pNewChannel->hChannelMutex, INFINITE); // // 获得DMA通道指针 pNewChannel->DmaRegPtr = (DDMA_CHANNEL*)(0xB4002000 + (0x100*pNewChannel->DmaChannel)); // // 确保通道是关闭的 WRITE_REGISTER_ULONG((PULONG)&pNewChannel->DmaRegPtr->cfg, 0); // 使EN位为0,表通道使能关闭 return (PDMA_CHANNEL_OBJECT)pNewChannel; ErrorReturn: // cleanup if (pNewChannel) { LocalFree(pNewChannel); } return NULL; }
HalInitDmaChannel :
DdmaConfig数组信息的填充在第一步中就完成了。
当第(1)中的信息填充了我们的DDMA对象时,对象中有些内容还是得另外填充,eg: pBufferA、pBufferB、pDescA、pDescB内容的申请。
// Allocate two buffers
ChannelObject->BufferAPhys.QuadPart = 0;
ChannelObject->BufferBPhys.QuadPart = 0;
ChannelObject->pBufferA = AllocPhysMem(BufferSize*2,
PAGE_READWRITE | PAGE_NOCACHE,
DMA_ALIGNMENT_REQUIREMENT,
0,
&ChannelObject->BufferAPhys.LowPart);
ChannelObject->pBufferB = (PUCHAR)(ChannelObject->pBufferA) + BufferSize;
ChannelObject->BufferBPhys.LowPart = ChannelObject->BufferAPhys.LowPart + BufferSize;
============================
// Allocate two descriptors
ChannelObject->DescAPhys.QuadPart = 0;
ChannelObject->DescBPhys.QuadPart = 0;
ChannelObject->pDescA = AllocPhysMem(sizeof(DDMA_DESCRIPTOR_STD) * 4, // IMR TEST
PAGE_READWRITE | PAGE_NOCACHE,
DMA_ALIGNMENT_REQUIREMENT,
0,
&ChannelObject->DescAPhys.LowPart);
ChannelObject->pDescB = (PVOID)((PUCHAR)(ChannelObject->pDescA) + (2*sizeof(DDMA_DESCRIPTOR_STD)));
ChannelObject->DescBPhys.LowPart = ChannelObject->DescAPhys.LowPart + (2*sizeof(DDMA_DESCRIPTOR_STD));
描述符:是源和目的间传送的内存结构。这些描述符包含了指导DDMA控制器如何传送数据的域。
DDMA支持3类传送:
源到目的的传关、比较和分支、逐字的写。
标准的描述符成员有:传送的命令信息cmd0、cmd1、源地址的低32位source0、source1.
if (pDevCfg->DevIsRead) {
WRITE_REGISTER_ULONG((PULONG)&ChannelObject->pDescA->source0, pDevCfg->FifoAddr);
WRITE_REGISTER_ULONG((PULONG)&ChannelObject->pDescB->source0, pDevCfg->FifoAddr);
WRITE_REGISTER_ULONG((PULONG)&ChannelObject->pDescA->dest0, ChannelObject->BufferAPhys.LowPart);
WRITE_REGISTER_ULONG((PULONG)&ChannelObject->pDescB->dest0, ChannelObject->BufferBPhys.LowPart);
} else {
WRITE_REGISTER_ULONG((PULONG)&ChannelObject->pDescA->dest0, pDevCfg->FifoAddr);
WRITE_REGISTER_ULONG((PULONG)&ChannelObject->pDescB->dest0, pDevCfg->FifoAddr);
WRITE_REGISTER_ULONG((PULONG)&ChannelObject->pDescA->source0, ChannelObject->BufferAPhys.LowPart);
WRITE_REGISTER_ULONG((PULONG)&ChannelObject->pDescB->source0, ChannelObject->BufferBPhys.LowPart);
}
WRITE_REGISTER_ULONG((PULONG)&ChannelObject->pDescA->source1, pDevCfg->DescSrc1);
WRITE_REGISTER_ULONG((PULONG)&ChannelObject->pDescB->source1, pDevCfg->DescSrc1);
WRITE_REGISTER_ULONG((PULONG)&ChannelObject->pDescA->dest1, pDevCfg->DescDest1);
WRITE_REGISTER_ULONG((PULONG)&ChannelObject->pDescB->dest1, pDevCfg->DescDest1);
以上加红部分中的FifoAddr是从上文 1、 中获得的,它是我们告诉DDMA从哪里接收数据,把数据发往哪里的根据。
在这里与DDMA的source0或dest0绑定起来了。
// 如果传0 或NULL就为通道用默认的,有时默认的不能被用且一个值被要求 BOOL HalInitDmaChannel(PDMA_CHANNEL_OBJECT DmaChannelObject, DMA_LOGICAL_DEVICE Device, ULONG BufferSize, BOOL InterruptEnable) { PCHANNEL_OBJECT ChannelObject = (PCHANNEL_OBJECT)DmaChannelObject; DDMA_DEVICE_CONFIG *pDevCfg; ULONG descCmd; // Check Device is in range if (Device >= MAX_DMA_LOGICAL_DEVICES) { RETAILMSG(1,(TEXT("HalInitDmaChannel: Device %d is out of range\r\n"),Device)); goto errorReturn; } // 获得设备的配置 pDevCfg = &DdmaConfig[Device]; // 检查设备有可用的配置 if (!pDevCfg->Valid) { RETAILMSG(1,(TEXT("HalInitDmaChannel: Device %d does not have valid configuration\r\n"),Device)); goto errorReturn; } ChannelObject->pDevCfg = pDevCfg; ChannelObject->BufferSize = BufferSize; ChannelObject->Name = pDevCfg->Name; ChannelObject->DeviceID = Device; // 分配两个buffers ChannelObject->BufferAPhys.QuadPart = 0; ChannelObject->BufferBPhys.QuadPart = 0; ChannelObject->pBufferA = AllocPhysMem(BufferSize*2, PAGE_READWRITE | PAGE_NOCACHE, DMA_ALIGNMENT_REQUIREMENT, 0, &ChannelObject->BufferAPhys.LowPart); ChannelObject->pBufferB = (PUCHAR)(ChannelObject->pBufferA) + BufferSize; ChannelObject->BufferBPhys.LowPart = ChannelObject->BufferAPhys.LowPart + BufferSize; // 分配两个描述符 ChannelObject->DescAPhys.QuadPart = 0; ChannelObject->DescBPhys.QuadPart = 0; ChannelObject->pDescA = AllocPhysMem(sizeof(DDMA_DESCRIPTOR_STD) * 4, // IMR TEST PAGE_READWRITE | PAGE_NOCACHE, DMA_ALIGNMENT_REQUIREMENT, 0, &ChannelObject->DescAPhys.LowPart); ChannelObject->pDescB = (PVOID)((PUCHAR)(ChannelObject->pDescA) + (2*sizeof(DDMA_DESCRIPTOR_STD))); ChannelObject->DescBPhys.LowPart = ChannelObject->DescAPhys.LowPart + (2*sizeof(DDMA_DESCRIPTOR_STD)); // 设置描述符 descCmd = pDevCfg->DescCmd; if (InterruptEnable) { ChannelObject->InterruptsEnabled = TRUE; descCmd |= DDMA_DESCCMD_IE; } descCmd |= DDMA_DESCCMD_CV; // 在描述符完成时清除可用Bit // 配置DDMA寄存器(根据实际的机器来配置) if (pDevCfg->DevIsRead) { WRITE_REGISTER_ULONG((PULONG)&ChannelObject->pDescA->source0, pDevCfg->FifoAddr); //把寄存器DDMA_PSC1_TX_ADDR 的地址读到源当之 WRITE_REGISTER_ULONG((PULONG)&ChannelObject->pDescB->source0, pDevCfg->FifoAddr); /* 从以下可以看出: // 分配两个描述符ChannelObject->DescAPhys 与 ChannelObject->pDescA是联的 ChannelObject->DescAPhys.QuadPart = 0; ChannelObject->DescBPhys.QuadPart = 0; ChannelObject->pDescA = AllocPhysMem(sizeof(DDMA_DESCRIPTOR_STD) * 4, // IMR TEST PAGE_READWRITE | PAGE_NOCACHE, DMA_ALIGNMENT_REQUIREMENT, 0, &ChannelObject->DescAPhys.LowPart); ChannelObject->pDescB = (PVOID)((PUCHAR)(ChannelObject->pDescA) + (2*sizeof(DDMA_DESCRIPTOR_STD))); ChannelObject->DescBPhys.LowPart = ChannelObject->DescAPhys.LowPart + (2*sizeof(DDMA_DESCRIPTOR_STD)); */ WRITE_REGISTER_ULONG((PULONG)&ChannelObject->pDescA->dest0, ChannelObject->BufferAPhys.LowPart); // 目的 WRITE_REGISTER_ULONG((PULONG)&ChannelObject->pDescB->dest0, ChannelObject->BufferBPhys.LowPart); } else { WRITE_REGISTER_ULONG((PULONG)&ChannelObject->pDescA->dest0, pDevCfg->FifoAddr); WRITE_REGISTER_ULONG((PULONG)&ChannelObject->pDescB->dest0, pDevCfg->FifoAddr); WRITE_REGISTER_ULONG((PULONG)&ChannelObject->pDescA->source0, ChannelObject->BufferAPhys.LowPart); WRITE_REGISTER_ULONG((PULONG)&ChannelObject->pDescB->source0, ChannelObject->BufferBPhys.LowPart); } WRITE_REGISTER_ULONG((PULONG)&ChannelObject->pDescA->source1, pDevCfg->DescSrc1); WRITE_REGISTER_ULONG((PULONG)&ChannelObject->pDescB->source1, pDevCfg->DescSrc1); WRITE_REGISTER_ULONG((PULONG)&ChannelObject->pDescA->dest1, pDevCfg->DescDest1); WRITE_REGISTER_ULONG((PULONG)&ChannelObject->pDescB->dest1, pDevCfg->DescDest1); WRITE_REGISTER_ULONG((PULONG)&ChannelObject->pDescA->cmd0, descCmd); WRITE_REGISTER_ULONG((PULONG)&ChannelObject->pDescB->cmd0, descCmd); // 设置 loop WRITE_REGISTER_ULONG((PULONG)&ChannelObject->pDescA->nxt_ptr, ChannelObject->DescBPhys.LowPart >> 5); // 除以32 WRITE_REGISTER_ULONG((PULONG)&ChannelObject->pDescB->nxt_ptr, ChannelObject->DescAPhys.LowPart >> 5); // 除以32 // 设置通道配置 WRITE_REGISTER_ULONG((PULONG)&ChannelObject->DmaRegPtr->cfg, pDevCfg->ChanCfg); // 设置描述符指向A WRITE_REGISTER_ULONG((PULONG)&ChannelObject->DmaRegPtr->des_ptr,ChannelObject->DescAPhys.LowPart); ChannelObject->NextDMABuffer = ChannelObject->DescAPhys.LowPart;// ???? RETAILMSG(1,(TEXT("HalInitDmaChannel: Channel %d initialized for %s\r\n"),ChannelObject->DmaChannel,ChannelObject->Name)); return TRUE; }
BOOL DoTransferDma8( ULONG Size, PBYTE pInBuffer, PBYTE pOutBuffer) { PDEVICE_INSTANCE DeviceInstance = g_DeviceInstance; PSC_SPI *pSPI = DeviceInstance->pSPI; ULONG SPIConfiguration = 0; ULONG data = 0; PBYTE pRxDmaBuffer,pTxDmaBuffer; BOOL status = TRUE; ULONG intStat; int timeout; WRITE_REGISTER_ULONG((PULONG)&pSPI->msk,0xffffffff); SPIConfiguration = READ_REGISTER_ULONG((PULONG)&pSPI->cfg); SPIConfiguration &= ~PSC_SPI_CFG_DE; WRITE_REGISTER_ULONG((PULONG)&pSPI->cfg, SPIConfiguration); //SPIConfiguration |= (PSC_SPI_CFG_TRD_N(0) | PSC_SPI_CFG_RRD_N(0)); SPIConfiguration &= ~PSC_SPI_CFG_DD; //SPIConfiguration |= PSC_SPI_CFG_CDE;// delay WRITE_REGISTER_ULONG((PULONG)&pSPI->cfg, SPIConfiguration); WRITE_REGISTER_ULONG((PULONG)&pSPI->cfg, SPIConfiguration | PSC_SPI_CFG_DE); timeout = 50; // 等待DMA寄存器的状态指示器指示有数据 while (timeout && !((READ_REGISTER_ULONG((PULONG)&pSPI->sts)) & PSC_SPI_STS_DR)) { StallExecution(1000); timeout--; } if (!timeout) { status = FALSE; RETAILMSG(1,(TEXT("SPI: DoTransferDMA: Timeout waiting for DR!\r\n"))); } //Rx Data Clear and Tx Data Clear WRITE_REGISTER_ULONG((PULONG)&pSPI->pcr,PSC_SPI_PCR_RC | PSC_SPI_PCR_TC); // 启动DMA的Rx和Tx if (pOutBuffer!=NULL) { HalSetDMAForReceive(DeviceInstance->RxDma); HalStartDMA(DeviceInstance->RxDma); } HalStartDMA(DeviceInstance->TxDma); // 获得下一个Tx的DMA Buffer pTxDmaBuffer = (PBYTE)HalGetNextDMABuffer(DeviceInstance->TxDma); // 复制要发送的Tx数据,如果Tx为NULL,那么给它0xFF.这样就仅有Rx传送 if (pInBuffer==NULL) { memset(pTxDmaBuffer, 0xFF, Size); } else { memcpy(pTxDmaBuffer, pInBuffer, Size); } // Give buffer back to DMA HalActivateDMABuffer(DeviceInstance->TxDma,pTxDmaBuffer,Size); // Start Master xfer WRITE_REGISTER_ULONG((PULONG)&pSPI->pcr, PSC_SPI_PCR_MS); // 等待中断 WaitForSingleObject(DeviceInstance->hIsrEvent,INFINITE); // 把Rx接收的数据复制出来 if (pOutBuffer!=NULL) { ULONG RxSize; pRxDmaBuffer = HalGetNextDMABuffer(DeviceInstance->RxDma); RxSize = HalGetDMABufferRxSize(DeviceInstance->RxDma,pRxDmaBuffer); //for (timeout=0; timeout<8000; timeout++) //for (timeout=0; timeout<1000; timeout++) //; // RX memcpy(pOutBuffer,pRxDmaBuffer,Size); HalActivateDMABuffer(DeviceInstance->RxDma,pRxDmaBuffer,DeviceInstance->DmaBufferSize); } // 回复中断 intStat = HalCheckForDMAInterrupt(DeviceInstance->TxDma); HalAckDMAInterrupt(DeviceInstance->TxDma,intStat); InterruptDone(DeviceInstance->SysIntr); // 停止DMA的Rx与Tx if (pOutBuffer!=NULL) HalStopDMA(DeviceInstance->RxDma); HalStopDMA(DeviceInstance->TxDma); return status; }
BOOL SPI_IOControl( IN OUT ULONG DeviceContext, IN ULONG Code, IN PUCHAR InputBuffer, IN ULONG InputBufferLength, OUT PUCHAR OutputBuffer, IN ULONG OutputBufferLength, OUT PULONG ActualOutput ) { PDEVICE_INSTANCE DeviceInstance = (PDEVICE_INSTANCE)DeviceContext; BOOL Status = FALSE; switch (Code) { case IOCTL_SPI_RECEIVE: SPIReadData(0, 0, (PULONG)OutputBuffer); Status = TRUE; break; default: SetLastError(ERROR_CALL_NOT_IMPLEMENTED); Status = FALSE; break; } if (!Status) { DEBUGMSG(ZONE_ERROR|ZONE_IOCTL, ( TEXT("SPI: SSO_IOControl returning FALSE.\r\n"))); } return Status; }
接下来我们就来设计SPIReadData接口:
void SPIReadData(BYTE UartInternalReg, int Channel, PULONG Val) { //BYTE InitTemp; BYTE tempVal = 0; //InitTemp = 0x80; //InitTemp |= (UartInternalReg << 3) | (Channel << 1); //GPIO_CTL(51) = GPIO_CTL_OUTPUT0; //CS0 //SET_CS_LOW(); //DoTransferDma8(1,(PBYTE)&InitTemp,NULL); DoTransferDma8(1, NULL, (PBYTE)&tempVal); *Val |= tempVal; }
Handle句柄怎么得来的,你应该知道的,这里不讲了。
BOOL CSPIPort::SPI_DoTransfer( HANDLE Handle, ULONG Size, PULONG pTxBuffer, PULONG pRxBuffer ) { ULONG Tmp; BOOL RetVal; enum { IOCTL_SPI_TRANSFER = 0x80002000, // some arbirary base IOCTL_SPI_TRANSFER_DMA = 0x80002001, IOCTL_SPI_RECEIVE = 0x80002002 }; RetVal = DeviceIoControl( Handle, IOCTL_SPI_RECEIVE, pTxBuffer, Size, pRxBuffer, Size, &Tmp, NULL); return RetVal; }