uart的时钟路径
管理串口时钟的寄存器CCM_CSCDR1.
在此寄存器中我们可以设置UART_CLK_ROOT的时钟
上图中,第六位UART_CLK_SEL一般设置为0,即选择pll3_80m
而UART_CLK_PODF则为一个6位的分频器,将80MHz的频率分频作为UART_CLK_ROOT
一般设置为1分频,所以UART_CLK_ROOT=80MHz
lpuart1_ipg_clk 时钟,这是串口 1 的外设时钟,用于驱动串口 1 的正常运行(除波特率发生器以外的时钟,都由该时钟驱动),该时钟来自 IPG_CLK_ROOT,由 CCGR5[CG12]控制。
lpuart1_ipg_clk_s 时钟,这是串口 1 的访问时钟,必须开启该时钟,才可以访问串口 1 相关寄存器,该时钟来自 IPG_CLK_ROOT,由 CCGR5[CG12]控制。
lpuart1_lpuart_baud_clk 时钟,这是串口 1 波特率发生器的时钟源,来自:UART_CLK_ROOT,可以把它看作是 lpuart1_lpuart_baud_gateed_clk 时钟的上一级,它无需开关控制。
lpuart1_lpuart_baud_gateed_clk 时钟,这是串口 1 波特率发生器的时钟,该时钟同样是来自:UART_CLK_ROOT,串口 1 的波特率生成和这个时钟直接相关,由 CCGR5[CG12]控制。
1.时钟使能
需要使能3个时钟,lpuart1_ipg_clk、lpuart1_ipg_clk_s 、lpuart1_lpuart_baud_gateed_clk 这三个时钟均由CCGR5[CG12]控制
设置这两位为1
2.串口波特率设置
串口波特率设置。每个串口都有一个自己独立的波特率寄存器 BAUD,通过设置该寄存器就可以达到配置不同波特率的目的。
3.串口设置
LPUART Control Register (CTRL)
RIE 位(位 21)为接收中断使能位,设置该位为 1,则当 STAT 寄存器的 RDRF 位(接收数据寄存器满标志)为 1 时,将产生串口中断;
TE 位(位 19)为串口发送使能位,设置该位为 1,则开启串口发送功能;
RE 位(位 18)为串口接收使能位,设置该位为 1,则开启串口接收功能;
M 位(位 4)为 9/8 位模式选择位,设置该位为 0,则使用 8 位数据模式;
PE 位(位 1)为校验使能位,设置该位为 0,则不使用硬件奇偶校验。
4.数据接收和发送
LPUART Data Register (DATA)
当我们需要发送数据的时候,往 LPUARTx→DATA(x=1~8)寄存器写入你想要发送的数据,然后加载到 Tx Buffer,通过串口发送出去。
而当有串口数据接收到,需要读取出来的时候,通过读取 LPUARTx→DATA 寄存器,即可读取 Rx Buffer,将数据读取出来。
这里 Rx/Tx Buffer实际上上就是 RX/TX FIFO,因为我们没设置 FIFO,默认 Rx/Tx Buffer 就是 1 个字符。
5.串口状态
LPUART Status Register (STAT)
21位:RDRF(接收数据寄存器满标志),当该位被置 1 的时候,就是提示已经有数据被接收到了(存放在 Rx Buffer),并且可以读出来了。这时候我们要做的就是尽快去读取 LPUARTx→DATA,通过读 LPUARTx→DATA 可以将该位清零。
23位:TDRE(发送数据寄存器空标志),当该位被置位的时候,表示 Tx Buffer 里面的数据已经被发送完成了。如果设置了这个位的中断,则会产生中断。通过往 LPUARTx→DATA 寄存器写入数据可以将该位清零。
在fsl_lpuart.c 和 fsl_lpuart.h 中
status_t LPUART_Init(LPUART_Type *base, const lpuart_config_t *config, uint32_t srcClock_Hz)
base:LPUART1~LPUART8。
config 用来设置串口的初始化参数
lpuart_config_t 定义如下:
typedef struct _lpuart_config
{
uint32_t baudRate_Bps; /*!< LPUART baud rate 波特率*/
lpuart_parity_mode_t parityMode; /*!< Parity mode, disabled (default), even, odd 奇偶校验*/
lpuart_data_bits_t dataBitsCount; /*!< Data bits count, eight (default), seven 数据长度*/
bool isMsb; /*!< Data bits order, LSB (default), MSB 是否为MSB*/
#if defined(FSL_FEATURE_LPUART_HAS_STOP_BIT_CONFIG_SUPPORT) && FSL_FEATURE_LPUART_HAS_STOP_BIT_CONFIG_SUPPORT
lpuart_stop_bit_count_t stopBitCount; /*!< Number of stop bits, 1 stop bit (default) or 2 stop bits 停止位 */
#endif
#if defined(FSL_FEATURE_LPUART_HAS_FIFO) && FSL_FEATURE_LPUART_HAS_FIFO
uint8_t txFifoWatermark; /*!< TX FIFO watermark */
uint8_t rxFifoWatermark; /*!< RX FIFO watermark */
#endif
#if defined(FSL_FEATURE_LPUART_HAS_MODEM_SUPPORT) && FSL_FEATURE_LPUART_HAS_MODEM_SUPPORT
bool enableRxRTS; /*!< RX RTS enable 接收RTS*/
bool enableTxCTS; /*!< TX CTS enable 发送RTS*/
lpuart_transmit_cts_source_t txCtsSource; /*!< TX CTS source */
lpuart_transmit_cts_config_t txCtsConfig; /*!< TX CTS configure */
#endif
lpuart_idle_type_select_t rxIdleType; /*!< RX IDLE type. */
lpuart_idle_config_t rxIdleConfig; /*!< RX IDLE configuration. */
bool enableTx; /*!< Enable TX 使能发送*/
bool enableRx; /*!< Enable RX 使能接收*/
} lpuart_config_t;
baudRate_Bps 用来设置串口波特率。
parityMode 用来设置校验模式
typedef enum _lpuart_parity_mode
{
kLPUART_ParityDisabled = 0x0U, //无奇偶校验
kLPUART_ParityEven = 0x2U, //偶校验
kLPUART_ParityOdd = 0x3U, //奇校验
} lpuart_parity_mode_t;
dataBitsCount 用来设置数据数据长度,可以设置为 8 位数据或者 7 位数据(不包含停止位),
typedef enum _lpuart_data_bits
{
kLPUART_EightDataBits = 0x0U, //8 位数据位
#if defined(FSL_FEATURE_LPUART_HAS_7BIT_DATA_SUPPORT) &&
FSL_FEATURE_LPUART_HAS_7BIT_DATA_SUPPORT
kLPUART_SevenDataBits = 0x1U, //7 位数据位
#endif
} lpuart_data_bits_t;
isMsb 用来设置是否开启高位在前的传输模式。
stopBitCount 用来设置停止位,可以设置 1 位或 2 位停止位
typedef enum _lpuart_stop_bit_count
{
kLPUART_OneStopBit = 0U, //1 位停止位
kLPUART_TwoStopBit = 1U, //2 位停止位
} lpuart_stop_bit_count_t;
enableTx 和 enableRx 用来设置串口的收发开关的。我们一般都是收发全部打开的。
srcClock_Hz 用来设置串口的根时钟频率,比如我们一般设置串口的根时钟频率为 PLL3_SW_CLK/6=80M,因此 srcClock_Hz=80000000。
LPUART_Init 函数会调用 CLOCK_EnableClock 函数来使能 LPUART 时钟的
void LPUART_GetDefaultConfig(lpuart_config_t *config)
{
assert(NULL != config);
/* Initializes the configure structure to zero. */
(void)memset(config, 0, sizeof(*config));
config->baudRate_Bps = 115200U; //波特率115200
config->parityMode = kLPUART_ParityDisabled; //关闭奇偶校验
config->dataBitsCount = kLPUART_EightDataBits; //8位数据位
config->isMsb = false;
#if defined(FSL_FEATURE_LPUART_HAS_STOP_BIT_CONFIG_SUPPORT) && FSL_FEATURE_LPUART_HAS_STOP_BIT_CONFIG_SUPPORT
config->stopBitCount = kLPUART_OneStopBit; //1位停止位
#endif
#if defined(FSL_FEATURE_LPUART_HAS_FIFO) && FSL_FEATURE_LPUART_HAS_FIFO
config->txFifoWatermark = 0U;
config->rxFifoWatermark = 0U;
#endif
#if defined(FSL_FEATURE_LPUART_HAS_MODEM_SUPPORT) && FSL_FEATURE_LPUART_HAS_MODEM_SUPPORT
config->enableRxRTS = false; //关闭RTS
config->enableTxCTS = false; //关闭CTS
config->txCtsConfig = kLPUART_CtsSampleAtStart;
config->txCtsSource = kLPUART_CtsSourcePin;
#endif
config->rxIdleType = kLPUART_IdleTypeStartBit;
config->rxIdleConfig = kLPUART_IdleCharacter1;
config->enableTx = false; //关闭发送
config->enableRx = false; //关闭接收
}
中断使能函数 LPUART_EnableInterrupts(LPUART_Type *base, uint32_t mask)
中断具体类型
enum _lpuart_interrupt_enable
{
#if defined(FSL_FEATURE_LPUART_HAS_LIN_BREAK_DETECT) && FSL_FEATURE_LPUART_HAS_LIN_BREAK_DETECT
kLPUART_LinBreakInterruptEnable = (LPUART_BAUD_LBKDIE_MASK >> 8), /*!< LIN break detect. */
#endif
kLPUART_RxActiveEdgeInterruptEnable = (LPUART_BAUD_RXEDGIE_MASK >> 8), /*!< Receive Active Edge. */
kLPUART_TxDataRegEmptyInterruptEnable = (LPUART_CTRL_TIE_MASK), /*!< Transmit data register empty. */
kLPUART_TransmissionCompleteInterruptEnable = (LPUART_CTRL_TCIE_MASK), /*!< Transmission complete. */
kLPUART_RxDataRegFullInterruptEnable = (LPUART_CTRL_RIE_MASK), /*!< Receiver data register full. */
kLPUART_IdleLineInterruptEnable = (LPUART_CTRL_ILIE_MASK), /*!< Idle line. */
kLPUART_RxOverrunInterruptEnable = (LPUART_CTRL_ORIE_MASK), /*!< Receiver Overrun. */
kLPUART_NoiseErrorInterruptEnable = (LPUART_CTRL_NEIE_MASK), /*!< Noise error flag. */
kLPUART_FramingErrorInterruptEnable = (LPUART_CTRL_FEIE_MASK), /*!< Framing error flag. */
kLPUART_ParityErrorInterruptEnable = (LPUART_CTRL_PEIE_MASK), /*!< Parity error flag. */
#if defined(FSL_FEATURE_LPUART_HAS_FIFO) && FSL_FEATURE_LPUART_HAS_FIFO
kLPUART_TxFifoOverflowInterruptEnable = (LPUART_FIFO_TXOFE_MASK >> 8), /*!< Transmit FIFO Overflow. */
kLPUART_RxFifoUnderflowInterruptEnable = (LPUART_FIFO_RXUFE_MASK >> 8), /*!< Receive FIFO Underflow. */
#endif
};
关闭中断的函数void LPUART_DisableInterrupts(LPUART_Type *base, uint32_t mask)
数据发送函数
static inline void LPUART_WriteByte(LPUART_Type *base, uint8_t data)
{
base->DATA = data;
}
base:串口
data:写入的数据
数据接收函数
static inline uint8_t LPUART_ReadByte(LPUART_Type *base)
{
#if defined(FSL_FEATURE_LPUART_HAS_7BIT_DATA_SUPPORT) && FSL_FEATURE_LPUART_HAS_7BIT_DATA_SUPPORT
uint32_t ctrl = base->CTRL;
uint8_t result;
bool isSevenDataBits = (((ctrl & LPUART_CTRL_M7_MASK) != 0U) ||
(((ctrl & LPUART_CTRL_M7_MASK) == 0U) && ((ctrl & LPUART_CTRL_M_MASK) == 0U) &&
((ctrl & LPUART_CTRL_PE_MASK) != 0U)));
if (isSevenDataBits)
{
result = (uint8_t)(base->DATA & 0x7FU);
}
else
{
result = (uint8_t)base->DATA;
}
return result;
#else
return (uint8_t)(base->DATA);
#endif
}
参数 base 指定要操作的串口
函数返回值就是读取到的串口接收值,此函数就是读取串口的 DATA 寄存器。
多次数据收发
void LPUART_WriteBlocking(LPUART_Type *base, const uint8_t *data, size_t length)
status_t LPUART_ReadBlocking(LPUART_Type *base, uint8_t *data, size_t length)
LPUART_WriteBlocking 用于多字节发送,此函数会产生阻塞,也就是每发送一个字节的数据,然后阻塞等待发送完成,发送完成以后就发送下一个字节的数据。参数 base 表明操作的哪个串口,data 是要发送的数据,length 是要发送的数据长度。
LPUART_ReadBlocking 用于多字节的接收,此函数也会产生阻塞。参数 base 表明操作的哪
个串口,data 是接收数据缓冲区,length 是要接收的数据长度。
观察串口的工作状态
uint32_t LPUART_GetStatusFlags(LPUART_Type *base)
{
uint32_t temp;
temp = base->STAT;
#if defined(FSL_FEATURE_LPUART_HAS_FIFO) && FSL_FEATURE_LPUART_HAS_FIFO
temp |= (base->FIFO &
(LPUART_FIFO_TXEMPT_MASK | LPUART_FIFO_RXEMPT_MASK | LPUART_FIFO_TXOF_MASK | LPUART_FIFO_RXUF_MASK)) >>
16U;
#endif
return temp;
}
void LPUART1_Init(uint32 bound)
{
lpuart_config_t lpuart1_config;
uint32 freq=0;
CLOCK_EnableClock(kCLOCK_Lpuart1);//使能LPUART1时钟,CCM_CCGR5_CG12
CLOCK_SetMux(kCLOCK_UartMux,0);//2路复用选择
CLOCK_SetDiv(kCLOCK_UartDiv,0);//分频
//set iomuxc
IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B0_12_LPUART1_TX,0U);
IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B0_13_LPUART1_RX,0U);
//set io B0_12&B0_13
//关闭 Hyst,下拉 100K Ohm,选择Keeper,使能pull/keeper,关闭开漏,100MHz_SPEED1,驱动能力R0/6,低转换速度
IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B0_12_LPUART1_TX,0x10B0u);
IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B0_13_LPUART1_RX,0x10B0u);
freq = BOARD_DebugConsoleSrcFreq();
LPUART_GetDefaultConfig(&lpuart1_config);
lpuart1_config.baudRate_Bps=bound;
lpuart1_config.dataBitsCount=kLPUART_EightDataBits;
lpuart1_config.stopBitCount=kLPUART_OneStopBit;
lpuart1_config.parityMode=kLPUART_ParityDisabled;
lpuart1_config.enableRx=true;
lpuart1_config.enableTx=true;
LPUART_Init(LPUART1,&lpuart1_config,freq);
// NVIC_SetPriority(LPUART8_IRQn,15);
// uart_rx_irq(USART_8,1);
}
本文参照正点原子RT1052 开发指南。