转载请标明是引用于 http://blog.csdn.net/chenyujing1234
对于文章中有什么意见或是需要代码的可以留言联系我。
1、DMA入口
// 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;
........
}
以上DMA_SPI_RX这个ID的确定得根据实现硬件DDMA的要求,我的要求是这样的:
以上最重要的是参数是Physical Address,它是我们告诉DDMA从哪里接收数据,把数据发往哪里的根据。
从以上代码可以看出Physical Address给了FifoAddr变量。在接下文的2、3中会讲到怎么把它赋给DDMA寄存器。
2、分配DMA对象并初始化DMA对象。可以在XXX_Init 里调用
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 :
2、1 根据Device从DdmaConfig数组中取得预先配置好的DMA信息初始化DMA对象。
DdmaConfig数组信息的填充在第一步中就完成了。
2、2 分配描述符A与描述符B。
当第(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));
2、3 接下来把描述符与我拉配置中的FIFO地址及Buffer地址绑定在一起。
描述符:是源和目的间传送的内存结构。这些描述符包含了指导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;
}
3、应用层如何获得DMA的数据
3、1 设计驱动层获取DMA数据的接口函数(这里以获得8bit为例)
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;
}
3、2 应用层与驱动层的调用(获得数据),我们以IOCTL方式为例
3、2、1 驱动层设计
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;
}
3、2、2 应用层设计
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;
}