Kinetis KL8x 使用eDMA模塊接收串口數據

飛思卡爾的芯片KL系列Cortex-M0+內核的,其他的應該可以通用,大體一致,之前在KL25上用過,這次是KL81,我對比兩者使用類似,就是某些寄存器不同罷了

正文開始:

需要用LPUART接收上層接口的數據,比較大,而且大小不固定,之前用FIFO來接收,但是遇到收發錯亂,很不穩定,故使用eDMA來接收

#include "fsl_port_hal.h"
#include "fsl_device_registers.h"

#include "fsl_lpuart_edma_driver.h"
#include "fsl_interrupt_manager.h"
#include "board.h"
#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#if 1
unsigned char eDMA_recv_buf[1024];
int recv_flag;


void Lpuart1Init(int channal)
{
  
  //PINC3-RX,PINC4--TX
  *(volatile unsigned int *)(0x4004B00C) |= 0x00000300;
  *(volatile unsigned int *)(0x4004B010) |= 0x00000300;
  
  //uart Clock
  *(volatile unsigned int *)(0x40048004) &= 0xF3FFFFFF;
  *(volatile unsigned int *)(0x40048004) |= 0x08000000;
  *(volatile unsigned int *)(0x40048038) |= 0x00200000;
 
    LPUART1_BAUD = 0x0700000D;
    LPUART1_STAT = 0xC01FC000;
    LPUART1_CTRL = 0x00000000;
    // Add this code to ensure that the TE bit has been cleared.
    while(LPUART_BRD_CTRL_TE(LPUART1)){}
    LPUART1_MATCH = 0x00000000;
#if FSL_FEATURE_LPUART_HAS_MODEM_SUPPORT
    LPUART1_MODIR = 0x00000000;
#endif
#if FSL_FEATURE_LPUART_HAS_FIFO
//    LPUART1_FIFO = 0x0000400F;
//    LPUART1_WATER = 0x000D0000;//water = 6
#endif
    
  LPUART1_BAUD |= LPUART_BAUD_RDMAE_MASK;//RDMA Enable
  LPUART1_CTRL = 0x003C0200;//RIE ILIE TE RE LPUART1_CTRL=010
  
  NVIC_EnableIRQ(LPUART1_IRQn);
}
void Lpuart1_eDMA0Init(int channal,unsigned int D_Addr,unsigned int Block_Size)
{
  
  // Enable clock gate of eDMA module
  SIM_SCGC6 |= SIM_SCGC6_DMACHMUX_MASK;
  SIM_SCGC7 |= SIM_SCGC7_DMA_MASK;
  //DMAMUX Config
  DMAMUX_CHCFG(channal) = 0x00;
  // Enables the DMA channel and select the DMA Channel Source  
  DMAMUX_CHCFG(channal) = DMAMUX_CHCFG_SOURCE(kDmaRequestMux0LPUART1Rx & 0xFF);//選擇DMA觸發源
  DMAMUX_CHCFG(channal) |= DMAMUX_CHCFG_ENBL_MASK;//使能DMAMUX通道
                          
  
  DMA_CR = 0;
  DMA_SADDR(channal) = 0x4005500Cu;//Set Source Address is buff 設置源起始地址,這裏直接固定爲串口1的數據寄存器
  DMA_DADDR(channal) = D_Addr;//Set Destination Address is UART_DATA_REG 設置目標起始地址
  DMA_NBYTES_MLNO(channal) = 1;//Minor Byte Transfer Count is 1 設置 Minor_Byte 最小字節數,一般都是1個字節,這個根據傳輸的數據結構來定
  DMA_ATTR(channal) = (0 
                 | DMA_ATTR_SMOD(0)			// Source modulo feature disabled 設定源地址緩衝區邊界
                 | DMA_ATTR_SSIZE(0)		// Source size, 8bit 設定源地址位大小
                 | DMA_ATTR_DMOD(0)			// Destination modulo feature disabled 設定目的地址緩衝區邊界
                 | DMA_ATTR_DSIZE(0)		// Destination size, 8bit 
                  );
  DMA_SOFF(channal)  = 0x0000;// Signed Source Address Offset is 0 byte 設定源地址每次傳輸的增量
  DMA_DOFF(channal)  = 0x0001;// Signed Destination Address Offset is 1 byte 設定目的地址每次傳輸的增量
  DMA_SLAST(channal) = 0x00;//Last Source Address Adjustment 完成一次輸出之後即循環遞減完後源地址的修正量
  DMA_DLAST_SGA(channal) = 0x00;//Last Destination Address Adjustment/Scatter Gather Address 
  DMA_CITER_ELINKNO(channal) = DMA_CITER_ELINKNO_CITER(Block_Size);//設定一個循環的 Minor_Byte 量
  DMA_BITER_ELINKNO(channal) = DMA_BITER_ELINKNO_BITER(Block_Size);//
  
  DMA_CSR(channal) = 0;//
  DMA_INT |= (1 << channal);//Interrupt Request Register 寫1清0 清除中斷
  DMA_CSR(channal) |= DMA_CSR_INTMAJOR_MASK;//The end-of-major loop interrupt is enabled 設置一次循環完成中斷
  
  DMA_ERQ |= (1 << channal);//使能DMA請求
  
  NVIC_EnableIRQ(DMA0_DMA4_IRQn);//開啓DMA中斷處理

}

void eDMA_Start(int eDMA_CHn)
{
  DMA_ERQ |= (1 << eDMA_CHn);
}
void eDMA_Stop(int eDMA_CHn)
{
  DMA_ERQ &= ~(1 << eDMA_CHn);
}

void LPUART1_IRQHandler_ZNG(void)
{
  if((LPUART1_STAT & LPUART_STAT_IDLE_MASK) == LPUART_STAT_IDLE_MASK)//UART空閒中斷,這裏就是需要使用串口空閒中斷來設定一次DMA數據傳輸完成
  {
    recv_flag = 1;
    DMA_DADDR(0) = (unsigned int)eDMA_recv_buf;//填充DMA目的地址
    LPUART1_STAT |= LPUART_STAT_IDLE_MASK;
  }
  
}
/*! @brief EDMA IRQ handler with the same name in the startup code*/
void DMA0_DMA4_IRQHandler_ZNG(void)
{
    if((DMA_INT & DMA_INT_INT0_MASK) == DMA_INT_INT0_MASK)
    {
      DMA_INT |= DMA_INT_INT0_MASK;//清除中斷
      DMA_ERQ |= DMA_ERQ_ERQ0_MASK;//使能DMA請求
//      DMA_DADDR(0) = (unsigned int)recv_buf;
    }
}


#endif


在main中就只要輪詢recv_flag是否置位然後打印buff



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