/* *Copyright (C),2023 , NANOCHAP *File name: ENS1_UART.C *Author: *Version: V1.0 *Date: 2023-11- *Description: *Function List: History: 1.V1.0 Date: Author: Modification: 初版 */ /* ENS1 uart特性说明 1 符合AMBA APB规范 2 最高115200bps波特率(可以有更高的设置) 3 发送 接收 分离FIFO (16字节) 4 支持自动流控 5 标准异步通信位(开始、停止、奇偶校验) 6 DMA 7 支持回环测试 8 中断 9 全可编程串行接口特点: 数据位可设置: 5,6,7,8 偶、奇或非奇偶位的生成和检测 可产生1、1.5或2位停止位 */ #include "my_header.h" #include "ENS1_UART.h" #include "ENS1_GPIO.h" UART_FifoStructrue UART1_Fifo = { .level = bytes_8 , .DMA_Enable = 0 , .FIFO_Enable = 1 , }; UART_InitStructure UART1_Init = { .UART_BaudRate = 115200 , //计算出来的DLL DLH不为整数, 1、需要校准RC精确度,2、需要调整此处的波特率 .UART_HardwareFlowControl = 0, .FifoSetting = &UART1_Fifo , }; UART_ITStructure UART1_ITSet = { .UartIntModel = RLSI_EN | RDAI_EN , }; /*判断是否有中断挂起*/ uint8_t UART_INT_PEND(CMSDK_UART_TypeDef* UARTx) //为0时有UART的中断挂起 { return (uint8_t)(UARTx->IIR & 0x1); } /*中断类型判断*/ uint8_t UART_INT_TYPE(CMSDK_UART_TypeDef* UARTx) { return (uint8_t)((UARTx->IIR >> 1) & 0x7 ); } /*fifo 使用指示器*/ uint8_t UART_FIFO_USE(CMSDK_UART_TypeDef* UARTx) //0:非fifo模式 1:fifo 使能 { return (uint8_t)((UARTx->IIR >> 6) & 0x3); } /*清除传输FIFO*/ void UART_TXCLR(CMSDK_UART_TypeDef* UARTx) { UARTx->FCR |= (1<<2) ; } /*清除接收FIFO*/ void UART_RXCLR(CMSDK_UART_TypeDef* UARTx) { UARTx->FCR |= (1<<1); } /*FIFO使能*/ void UART_FIFOEnable(CMSDK_UART_TypeDef* UARTx) { UARTx->FCR |= (1); } /*FIFO关闭*/ void UART_FIFODisable(CMSDK_UART_TypeDef* UARTx) { UARTx->FCR &=~ 1; } /*接收数据*/ uint8_t READ_UART_RCVBuff(CMSDK_UART_TypeDef* UARTx ) { return (uint8_t)(UARTx->RBR & 0xff); } /*发送数据*/ void WRITE_UART_THRBuff(CMSDK_UART_TypeDef* UARTx ,uint8_t data) { UARTx->THR = data; } /*FIFO 状态读取*/ uint8_t UART_RX_FIFO_LEN(CMSDK_UART_TypeDef* UARTx) { return (uint8_t)((UARTx->FSR & 0x001f0000)>>16); //读取当前接收FIFO数据长度 } uint8_t UART_TX_FIFO_LEN(CMSDK_UART_TypeDef* UARTx) { return (uint8_t)((UARTx->FSR & 0x00001f00)>>8); //读取当前发送FIFO数据长度 } uint8_t UART_RX_FIFO_FULL(CMSDK_UART_TypeDef* UARTx) { return (uint8_t)((((UARTx->FSR & 0x8)>> 3 )==1) ? (1) : (0)) ; //当前读取FIFO是否为满? } uint8_t UART_RX_FIFO_EMPTY(CMSDK_UART_TypeDef* UARTx) { return (uint8_t)((((UARTx->FSR & 0x4) >> 2)==1) ? (1) : (0) ) ; //当前读取FIFO是否为空? } uint8_t UART_TX_FIFO_FULL(CMSDK_UART_TypeDef* UARTx) { return (uint8_t)((((UARTx->FSR & 0x2) >> 1)==1) ? (1) : (0)) ; //当前发送FIFO是否为满? } uint8_t UART_TX_FIFO_EMPTY(CMSDK_UART_TypeDef* UARTx) { return (uint8_t)(((UARTx->FSR & 0x1)==1) ? (1) : (0)) ; //当前发送FIFO是否为空? } /*收发线状态获取*/ uint8_t UARTLine_RCVError(CMSDK_UART_TypeDef* UARTx) { return (uint8_t)((UARTx->LSR>>7) & 0x1); //返回0 没有错误, 返回1 在fifo和非fifo状态下都有一个校验/帧/或接收缓存或fifo 的中断指示(默认不使能break) } /*判断发送缓存是否为空*/ uint8_t UARTLine_TRANSEmpty(CMSDK_UART_TypeDef* UARTx) { return (uint8_t)((UARTx->LSR>>6) & 0x1) ; } /*判断THR是否为空*/ uint8_t UARTLine_THREmpty(CMSDK_UART_TypeDef* UARTx) { return (uint8_t)((UARTx->LSR>>5) & 0x1) ; } /* 初始化UART需要以下步骤: 1. 执行必要的设备引脚多路复用设置。 2. 通过将适当的时钟除数值写入除数锁存寄存器(DLL和DLH)来设置所需的波特率。 3. 如果要使用FIFO,请选择所需的触发等级,并通过将适当的值写入(FCR)来启用FIFO。 在FCR寄存器的 FIFOEN 位需首先配置。 4. 通过向行控制寄存器(LCR)写入适当的值来选择所需的协议设置。 5. 如果需要自动流量控制,则将适当的值写入调制解调器控制寄存器(MCR)。 请注意,并非所有uart都支持自动流量控制。 6. 对挂起事件的选择所需响应通过配置FREE位, 通过在(PMU)寄存器中设置TXRST和RXRST位来释放位并使能UART */ //uart初始化,参数1:uart0/1,参数2:uart参数设置结构体 void UART_Init(CMSDK_UART_TypeDef *CMSDK_UART, UART_InitStructure* uart_paraX){ uint16_t divisor_value; uint8_t overSamp_mode; /* 1 GPIO - alt_function*/ if(CMSDK_UART == CMSDK_UART0){ PCLK_Enable(UART0_PCLK_EN); GPIO_AltFunction(UART0_RX , ALT_FUNC1); //rx GPIO_AltFunction(UART0_TX , ALT_FUNC1); //tx } else if(CMSDK_UART == CMSDK_UART1) { PCLK_Enable(UART1_PCLK_EN); GPIO_AltFunction(UART1_RX , ALT_FUNC1); //RX GPIO_AltFunction(UART1_TX , ALT_FUNC1); //TX } /* 2 波特率设置*/ if(((CMSDK_UART->MDR)&0x00000001) == 0) { overSamp_mode = 16; //默认0 } else { overSamp_mode = 13; } divisor_value = (uint16_t)((uint32_t)(APB_Clock_Freq / uart_paraX->UART_BaudRate / overSamp_mode) - 1); CMSDK_UART->DLL = (uint8_t)(divisor_value & 0x0011); CMSDK_UART->DLH = (uint8_t)((divisor_value & 0x1100)>>8); /*FCR配置 FIFO control*/ CMSDK_UART->FCR |= (uart_paraX->FifoSetting->level <<6); if(uart_paraX->FifoSetting->FIFO_Enable == 1) { CMSDK_UART->FCR |= (1); } /*LCR配置,不做配置,默认N 8 1 */ /*MCR自动流控配置*/ if(uart_paraX->UART_HardwareFlowControl == 1) { CMSDK_UART->MCR |= (1<<5); } /*电源管理寄存器PMU 的TXRST和RXRST设置,不需要设置*/ } /*UART 的中断设置*/ void UART_ITConfig(CMSDK_UART_TypeDef *CMSDK_UART, UART_ITStructure* uart_paraX) { if(CMSDK_UART == CMSDK_UART1){ NVIC_DisableIRQ(UART1_IRQn);//Disable NVIC interrupt NVIC_ClearPendingIRQ(UART1_IRQn);//Clear Pending NVINVIC_EnableIRQ(UART1_IRQn);//Enable NVIC interrupt } else if(CMSDK_UART == CMSDK_UART0){ NVIC_DisableIRQ(UART0_IRQn);//Disable NVIC interrupt NVIC_ClearPendingIRQ(UART0_IRQn);//Clear Pending NVIC interrupt } /*IER配置,中断使能寄存器*/ CMSDK_UART->IER |= (uart_paraX->UartIntModel); if(CMSDK_UART == CMSDK_UART1){ NVIC_EnableIRQ(UART1_IRQn); } else if(CMSDK_UART == CMSDK_UART0){ NVIC_EnableIRQ(UART0_IRQn); } } unsigned char UartPutc(CMSDK_UART_TypeDef *CMSDK_UART ,unsigned char my_ch) { while (UARTLine_THREmpty(CMSDK_UART) == 0x0); WRITE_UART_THRBuff(CMSDK_UART,my_ch); return (my_ch); } /* 中断与中断状态清除 1 接收线状态:INT_RCV_LINE_STATUS 溢出、校验、帧错误或检测到break 中断清除方式:对于溢出错误,读取LSR 可清除中断,对于校验、帧错误或break,中断需要等待所有的错误数据被读取后才被清除 2 接收数据就绪: INT_RCV_DATA_AVAILABLE 非FIFO模式下,接收数据准备就绪, fifo模式下,达到触发阈值,如果四个字节时间内没有访问FIFO ,就再次触发 中断清除方式:非FIFO模式下,RBR被读取 , FIFO模式下,FIFO低于触发阈值被清除 3 接收超时:INT_CHAR_TIMEOUT_INDICATION 仅仅FIFO模式有效 , 在最后四个字节的时间内,没有字符从接收器FIFO 中移除或者输入,并且在此期间接收器FIFO中至少有一个字符 中断清除方式:(1)1个字节从接收FIFO中被读出 (2)一个新的字节到达接收FIFO (3)PMU寄存器中的URRST 位置1 4 传输保持寄存器空(THR) INT_THR_EMPTY 非FIFO模式下: THR空。 FIFO模式下,传输器FIFO空 中断清除方式:一个字节被写到 THR */ void UART0_Handler(void) { uint8_t rev_data = 0; NVIC_ClearPendingIRQ(UART0_IRQn); //接收线中断 有错误或者break if(UART_INT_TYPE(CMSDK_UART0) == INT_RCV_LINE_STATUS) { CMSDK_UART0->IER &= ~CMSDK_UART_IER_RLSI_EN_Msk; } //数据就绪中断 //接收超时中断 if((UART_INT_TYPE(CMSDK_UART0) == INT_RCV_DATA_AVAILABLE) || (UART_INT_TYPE(CMSDK_UART0) == INT_CHAR_TIMEOUT_INDICATION)) { CMSDK_UART0->IER &= ~CMSDK_UART_IER_RDAI_EN_Msk; rev_data = CMSDK_UART0->RBR; UartPutc(CMSDK_UART0,rev_data); CMSDK_UART0->IER |= CMSDK_UART_IER_RDAI_EN_Msk; } return; } void UART1_Handler(void) { uint8_t rev_data = 0; NVIC_ClearPendingIRQ(UART1_IRQn); //接收线中断 有错误或者break if(UART_INT_TYPE(CMSDK_UART1) == INT_RCV_LINE_STATUS) { CMSDK_UART1->IER &= ~CMSDK_UART_IER_RLSI_EN_Msk; } //数据就绪中断 //接收超时中断 if((UART_INT_TYPE(CMSDK_UART1) == INT_RCV_DATA_AVAILABLE) || (UART_INT_TYPE(CMSDK_UART1) == INT_CHAR_TIMEOUT_INDICATION)) { CMSDK_UART1->IER &= ~CMSDK_UART_IER_RDAI_EN_Msk; rev_data = CMSDK_UART1->RBR; UartPutc(CMSDK_UART1,rev_data); CMSDK_UART1->IER |= CMSDK_UART_IER_RDAI_EN_Msk; } return; }