#include "hard_rc_sbus.h" #include "stdbool.h" #include "board.h" #include "hpm_uart_drv.h" #include "hpm_pwm_drv.h" #include "hpm_dma_drv.h" #include "hpm_dmamux_drv.h" #include "hard_sbus_out.h" #include "test.h" #include "hard_hdma_int.h" #include "main.h" /* 实际项目没用到该接口 没有发送sbus */ #define SBUS_UART2_TX HPM_UART2 #define SBUS_UART2_CLK_NAME clock_uart2 #define SBUS_UART2_IRQ IRQn_UART2 #define SBUS_UART2_BAUD 115200 #define SBUS_UART2_IRQ_RANK 2 /* SBUS PWM CONFIG*/ #define SBUS_PWM0 HPM_PWM0 #define SBUS_PWM0_CLOCK_NAME #define SBUS_PWM0_OUT 1 #define SBUS_PWM0_CMP 0 // pwm通道关联的cmp通道 /* 发送缓冲区大小*/ #define UART2_TX_LENDTH_MAX 25 ATTR_PLACE_AT_NONCACHEABLE static uint8_t uart2_dma_tx_buf[UART2_TX_LENDTH_MAX] = {0}; /* 静态函数声明 */ static void Initial_UART2_TX(uint32_t baudrate); static void UART2_TX_DMA_Config(void); static void UART2_TX_NVIC_Config(void); /** * @brief 开启PWM输出 要求来自同一个pwm 不然都得重新配置 */ static void sbusout_af_pwm_gpio_config(void) { HPM_IOC->PAD[IOC_PAD_PC00].FUNC_CTL = IOC_PC00_FUNC_CTL_PWM0_P_1; // 使用PWM0 1通道 } static void sbusout_af_pwm_timer_config(uint32_t sbus_af_pwm_period) { pwm_cmp_config_t cmp_config = {0}; pwm_config_t pwm_config = {0}; // 准备pwm_config pwm_get_default_pwm_config(SBUS_PWM0, &pwm_config); // 填充 pwm_config_t 默认值 pwm_config.enable_output = true; pwm_config.dead_zone_in_half_cycle = 0; #ifdef WAVE_INV pwm_config.invert_output = true; #else pwm_config.invert_output = false; #endif // 准备cmp_config pwm_get_default_cmp_config(SBUS_PWM0, &cmp_config); // 填充 pwm_cmp_config_t 默认值 cmp_config.mode = pwm_cmp_mode_output_compare; // 设置PWM工作模式为输出 cmp_config.cmp = PRESCALER_FACTOR*1000; // 设置初始CMP值,这样直接设置为 1/2 则后续不需要更新即可生成 50% 占空比 // cmp_config.cmp = pwm_reload + 1; // CMP > RLD, 由于计数器值 CNT 始终达不到 CMPx,比较器输出 OCx 会保持逻辑 0 cmp_config.update_trigger = pwm_shadow_register_update_on_modify; // 设置CMP影子寄存器值生效时刻为 更新后的下一个周期 // pwm_shadow_register_update_on_modify 这种方式下一个指令周期就会重装CMP,可能会导致PWM波形不完整,手册不推荐这种方式 pwm_stop_counter(SBUS_PWM0); // 停止计数(没有也可以) pwm_set_reload(SBUS_PWM0, 0, sbus_af_pwm_period*PRESCALER_FACTOR); // 设置RLD寄存器 pwm_set_start_count(SBUS_PWM0, 0, 0); // 设置STA寄存器 // 使用给定参数对PWM通道进行设置 if (status_success != pwm_setup_waveform(SBUS_PWM0, SBUS_PWM0_OUT, &pwm_config, SBUS_PWM0_CMP, &cmp_config, 1)) { printf("failed to setup waveform\\n"); while(1); } pwm_start_counter(SBUS_PWM0); // 开始计数(PWM输出开始) pwm_issue_shadow_register_lock_event(SBUS_PWM0); // 锁定影子寄存器 // 和 cmp = pwm_reload + 1 一起使用,也可以得到 50% 占空比的 PWM波形 // 在这里更新CMP影子寄存器,下一个周期CMP寄存器会得到更新,这种方式便于动态更新PWM波形 // pwm_update_raw_cmp_edge_aligned(pwm_x, cmp_index, pwm_reload / 2); // 50 % HIGH } /* @brief sbus pwm 输出占空比 */ void sbus_out_af_pwm_set_pulse_value(uint32_t pulse_value) { /* 更新比较值以改变占空比 */ pwm_cmp_update_cmp_value(SBUS_PWM0, SBUS_PWM0_CMP, pulse_value, 0); } void sbusout_af_pwm_init(uint32_t pwm_period) { sbusout_af_pwm_gpio_config(); sbusout_af_pwm_timer_config(pwm_period); } static void rc_uart2_pin_config(void) // 如果使用的是同一个串口的rx 和tx 就初始化1次 { HPM_IOC->PAD[IOC_PAD_PB21].FUNC_CTL = IOC_PB21_FUNC_CTL_UART2_RXD; HPM_IOC->PAD[IOC_PAD_PB22].FUNC_CTL = IOC_PB22_FUNC_CTL_UART2_TXD; } /*--------------------------------------------------------------------------*/ /* SBUS 输出初始化(UART + DMA) */ /*--------------------------------------------------------------------------*/ void sbus_out_init(uint32_t baud) { Initial_UART2_TX(baud); UART2_TX_DMA_Config(); UART2_TX_NVIC_Config(); } static void Initial_UART2_TX(uint32_t baudrate) { uart_config_t config = {0}; hpm_stat_t stat; /* 初始化UART */ rc_uart2_pin_config(); clock_set_source_divider(SBUS_UART2_CLK_NAME, clk_src_osc24m, 1); clock_add_to_group(SBUS_UART2_CLK_NAME, 0); uint32_t freq = clock_get_frequency(SBUS_UART2_CLK_NAME); printf("uart2 clk fre %d\r\n", freq); /* UART默认配置 */ uart_default_config(SBUS_UART2_TX, &config); /* SBUS参数配置 */ config.baudrate = baudrate; /* 100000bps */ config.word_length = word_length_8_bits; /* 9位数据(8位+偶校验) */ config.num_of_stop_bits = stop_bits_2; /* 2停止位 */ config.parity = parity_even; /* 偶校验 */ config.fifo_enable = true; /* 使能FIFO */ config.src_freq_in_hz = clock_get_frequency(SBUS_UART2_CLK_NAME); /* 设置FIFO阈值 - 设为接近一帧的长度 要小于实际期望接收的字节数 25 */ config.rx_fifo_level = uart_rx_fifo_trg_gt_three_quarters; /* 约24字节 */ stat = uart_init(SBUS_UART2_TX, &config); if (stat != status_success) { printf("SBUS UART2 RX init failed\n"); while (1); } } static void UART2_TX_DMA_Config(void) { dma_handshake_config_t handshake_config; dma_channel_config_t channel_config; /* 使能 DMA 时钟 */ // HDMA 时钟来源于系统总线时钟(AHB) /* ========== 配置 TX DMA 通道 ========== */ /* 初始化 DMA 通道 */ dma_default_channel_config(SBUS_UART2_DMA_CONTROLLER, &channel_config); /* 配置 DMAMUX:将 UART3 TX 请求连接到 TX DMA 通道 */ dmamux_config(SBUS_UART2_DMAMUX_CONTROLLER, SBUS_UART2_TX_DMAMUX_CH, SBUS_UART2_TX_DMA_REQ, true); /* 配置 TX 握手参数 */ dma_default_handshake_config(SBUS_UART2_DMA_CONTROLLER, &handshake_config); } static void UART2_TX_NVIC_Config(void) { intc_m_enable_irq_with_priority(SBUS_UART2_DMA_IRQ, SBUS_UART2_DMA_IRQ_RANK); } void UART2_Put_Char(uint8_t DataToSend) { /* 等待发送寄存器空 */ while (!uart_check_status(SBUS_UART2_TX, uart_stat_transmitter_empty)); /* 发送数据 */ uart_send_byte(SBUS_UART2_TX, DataToSend); /* 等待发送完成 */ while (!uart_check_status(SBUS_UART2_TX, uart_stat_transmitter_empty)); } static bool usart2_tx_isbusy(void) { return !uart2_tx_dma_done; } void open_dma1_stream6_tx(unsigned short count) { dma_handshake_config_t handshake_config; /* 等待上次发送完成 */ uint32_t timeout = 1000000; while (usart2_tx_isbusy() && timeout--) { __asm("nop"); } if (timeout == 0) { // 超时处理,复位DMA dma_abort_channel(SBUS_UART2_DMA_CONTROLLER, SBUS_UART2_TX_DMA_CH); uart2_tx_dma_done = true; // 强制完成 } /* 重新配置 TX 传输大小 */ dma_default_handshake_config(SBUS_UART2_DMA_CONTROLLER, &handshake_config); handshake_config.ch_index = SBUS_UART2_TX_DMA_CH; handshake_config.dst = (uint32_t)&SBUS_UART2_TX->THR; handshake_config.dst_fixed = true; handshake_config.src = core_local_mem_to_sys_address(0, (uint32_t)uart2_dma_tx_buf); handshake_config.src_fixed = false; handshake_config.data_width = DMA_TRANSFER_WIDTH_BYTE; handshake_config.size_in_byte = count; dma_setup_handshake(SBUS_UART2_DMA_CONTROLLER, &handshake_config, true); // true表示触发一次 } /*--------------------------------------------------------------------------*/ /* PWM 值转 SBUS 数值(原样保留) */ /*--------------------------------------------------------------------------*/ void pwm_to_sbus(short *out_pwm, short *out_subs) { int i = 0; for (i = 0; i < 8; i++) { out_subs[i] = ((out_pwm[i] - 860) / 0.625f); } #ifdef ALL_CHANNELS for (i = 8; i < 14; i++) { out_subs[i] = ((out_pwm[i] - 860) / 0.625f); } #endif } /*--------------------------------------------------------------------------*/ /* SBUS 数据打包(原样保留) */ /*--------------------------------------------------------------------------*/ void sbus_channel_packet(short *rc_ch) { /* assemble the SBUS packet */ // SBUS header uart2_dma_tx_buf[0] = 0x0f; // 16 channels of 11 bit data uart2_dma_tx_buf[1] = (uint8_t)((rc_ch[0] & 0x07FF)); uart2_dma_tx_buf[2] = (uint8_t)((rc_ch[0] & 0x07FF) >> 8 | (rc_ch[1] & 0x07FF) << 3); uart2_dma_tx_buf[3] = (uint8_t)((rc_ch[1] & 0x07FF) >> 5 | (rc_ch[2] & 0x07FF) << 6); uart2_dma_tx_buf[4] = (uint8_t)((rc_ch[2] & 0x07FF) >> 2); uart2_dma_tx_buf[5] = (uint8_t)((rc_ch[2] & 0x07FF) >> 10 | (rc_ch[3] & 0x07FF) << 1); uart2_dma_tx_buf[6] = (uint8_t)((rc_ch[3] & 0x07FF) >> 7 | (rc_ch[4] & 0x07FF) << 4); uart2_dma_tx_buf[7] = (uint8_t)((rc_ch[4] & 0x07FF) >> 4 | (rc_ch[5] & 0x07FF) << 7); uart2_dma_tx_buf[8] = (uint8_t)((rc_ch[5] & 0x07FF) >> 1); uart2_dma_tx_buf[9] = (uint8_t)((rc_ch[5] & 0x07FF) >> 9 | (rc_ch[6] & 0x07FF) << 2); uart2_dma_tx_buf[10] = (uint8_t)((rc_ch[6] & 0x07FF) >> 6 | (rc_ch[7] & 0x07FF) << 5); uart2_dma_tx_buf[11] = (uint8_t)((rc_ch[7] & 0x07FF) >> 3); #ifdef ALL_CHANNELS uart2_dma_tx_buf[12] = (uint8_t)((rc_ch[8] & 0x07FF)); uart2_dma_tx_buf[13] = (uint8_t)((rc_ch[8] & 0x07FF) >> 8 | (rc_ch[9] & 0x07FF) << 3); uart2_dma_tx_buf[14] = (uint8_t)((rc_ch[9] & 0x07FF) >> 5 | (rc_ch[10] & 0x07FF) << 6); uart2_dma_tx_buf[15] = (uint8_t)((rc_ch[10] & 0x07FF) >> 2); uart2_dma_tx_buf[16] = (uint8_t)((rc_ch[10] & 0x07FF) >> 10 | (rc_ch[11] & 0x07FF) << 1); uart2_dma_tx_buf[17] = (uint8_t)((rc_ch[11] & 0x07FF) >> 7 | (rc_ch[12] & 0x07FF) << 4); uart2_dma_tx_buf[18] = (uint8_t)((rc_ch[12] & 0x07FF) >> 4 | (rc_ch[13] & 0x07FF) << 7); uart2_dma_tx_buf[19] = (uint8_t)((rc_ch[13] & 0x07FF) >> 1); uart2_dma_tx_buf[20] = (uint8_t)((rc_ch[13] & 0x07FF) >> 9 | (rc_ch[14] & 0x07FF) << 2); uart2_dma_tx_buf[21] = (uint8_t)((rc_ch[14] & 0x07FF) >> 6 | (rc_ch[15] & 0x07FF) << 5); uart2_dma_tx_buf[22] = (uint8_t)((rc_ch[15] & 0x07FF) >> 3); // flags uart2_dma_tx_buf[23] = 0x00; #endif switch (uart2_dma_tx_buf[24]) { case 0x04: uart2_dma_tx_buf[24] = 0x14; break; case 0x14: uart2_dma_tx_buf[24] = 0x24; break; case 0x24: uart2_dma_tx_buf[24] = 0x34; break; case 0x34: default: uart2_dma_tx_buf[24] = 0x04; break; } // DMA方式发送 open_dma1_stream6_tx(UART2_TX_LENDTH_MAX); } #ifdef UART2_TX_TEST /* uart2 tx_dma demo 2026/03/16 pass*/ void sbus_uart2_out_test(void) { short test_channels[16]; /* 1. 初始化SBUS硬件 */ sbus_out_init(SBUS_UART2_BAUD); printf("SBUS初始化完成\r\n"); /* 2. 构造测试数据:通道0=最大值,通道1=最小值,其他=中位值 */ for (int i = 0; i < 16; i++) { test_channels[i] = 1024; // 中位值 } test_channels[0] = 1876; // 最大值 test_channels[1] = 172; // 最小值 printf("发送测试数据: Ch0=%d, Ch1=%d, Ch2=%d\r\n", test_channels[0], test_channels[1], test_channels[2]); /* 3. 打包并发送 */ sbus_channel_packet(test_channels); /* 4. 等待发送完成 */ printf("等待发送完成...\r\n"); while(usart2_tx_isbusy()) { board_delay_ms(1); } printf("发送完成!\r\n"); } #endif /* // sbus最大通道数18 #define SBUS_MAX_CHANNEL 18 // sbus一包数据25个字节 #define SBUS_FRAME_SIZE 25 // sbus起始位 #define SBUS_FRAME_SYNC_BYTE 0x0F //第24个字节的解析 #define SBUS_FLAG_CHANNEL_17 (1 << 0) #define SBUS_FLAG_CHANNEL_18 (1 << 1) #define SBUS_FLAG_SIGNAL_LOSS (1 << 2) #define SBUS_FLAG_FAILSAFE_ACTIVE (1 << 3) struct sbusframe_s { unsigned char sync_byte; // 176 bits of data (11 bits per channel * 16 channels) = 22 bytes. unsigned int chan0 : 11; unsigned int chan1 : 11; unsigned int chan2 : 11; unsigned int chan3 : 11; unsigned int chan4 : 11; unsigned int chan5 : 11; unsigned int chan6 : 11; unsigned int chan7 : 11; unsigned int chan8 : 11; unsigned int chan9 : 11; unsigned int chan10 : 11; unsigned int chan11 : 11; unsigned int chan12 : 11; unsigned int chan13 : 11; unsigned int chan14 : 11; unsigned int chan15 : 11; unsigned char flags; // The endByte is 0x00 on FrSky and some futaba RX's, on Some SBUS2 RX's the // value indicates the telemetry byte that is sent after every 4th sbus frame. // // See // https://github.com/cleanflight/cleanflight/issues/590#issuecomment-101027349 // and // https://github.com/cleanflight/cleanflight/issues/590#issuecomment-101706023 unsigned char end_byte; } __attribute__((__packed__)); typedef union { uint8_t sbus_data[SBUS_FRAME_SIZE]; struct sbusframe_s frame; } sbusframe_t; static sbusframe_t sbusframe; */