STM32 串口傳輸最佳處理方式 FreeRTOS+隊列+DMA+IDLE (一)

當多個串口數據都有大量數據來時,我們如何最佳處理STM32串口通信數據?
可以通過FreeRTOS+隊列的發送方式。
下面將串口DMA發送處理過程
中心思想:
1、建立一個大的環形數組
2、發送的數據時,將數據存入到大的數組
3、需要發送數據的長度以及在大數組中的位置,通過隊列,發送出去。
4、通過隊列,等待有數據進入隊列。
5、啓動DMA,等待DMA傳輸完成。

/******************************************************************
將需要發送的數據存入一個大數組內,通過隊列發送,將長度,以及數組內的地址
發送出去。 數組的大小可以是隊列項目數的N倍,一般5倍就好了,隊列項目數5個
已經不少了。
即:假如創建5個隊列消息,每個長度爲4字節。數組大小 MAX_FRAME_COMM_BUFFER_SIZE 
=5*每一次串口傳輸數據長度;
static uint8_t txbuf_Blue_DMA[MAX_FRAME_COMM_BUFFER_SIZE]; /*緩存的數組大小*/
DMA_MemoryBaseAddr=txbuf_Blue_tmp;
*****************************************************************/
void USART1_SendData(uint8_t *ps,uint16_t len)
{
    uint16_t i;		
    BufferLoopData_Typedef buffer_loop;
    buffer_loop.start_addr = ps_tbwr_Blue;
    buffer_loop.len = len;

    for (i=0;i<len;i++)
    {
        if (ps_tbwr_Blue >= MAX_FRAME_COMM_BUFFER_SIZE)
        {
            ps_tbwr_Blue = 0;
        }        
        txbuf_Blue_DMA[ps_tbwr_Blue] = *(ps+i);//txbuf_Blue_DMA爲
        ps_tbwr_Blue++;        
    }
    xQueueSendToBack(xQueue_Blue_tx,(void *)&buffer_loop,portMAX_DELAY);   
}

/******************************************************************
隊列接收到數據所在數組的地址以及長度,然後通過DMA發送出去
*****************************************************************/
void USART1_SendTask(void const * argument)
{
    uint16_t i;
    BufferLoopData_Typedef buffer_loop;
    extern uint8_t txbuf_Blue_tmp[MAX_FRAME_COMM_LEN];   
      for (;;)
    {
        xQueueReceive(xQueue_Blue_tx,&buffer_loop,portMAX_DELAY);  
		//SCB_CleanDCache();
        for (i=0;i<buffer_loop.len;i++)
        {
            if (buffer_loop.start_addr >= MAX_FRAME_COMM_BUFFER_SIZE)
            {
                buffer_loop.start_addr = buffer_loop.start_addr - MAX_FRAME_COMM_BUFFER_SIZE;
            }

            txbuf_Blue_tmp[i] = txbuf_Blue_DMA[buffer_loop.start_addr];
            
            buffer_loop.start_addr += 1;
            
        }   
        //SCB_CleanInvalidateDCache();
        Uart1_DMASend_Start(&txbuf_Blue_tmp[0],buffer_loop.len);//通過DMA發送
        xSemaphoreTake(BinarySem_UART1_tx_finish_Handle,portMAX_DELAY); //等待DMA發送成功
        taskYIELD();  
    } 
}

串口DMA發送代碼:

/**********************************************************************
串口USART1  DMA發送數據
********************************/
uint8_t Uart1_DMASend_Start(uint8_t* buffer, u16 size)
{
	if(!size) return 0;
  while (DMA_GetCurrDataCounter(DMA1_Channel4));
  if(buffer) memcpy(txbuf_Blue_tmp, buffer,(size > 1024?1024:size));
	
  //DMA發送數據,DMA
  DMA_Cmd(DMA1_Channel4, DISABLE);
  DMA1_Channel4->CNDTR = size;
  DMA_Cmd(DMA1_Channel4, ENABLE);  
  return size;
}

中斷代碼:
//中斷傳輸完成

void DMA1_Channel4_IRQHandler(void)   
{
	portBASE_TYPE xHigherPriorityTaskWoken;
	if(DMA_GetITStatus(DMA1_FLAG_TC4))
	{
		DMA_ClearFlag(DMA1_FLAG_TC4);
		xSemaphoreGiveFromISR(BinarySem_UART1_tx_finish_Handle,&xHigherPriorityTaskWoken); 
	}
}

串口初始化:

	USART_Config();
    UART_DMA_Config();
	

串口初始化詳細代碼

//串口DMA初始化
void UART_DMA_Config(void){
	NVIC_InitTypeDef NVIC_InitStructure;

    DMA_Config(DMA1_Channel4,(u32)&USART1->DR,(u32)txbuf_Blue_tmp,DMA_DIR_PeripheralDST,DMA_Priority_Medium,0,DMA_Mode_Normal);
//txbuf_Blue_tmp  USART1 DMA發送基地址
	DMA_Config(DMA1_Channel5,(u32)&USART1->DR,(u32)rxbuf_Uart1_DMA,DMA_DIR_PeripheralSRC,DMA_Priority_Medium,MaxSize_FRAME_DISP,DMA_Mode_Circular);
  //rxbuf_Uart1_DMADMA接收基地址
  
	//NVIC初始化
	NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel4_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=6 ;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure);

	DMA_ITConfig(DMA1_Channel4,DMA_IT_TC,ENABLE);
	USART_DMACmd(USART1,USART_DMAReq_Tx,ENABLE); 
	USART_DMACmd(USART1,USART_DMAReq_Rx,ENABLE);

	DMA_Cmd (USART_RX_DMA_CHANNEL,ENABLE);
}

//串口配置初始化
void USART_Config(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	USART_InitTypeDef USART_InitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;

	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA|RCC_APB2   Periph_AFIO, ENABLE);

	//USART1_TX   GPIOA.9
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_Init(GPIOA, &GPIO_InitStructure);

	
   //USART1_RX GPIOA.10  
  	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//PA10
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
	GPIO_Init(GPIOA, &GPIO_InitStructure);

	NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=6 ;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);	
  	USART_InitStructure.USART_BaudRate = DEBUG_USART_BAUDRATE;
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;
	USART_InitStructure.USART_StopBits = USART_StopBits_1;
	USART_InitStructure.USART_Parity = USART_Parity_No;
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
	USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
	
	USART_Init(USART1, &USART_InitStructure);
	USART_ITConfig(USART1,USART_IT_IDLE,ENABLE);
	USART_Cmd(USART1, ENABLE);       
}

//DMA初始化 做成了一個封裝函數
void DMA_Config(DMA_Channel_TypeDef*DMA_CHx,u32 PeripheralBaseAddr,u32 MemoryBaseAddr,u32 dma_dir,u32 priority,u16 bufsize,u32 mode)
{
	DMA_InitTypeDef DMA_InitStructure;
 	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
    DMA_DeInit(DMA_CHx);
   	DMA_InitStructure.DMA_PeripheralBaseAddr = PeripheralBaseAddr;
	DMA_InitStructure.DMA_MemoryBaseAddr = MemoryBaseAddr;
	DMA_InitStructure.DMA_DIR = dma_dir;
	DMA_InitStructure.DMA_BufferSize = bufsize;
	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 = mode;
	DMA_InitStructure.DMA_Priority = priority;
	DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
	DMA_Init(DMA_CHx, &DMA_InitStructure);  
} 

下一篇文章來介紹如何通過DMA+FreeRTOS+IDLE接收數據

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