#include "board.h" #include "hw_dma_uart.h" #include "Action.h" #include "MachineConfig.h" typedef struct { GPIO_TypeDef *tx_port; uint8_t tx_pin; GPIO_TypeDef *rx_port; uint8_t rx_pin; uint32_t remap; //remap描述,不为0时说明需要remap GPIO_TypeDef *rs485_port; unsigned short rs485_pin; } hw_uart_pin_t; typedef struct { USART_TypeDef *base; //串口对像 uint32_t speed; //通讯速度 uint8_t rx_dma_stream; //接收所在的DMA //uint8_t rx_dma_ch; //接收所在DMA通道 uint8_t tx_dma_stream; //接收所在的DMA //uint8_t tx_dma_ch; //发送所在DMA通道 int rx_timeout; //接收空闲时间 int tx_endtime; //发送完毕后多少时候算完成 unsigned short rx_length; //接收长度 unsigned short dma_value; //上次DMA接收的长度值 sw_timer_t recv_timer; sw_timer_t send_timer; } hw_dma_uart_t; //管脚配置 //管脚功能复用,需要自己去查找数据手册 static hw_uart_pin_t hw_uart_pins_map[HW_DMA_UART_NUMBER] = { { GPIOA, 9,GPIOA, 10, 0, 0,0 }, { GPIOD, 5, GPIOD, 6, GPIO_Remap_USART2, GPIOF, 3 }, { GPIOD, 8, GPIOD, 9, GPIO_FullRemap_USART3, 0, 0 }, { GPIOC, 10, GPIOC, 11, 0, GPIOD, 7 } }; //串口配置 //DMA对应的数据流通道,可以查找手册查到 static hw_dma_uart_t hw_uarts_map[HW_DMA_UART_NUMBER] = { { USART1, 115200, ST_DMA1_STREAM5,ST_DMA1_STREAM4,2000, 0 }, { USART2, 19200, ST_DMA1_STREAM6,ST_DMA1_STREAM7,2000, 0 }, { USART3, 256000, ST_DMA1_STREAM3,ST_DMA1_STREAM2,100, 0 }, { UART4, 115200, ST_DMA2_STREAM3,ST_DMA2_STREAM5,2000, 0 } }; #define RS485_RX_ENABLE(port,pin) port->BRR = 1 << pin #define RS485_TX_ENABLE(port,pin) port->BSRR = 1 << pin static int current_core_freq = 1; void hw_dma_uart_init(int clk) { uint32_t brr_value = 0; int index = 0; int src_clk = 0; //使能DMA2的时钟 current_core_freq = clk; // if(USE_EXTEND_INOUTPUT) // { // hw_uarts_map[0].speed = 256000; // } for (index = 0; index < HW_DMA_UART_NUMBER; index++) { uint32_t port = (uint32_t)hw_uart_pins_map[index].rx_port; uint16_t pin = hw_uart_pins_map[index].rx_pin; if (port >= GPIOA_BASE && port <= GPIOG_BASE) { RCC->APB2ENR |= 0x04 << ((port - GPIOA_BASE) / 0x400); GPIO_Set((GPIO_TypeDef *)port, 1 << pin, GPIO_MODE_IPD, GPIO_SPEED_50M, GPIO_PUPD_PD); } port = (uint32_t)hw_uart_pins_map[index].tx_port; pin = hw_uart_pins_map[index].tx_pin; if (port >= GPIOA_BASE && port <= GPIOG_BASE) { RCC->APB2ENR |= 0x04 << ((port - GPIOA_BASE) / 0x400); GPIO_Set((GPIO_TypeDef *)port, 1 << pin, GPIO_MODE_AF_PP, GPIO_SPEED_50M, GPIO_PUPD_PD); } //不为0时说明管脚需要开启重新赋值 if (hw_uart_pins_map[index].remap != 0) { GPIO_Remap_Set(hw_uart_pins_map[index].remap, 1); } port = (uint32_t)hw_uart_pins_map[index].rs485_port; pin = hw_uart_pins_map[index].rs485_pin; if (port >= GPIOA_BASE && port <= GPIOG_BASE) { RCC->APB2ENR |= 0x04 << ((port - GPIOA_BASE) / 0x400); GPIO_Set((GPIO_TypeDef *)port, 1 << pin, GPIO_MODE_OUT_PP, GPIO_SPEED_50M, GPIO_PUPD_PU); RS485_RX_ENABLE(((GPIO_TypeDef *)port), pin); } } for (index = 0; index < HW_DMA_UART_NUMBER; index++) { uint32_t base = (uint32_t)hw_uarts_map[index].base; //设置跟随波特率 hw_noinit_write(2 * index + 2, hw_uarts_map[index].speed); if (base >= USART2_BASE && base <= UART5_BASE) { uint32_t rcc_src = 1 << ((base - USART2_BASE) / 0x400 + 17); do { RCC->APB1ENR |= rcc_src; }while ((RCC->APB1ENR & rcc_src) == 0); src_clk = 1000000 * clk / 2; } else if (base == USART1_BASE) { uint32_t rcc_src = 1 << 14; do { RCC->APB2ENR |= rcc_src; }while ((RCC->APB2ENR & rcc_src) == 0); src_clk = 1000000 * clk; } { hw_dma_uart_t *uart = &hw_uarts_map[index]; int streamx = 0; float temp = 0; uint16_t baud_value = 0; uint16_t fraction = 0; DMA_Stream_TypeDef *st_dma_stream = (DMA_Stream_TypeDef *)st_dma_get_stream(uart->rx_dma_stream); DMA_TypeDef *st_dma = (DMA_TypeDef *)st_dma_get_dmax(uart->rx_dma_stream); streamx = uart->rx_dma_stream % 7; st_dma_stream->CCR &= ~0x00000001; SW_WAIT_FINISH(st_dma_stream->CCR & 0X01); st_dma->IFCR |= 0X0F << (4 * streamx); //清空之前该stream上的所有中断标志 st_dma_stream->CPAR = (uint32_t)(uart->base->DR); //DMA外设地址 st_dma_stream->CCR = 0; //先全部复位CR寄存器值 st_dma_stream->CCR |= 0 << 4; //存储器到外设模式 st_dma_stream->CCR |= 0 << 5; //非循环模式(即使用普通模式) st_dma_stream->CCR |= 0 << 6; //外设非增量模式 st_dma_stream->CCR |= 1 << 7; //存储器增量模式 st_dma_stream->CCR |= 0 << 8; //外设数据长度:8位 st_dma_stream->CCR |= 0 << 10; //存储器数据长度:8位 st_dma_stream->CCR |= 1 << 12; //中等优先级 st_dma_stream->CCR |= 0 << 14; //非存储器到存储器模式 st_dma_stream = (DMA_Stream_TypeDef *)st_dma_get_stream(uart->tx_dma_stream); st_dma = (DMA_TypeDef *)st_dma_get_dmax(uart->tx_dma_stream); streamx = uart->tx_dma_stream % 7; st_dma_stream->CCR &= ~0x00000001; SW_WAIT_FINISH(st_dma_stream->CCR & 0X01); st_dma->IFCR |= 0X0F << (4 * streamx); //清空之前该stream上的所有中断标志 st_dma_stream->CPAR = (uint32_t)(uart->base->DR); //DMA外设地址 st_dma_stream->CCR = 0; //先全部复位CR寄存器值 st_dma_stream->CCR |= 1 << 4; //存储器到外设模式 st_dma_stream->CCR |= 0 << 5; //非循环模式(即使用普通模式) st_dma_stream->CCR |= 0 << 6; //外设非增量模式 st_dma_stream->CCR |= 1 << 7; //存储器增量模式 st_dma_stream->CCR |= 0 << 8; //外设数据长度:8位 st_dma_stream->CCR |= 0 << 10; //存储器数据长度:8位 st_dma_stream->CCR |= 1 << 12; //中等优先级 st_dma_stream->CCR |= 0 << 14; //非存储器到存储器模式 uart->base->CR1 = 0; //清零CR1寄存器 temp = (float)(src_clk) / (uart->speed * 16); baud_value = (u16)temp; fraction = (u16)((temp - baud_value) * 16 + 0.5); brr_value = (baud_value << 4) + fraction; uart->base->BRR = brr_value; uart->base->CR1 |= 0 << 12; //设置M0=0&M1=0,选择8位字长 uart->base->CR1 |= 1 << 3; //串口发送使能 uart->base->CR1 |= 1 << 2; //串口接收使能 //不带任何校验 uart->base->CR2 &= ~(0x03 << 12); //1位停止位 uart->base->CR3 |= 1 << 7; //DMA发送使能 uart->base->CR1 |= 1 << 13; //串口使能 //使能脚默认接收模式 if (hw_uart_pins_map[index].rs485_port != (void *)0) { RS485_RX_ENABLE(hw_uart_pins_map[index].rs485_port,hw_uart_pins_map[index].rs485_pin); } } } } /** * 读取串口缓冲, * * @author lxz * * @param uart_index 串口编号 * @param buffer 读取数据的缓冲 * @param size 读取的最大长度 * * @return int 实际读取数量 */ int hw_dma_uart_begin_read(unsigned char uart_index, unsigned char *buffer, int size) { if (uart_index < HW_DMA_UART_NUMBER && size > 0) { hw_dma_uart_t *uart = &hw_uarts_map[uart_index]; uint32_t sr; int streamx = 0; DMA_Stream_TypeDef *st_dma_stream = (DMA_Stream_TypeDef *)st_dma_get_stream(uart->rx_dma_stream); DMA_TypeDef *st_dma = (DMA_TypeDef *)st_dma_get_dmax(uart->rx_dma_stream); streamx = uart->rx_dma_stream % 7; st_dma_stream->CCR &= ~0x00000001; SW_WAIT_FINISH(st_dma_stream->CCR & 0X01); st_dma->IFCR |= 0X0F << (4 * streamx); //清空之前该stream上的所有中断标志 sr = uart->base->SR; uart->base->SR &= ~(1 << 3); sr = uart->base->DR; sr = sr; (void)sr; uart->dma_value = size; uart->rx_length = size; //开始接收 st_dma_stream->CCR = 0; //先全部复位CR寄存器值 st_dma_stream->CCR |= (1 << 7) | (1 << 12); //存储器增量模式 st_dma_stream->CPAR = (uint32_t)(&uart->base->DR); st_dma_stream->CMAR = (uint32_t)buffer; st_dma_stream->CNDTR = size; st_dma_stream->CCR |= 1 << 0; uart->base->CR3 |= 1 << 6; //DMA接收使能 if (hw_uart_pins_map[uart_index].rs485_port != (void *)0) { RS485_RX_ENABLE(hw_uart_pins_map[uart_index].rs485_port, hw_uart_pins_map[uart_index].rs485_pin); } } return 0; } /** * 输出到串口缓冲 * * @author lxz * * @param uart_index 串口编号 * @param buffer 发送数据的缓冲 * @param size 发送的数据长度 * * @return int 实际发送的数据长度 * */ int hw_dma_uart_begin_write(unsigned char uart_index, const char *buffer, int size) { int temp; if (uart_index < HW_DMA_UART_NUMBER && size > 0) { //使能脚发判断模式 if (hw_uart_pins_map[uart_index].rs485_port != (void *)0) { RS485_TX_ENABLE(hw_uart_pins_map[uart_index].rs485_port, hw_uart_pins_map[uart_index].rs485_pin); } #ifdef USART_WRITE_DEBUG hw_dma_uart_t *uart = &hw_uarts_map[uart_index]; while (size > 0) { if ((uart->base->ISR & 0x80)) { size--; uart->base->TDR = *buffer; buffer++; } } #else hw_dma_uart_t *uart = &hw_uarts_map[uart_index]; temp = uart->base->SR; int streamx = 0; DMA_Stream_TypeDef *st_dma_stream = (DMA_Stream_TypeDef *)st_dma_get_stream(uart->tx_dma_stream); DMA_TypeDef *st_dma = (DMA_TypeDef *)st_dma_get_dmax(uart->tx_dma_stream); streamx = uart->tx_dma_stream % 7; st_dma_stream->CCR &= ~0x00000001; SW_WAIT_FINISH(st_dma_stream->CCR & 0X01); st_dma->IFCR |= 0X0F << (4 * streamx); //清空之前该stream上的所有中断标志 st_dma_stream->CPAR = (uint32_t)(&uart->base->DR); st_dma_stream->CMAR = (uint32_t)buffer; st_dma_stream->CNDTR = size; st_dma_stream->CCR |= 1 << 0; #endif } return 0; } /** * 检查是否读取成功,成功会返回对应长度 * * @author lxz * * @param void * * @return int */ int hw_dma_uart_read_finish(unsigned char uart_index) { if (uart_index < HW_DMA_UART_NUMBER && hw_uarts_map[uart_index].rx_length > 0) { DMA_Stream_TypeDef *st_dma_stream = (DMA_Stream_TypeDef *)st_dma_get_stream(hw_uarts_map[uart_index].rx_dma_stream); hw_dma_uart_t *uart = &hw_uarts_map[uart_index]; int res = st_dma_stream->CNDTR; int sr = uart->base->SR; //如果硬件产生了错误,需要手动清除 if (sr & (1 << 3)) { uart->base->SR &= ~(1 << 3); } if (res == 0) { res = uart->rx_length - res; uart->rx_length = 0; uart->base->CR3 &= ~(1 << 6); //取消DMA接收使能 return res; } else if (res != uart->dma_value) { uart->dma_value = res; sw_timer_start(&uart->recv_timer, 0, uart->rx_timeout); } else if (uart->rx_length != res && sw_timer_expire(&uart->recv_timer)) { //停止接收 st_dma_stream->CCR &= ~0x00000001; res = uart->rx_length - res; uart->rx_length = 0; uart->base->CR3 &= ~(1 << 6); //取消DMA接收使能 return res; } } return 0; } /** * 检测是否写入成功,写入成功会返回1 * * @author lxz * * @param void * * @return int */ int hw_dma_uart_write_finish(unsigned char uart_index) { if (uart_index < HW_DMA_UART_NUMBER) { hw_dma_uart_t *uart = &hw_uarts_map[uart_index]; if (uart->base->SR & 1 << 6) { if (sw_timer_expire(&uart->send_timer)) { //使能脚转接收模式 if (hw_uart_pins_map[uart_index].rs485_port != (void *)0) { RS485_RX_ENABLE(hw_uart_pins_map[uart_index].rs485_port, hw_uart_pins_map[uart_index].rs485_pin); } return 1; } } else { sw_timer_start(&uart->send_timer, 0, uart->tx_endtime); } } return 0; } /** * 串口一些参数动态设置接口 * * @author lxz * * @param uart_index * @param cmd * @param value */ int hw_dma_uart_control(unsigned char uart_index, char cmd, void *value) { if (uart_index >= HW_DMA_UART_NUMBER) { return -1; } switch (cmd) { case UART_CTRL_SET_SPEED : //设置串口速度 { uint32_t base = (uint32_t)hw_uarts_map[uart_index].base; uint32_t brr_value = 0; float temp = 0; uint16_t baud_value = 0; uint16_t fraction = 0; int src_clk = 0; int speed = *((int *)value); hw_dma_uart_t *uart = &hw_uarts_map[uart_index]; if (base >= USART2_BASE && base <= UART5_BASE) { src_clk = 1000000 * current_core_freq / 2; } else if (base == USART1_BASE) { src_clk = 1000000 * current_core_freq; } uart->speed = speed; hw_noinit_write(2 * uart_index + 2, speed); temp = (float)(src_clk) / (uart->speed * 16); baud_value = (u16)temp; fraction = (u16)((temp - baud_value) * 16); brr_value = (baud_value << 4) + fraction; uart->base->CR1 &= ~(1 << 13); //清零CR1寄存器 uart->base->BRR = brr_value; uart->base->CR1 |= 1 << 13; //串口使能 } break; case UART_CTRL_SET_RDFIN_TIME : //设置串口接收完成判断时间 { hw_uarts_map[uart_index].rx_timeout = *((int *)value); } break; case UART_CTRL_SET_WRFIN_TIME : //设置串口发送完成判断时间 { hw_uarts_map[uart_index].tx_endtime = *((int *)value); } break; case UART_CTRL_GET_SPEED : //获取当前速度 { return hw_uarts_map[uart_index].speed; } break; case UART_CTRL_GET_RDFIN_TIME : //获取当前串口接收完成时间 { return hw_uarts_map[uart_index].rx_timeout; } break; case UART_CTRL_GET_WRFIN_TIME : //获取当前串口写入完成时间 { return hw_uarts_map[uart_index].tx_endtime; } break; case UART_CTRL_GET_RDFIN : //串口接收是否完成,如果完成会返回接收长度 { return hw_dma_uart_read_finish(uart_index); } break; case UART_CTRL_GET_WRFIN : //串口发送是否完成 { return hw_dma_uart_write_finish(uart_index); } default: break; } return 0; }