hard_sbus_out.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408
  1. #include "hard_rc_sbus.h"
  2. #include "stdbool.h"
  3. #include "board.h"
  4. #include "hpm_uart_drv.h"
  5. #include "hpm_pwm_drv.h"
  6. #include "hpm_dma_drv.h"
  7. #include "hpm_dmamux_drv.h"
  8. #include "hard_sbus_out.h"
  9. #include "test.h"
  10. #include "hard_hdma_int.h"
  11. #include "main.h"
  12. /* 实际项目没用到该接口 没有发送sbus
  13. */
  14. #define SBUS_UART2_TX HPM_UART2
  15. #define SBUS_UART2_CLK_NAME clock_uart2
  16. #define SBUS_UART2_IRQ IRQn_UART2
  17. #define SBUS_UART2_BAUD 115200
  18. #define SBUS_UART2_IRQ_RANK 2
  19. /* SBUS PWM CONFIG*/
  20. #define SBUS_PWM0 HPM_PWM0
  21. #define SBUS_PWM0_CLOCK_NAME
  22. #define SBUS_PWM0_OUT 1
  23. #define SBUS_PWM0_CMP 0 // pwm通道关联的cmp通道
  24. /* 发送缓冲区大小*/
  25. #define UART2_TX_LENDTH_MAX 25
  26. ATTR_PLACE_AT_NONCACHEABLE static uint8_t uart2_dma_tx_buf[UART2_TX_LENDTH_MAX] = {0};
  27. /* 静态函数声明 */
  28. static void Initial_UART2_TX(uint32_t baudrate);
  29. static void UART2_TX_DMA_Config(void);
  30. static void UART2_TX_NVIC_Config(void);
  31. /**
  32. * @brief 开启PWM输出 要求来自同一个pwm 不然都得重新配置
  33. */
  34. static void sbusout_af_pwm_gpio_config(void)
  35. {
  36. HPM_IOC->PAD[IOC_PAD_PC00].FUNC_CTL = IOC_PC00_FUNC_CTL_PWM0_P_1; // 使用PWM0 1通道
  37. }
  38. static void sbusout_af_pwm_timer_config(uint32_t sbus_af_pwm_period)
  39. {
  40. pwm_cmp_config_t cmp_config = {0};
  41. pwm_config_t pwm_config = {0};
  42. // 准备pwm_config
  43. pwm_get_default_pwm_config(SBUS_PWM0, &pwm_config); // 填充 pwm_config_t 默认值
  44. pwm_config.enable_output = true;
  45. pwm_config.dead_zone_in_half_cycle = 0;
  46. #ifdef WAVE_INV
  47. pwm_config.invert_output = true;
  48. #else
  49. pwm_config.invert_output = false;
  50. #endif
  51. // 准备cmp_config
  52. pwm_get_default_cmp_config(SBUS_PWM0, &cmp_config); // 填充 pwm_cmp_config_t 默认值
  53. cmp_config.mode = pwm_cmp_mode_output_compare; // 设置PWM工作模式为输出
  54. cmp_config.cmp = PRESCALER_FACTOR*1000; // 设置初始CMP值,这样直接设置为 1/2 则后续不需要更新即可生成 50% 占空比
  55. // cmp_config.cmp = pwm_reload + 1; // CMP > RLD, 由于计数器值 CNT 始终达不到 CMPx,比较器输出 OCx 会保持逻辑 0
  56. cmp_config.update_trigger = pwm_shadow_register_update_on_modify; // 设置CMP影子寄存器值生效时刻为 更新后的下一个周期
  57. // pwm_shadow_register_update_on_modify 这种方式下一个指令周期就会重装CMP,可能会导致PWM波形不完整,手册不推荐这种方式
  58. pwm_stop_counter(SBUS_PWM0); // 停止计数(没有也可以)
  59. pwm_set_reload(SBUS_PWM0, 0, sbus_af_pwm_period*PRESCALER_FACTOR); // 设置RLD寄存器
  60. pwm_set_start_count(SBUS_PWM0, 0, 0); // 设置STA寄存器
  61. // 使用给定参数对PWM通道进行设置
  62. if (status_success != pwm_setup_waveform(SBUS_PWM0, SBUS_PWM0_OUT, &pwm_config, SBUS_PWM0_CMP, &cmp_config, 1)) {
  63. printf("failed to setup waveform\\n");
  64. while(1);
  65. }
  66. pwm_start_counter(SBUS_PWM0); // 开始计数(PWM输出开始)
  67. pwm_issue_shadow_register_lock_event(SBUS_PWM0); // 锁定影子寄存器
  68. // 和 cmp = pwm_reload + 1 一起使用,也可以得到 50% 占空比的 PWM波形
  69. // 在这里更新CMP影子寄存器,下一个周期CMP寄存器会得到更新,这种方式便于动态更新PWM波形
  70. // pwm_update_raw_cmp_edge_aligned(pwm_x, cmp_index, pwm_reload / 2); // 50 % HIGH
  71. }
  72. /* @brief sbus pwm 输出占空比 */
  73. void sbus_out_af_pwm_set_pulse_value(uint32_t pulse_value)
  74. {
  75. /* 更新比较值以改变占空比 */
  76. pwm_cmp_update_cmp_value(SBUS_PWM0, SBUS_PWM0_CMP, pulse_value, 0);
  77. }
  78. void sbusout_af_pwm_init(uint32_t pwm_period)
  79. {
  80. sbusout_af_pwm_gpio_config();
  81. sbusout_af_pwm_timer_config(pwm_period);
  82. }
  83. static void rc_uart2_pin_config(void) // 如果使用的是同一个串口的rx 和tx 就初始化1次
  84. {
  85. HPM_IOC->PAD[IOC_PAD_PB21].FUNC_CTL = IOC_PB21_FUNC_CTL_UART2_RXD;
  86. HPM_IOC->PAD[IOC_PAD_PB22].FUNC_CTL = IOC_PB22_FUNC_CTL_UART2_TXD;
  87. }
  88. /*--------------------------------------------------------------------------*/
  89. /* SBUS 输出初始化(UART + DMA) */
  90. /*--------------------------------------------------------------------------*/
  91. void sbus_out_init(uint32_t baud)
  92. {
  93. Initial_UART2_TX(baud);
  94. UART2_TX_DMA_Config();
  95. UART2_TX_NVIC_Config();
  96. }
  97. static void Initial_UART2_TX(uint32_t baudrate)
  98. {
  99. uart_config_t config = {0};
  100. hpm_stat_t stat;
  101. /* 初始化UART */
  102. rc_uart2_pin_config();
  103. clock_set_source_divider(SBUS_UART2_CLK_NAME, clk_src_osc24m, 1);
  104. clock_add_to_group(SBUS_UART2_CLK_NAME, 0);
  105. uint32_t freq = clock_get_frequency(SBUS_UART2_CLK_NAME);
  106. printf("uart2 clk fre %d\r\n", freq);
  107. /* UART默认配置 */
  108. uart_default_config(SBUS_UART2_TX, &config);
  109. /* SBUS参数配置 */
  110. config.baudrate = baudrate; /* 100000bps */
  111. config.word_length = word_length_8_bits; /* 9位数据(8位+偶校验) */
  112. config.num_of_stop_bits = stop_bits_2; /* 2停止位 */
  113. config.parity = parity_even; /* 偶校验 */
  114. config.fifo_enable = true; /* 使能FIFO */
  115. config.src_freq_in_hz = clock_get_frequency(SBUS_UART2_CLK_NAME);
  116. /* 设置FIFO阈值 - 设为接近一帧的长度 要小于实际期望接收的字节数 25 */
  117. config.rx_fifo_level = uart_rx_fifo_trg_gt_three_quarters; /* 约24字节 */
  118. stat = uart_init(SBUS_UART2_TX, &config);
  119. if (stat != status_success) {
  120. printf("SBUS UART2 RX init failed\n");
  121. while (1);
  122. }
  123. }
  124. static void UART2_TX_DMA_Config(void)
  125. {
  126. dma_handshake_config_t handshake_config;
  127. dma_channel_config_t channel_config;
  128. /* 使能 DMA 时钟 */
  129. // HDMA 时钟来源于系统总线时钟(AHB)
  130. /* ========== 配置 TX DMA 通道 ========== */
  131. /* 初始化 DMA 通道 */
  132. dma_default_channel_config(SBUS_UART2_DMA_CONTROLLER, &channel_config);
  133. /* 配置 DMAMUX:将 UART3 TX 请求连接到 TX DMA 通道 */
  134. dmamux_config(SBUS_UART2_DMAMUX_CONTROLLER, SBUS_UART2_TX_DMAMUX_CH, SBUS_UART2_TX_DMA_REQ, true);
  135. /* 配置 TX 握手参数 */
  136. dma_default_handshake_config(SBUS_UART2_DMA_CONTROLLER, &handshake_config);
  137. }
  138. static void UART2_TX_NVIC_Config(void)
  139. {
  140. intc_m_enable_irq_with_priority(SBUS_UART2_DMA_IRQ, SBUS_UART2_DMA_IRQ_RANK);
  141. }
  142. void UART2_Put_Char(uint8_t DataToSend)
  143. {
  144. /* 等待发送寄存器空 */
  145. while (!uart_check_status(SBUS_UART2_TX, uart_stat_transmitter_empty));
  146. /* 发送数据 */
  147. uart_send_byte(SBUS_UART2_TX, DataToSend);
  148. /* 等待发送完成 */
  149. while (!uart_check_status(SBUS_UART2_TX, uart_stat_transmitter_empty));
  150. }
  151. static bool usart2_tx_isbusy(void)
  152. {
  153. return !uart2_tx_dma_done;
  154. }
  155. void open_dma1_stream6_tx(unsigned short count)
  156. {
  157. dma_handshake_config_t handshake_config;
  158. /* 等待上次发送完成 */
  159. uint32_t timeout = 1000000;
  160. while (usart2_tx_isbusy() && timeout--) {
  161. __asm("nop");
  162. }
  163. if (timeout == 0) {
  164. // 超时处理,复位DMA
  165. dma_abort_channel(SBUS_UART2_DMA_CONTROLLER, SBUS_UART2_TX_DMA_CH);
  166. uart2_tx_dma_done = true; // 强制完成
  167. }
  168. /* 重新配置 TX 传输大小 */
  169. dma_default_handshake_config(SBUS_UART2_DMA_CONTROLLER, &handshake_config);
  170. handshake_config.ch_index = SBUS_UART2_TX_DMA_CH;
  171. handshake_config.dst = (uint32_t)&SBUS_UART2_TX->THR;
  172. handshake_config.dst_fixed = true;
  173. handshake_config.src = core_local_mem_to_sys_address(0, (uint32_t)uart2_dma_tx_buf);
  174. handshake_config.src_fixed = false;
  175. handshake_config.data_width = DMA_TRANSFER_WIDTH_BYTE;
  176. handshake_config.size_in_byte = count;
  177. dma_setup_handshake(SBUS_UART2_DMA_CONTROLLER, &handshake_config, true); // true表示触发一次
  178. }
  179. /*--------------------------------------------------------------------------*/
  180. /* PWM 值转 SBUS 数值(原样保留) */
  181. /*--------------------------------------------------------------------------*/
  182. void pwm_to_sbus(short *out_pwm, short *out_subs)
  183. {
  184. int i = 0;
  185. for (i = 0; i < 8; i++)
  186. {
  187. out_subs[i] = ((out_pwm[i] - 860) / 0.625f);
  188. }
  189. #ifdef ALL_CHANNELS
  190. for (i = 8; i < 14; i++)
  191. {
  192. out_subs[i] = ((out_pwm[i] - 860) / 0.625f);
  193. }
  194. #endif
  195. }
  196. /*--------------------------------------------------------------------------*/
  197. /* SBUS 数据打包(原样保留) */
  198. /*--------------------------------------------------------------------------*/
  199. void sbus_channel_packet(short *rc_ch)
  200. {
  201. /* assemble the SBUS packet */
  202. // SBUS header
  203. uart2_dma_tx_buf[0] = 0x0f;
  204. // 16 channels of 11 bit data
  205. uart2_dma_tx_buf[1] = (uint8_t)((rc_ch[0] & 0x07FF));
  206. uart2_dma_tx_buf[2] =
  207. (uint8_t)((rc_ch[0] & 0x07FF) >> 8 | (rc_ch[1] & 0x07FF) << 3);
  208. uart2_dma_tx_buf[3] =
  209. (uint8_t)((rc_ch[1] & 0x07FF) >> 5 | (rc_ch[2] & 0x07FF) << 6);
  210. uart2_dma_tx_buf[4] = (uint8_t)((rc_ch[2] & 0x07FF) >> 2);
  211. uart2_dma_tx_buf[5] =
  212. (uint8_t)((rc_ch[2] & 0x07FF) >> 10 | (rc_ch[3] & 0x07FF) << 1);
  213. uart2_dma_tx_buf[6] =
  214. (uint8_t)((rc_ch[3] & 0x07FF) >> 7 | (rc_ch[4] & 0x07FF) << 4);
  215. uart2_dma_tx_buf[7] =
  216. (uint8_t)((rc_ch[4] & 0x07FF) >> 4 | (rc_ch[5] & 0x07FF) << 7);
  217. uart2_dma_tx_buf[8] = (uint8_t)((rc_ch[5] & 0x07FF) >> 1);
  218. uart2_dma_tx_buf[9] =
  219. (uint8_t)((rc_ch[5] & 0x07FF) >> 9 | (rc_ch[6] & 0x07FF) << 2);
  220. uart2_dma_tx_buf[10] =
  221. (uint8_t)((rc_ch[6] & 0x07FF) >> 6 | (rc_ch[7] & 0x07FF) << 5);
  222. uart2_dma_tx_buf[11] = (uint8_t)((rc_ch[7] & 0x07FF) >> 3);
  223. #ifdef ALL_CHANNELS
  224. uart2_dma_tx_buf[12] = (uint8_t)((rc_ch[8] & 0x07FF));
  225. uart2_dma_tx_buf[13] =
  226. (uint8_t)((rc_ch[8] & 0x07FF) >> 8 | (rc_ch[9] & 0x07FF) << 3);
  227. uart2_dma_tx_buf[14] =
  228. (uint8_t)((rc_ch[9] & 0x07FF) >> 5 | (rc_ch[10] & 0x07FF) << 6);
  229. uart2_dma_tx_buf[15] = (uint8_t)((rc_ch[10] & 0x07FF) >> 2);
  230. uart2_dma_tx_buf[16] =
  231. (uint8_t)((rc_ch[10] & 0x07FF) >> 10 | (rc_ch[11] & 0x07FF) << 1);
  232. uart2_dma_tx_buf[17] =
  233. (uint8_t)((rc_ch[11] & 0x07FF) >> 7 | (rc_ch[12] & 0x07FF) << 4);
  234. uart2_dma_tx_buf[18] =
  235. (uint8_t)((rc_ch[12] & 0x07FF) >> 4 | (rc_ch[13] & 0x07FF) << 7);
  236. uart2_dma_tx_buf[19] = (uint8_t)((rc_ch[13] & 0x07FF) >> 1);
  237. uart2_dma_tx_buf[20] =
  238. (uint8_t)((rc_ch[13] & 0x07FF) >> 9 | (rc_ch[14] & 0x07FF) << 2);
  239. uart2_dma_tx_buf[21] =
  240. (uint8_t)((rc_ch[14] & 0x07FF) >> 6 | (rc_ch[15] & 0x07FF) << 5);
  241. uart2_dma_tx_buf[22] = (uint8_t)((rc_ch[15] & 0x07FF) >> 3);
  242. // flags
  243. uart2_dma_tx_buf[23] = 0x00;
  244. #endif
  245. switch (uart2_dma_tx_buf[24])
  246. {
  247. case 0x04:
  248. uart2_dma_tx_buf[24] = 0x14;
  249. break;
  250. case 0x14:
  251. uart2_dma_tx_buf[24] = 0x24;
  252. break;
  253. case 0x24:
  254. uart2_dma_tx_buf[24] = 0x34;
  255. break;
  256. case 0x34:
  257. default:
  258. uart2_dma_tx_buf[24] = 0x04;
  259. break;
  260. }
  261. // DMA方式发送
  262. open_dma1_stream6_tx(UART2_TX_LENDTH_MAX);
  263. }
  264. #ifdef UART2_TX_TEST
  265. /* uart2 tx_dma demo 2026/03/16 pass*/
  266. void sbus_uart2_out_test(void)
  267. {
  268. short test_channels[16];
  269. /* 1. 初始化SBUS硬件 */
  270. sbus_out_init(SBUS_UART2_BAUD);
  271. printf("SBUS初始化完成\r\n");
  272. /* 2. 构造测试数据:通道0=最大值,通道1=最小值,其他=中位值 */
  273. for (int i = 0; i < 16; i++) {
  274. test_channels[i] = 1024; // 中位值
  275. }
  276. test_channels[0] = 1876; // 最大值
  277. test_channels[1] = 172; // 最小值
  278. printf("发送测试数据: Ch0=%d, Ch1=%d, Ch2=%d\r\n",
  279. test_channels[0], test_channels[1], test_channels[2]);
  280. /* 3. 打包并发送 */
  281. sbus_channel_packet(test_channels);
  282. /* 4. 等待发送完成 */
  283. printf("等待发送完成...\r\n");
  284. while(usart2_tx_isbusy()) {
  285. board_delay_ms(1);
  286. }
  287. printf("发送完成!\r\n");
  288. }
  289. #endif
  290. /*
  291. // sbus最大通道数18
  292. #define SBUS_MAX_CHANNEL 18
  293. // sbus一包数据25个字节
  294. #define SBUS_FRAME_SIZE 25
  295. // sbus起始位
  296. #define SBUS_FRAME_SYNC_BYTE 0x0F
  297. //第24个字节的解析
  298. #define SBUS_FLAG_CHANNEL_17 (1 << 0)
  299. #define SBUS_FLAG_CHANNEL_18 (1 << 1)
  300. #define SBUS_FLAG_SIGNAL_LOSS (1 << 2)
  301. #define SBUS_FLAG_FAILSAFE_ACTIVE (1 << 3)
  302. struct sbusframe_s {
  303. unsigned char sync_byte;
  304. // 176 bits of data (11 bits per channel * 16 channels) = 22 bytes.
  305. unsigned int chan0 : 11;
  306. unsigned int chan1 : 11;
  307. unsigned int chan2 : 11;
  308. unsigned int chan3 : 11;
  309. unsigned int chan4 : 11;
  310. unsigned int chan5 : 11;
  311. unsigned int chan6 : 11;
  312. unsigned int chan7 : 11;
  313. unsigned int chan8 : 11;
  314. unsigned int chan9 : 11;
  315. unsigned int chan10 : 11;
  316. unsigned int chan11 : 11;
  317. unsigned int chan12 : 11;
  318. unsigned int chan13 : 11;
  319. unsigned int chan14 : 11;
  320. unsigned int chan15 : 11;
  321. unsigned char flags;
  322. // The endByte is 0x00 on FrSky and some futaba RX's, on Some SBUS2 RX's the
  323. // value indicates the telemetry byte that is sent after every 4th sbus
  324. frame.
  325. //
  326. // See
  327. //
  328. https://github.com/cleanflight/cleanflight/issues/590#issuecomment-101027349
  329. // and
  330. //
  331. https://github.com/cleanflight/cleanflight/issues/590#issuecomment-101706023
  332. unsigned char end_byte;
  333. } __attribute__((__packed__));
  334. typedef union {
  335. uint8_t sbus_data[SBUS_FRAME_SIZE];
  336. struct sbusframe_s frame;
  337. } sbusframe_t;
  338. static sbusframe_t sbusframe;
  339. */