winCE中采用DMA传输数据的方法

 转载请标明是引用于 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的要求,我的要求是这样的:

winCE中采用DMA传输数据的方法_第1张图片

以上最重要的是参数是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;
}


 

 

你可能感兴趣的:(object,null,WinCE,Descriptor,alignment,structure)