hw_dma_uart.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417
  1. #include "board.h"
  2. typedef struct
  3. {
  4. uint32_t tx_port;
  5. uint8_t tx_pin;
  6. uint8_t tx_pin_af;
  7. uint32_t rx_port;
  8. uint8_t rx_pin;
  9. uint8_t rx_pin_af;
  10. uint32_t rs485_port;
  11. unsigned short rs485_pin;
  12. } hw_uart_pin_t;
  13. typedef struct
  14. {
  15. uint32_t base; //串口对像
  16. uint32_t speed; //通讯速度
  17. dma_channel_enum rx_dma_stream; //接收所在的DMA
  18. dma_channel_enum tx_dma_stream; //接收所在的DMA
  19. int rx_timeout; //接收空闲时间
  20. int tx_endtime; //发送完毕后多少时候算完成
  21. unsigned short rx_length; //接收长度
  22. unsigned short dma_value; //上次DMA接收的长度值
  23. sw_timer_t recv_timer;
  24. sw_timer_t send_timer;
  25. } hw_dma_uart_t;
  26. //管脚配置
  27. //管脚功能复用,需要自己去查找数据手册
  28. static hw_uart_pin_t hw_uart_pins_map[HW_DMA_UART_NUMBER] = {
  29. { GPIOA, 9, GPIO_AF_1, GPIOA, 10, GPIO_AF_1, 0, 0 },
  30. { GPIOA, 2, GPIO_AF_1, GPIOA, 3, GPIO_AF_1, GPIOC, 15 }
  31. };
  32. //串口配置
  33. //DMA对应的数据流通道,可以查找手册查到
  34. static hw_dma_uart_t hw_uarts_map[HW_DMA_UART_NUMBER] = {
  35. { USART0, 115200, DMA_CH2, DMA_CH1, 2000, 0 },
  36. { USART1, 19200, DMA_CH4, DMA_CH3, 2000, 0 }
  37. };
  38. #define RS485_RX_ENABLE(port,pin) GPIO_BOP(port) = 1 << (pin + 16)
  39. #define RS485_TX_ENABLE(port,pin) GPIO_BOP(port) = 1 << pin
  40. static int current_core_freq = 1;
  41. void hw_dma_uart_init(int clk) {
  42. int index = 0;
  43. //使能DMA时钟
  44. rcu_periph_clock_enable(rcu_periph_clock_bit(DMA));
  45. for (index = 0; index < HW_DMA_UART_NUMBER; index++) {
  46. uint32_t port = (uint32_t)hw_uart_pins_map[index].rx_port;
  47. uint16_t pin = 1 << hw_uart_pins_map[index].rx_pin;
  48. uint8_t af = hw_uart_pins_map[index].rx_pin_af;
  49. if (port != 0) {
  50. //使能时钟
  51. rcu_periph_clock_enable(rcu_periph_clock_bit(port));
  52. //配置IO为输出
  53. gpio_mode_set(port, GPIO_MODE_AF, GPIO_PUPD_PULLUP, pin);
  54. gpio_output_options_set(port, GPIO_OTYPE_PP, GPIO_OSPEED_10MHZ, pin);
  55. gpio_af_set(port, af, pin);
  56. }
  57. port = (uint32_t)hw_uart_pins_map[index].tx_port;
  58. pin = 1 << hw_uart_pins_map[index].tx_pin;
  59. af = hw_uart_pins_map[index].tx_pin_af;
  60. if (port != 0) {
  61. //使能时钟
  62. rcu_periph_clock_enable(rcu_periph_clock_bit(port));
  63. //配置IO为输出
  64. gpio_mode_set(port, GPIO_MODE_AF, GPIO_PUPD_PULLUP, pin);
  65. gpio_output_options_set(port, GPIO_OTYPE_PP, GPIO_OSPEED_10MHZ, pin);
  66. gpio_af_set(port, af, pin);
  67. }
  68. port = (uint32_t)hw_uart_pins_map[index].rs485_port;
  69. pin = 1 << hw_uart_pins_map[index].rs485_pin;
  70. if (port != 0) {
  71. //使能时钟
  72. rcu_periph_clock_enable(rcu_periph_clock_bit(port));
  73. //配置IO为输出
  74. gpio_mode_set(port, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLUP, pin);
  75. gpio_output_options_set(port, GPIO_OTYPE_PP, GPIO_OSPEED_10MHZ, pin);
  76. }
  77. }
  78. for (index = 0; index < HW_DMA_UART_NUMBER; index++) {
  79. uint32_t base = (uint32_t)hw_uarts_map[index].base;
  80. //设置跟随波特率
  81. hw_noinit_write(2 * index + 2,hw_uarts_map[index].speed);
  82. //使能串口时钟
  83. rcu_periph_clock_enable(rcu_periph_clock_bit(base));
  84. //复位串口
  85. usart_deinit(base);
  86. //设置波特率
  87. usart_baudrate_set(base, hw_uarts_map[index].speed);
  88. //使能接收
  89. usart_receive_config(base, USART_RECEIVE_ENABLE);
  90. //使能发送
  91. usart_transmit_config(base, USART_TRANSMIT_ENABLE);
  92. //8位长度
  93. usart_word_length_set(base, 8);
  94. //1位停止位
  95. usart_stop_bit_set(base, 1);
  96. //使能串口
  97. usart_enable(base);
  98. {
  99. dma_channel_enum channelx = hw_uarts_map[index].rx_dma_stream;
  100. uint32_t ctl;
  101. //复位DMA配置
  102. dma_deinit(channelx);
  103. //通道禁止
  104. dma_channel_disable(channelx);
  105. //外设地址
  106. DMA_CHPADDR(channelx) = hw_uarts_map[index].base + 0x24;
  107. //内存地址,暂时不需要
  108. DMA_CHMADDR(channelx) = 0x20000000;
  109. //要传送的数量
  110. DMA_CHCNT(channelx) = (0 & DMA_CHANNEL_CNT_MASK);
  111. //清除DMA配置寄存器
  112. ctl = DMA_CHCTL(channelx);
  113. ctl &= ~(DMA_CHXCTL_PWIDTH | DMA_CHXCTL_MWIDTH | DMA_CHXCTL_PRIO | DMA_CHXCTL_PNAGA);
  114. //禁止外设地址递增
  115. ctl &= ~(DMA_CHXCTL_PNAGA);
  116. //禁止循环模式
  117. ctl &= ~(DMA_CHXCTL_CMEN);
  118. //禁止内存到内存模式
  119. ctl &= ~(DMA_CHXCTL_M2M);
  120. //设置DMA的位宽与优先级,设置内存地址递增
  121. ctl |= (DMA_PERIPHERAL_WIDTH_8BIT | DMA_MEMORY_WIDTH_8BIT | DMA_PRIORITY_ULTRA_HIGH);
  122. //使能内存地址递增
  123. ctl |= DMA_CHXCTL_MNAGA;
  124. //方向为外设进内存
  125. ctl &= ~(DMA_CHXCTL_DIR);
  126. DMA_CHCTL(channelx) = ctl;
  127. //使能DMA接收
  128. //usart_dma_receive_config(hw_uarts_map[index].base, USART_DENR_ENABLE);
  129. //使能DMA通道
  130. //DMA_CHCTL(channelx) |= DMA_CHXCTL_CHEN;
  131. channelx = hw_uarts_map[index].tx_dma_stream;
  132. //复位DMA配置
  133. dma_deinit(channelx);
  134. //通道禁止
  135. dma_channel_disable(channelx);
  136. //外设地址
  137. DMA_CHPADDR(channelx) = hw_uarts_map[index].base + 0x28;
  138. //内存地址,暂时不需要
  139. DMA_CHMADDR(channelx) = 0x20000000;
  140. //要传送的数量
  141. DMA_CHCNT(channelx) = (0 & DMA_CHANNEL_CNT_MASK);
  142. //清除DMA配置寄存器
  143. ctl = DMA_CHCTL(channelx);
  144. ctl &= ~(DMA_CHXCTL_PWIDTH | DMA_CHXCTL_MWIDTH | DMA_CHXCTL_PRIO | DMA_CHXCTL_PNAGA);
  145. //禁止外设地址递增
  146. ctl &= ~(DMA_CHXCTL_PNAGA);
  147. //禁止循环模式
  148. ctl &= ~(DMA_CHXCTL_CMEN);
  149. //禁止内存到内存模式
  150. ctl &= ~(DMA_CHXCTL_M2M);
  151. //设置DMA的位宽与优先级,设置内存地址递增
  152. ctl |= (DMA_PERIPHERAL_WIDTH_8BIT | DMA_MEMORY_WIDTH_8BIT | DMA_PRIORITY_ULTRA_HIGH);
  153. //使能内存地址递增
  154. ctl |= DMA_CHXCTL_MNAGA;
  155. //方向为内存到外设
  156. ctl |= (DMA_CHXCTL_DIR);
  157. DMA_CHCTL(channelx) = ctl;
  158. //使能DMA发送
  159. //usart_dma_receive_config(hw_uarts_map[index].base, USART_DENT_ENABLE);
  160. //使能DMA通道
  161. //DMA_CHCTL(channelx) |= DMA_CHXCTL_CHEN;
  162. //默认485是接收模式
  163. if (hw_uart_pins_map[index].rs485_port != 0) {
  164. RS485_RX_ENABLE(hw_uart_pins_map[index].rs485_port, hw_uart_pins_map[index].rs485_pin);
  165. }
  166. }
  167. }
  168. }
  169. /**
  170. * 读取串口缓冲,
  171. *
  172. * @author lxz
  173. *
  174. * @param uart_index 串口编号
  175. * @param buffer 读取数据的缓冲
  176. * @param size 读取的最大长度
  177. *
  178. * @return int 实际读取数量
  179. */
  180. int hw_dma_uart_begin_read(unsigned char uart_index, unsigned char *buffer, int size) {
  181. if (uart_index < HW_DMA_UART_NUMBER && size > 0){
  182. dma_channel_enum channelx = hw_uarts_map[uart_index].rx_dma_stream;
  183. //通道禁止
  184. dma_channel_disable(channelx);
  185. //清除所有标志
  186. dma_interrupt_flag_clear(channelx, DMA_INT_FLAG_G);
  187. //内存地址
  188. DMA_CHMADDR(channelx) = (uint32_t)buffer;
  189. //传输大小
  190. DMA_CHCNT(channelx) = (size & DMA_CHANNEL_CNT_MASK);
  191. //使能DMA
  192. dma_channel_enable(channelx);
  193. //使能串口DMA接口
  194. usart_dma_receive_config(hw_uarts_map[uart_index].base, USART_DENR_ENABLE);
  195. hw_uarts_map[uart_index].rx_length = size;
  196. //进入接收模式
  197. if (hw_uart_pins_map[uart_index].rs485_port != 0) {
  198. RS485_RX_ENABLE(hw_uart_pins_map[uart_index].rs485_port, hw_uart_pins_map[uart_index].rs485_pin);
  199. }
  200. }
  201. return 0;
  202. }
  203. /**
  204. * 输出到串口缓冲
  205. *
  206. * @author lxz
  207. *
  208. * @param uart_index 串口编号
  209. * @param buffer 发送数据的缓冲
  210. * @param size 发送的数据长度
  211. *
  212. * @return int 实际发送的数据长度
  213. *
  214. */
  215. int hw_dma_uart_begin_write(unsigned char uart_index, const char *buffer, int size) {
  216. if (uart_index < HW_DMA_UART_NUMBER && size > 0){
  217. dma_channel_enum channelx = hw_uarts_map[uart_index].tx_dma_stream;
  218. //通道禁止
  219. dma_channel_disable(channelx);
  220. //清除所有标志
  221. dma_interrupt_flag_clear(channelx, DMA_INT_FLAG_G);
  222. //内存地址
  223. DMA_CHMADDR(channelx) = (uint32_t)buffer;
  224. //传输大小
  225. DMA_CHCNT(channelx) = (size & DMA_CHANNEL_CNT_MASK);
  226. //使能DMA
  227. dma_channel_enable(channelx);
  228. //使能串口DMA接口
  229. usart_dma_receive_config(hw_uarts_map[uart_index].base, USART_DENT_ENABLE);
  230. //进入接收模式
  231. if (hw_uart_pins_map[uart_index].rs485_port != 0) {
  232. RS485_TX_ENABLE(hw_uart_pins_map[uart_index].rs485_port, hw_uart_pins_map[uart_index].rs485_pin);
  233. }
  234. }
  235. return 0;
  236. }
  237. /**
  238. * 检查是否读取成功,成功会返回对应长度
  239. *
  240. * @author lxz
  241. *
  242. * @param void
  243. *
  244. * @return int
  245. */
  246. int hw_dma_uart_read_finish(unsigned char uart_index) {
  247. if (uart_index < HW_DMA_UART_NUMBER && hw_uarts_map[uart_index].rx_length > 0) {
  248. dma_channel_enum channelx = hw_uarts_map[uart_index].rx_dma_stream;
  249. hw_dma_uart_t * uart = &hw_uarts_map[uart_index];
  250. int res = DMA_CHCNT(channelx);
  251. //如果硬件产生了错误,需要手动清除
  252. if (usart_flag_get(hw_uarts_map[uart_index].base, USART_FLAG_ORERR)) {
  253. usart_flag_clear(hw_uarts_map[uart_index].base, USART_FLAG_ORERR);
  254. }
  255. if (res == 0) {
  256. res = uart->rx_length - res;
  257. uart->rx_length = 0;
  258. //接收完毕,关闭DMA接收使能
  259. usart_dma_receive_config(hw_uarts_map[uart_index].base, USART_DENR_DISABLE);
  260. return res;
  261. } else if (res != uart->dma_value) {
  262. uart->dma_value = res;
  263. sw_timer_start(&uart->recv_timer, 0, uart->rx_timeout);
  264. } else if (uart->rx_length != res &&
  265. sw_timer_expire(&uart->recv_timer)) {
  266. //停止接收
  267. dma_channel_disable(channelx);
  268. res = uart->rx_length - res;
  269. uart->rx_length = 0;
  270. usart_dma_receive_config(hw_uarts_map[uart_index].base, USART_DENR_DISABLE);
  271. return res;
  272. }
  273. }
  274. return 0;
  275. }
  276. /**
  277. * 检测是否写入成功,写入成功会返回1
  278. *
  279. * @author lxz
  280. *
  281. * @param void
  282. *
  283. * @return int
  284. */
  285. int hw_dma_uart_write_finish(unsigned char uart_index) {
  286. if (uart_index < HW_DMA_UART_NUMBER) {
  287. hw_dma_uart_t *uart = &hw_uarts_map[uart_index];
  288. if (usart_flag_get(hw_uarts_map[uart_index].base, USART_FLAG_TC)) {
  289. if (sw_timer_expire(&uart->send_timer)) {
  290. //使能脚转接收模式
  291. if (hw_uart_pins_map[uart_index].rs485_port != 0) {
  292. RS485_RX_ENABLE(hw_uart_pins_map[uart_index].rs485_port, hw_uart_pins_map[uart_index].rs485_pin);
  293. }
  294. return 1;
  295. }
  296. } else {
  297. sw_timer_start(&uart->send_timer, 0, uart->tx_endtime);
  298. }
  299. }
  300. return 0;
  301. }
  302. /**
  303. * 串口一些参数动态设置接口
  304. *
  305. * @author lxz
  306. *
  307. * @param uart_index
  308. * @param cmd
  309. * @param value
  310. */
  311. int hw_dma_uart_control(unsigned char uart_index, char cmd, void *value) {
  312. if (uart_index >= HW_DMA_UART_NUMBER) {
  313. return -1;
  314. }
  315. switch (cmd) {
  316. case UART_CTRL_RECONFIG : //设置串口速度
  317. {
  318. uint32_t base = (uint32_t)hw_uarts_map[uart_index].base;
  319. hw_uart_config *config = (hw_uart_config *)value;
  320. usart_disable(base);
  321. //设置波特率
  322. usart_baudrate_set(base, config->speed);
  323. hw_uarts_map[uart_index].speed = config->speed;
  324. //8位长度
  325. usart_word_length_set(base, config->databits);
  326. //1位停止位
  327. usart_stop_bit_set(base, config->stopbits);
  328. if (config->parity == 1) {
  329. usart_parity_config(base, USART_PM_EVEN);
  330. } else if (config->parity == 2) {
  331. usart_parity_config(base, USART_PM_ODD);
  332. } else {
  333. usart_parity_config(base, USART_PM_NONE);
  334. }
  335. //使能串口
  336. usart_enable(base);
  337. }
  338. break;
  339. case UART_CTRL_SET_RDFIN_TIME : //设置串口接收完成判断时间
  340. {
  341. hw_uarts_map[uart_index].rx_timeout = *((int *)value);
  342. }
  343. break;
  344. case UART_CTRL_SET_WRFIN_TIME : //设置串口发送完成判断时间
  345. {
  346. hw_uarts_map[uart_index].tx_endtime = *((int *)value);
  347. }
  348. break;
  349. case UART_CTRL_GET_SPEED : //获取当前速度
  350. {
  351. return hw_uarts_map[uart_index].speed;
  352. }
  353. break;
  354. case UART_CTRL_GET_RDFIN_TIME : //获取当前串口接收完成时间
  355. {
  356. return hw_uarts_map[uart_index].rx_timeout;
  357. }
  358. break;
  359. case UART_CTRL_GET_WRFIN_TIME : //获取当前串口写入完成时间
  360. {
  361. return hw_uarts_map[uart_index].tx_endtime;
  362. }
  363. break;
  364. case UART_CTRL_GET_RDFIN : //串口接收是否完成,如果完成会返回接收长度
  365. {
  366. return hw_dma_uart_read_finish(uart_index);
  367. }
  368. break;
  369. case UART_CTRL_GET_WRFIN : //串口发送是否完成
  370. {
  371. return hw_dma_uart_write_finish(uart_index);
  372. }
  373. break;
  374. default:
  375. break;
  376. }
  377. return 0;
  378. }