stm32 利用 串口接收空閒中斷 + dma 實現不定長度dma 接收

#include "includes.h"
void UartDmaSend(INT8U *pt,INT8U len)
{
	INT8U err;
	DmaSendData(DMA1_Channel7,pt,len);
	OSSemPend(OSSemDmaU2Tx,0,&err);
}

void UsbTask(void *pdata)
{
	INT8U err,*pt,len;
	INT32U d;
	SysTick_CounterCmd(SysTick_Counter_Enable);		//系統時鐘開始計數
	while(1)
	{
		d=(INT32U)OSQPend(OSQUsbRec,0,&err);		//接收到 usb 發送來的數據
		len=d>>24;
		pt=(INT8U*)OSMemBufC2B+(d&0xff)*sizeof(OSMemBufC2B[0]);
		UartDmaSend(pt,len);						//通過串口dma發送
		OSMemPut(OSMemC2B,pt);
	}
}

void UartRxTask(void *pdata)
{
	INT8U err,len,*pt,*pRec;
	INT32U d;
	OSSemDmaU2Tx=OSSemCreate(0);
	UartInit(USART2, U2BOUD, 0,1);	
	USART_ITConfig(USART2,USART_IT_RXNE,DISABLE);		//關閉串口接收終端
	USART_ITConfig(USART2,USART_IT_IDLE,ENABLE);		//開啓串口接收空閒中斷
	Dma_Tx_Init(DMA1_Channel7,(INT32U)&USART2->DR,1);	//dma 發送 
	USART_DMACmd(USART2,USART_DMAReq_Tx,ENABLE);		//綁定串口dma 觸發
	Dma_Rx_Init(DMA1_Channel6,(INT32U)&USART2->DR,1);	//dma 接收 
	USART_DMACmd(USART2,USART_DMAReq_Rx,ENABLE);		//綁定dma 接收觸發
	pt=OSMemGet(OSMemC2B,&err);
	DmaGetData(DMA1_Channel6,pt,64,&pRec);
	while(1)
	{
		d=(INT32U)OSQPend(OSQUartRec,0,&err);		//接收到 usb 發送來的數據
		len=d>>24;
		pt=(INT8U*)OSMemBufC2B+(d&0xff)*sizeof(OSMemBufC2B[0]);
		SendUsbData(pt,len);
		OSMemPut(OSMemC2B,pt);
	}
}

void USART2_IRQHandler(void)
{
	INT8U d,*pt,*pRec;
	OSIntEnter();
	if(USART2->SR&0x08)		//數據過載,清除
	{
		d=USART2->SR;
		d=USART2->CR1;
		d=USART2->DR;
		d=d;				//爲了消除 編譯器 警告
	}
	if(USART2->SR&0x10)		//idle
	{
		d=USART2->DR;
		pt=OSMemGet(OSMemC2B,&d);
		d=DmaGetData(DMA1_Channel6,pt,64,&pRec);
		OSQPost(OSQUartRec,(void*)( ((INT32U)pRec-(INT32U)OSMemBufC2B)/sizeof(OSMemBufC2B[0])+((INT32U)d<<24) ));									//接收到數據包 轉發的處理的任務
	}	
	OSIntExit();
}

void  DMAChannel7_IRQHandler (void)
{
	OSIntEnter();
	DMA_ClearFlag(DMA1_FLAG_TC7);								//清除發送完成標誌位
	OSSemPost(OSSemDmaU2Tx);
    OSIntExit();                                                /* Tell uC/OS-II that we are leaving the ISR                */
}

void  DMAChannel6_IRQHandler (void)
{
	INT8U d,*pt,*pRec;
	OSIntEnter();
	DMA_ClearFlag(DMA1_FLAG_TC6);								//清除發送完成標誌位
	pt=OSMemGet(OSMemC2B,&d);
	d=DmaGetData(DMA1_Channel6,pt,64,&pRec);
	OSQPost(OSQUartRec,(void*)( ((INT32U)pRec-(INT32U)OSMemBufC2B)/sizeof(OSMemBufC2B[0])+((INT32U)d<<24) ));									//接收到數據包 轉發的處理的任務
    OSIntExit();                                                /* Tell uC/OS-II that we are leaving the ISR                */
}

dma的代碼如下

#include "includes.h"
#ifndef  IRQPreemptionPriority
#define IRQPreemptionPriority 0
#endif

