BetaFlight模块设计之三十七:SBUS
- 1. 源由
- 2. sbus启动&动态任务
- 3. 主要函数
- 3.1 sbus初始化
- 3.2 sbusFrameStatus更新
- 3.3 rxFrameTimeUs
- 3.4 sbusDataReceive接收数据
- 4. 辅助函数
- 4.1 sbusChannelsDecode
- 5. 参考资料
1. 源由
接着BetaFlight模块设计之三十六:SoftSerial,就Betaflight关于STM32F405 SBUS协议兼容硬件电气特性问题的代码支持问题做一个研读,看看目前设计上这个框架代码是否支持SBUS。
2. sbus启动&动态任务
main
└──> init
└──> rxInit
└──> serialRxInit
└──> sbusInit
main
└──> run
└──> scheduler
└──> rxFrameCheck
└──> rcFrameStatusFn(sbusFrameStatus)
[TASK_RX] = DEFINE_TASK("RX", NULL, rxUpdateCheck, taskUpdateRxMain, TASK_PERIOD_HZ(33), TASK_PRIORITY_HIGH), // If event-based scheduling doesn't work, fallback to periodic scheduling
└──> taskUpdateRxMain
└──> processRx
└──> updateRcRefreshRate
└──> rxGetFrameDelta
└──> rcFrameTimeUsFn(rxFrameTimeUs)
3. 主要函数
3.1 sbus初始化
sbusInit
│ //支持SBUS_MAX_CHANNEL(18)个通道
├──> static uint16_t sbusChannelData[SBUS_MAX_CHANNEL];
├──> static sbusFrameData_t sbusFrameData;
├──> static uint32_t sbusBaudRate;
│
├──> rxRuntimeState->channelData = sbusChannelData;
├──> rxRuntimeState->frameData = &sbusFrameData;
│
│ //初始化通道数据
├──> sbusChannelsInit(rxConfig, rxRuntimeState);
│
├──> rxRuntimeState->channelCount = SBUS_MAX_CHANNEL;
│
│ //配置波特率SBUS_FAST_BAUDRATE(200000)/SBUS_BAUDRATE(6000)
├──> <rxConfig->sbus_baud_fast>
│ └──> sbusBaudRate = SBUS_FAST_BAUDRATE;
├──> < else >
│ └──> sbusBaudRate = SBUS_BAUDRATE;
│
│ //挂两个钩子函数:sbusFrameStatus/rxFrameTimeUs
├──> rxRuntimeState->rcFrameStatusFn = sbusFrameStatus;
├──> rxRuntimeState->rcFrameTimeUsFn = rxFrameTimeUs;
│
├──> const serialPortConfig_t *portConfig = findSerialPortConfig(FUNCTION_RX_SERIAL);
├──> <!portConfig>
│ └──> return false;
│
├──> <USE_TELEMETRY>
│ └──> bool portShared = telemetryCheckRxPortShared(portConfig, rxRuntimeState->serialrxProvider);
├──> <#else>
│ └──> bool portShared = false;
│
│ //端口初始化,回调函数sbusDataReceive
├──> serialPort_t *sBusPort = openSerialPort(portConfig->identifier,
│ FUNCTION_RX_SERIAL,
│ sbusDataReceive,
│ &sbusFrameData,
│ sbusBaudRate,
│ portShared ? MODE_RXTX : MODE_RX,
│ SBUS_PORT_OPTIONS | (rxConfig->serialrx_inverted ? 0 : SERIAL_INVERTED) | (rxConfig->halfDuplex ? SERIAL_BIDIR : 0))
├──> <rxConfig->rssi_src_frame_errors>
│ └──> rssiSource = RSSI_SOURCE_FRAME_ERRORS;
│
├──> <USE_TELEMETRY><portShared>
│ └──> telemetrySharedPort = sBusPort;
└──> return sBusPort != NULL;
3.2 sbusFrameStatus更新
sbusFrameStatus
│ //检查帧状态
├──> sbusFrameData_t *sbusFrameData = rxRuntimeState->frameData;
├──> <!sbusFrameData->done>
│ └──> return RX_FRAME_PENDING;
│
├──> sbusFrameData->done = false;
│
├──> DEBUG_SET(DEBUG_SBUS, DEBUG_SBUS_FRAME_FLAGS, sbusFrameData->frame.frame.channels.flags);
│ //帧数据解码
├──> const uint8_t frameStatus = sbusChannelsDecode(rxRuntimeState, &sbusFrameData->frame.frame.channels);
│
│ //更新最近一次有效帧时间戳
├──> <!(frameStatus & (RX_FRAME_FAILSAFE | RX_FRAME_DROPPED))>
│ └──> rxRuntimeState->lastRcFrameTimeUs = sbusFrameData->startAtUs;
│
└──> return frameStatus;
typedef enum {
RX_FRAME_PENDING = 0,
RX_FRAME_COMPLETE = (1 << 0),
RX_FRAME_FAILSAFE = (1 << 1),
RX_FRAME_PROCESSING_REQUIRED = (1 << 2),
RX_FRAME_DROPPED = (1 << 3)
} rxFrameState_e;
3.3 rxFrameTimeUs
获取最近一帧有效数据的时间。
timeUs_t rxFrameTimeUs(void)
{
return rxRuntimeState.lastRcFrameTimeUs;
}
3.4 sbusDataReceive接收数据
sbusDataReceive
├──> sbusFrameData_t *sbusFrameData = data;
├──> const timeUs_t nowUs = microsISR();
├──> const timeDelta_t sbusFrameTime = cmpTimeUs(nowUs, sbusFrameData->startAtUs);
│
│ //超时500,从新SBUS数据帧开始算(数据中断异常)
├──> <sbusFrameTime > (long)(SBUS_TIME_NEEDED_PER_FRAME + 500)>
│ └──> sbusFrameData->position = 0;
│
│ //确保帧起始位置
├──> <sbusFrameData->position == 0>
│ ├──> <c != SBUS_FRAME_BEGIN_BYTE>
│ │ └──> return;
│ └──> sbusFrameData->startAtUs = nowUs;
│
│ //读取一帧数据
└──> <sbusFrameData->position < SBUS_FRAME_SIZE>
├──> sbusFrameData->frame.bytes[sbusFrameData->position++] = (uint8_t)c;
├──> <sbusFrameData->position < SBUS_FRAME_SIZE>
│ └──> sbusFrameData->done = false;
└──> < else >
├──> sbusFrameData->done = true;
└──> DEBUG_SET(DEBUG_SBUS, DEBUG_SBUS_FRAME_TIME, sbusFrameTime);
typedef struct sbusChannels_s {
// 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;
uint8_t flags;
} __attribute__((__packed__)) sbusChannels_t;
#define SBUS_CHANNEL_DATA_LENGTH sizeof(sbusChannels_t)
#define SBUS_FRAME_SIZE (SBUS_CHANNEL_DATA_LENGTH + 2)
4. 辅助函数
4.1 sbusChannelsDecode
对通道数据进行译码,并根据接收机内部信息判别FAILSAFE
和SIGNAL_LOSS
事件。
sbusChannelsDecode
│ //16通道赋值
├──> uint16_t *sbusChannelData = rxRuntimeState->channelData;
├──> sbusChannelData[0] = channels->chan0;
├──> sbusChannelData[1] = channels->chan1;
├──> sbusChannelData[2] = channels->chan2;
├──> sbusChannelData[3] = channels->chan3;
├──> sbusChannelData[4] = channels->chan4;
├──> sbusChannelData[5] = channels->chan5;
├──> sbusChannelData[6] = channels->chan6;
├──> sbusChannelData[7] = channels->chan7;
├──> sbusChannelData[8] = channels->chan8;
├──> sbusChannelData[9] = channels->chan9;
├──> sbusChannelData[10] = channels->chan10;
├──> sbusChannelData[11] = channels->chan11;
├──> sbusChannelData[12] = channels->chan12;
├──> sbusChannelData[13] = channels->chan13;
├──> sbusChannelData[14] = channels->chan14;
├──> sbusChannelData[15] = channels->chan15;
│
│ //根据Flag标识赋值MAX/MIN
├──> <channels->flags & SBUS_FLAG_CHANNEL_17>
│ └──> sbusChannelData[16] = SBUS_DIGITAL_CHANNEL_MAX;
├──> < else >
│ └──> sbusChannelData[16] = SBUS_DIGITAL_CHANNEL_MIN;
│
│ //根据Flag标识赋值MAX/MIN
├──> <channels->flags & SBUS_FLAG_CHANNEL_18>
│ └──> sbusChannelData[17] = SBUS_DIGITAL_CHANNEL_MAX;
├──> < else >
│ └──> sbusChannelData[17] = SBUS_DIGITAL_CHANNEL_MIN;
│
│ //接收机标识FAILSAFE
├──> <channels->flags & SBUS_FLAG_FAILSAFE_ACTIVE>
│ │ // internal failsafe enabled and rx failsafe flag set
│ │ // RX *should* still be sending valid channel data (repeated), so use it.
│ └──> return RX_FRAME_COMPLETE | RX_FRAME_FAILSAFE;
│
│ //接收机标识SIGNAL_LOSS
├──> <channels->flags & SBUS_FLAG_SIGNAL_LOSS>
│ │ // The received data is a repeat of the last valid data so can be considered complete.
│ └──> return RX_FRAME_COMPLETE | RX_FRAME_DROPPED;
│
└──> return RX_FRAME_COMPLETE;
5. 参考资料
【1】BetaFlight开源代码框架简介
【2】BetaFlight模块设计之三十六:SoftSerial
【3】Betaflight关于STM32F405 SBUS协议兼容硬件电气特性问题