| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408 |
- #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;
- */
|