/*
	USART_DMACmd(USARTX,USART_DMAReq_Tx,ENABLE);
	DmaSendData(DMA1_Channel4,(INT8U*)tmpStr,sizeof(tmpStr));
*/
/*---- D M A _   I N I T ----
【功能】:****
【參數】:****
【返回】:****
【說明】:如果採用ucos的話,初始化要放在 	OSInit() 之後,因爲採用信號量
--------------作者:盧傑西   2009年10月4日 星期日20:30:13--------------------------------*/
//USART_DMACmd(USART1,USART_DMAReq_Tx,ENABLE);
void Dma_Tx_Init(DMA_Channel_TypeDef* chn,u32 dstAddr,u8 bInt)
{
	DMA_InitTypeDef    DMA_InitStructure;
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);								//啓動DMA時鐘
	/* DMA1 Channel7 configuration ----------------------------------------------*/
	DMA_DeInit(chn);
	DMA_InitStructure.DMA_PeripheralBaseAddr = dstAddr;								//(u32)USART2_DR_Address;	//外設地址
	DMA_InitStructure.DMA_MemoryBaseAddr = (u32)0;										//內存地址,發送時候
	DMA_InitStructure.DMA_DIR =DMA_DIR_PeripheralDST;									// DMA_DIR_PeripheralSRC;								//
	DMA_InitStructure.DMA_BufferSize = 0;
	DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
	DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
	DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
	DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
	DMA_InitStructure.DMA_Priority = DMA_Priority_High;
	DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
	DMA_Init(chn, &DMA_InitStructure);	

	/*
	#define DMA1_Channel1_BASE    (AHBPERIPH_BASE + 0x0008)
	#define DMA1_Channel2_BASE    (AHBPERIPH_BASE + 0x001C)
	#define DMA1_Channel3_BASE    (AHBPERIPH_BASE + 0x0030)
	#define DMA1_Channel4_BASE    (AHBPERIPH_BASE + 0x0044)
	#define DMA1_Channel5_BASE    (AHBPERIPH_BASE + 0x0058)
	#define DMA1_Channel6_BASE    (AHBPERIPH_BASE + 0x006C)
	#define DMA1_Channel7_BASE    (AHBPERIPH_BASE + 0x0080)
	*/

	if(bInt)
	{
		NVIC_InitTypeDef NVIC_InitStructure;
		/* Enable the USART1 Interrupt */
		NVIC_InitStructure.NVIC_IRQChannel =DMA1_Channel1_IRQChannel+((u32)chn-(u32)DMA1_Channel1)/0x14;; //DMAChannel7_IRQChannel;
		NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = IRQPreemptionPriority;
		NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
		NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
		NVIC_Init(&NVIC_InitStructure);
		DMA_ITConfig(chn,DMA_IT_TC,ENABLE);
	}
}

void Dma_Rx_Init(DMA_Channel_TypeDef* chn,u32 srcAddr,u8 bInt)
{
	DMA_InitTypeDef    DMA_InitStructure;
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);								//啓動DMA時鐘
	/* DMA1 Channel7 configuration ----------------------------------------------*/
	DMA_DeInit(chn);
	DMA_InitStructure.DMA_PeripheralBaseAddr = srcAddr;									//(u32)USART2_DR_Address;	//外設地址
	DMA_InitStructure.DMA_MemoryBaseAddr = (u32)0;										//內存地址,發送時候
	DMA_InitStructure.DMA_DIR =DMA_DIR_PeripheralSRC;									// DMA_DIR_PeripheralSRC;								//
	DMA_InitStructure.DMA_BufferSize = 0;
	DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
	DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
	DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
	DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
	DMA_InitStructure.DMA_Priority = DMA_Priority_High;
	DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
	DMA_Init(chn, &DMA_InitStructure);
	if(bInt)
	{
		NVIC_InitTypeDef NVIC_InitStructure;
		/* Enable the USART1 Interrupt */
		NVIC_InitStructure.NVIC_IRQChannel =DMA1_Channel1_IRQChannel+((u32)chn-(u32)DMA1_Channel1)/0x14;; //DMAChannel7_IRQChannel;
		NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = IRQPreemptionPriority;
		NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
		NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
		NVIC_Init(&NVIC_InitStructure);
		DMA_ITConfig(chn,DMA_IT_TC,ENABLE);
	}	
}

void DmaSendData(DMA_Channel_TypeDef* pDmaChnl,INT8U* pSrc,INT32U len)
{
	DMA_Cmd(pDmaChnl,DISABLE);				//停止使能 才能修改計數器
	pDmaChnl->CNDTR=len;
	pDmaChnl->CMAR=(INT32U)pSrc;
	DMA_Cmd(pDmaChnl,ENABLE);				//啓動發送	
}

INT8U DmaGetData(DMA_Channel_TypeDef* pDmaChnl,INT8U *pDst,INT32U max,INT8U **ppDat)
{
	INT8U cnt=0;
	DMA_Cmd(pDmaChnl,DISABLE);												//停止使能 才能修改計數器
	DMA_ClearFlag(DMA_IT_TC<<(((u32)pDmaChnl-(u32)DMA1_Channel1)/5));		//清除傳輸完成標識 
	*ppDat=(INT8U*)pDmaChnl->CMAR;
	cnt=max-pDmaChnl->CNDTR;
	pDmaChnl->CMAR=(INT32U)pDst;
	pDmaChnl->CNDTR=max;
	DMA_Cmd(pDmaChnl,ENABLE);													//啓動接收
	return cnt;
}

#if 0
void DmaSetGetData(DMA_Channel_TypeDef* pDmaChnl,INT8U *pDst,INT32U max)
{
	DMA_Cmd(pDmaChnl,DISABLE);				//停止使能 才能修改計數器
	pDmaChnl->CMAR=(INT32U)pDst;
	pDmaChnl->CNDTR=max;
	DMA_Cmd(pDmaChnl,ENABLE);					//啓動發送		
}
#endif

#if 0
void  DMAChannel7_IRQHandler (void)
{
	OSIntEnter();
	DMA_ClearFlag(DMA1_FLAG_TC7);								//清除發送完成標誌位
	OSSemPost(OSSEMPRT);
    OSIntExit();                                                /* Tell uC/OS-II that we are leaving the ISR                */
}
#endif


//void  DMAChannel3_IRQHandler (void)
//{
//	OSIntEnter();
//	DMA_ClearFlag(DMA1_FLAG_TC3);								//清除發送完成標誌位
//	//OSSemPost(OSSEMPRT);
//    OSIntExit();                                                /* Tell uC/OS-II that we are leaving the ISR                */
//}

 

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