2024-01-08 04:54 AM
Hey folks. So for a beginner DIY fixed-wing flight controller, I am trying to incorporate servo values from an external receiver via SBUS [by FrSky (0-> Low, 1-> High; contrary to the standard SBUS by Futaba)] into my software.
I found a good amount of code for the sum frame decoding, but appear to not receive any UART communication at all from the receiver.
A UART RX Callback function generates an interrupt whenever there's a new frame received. The function is supposed to write a message via another UART to my Putty-terminal (which works fine), upon calling.
Further into it, the SBUS frame gets torn apart and the individual channel values generated - but I'm not even at this stage, and by the looks of it, it should work fine. My code:
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
uint16_t failsafe_status;
uint8_t buf[25];
uint16_t CH[18];
int lenght=0;
uint16_t USB_Send_Data[]={0};
char msg[25];
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart1)
{
sprintf(msg, "FRAME AQCUIRED\r\n");
HAL_UART_Transmit(&huart2, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
if (buf[0] == 0x0F) {
CH[0] = (buf[1] >> 0 | (buf[2] << 8)) & 0x07FF;
CH[1] = (buf[2] >> 3 | (buf[3] << 5)) & 0x07FF;
CH[2] = (buf[3] >> 6 | (buf[4] << 2) | buf[5] << 10) & 0x07FF;
CH[3] = (buf[5] >> 1 | (buf[6] << 7)) & 0x07FF;
CH[4] = (buf[6] >> 4 | (buf[7] << 4)) & 0x07FF;
CH[5] = (buf[7] >> 7 | (buf[8] << 1) | buf[9] << 9) & 0x07FF;
CH[6] = (buf[9] >> 2 | (buf[10] << 6)) & 0x07FF;
CH[7] = (buf[10] >> 5 | (buf[11] << 3)) & 0x07FF;
CH[8] = (buf[12] << 0 | (buf[13] << 8)) & 0x07FF;
CH[9] = (buf[13] >> 3 | (buf[14] << 5)) & 0x07FF;
CH[10] = (buf[14] >> 6 | (buf[15] << 2) | buf[16] << 10) & 0x07FF;
CH[11] = (buf[16] >> 1 | (buf[17] << 7)) & 0x07FF;
CH[12] = (buf[17] >> 4 | (buf[18] << 4)) & 0x07FF;
CH[13] = (buf[18] >> 7 | (buf[19] << 1) | buf[20] << 9) & 0x07FF;
CH[14] = (buf[20] >> 2 | (buf[21] << 6)) & 0x07FF;
CH[15] = (buf[21] >> 5 | (buf[22] << 3)) & 0x07FF;
if (buf[23] & (1 << 0)) {
CH[16] = 1;
} else {
CH[16] = 0;
}
if (buf[23] & (1 << 1)) {
CH[17] = 1;
} else {
CH[17] = 0;
}
// Failsafe
failsafe_status = SBUS_SIGNAL_OK;
if (buf[23] & (1 << 2)) {
failsafe_status = SBUS_SIGNAL_LOST;
}
if (buf[23] & (1 << 3)) {
failsafe_status = SBUS_SIGNAL_FAILSAFE;
}
// SBUS_footer=buf[24];
}
}
/* USER CODE END 0 */
This snippet is not mine, and I've got the feeling that the translation from the values into the buffer is missing. Could that be? If so, how would that look? To keep things simple I would like to avoid DMA in the beginning.
The while-loop is basically just the channel values 1-6 being printed to the serial terminal repeatedly.
CONCLUSION: Since the serial communication itself works, but neither gets any values nor notifies for a new frame, I think the issue lies within the SBUS -> UART part of it. Means, the Callback doesnt get executed for whatever reason. Additionally, here's my .ioc:
Iv'e tried it with 9 or 8 bits word length, but that doesnt change anything. Since FrSky is using the Inverted-SBUS, which is inverted itself (0->H, 1->L), I figured the data polarity is correct aswell as the jumper wires and config settings on the RX.
Regarding the transfer to the buffer AND/OR the Callback, what are your thoughts?
2024-01-19 05:26 AM
I have been experiencing a similar issue with a different receiver.
I think that you are receiving an inverted signal.
I suggest changing the data visualization to bits for a better understanding of the problem. In my case, I received consistent buffer data that looked inverted, but some channels where overlaping.
Inverting the bits by software also resulted in incorrect data.
The processor is taking the wrong bits as header, parity, and stop. Moving the joysticks on the remote controller changes these bits, causing the data stream to shift and disrupting the order of the repetitive patterns.
If you get something similar, you will need an external hardware inverter. A simple transistor will be enough.
2024-01-31 02:06 PM - edited 2024-02-01 06:49 AM
So today I had the time to try out the inverted signal. Buckle up.
I am inverting the signal with a p-ch MOSFET (IRF5305) using this example and verified it working as expected by testing it with an LED (Gate HIGH = Led LOW; Gate LOW = Led HIGH; 3.3V Logic Level). The gate gets discharged via 10k to GND, but leaving it away made essentionally no difference.
I tried both, inverted and uninverted input from the receiver to the F446.
@Karl YamashitaThe appearance of patterns that seem to shift stopped when reducing the RX buffer size to 24 instead of 25 bits. Note that in most SBUS tutorials that seem to work it is being worked with 25 bytes as frame size. But the shifting disappeared and you can now clearly see when you move a stick on the Tx that the approximate index of the frame (where the channel value is stored) differs from the one before. Meaning, moving the Throttle input (as CH1), it changes the frame from the beginning whereas when I am moving Aileron (on CH4) the difference in frames is only noticeable further to the end of the 24 byte hex output. I want to stress that while this looks "more right" it is actually against what can be read about SBUS (25 byte frame size). Could the fact that one byte is "missing" be an effect caused by some intricacy in the way HAL UART works?
Working with 8 bits incl. parity results in said "clean" appearance, whereas with 9 bits incl. parity you have it shifting again - that was more of a "why not try it"-idea but kinda confirmed the apparent frame length of 24 not 25 byte.
9b. incl p. and 25byte frame size resulted in the shift too.
Inverting the signal did change the output in its values, but it still only occasionally recognizes the starting flag (0x0F or dec 15), preferably with throttle (CH1) in the lowest position and the rest centered. The effects I first described above could be observed wether inverted or not.
Just an example of how the output looks like:
Taken while moving a stick.
@danielscmThanks for your ideas. As described above I went to work and unfortunately did not yield the same results as you seem to have gotten - may I ask what receiver you are using, and wether it was made by FrSky (with their own little interpretation of SBUS)? Inverting the signal seems to not make huge difference, it still can't catch the start flag and in the rare event that it does, the given values for each channel are not realistic (given that ~1024 is the middle value for 3 of 4 actively monitored channels and that value never remotely appeared). Unfortunately I will yet have to read into making the bare binary numbers visible. Will update.
@STeaRegarding the logic analyzer, I was having some compatibility issues that need fixing as to be able to use it properly. I was unknowingly locked down to 20kHz which is way too slow for a 100k baud signal. Will update.
Last but not least I want to tell you about two more phenomena I observed that I can't make anything out of.
1) After turning off the TX the receiver is entering failsafe mode where it is instructed to pass on "no pulses"; It feeds this:
It's a pattern that again appears shifted again regardless of 24byte-frame size, with the 7c in the end being a constant. Remember this for 2)... Unfortunately, the manual does not go into detail as to how the "no pulses mode" behaves. Out of a forum of OPENTX (the transmitters firmware), I get something along the lines of "No Pulse: on loss of signal the receiver produces no pulses on any channel. To use this type, select it in the menu and wait 9 seconds for the failsafe to take effect." - whatever that means for the SBUS output.
2) When disconnecting the RX from the F446's input (D2) something remarkable happens:
Now in order to make anything out of this, you probably need my current version of the code:
/* USER CODE BEGIN 0 */
uint16_t failsafe_status;
uint8_t buf[24];
uint16_t CH[16];
int length = 0;
uint16_t USB_Send_Data[]={0};
char msg[25];
bool valid = false;
bool newDataFlag = false;
HAL_StatusTypeDef hal_status;
void UART_EN_Interrupt(void)
{
hal_status = HAL_UART_Receive_IT(&huart1, (uint8_t*)buf, sizeof(buf)); // re-enable interrupt
}
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
newDataFlag = true;
UART_EN_Interrupt();
}
/* USER CODE END 0 */
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
//uint16_t raw;
UART_EN_Interrupt(); // initially start UART interrupt mode
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_USART2_UART_Init();
MX_USART1_UART_Init();
/* USER CODE BEGIN 2 */
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
if(newDataFlag)
{
newDataFlag = false;
valid = true;
//sprintf(msg, "FRAME AQCUIRED: %x\r\n", buf[0]);
//HAL_UART_Transmit(&huart2, (uint8_t*)msg, strlen(msg), 5);
}
if(hal_status == HAL_BUSY)
{
hal_status = HAL_OK;
UART_EN_Interrupt();
}
//PRINTING EACH ACQUIRED FRAME TO THE SERIAL TERMINAL IN SEPERATE HEX VALUES
for(int i = 0; i < 25; i++){
sprintf(msg, "%x ", buf[i]);
HAL_UART_Transmit(&huart2, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
if(i==24){
sprintf(msg, "\n\r ");
HAL_UART_Transmit(&huart2, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
}
}
//HAL_Delay(8);
//DECODING THE SBUS FRAME IF START FLAG (0x0f) IS FOUND
if (buf[0] == 0x0F) {
CH[0] = (buf[1] >> 0 | (buf[2] << 8)) & 0x07FF;
CH[1] = (buf[2] >> 3 | (buf[3] << 5)) & 0x07FF;
CH[2] = (buf[3] >> 6 | (buf[4] << 2) | buf[5] << 10) & 0x07FF;
CH[3] = (buf[5] >> 1 | (buf[6] << 7)) & 0x07FF;
CH[4] = (buf[6] >> 4 | (buf[7] << 4)) & 0x07FF;
CH[5] = (buf[7] >> 7 | (buf[8] << 1) | buf[9] << 9) & 0x07FF;
CH[6] = (buf[9] >> 2 | (buf[10] << 6)) & 0x07FF;
CH[7] = (buf[10] >> 5 | (buf[11] << 3)) & 0x07FF;
CH[8] = (buf[12] << 0 | (buf[13] << 8)) & 0x07FF;
CH[9] = (buf[13] >> 3 | (buf[14] << 5)) & 0x07FF;
CH[10] = (buf[14] >> 6 | (buf[15] << 2) | buf[16] << 10) & 0x07FF;
CH[11] = (buf[16] >> 1 | (buf[17] << 7)) & 0x07FF;
CH[12] = (buf[17] >> 4 | (buf[18] << 4)) & 0x07FF;
CH[13] = (buf[18] >> 7 | (buf[19] << 1) | buf[20] << 9) & 0x07FF;
CH[14] = (buf[20] >> 2 | (buf[21] << 6)) & 0x07FF;
CH[15] = (buf[21] >> 5 | (buf[22] << 3)) & 0x07FF;
//PRINT EACH CONVERTED CHANNEL VALUE IF START FLAG WAS FOUND
sprintf(msg, "%d ", buf[0]);
HAL_UART_Transmit(&huart2, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
sprintf(msg, "%d ", CH[1]);
HAL_UART_Transmit(&huart2, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
sprintf(msg, "%d ", CH[2]);
HAL_UART_Transmit(&huart2, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
sprintf(msg, "%d ", CH[3]);
HAL_UART_Transmit(&huart2, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
sprintf(msg, "%d ", CH[4]);
HAL_UART_Transmit(&huart2, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
sprintf(msg, "%d ", CH[5]);
HAL_UART_Transmit(&huart2, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
//SO ON AND SO FORTH
sprintf(msg, "%d ", CH[23]);
HAL_UART_Transmit(&huart2, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
sprintf(msg, "%d ", CH[24]);
HAL_UART_Transmit(&huart2, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
sprintf(msg, "%d \r\n", CH[25]);
HAL_UART_Transmit(&huart2, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
//MAKE IT NOTICEABLE
HAL_Delay(10000);
}
.
.
.
}
}
Now as far as I'm aware, the UART is working with an Interrupt to fill the buffer so it probably wont be interfering with the transmitting to the serial terminal (please correct me if Im mistaken).
First things first: Despite the frame now theoretically only consisting of "0" due to no signal, it yields the 7c (124 in dec) in the end of it - any ideas why that is?
But most importantly: Note the slow and not - as I would have expected it - instantaneous changing to 0 of the frame's bytes after disconnecting! (Discharge resistor applied to the MOSFETs Gate doesnt change anything).
Is there a reason for that in the code or could that be residual signal somewhere along the wire (can't be a real thing)? This is becoming way trickier than I thought it could get. Is it a timing issue in my communication? Any ideas as to why this happens?
Lastly, in the Receivers manual, i found this snippet of info:
Along with an email address of the technical support, which by now I am frustrated enough to contact for further info on the SBUS output. Wether this is changing anything or not is beyond me right now.
FURTHER INFO ON SBUS: https://www.youtube.com/watch?v=IqLUHj7nJhI
Wiki-page in video above: https://github.com/uzh-rpg/rpg_quadrotor_control/wiki/SBUS-Protocol
(not promoting anything, just found these helpful)
Maybe I'll take a look at the receiver with an osci at work next week.
HUGE THANK YOU FOR STICKING WITH ME! "WINNER" CAN EXPECT COFFEE :)
2024-02-01 07:29 AM
Hello @JGiem.1 ,
i have some suggestion you can try:
UART_EN_Interrupt();
after
HAL_Init();
BR
2024-02-04 01:58 PM - edited 2024-02-04 03:48 PM
@STea @Karl Yamashita @Tesla DeLorean @danielscm
UPDATE with the logic analyzer:
I finally got to take a look at what is actually leaving the receiver. The upper one is the "electronically-uninverted", raw output signal straight from the receiver. The lower one is inverted via the mosfet. That seems to be a little too slow as the timing appears a little off. Maybe some parasitic capacity in either the gate or wire, I think that's fixable.
Now, Channel 0, the valid one: For the software's decoder to be able to read it, I have to choose "Inverted - RS232". The signal output is a perfect SBUS frame (25 bytes btw!) - starting with the long sought-after 0x0F flag, ending with the two 0x00 end flags. Shown in the upper curve is one whole SBUS frame. Those do repeat in the expected time range of 3ms sending, 4ms idle equaling a "period" of what they correctly wrote was 7ms.
Apparently, LOW = 0, and HIGH = 1. As far as I saw on the Wikipedia page for UART that is correct too. So my original assumption/hope that I would not need an inverter is still valid. Yay.
This is the first byte of a random frame. It shows the 0x0F flag (binary 0000 1111). Looks all fine to me, so I assume my error lies somewhere in the configuration of UART1 (UART2 is the nucleo's serial terminal) or the latter software part.
@STeaI switched the EN function behind the HAL Init, and incorporated fflush(0); everywhere I saw fit.
Unfortunately, that did not bring better results. Another observation (also applicable to my last post) was the seeming loss of synchronization after resetting the MCU. Every red line marks a reset, where the signal is somewhat shifted and changes. Furthermore, the original issue persists.
Any ideas? The error must lie in the config I guess, but that's beyond my current understanding I'm afraid.
In all the above the TX was active and sticks not moved.
Coffee offer still stands ;)
EDIT:
Wrote a short snippet in Eclipse (C) with the logic analyzers values to test the frame's raw hex content aswell as my decoding "function". Two individual frames, first being all centered except throttle (minimum), second being all centered except throttle (maximum).
First line of each frame being Aileron, then Rudder, Throttle and Elevon. Throttle can nicely be observed shifting from 172 to 2047. For some reason, Aileron Elevon and Rudder should be centered around 1024, but tha's for another day. Throttle is correct nonetheless.
2024-02-06 07:18 AM
I have had the same problem of trying to decode SBUS the past couple days and I have managed to get it to work (mostly, more about that at the end of my post).
First let me start by saying that SBUS is always inverted, no matter if you have a Futaba or FrSky receiver. So you will always need an inverter for the F1 or F4 series. But building one from two resistors and an arbitrary NPN transistor is very easy and you should be able to find the parts almost anywhere.
There are some receivers where you can access the non-inverted signal by opening the rx and tap the signal before it gets inverted. The only exception might be some truly ancient receivers that I am forgetting right now, but for all others that should be true.
That said, your screen grabs are actually showing a non-inverted signal, which is a little bit odd... What receiver are you using and have you tried a different one yet?
Now down to business of decoding the SBUS signal. For the sake of completion for people finding this post later I will include absolutely everything, because I myself am just starting with the STM uCs and many things are not as obvious as we think.
First you want to start by setting up the USART (I used USART2) with a baud rate of 100000 Bits/s, word length of 9 Bits (inc. Parity) , even parity bit and 2 stop bits. Additionally don't forget to turn on the global interrupt in the NVIC settings, been there done that and wondered why it didn't work...
I also set up USART1 to print the frames and processed data over serial.
Now the code:
Since there is no boolean type in C you need to define it yourself. Additionally you need to include stdio.h and string.h if you want to use the same commands I used to print over serial.
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include <stdio.h>
#include <string.h>
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
typedef enum { false, true } bool;
/* USER CODE END PTD */
Then the variables & functions as described in posts in this thread. A buffer length of 25 bytes worked for me, but I'm basing this only on what I've read about SBUS by 3rd parties and not the actual protocol definition or my own investigation.
/* USER CODE BEGIN 0 */
char msg[25]; //used for debugging: for printing the frames & processed data over serial
// variables used for the processing of the sbus data
uint16_t sbusChannels[16];
#define sbusChannelsLength 16
bool lost_frame;
bool failsafe;
bool ch17, ch18;
uint8_t buffer[25];
#define bufferLength 25
bool newDataFlag = false;
HAL_StatusTypeDef hal_status;
void UART_EN_Interrupt(void)
{
hal_status = HAL_UART_Receive_IT(&huart2, (uint8_t*)buffer, bufferLength);
}
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
newDataFlag = true;
UART_EN_Interrupt();
}
/* USER CODE END 0 */
Start the interrupt mode before the infinite while loop.
/* USER CODE BEGIN 2 */
UART_EN_Interrupt(); //initially start UART interrupt mode
/* USER CODE END 2 */
After that you can do the data processing etc.
I've taken the processing from Bolder Flight Systems SBUS library.
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
if(newDataFlag)
{
newDataFlag = false;
//print received frames over UART 1
uint8_t index1 ;
for(index1 = 0 ; index1 < bufferLength; index1 ++)
{
sprintf(msg, "FRAME %u: %X\r\n", index1, buffer[index1]);
HAL_UART_Transmit(&huart1, (uint8_t*)msg, strlen(msg), 5);
}
sprintf(msg, "\n");
HAL_UART_Transmit(&huart1, (uint8_t*)msg, strlen(msg), 5);
// process data
sbusChannels[0] = (uint16_t) ((buffer[1] | buffer[2] <<8) & 0x07FF);
sbusChannels[1] = (uint16_t) ((buffer[2]>>3 | buffer[3] <<5) & 0x07FF);
sbusChannels[2] = (uint16_t) ((buffer[3]>>6 | buffer[4] <<2 | buffer[5]<<10) & 0x07FF);
sbusChannels[3] = (uint16_t) ((buffer[5]>>1 | buffer[6] <<7) & 0x07FF);
sbusChannels[4] = (uint16_t) ((buffer[6]>>4 | buffer[7] <<4) & 0x07FF);
sbusChannels[5] = (uint16_t) ((buffer[7]>>7 | buffer[8] <<1 | buffer[9]<<9) & 0x07FF);
sbusChannels[6] = (uint16_t) ((buffer[9]>>2 | buffer[10] <<6) & 0x07FF);
sbusChannels[7] = (uint16_t) ((buffer[10]>>5 | buffer[11]<<3) & 0x07FF);
sbusChannels[8] = (uint16_t) ((buffer[12] | buffer[13]<<8) & 0x07FF);
sbusChannels[9] = (uint16_t) ((buffer[13]>>3| buffer[14]<<5) & 0x07FF);
sbusChannels[10] = (uint16_t) ((buffer[14]>>6| buffer[15]<<2 | buffer[16]<<10) & 0x07FF);
sbusChannels[11] = (uint16_t) ((buffer[16]>>1| buffer[17]<<7) & 0x07FF);
sbusChannels[12] = (uint16_t) ((buffer[17]>>4| buffer[18]<<4) & 0x07FF);
sbusChannels[13] = (uint16_t) ((buffer[18]>>7| buffer[19]<<1 | buffer[20]<<9) & 0x07FF);
sbusChannels[14] = (uint16_t) ((buffer[20]>>2| buffer[21]<<6) & 0x07FF);
sbusChannels[15] = (uint16_t) ((buffer[21]>>5| buffer[22]<<3) & 0x07FF);
ch17 = buffer[23] & 0x01;
ch18 = buffer[23] & 0x02;
lost_frame = buffer[23] & 0x04;
failsafe = buffer[23] & 0x08;
//print processsed data over UART 1
uint8_t index2 ;
for(index2 = 0 ; index2 < sbusChannelsLength; index2 ++)
{
sprintf(msg, "CH %u: %u\r\n", (index2 + 1), sbusChannels[index2]);
HAL_UART_Transmit(&huart1, (uint8_t*)msg, strlen(msg), 5);
}
if (ch17)
{
sprintf(msg, "ch17: true\n");
}
else
{
sprintf(msg, "ch17: false\n");
}
HAL_UART_Transmit(&huart1, (uint8_t*)msg, strlen(msg), 5);
if (ch18)
{
sprintf(msg, "ch18: true\n");
}
else
{
sprintf(msg, "ch18: false\n");
}
HAL_UART_Transmit(&huart1, (uint8_t*)msg, strlen(msg), 5);
if (lost_frame)
{
sprintf(msg, "lost frame: true\n");
}
else
{
sprintf(msg, "lost frame: false\n");
}
HAL_UART_Transmit(&huart1, (uint8_t*)msg, strlen(msg), 5);
if (failsafe)
{
sprintf(msg, "failsafe: true\n");
}
else
{
sprintf(msg, "failsafe: false\n");
}
HAL_UART_Transmit(&huart1, (uint8_t*)msg, strlen(msg), 5);
sprintf(msg, "\n");
HAL_UART_Transmit(&huart1, (uint8_t*)msg, strlen(msg), 5);
//wait 500 ms
HAL_Delay(500);
}
if(hal_status == HAL_BUSY)
{
hal_status = HAL_OK;
UART_EN_Interrupt();
}
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
Bolder Flight Systems also mention that "FrSky receivers will output a range of 172 - 1811 with channels set to a range of -100% to +100%.", which is exactly what I'm getting with a FrSky XM. I haven't tried any other receivers yet, but they should all work the same.
Now, as mentioned earlier I'm just starting out with the STM uCs and therefore don't really know what I'm doing. There is one problem, to which I haven't figured out the solution yet:
Depending on when the uC starts up the first byte received might not be the starting byte of the SBUS transition. You can trigger this by pressing the reset button a couple times; at some point you'll run into the issue.
The question is how to solve this. I need a way to basically to reset/reframe when the interrupt gets triggered whenever the first frame is not the SBUS header (0x0F). I'd really appreciate if somebody could guide me in the right direction!
Cheers,
Stefan
2024-02-06 08:13 AM
Thanks for your thoughts. I will try your version by myself later.
In the meantime, to your synchronizing issue - how I understood it. Your issue is to recognize when a frame starts. In my version of the code, the values only get decoded if the first buffer value is the SBUS-specific starting flag "0x0F". All other values would hint towards the frame being incomplete or containing errors. To make it even safer, you can check for the two "stop" flags in the end. I solved that by a simple if-addition before decoding. Since the signal is continously streamed, you should end up synchronized eventually.
2024-02-06 08:27 AM - edited 2024-02-06 08:31 AM
Yes and no,
my issue is that the 25 bytes that get received might not necessarily be one whole SBUS packet but the second half of one and then the first half of the next, if you know what I mean.
Simply only decoding valid packets does not solve the problem since there will never be any valid packets if you happen to be unlucky with the timing while booting up the uC. It will not synchronise automatically since you only ever receive the 25 bytes specified in interrupt.
EDIT:
The only fix I could think of right now would be to increase the buffer size to double the length aka 50 and then search for the SBUS packet every time. But that does not seem like the right solution...
EDIT end
2024-02-06 11:10 AM
I understand, and after thinking about it for some time that could be one of the problems with my implementation so far aswell.
A possible solution could be to, after receiving the first new data packet, wait for exactly three milliseconds (the maximum duration for active sending of data, reference to my logic analyzer screenshot), clear the rx buffer, and wait for the next frame. In theory, even after starting in the middle of a transmission, with the pause between each packet of 4 milliseconds, you would always end up in a silent phase with a clear buffer waiting for new data. That would need to be done in a non-blocking way via a timer+output compare I believe.
This would still need to be verified as it's just an idea for now.
Would you be fine if i contacted you via direct messages? I feel like we have a very similar project going on and maybe we could work on solutions together as i myself am also a more-or-less beginner. BR
2024-02-06 12:10 PM
Of course, I'd be more than happy to share ideas!
Yeah, that would be one idea.
Another idea that I just had might be to read the data byte by byte. I'm pretty sure that's how Bolder Flight Systems does it in their Arduino library, but that might not work. I'll try that later tonight and see if I can make it work.
2024-02-06 12:25 PM
You can include the header for bool type
#include <stdbool.h>
Depending on when the uC starts up the first byte received might not be the starting byte of the SBUS transition. You can trigger this by pressing the reset button a couple times; at some point you'll run into the issue.
The question is how to solve this. I need a way to basically to reset/reframe when the interrupt gets triggered whenever the first frame is not the SBUS header (0x0F). I'd really appreciate if somebody could guide me in the right direction!
Use HAL_UARTEx_ReceiveToIdle_IT instead of HAL_UART_Receive_IT. The callback to use is HAL_UARTEx_RxEventCallback
That'll keep the packets in sync. Using a ring buffer and some packet length checks, you can be sure you have a valid packet.
See this project https://github.com/karlyamashita/ParseTelemetryData/wiki
That project uses a MOD256 checksum to validate the packet. But you could instead just check if each packet in the queue starts with 0x0F and ends with 0x00 to be considered a good packet.