LPUART是低功耗UART,它是Kinetis系列芯片(單片機)所支持的新型UART。與傳統的UART不同的是,它可以在不同的低功耗模式下操作,同時支持更高的波特率。本文將會從以下幾個方面對LPUART串口進行詳細闡述。
一、LPUART基礎介紹
LPUART是一種帶有衝突檢測特性的USART,主要用於處理異步串行通信。LPUART與傳統的UART類似,但是它支持更高的波特率,並且可以在低功耗模式下工作,這使得它非常適合用於那些對功耗要求較高的應用場合。在Kinetis系列芯片中,LPUART是內置的,同時也支持多個串口通信。LPUART的特點包括:
- 支持異步通信,包括8位和9位數據位模式
- 支持可編程波特率發生器,可以支持幾乎任何波特率
- 支持單個起始位或兩個起始位模式
- 支持奇偶校驗和無校驗模式
- 支持支持多種中斷模式和DMA傳輸模式
下面是LPUART的初始化函數,其中包含了LPUART的基本配置。
void LPUART_Init(LPUART_Type* base, const lpuart_config_t* config, uint32_t srcClock_Hz) { assert(config != NULL); uint32_t baudRate_Bps; uint32_t osr, sbr; if ((config->parityMode == kLPUART_ParityDisabled) && (config->stopBitCount == kLPUART_OneStopBit) && (config->bitCountPerChar == kLPUART_EightBitsPerChar)) { /* Calculate baudrate */ baudRate_Bps = config->baudRate_Bps; /* Get the OSR value */ osr = (((base->BAUD & LPUART_BAUD_OSR_MASK) >> LPUART_BAUD_OSR_SHIFT) + 1U); /* Calculate the sbr value using OSR and baud rate */ sbr = (srcClock_Hz / (baudRate_Bps * osr)); base->BAUD = LPUART_BAUD_OSR(osr - 1U) | LPUART_BAUD_SBR(sbr); } else { /* Configure parity/sb/char */ base->CTRL = (base->CTRL & ~(LPUART_CTRL_PE_MASK | LPUART_CTRL_PT_MASK | LPUART_CTRL_M_MASK)) | LPUART_CTRL_PE((config->parityMode != kLPUART_ParityDisabled ? 1UL : 0UL)) | LPUART_CTRL_PT((config->parityMode == kLPUART_ParityOdd ? 1UL : 0UL)) | LPUART_CTRL_M((config->bitCountPerChar == kLPUART_EightBitsPerChar ? 0UL : 1UL)); /* Calculate baud rate */ baudRate_Bps = config->baudRate_Bps; /* Calculate sbr */ sbr = srcClock_Hz / (baudRate_Bps * ((base->BAUD & LPUART_BAUD_OSR_MASK) + 1U)); base->BAUD = LPUART_BAUD_SBR(sbr); } }
二、LPUART中斷使用
LPUART可以使用中斷來實現數據接收和發送的異步操作。為了實現中斷操作,需要開啟LPUART的中斷使能,並且配置中斷處理函數。對於接收中斷,需要配置相應的中斷觸發條件,例如接收緩衝區非空時觸發中斷。當中斷觸發時,中斷處理函數會自動被調用,從而執行相應的接收或發送操作。下面是一個LPUART的中斷髮送和接收函數的例子:
void LPUART_TransferCreateHandle(LPUART_Type *base, lpuart_handle_t *handle, lpuart_transfer_callback_t callback, void *userData) { uint32_t instance; /* Zero the handle. */ memset(handle, 0, sizeof(*handle)); /* Get the instance number */ instance = LPUART_GetInstance(base); /* Save LPUART base and context used in IRQ handler */ s_lpuartBases[instance] = base; s_lpuartHandle[instance] = handle; /* Enable interrupt in NVIC. */ EnableIRQ(s_lpuartIRQ[instance]); /* Save callback and user data. */ handle->callback = callback; handle->userData = userData; }
三、LPUART DMA使用
LPUART還可以使用DMA來實現數據的接收和發送。DMA可以大大減小CPU的負載,同時也可以提高數據傳輸的效率。為了使用DMA來實現LPUART的數據傳輸,需要重新配置DMA模塊的通道、配置DMA傳輸模式以及DMA中斷處理函數等。下面是一個LPUART的DMA發送和接收函數的例子:
static void LPUART_TransferCompleteSendDMACallback(dma_handle_t *handle, void *userData, bool transferDone, uint32_t tcds) { lpuart_dma_handle_t *lpuartHandle = (lpuart_dma_handle_t *)userData; /* Disable LPUART TX DMA. */ LPUART_TransferAbortSendDMA(lpuartHandle->base, lpuartHandle); /* Invoke callback. */ if (lpuartHandle->callback) { lpuartHandle->callback(lpuartHandle, kStatus_LPUART_TxIdle, lpuartHandle->userData); } }
四、LPUART應用實例
LPUART可以在多種應用場合中使用,例如醫療、智能家居、工業控制等領域。下面是一個LPUART應用的例子,該例子演示如何使用LPUART來實現兩種不同的數據傳輸方式。其中一種是通過中斷實現,另一種是通過DMA實現。
#include "fsl_lpuart.h"
#include "fsl_debug_console.h"
#include "board.h"#include "fsl_dma.h"
#include "fsl_dmamux.h"
#include "fsl_common.h"
/*******************************************************************************
* Definitions
******************************************************************************/
#define DEMO_USART USART0
#define DEMO_USART_CLK_SRC kCLOCK_MainClk
#define DEMO_USART_CLK_FREQ CLOCK_GetFreq(kCLOCK_MainClk)
#define EXAMPLE_UART UART0
#define USART_IRQHandler FLEXCOMM0_IRQHandler
#define USART_IRQ FLEXCOMM0_IRQn#define LPUART_DMA_DMAMUX_BASEADDR DMAMUX
#define LPUART_DMA_BASEADDR DMA0
#define LPUART_TX_DMA_CHANNEL 0U
#define LPUART_RX_DMA_CHANNEL 1U
#define LPUART_TX_DMA_REQUEST kDmaRequestMuxLPUART0Tx
#define LPUART_RX_DMA_REQUEST kDmaRequestMuxLPUART0Rx
#define LPUART_DMA_TX_COMPLETE_IRQn DMA0_Channel0_IRQn
#define LPUART_DMA_RX_COMPLETE_IRQn DMA0_Channel1_IRQn
#define LPUART_DMA_TX_COMPLETE_HANDLER DMA0_Channel0_IRQHandler
#define LPUART_DMA_RX_COMPLETE_HANDLER DMA0_Channel1_IRQHandlertypedef enum _lpuart_dma_mode
{
kLPUART_UartPolling, /*!< LPUART polling operation mode */
kLPUART_UartInterrupt, /*!< LPUART interrupt operation mode */
kLPUART_UartDma /*!< LPUART DMA operation mode */
} lpuart_dma_mode_t;/*******************************************************************************
* Prototypes
******************************************************************************//*******************************************************************************
* Variables
******************************************************************************/
AT_NONCACHEABLE_SECTION_INIT(static uint8_t g_tipString[]) = "LPUART DMA example\r\nSend back received data.\r\n";
static lpuart_dma_mode_t s_dmaMode; /*!< LPUART DMA mode. */
static lpuart_transfer_t s_sendXfer; /* LPUART send data structure */
static lpuart_transfer_t s_receiveXfer; /* LPUART receive data structure */
static lpuart_handle_t s_lpuartHandle; /*!< Handler for LPUART driver */
static volatile bool s_lpuartTxIdle = false; /*!< LPUART transfer completed flag. */
static volatile bool s_lpuartRxIdle = false; /*!DATA, s_bufferLpuart, 1, sizeof(uint8_t), kDMA_PeripheralToMemory);
DMA_SubmitTransfer(&s_rxHandle);
DMA_StartTransfer(&s_rxHandle);
s_lpuartRxCompleteCount++;
}void LPUART_DMA_TX_COMPLETE_HANDLER(void)
{
s_lpuartTxIdle = true;
s_lpuartTxCompleteCount++;
}void LPUART_DmaUserCallback(LPUART_Type *base, lpuart_dma_handle_t *handle, status_t status, void *userData)
{
if (kStatus_LPUART_TxIdle == status)
{
s_lpuartTxIdle = true;
}if (kStatus_LPUART_RxIdle == status)
{
s_lpuartRxIdle = true;
}
}void LPUART_SendDataBlocking(LPUART_Type *base, const uint8_t *data, size_t length)
{
size_t i = 0;while (i STAT & LPUART_STAT_TDRE_MASK))
{
}
base->DATA = data[i++];
}
}status_t LPUART_RecvDataBlocking(LPUART_Type *base, uint8_t *data, size_t length)
{
size_t i = 0;while (i STAT & LPUART_STAT_RDRF_MASK))
{
}
data[i++] = base->DATA;
}return kStatus_Success;
}void LPUART_TransferInit(LPUART_Type *base, lpuart_dma_handle_t *handle, lpuart_dma_mode_t mode, uint8_t *ringBuffer,
uint32_t ringBufferSize)
{
lpuart_transfer_t xfer;memset(handle, 0, sizeof(*handle));
handle->dmaHandle = &s_txHandle;
handle->ringBuffer = ringBuffer;
handle->rxRingBufferIndex = 0;
handle->rxRingBufferSize = ringBufferSize;switch (mode)
{
case kLPUART_UartDma:
LPUART_TransferCreateHandleDMA(base, handle, LPUART_DmaUserCallback, NULL, &s_dmamuxRxHandle, &s_dmamuxTxHandle);
handle->mode = kLPUART_UartDma;
break;
case kLPUART_UartInterrupt:
LPUART_TransferCreateHandle(base, handle, LPUART_UserCallback, NULL);
NVIC_SetPriority(DEMO_USART_IRQ, 2U);
handle->mode = kLPUART_UartInterrupt;
break;
case kLPUART_UartPolling:
xfer.data = handle->ringBuffer;
xfer.dataSize = 1;
LPUART_TransferSendNonBlocking(base, &s_sendXfer);
handle->mode = kLPUART_UartPolling;
break;
default:
break;
}
}void DEMO_LPUART_Transfer(void)
{
lpuart_config_t config;
uint32_t srcClock_Hz;
s_lpuartTxIdle = false;
s_lpuartRxIdle = false;/*
* config.baudRate_Bps = 115200U;原創文章,作者:CQMAG,如若轉載,請註明出處:https://www.506064.com/zh-hk/n/334687.html