cancel
Showing results for 
Search instead for 
Did you mean: 

UART / SBUS Data Aqcuisition

JGiem.1
Associate III

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.

JGiem1_0-1704717971165.png

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:

JGiem1_1-1704718124386.png

JGiem1_2-1704718174444.png

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?

36 REPLIES 36

I checked the baud rate with +/-1000 tolerance pretty early on, which created essentially the same results.

Just so y'all know my setup: On the transmitter, I am currently actively using 4 channels: Throttle and Rudder on one stick, Aileron and Elevon on the other - Aileron, Elevon and Rudder are centered (around 1/2 of 2048 so I guess around 1024), Throttle is set to minimum at approx. ~100-200. Just to explain what kind of magnitude of values I would be expecting out of the SBUS signal after conversion. Aileron CH1, Elevon CH4, Rudder CH2 and Throttle on CH3 [, or in rc-terms AERT or mode 2 -> SBUS should give me this after conversion: 1024 1024 1024 0150 0000 0000 0000...].

Now by moving the stick for Ail/Elev, I can sometimes "provoke" a frame being converted (means that the value on buffer 0 is actually "0x0F" as intended. This must be due to SOME kind of signal actually being available between the Rx and my UART, but as I said that's really just a statistical thing - nothing at all reproducable unfortunately!

Generally and mostly, the values that the UART is recognizing vary greatly (e.g "7c", "7e", "14" all on buf[0], or reference every other screenshot of my putty - it's all extremely varying), without any susceptible rule. During the whole time it is powered on. The only thing kinda frequently appearing is something like 7c or 7e on buf[0], which "11111000" is similar to the opposite of "00001111" - the needed "Start"-Flag embedded in the SBUS frame.

But then again, by my understanding, I dont need to invert the signal? I will try to drastically shorten the Data wire, to about 3-4cm and see if that brings me further.

You could just to verify, is to use a USB<>Serial adapter and tap the Rx input of it to the Tx of the controller. Then you can monitor the data with a serial program. You can see if you are getting 0x0F + 24 other bytes until the next 0x0F.

Tips and Tricks with TimerCallback https://www.youtube.com/@eebykarl
If you find my solution useful, please click the Accept as Solution so others see the solution.

I'm not quite sure I understood what you meant and also unfortunately dont have a USB-serial adapter (yet), but tried to get as close to it as possible.

I started with your data acquisition snippet. From there, I went and pasted every one of the 25 bytes from the current frame one after another into the serial terminal. To my surprise, the "0x0F" or decimal 15 was nowhere to be seen, and most definetly not around buf[0].

Below image shows the serial terminal, it notifies for a new frame with its buf[0] and then just throws out all 25 values (beginning, again with buf[0]), raw and untouched yet from any conversion. For the sake of reading, it waits a second until it pastes the next fresh frame. Leaving that last step, meaning the delay, out doesnt change a thing as it seems.

 

JGiem1_0-1704916527094.png

Addition: Notice how some frames have their buf[0] be a specific value after the frame notification, and then are pasted with a different buf[0] as the whole frame is pasted. Looks weird to me - does that mean the frame gets overwritten in the meantime because pasting it via serial takes too long between each frame or is that a timing issue?

For example this, buffer0 being 48, in the whole pasted frame 92.

JGiem1_1-1704917052573.png

Seems shifted to the right I guess?

EDIT2: Shorter signal wire, now down to 3cm, did not change a thing. Don't want to manufacture a whole PCB before this works honestly

EDIT3: During further research I read somewhere that the duration between each SBUS frame is around 9ms. Looked toe me like it could be relevant, even though I don't know what to make of this.

 

@STea @Karl Yamashita 

EDIT4 (to keep this thread orderly):

I am now performing conversion after each frame is received and output both raw hex values and their actual converted values (the relevant data per channel). Signal trace is as short as can be. Still no real structure behind all that...

JGiem1_0-1704921155430.png

Channels 1-16 all give results in their expected range, while being seemingly random (the transmitter remains totally still as is not being manipulated).

From the beginning.

The UART is configured to 100k baud rate, polarity is assumed to be correct, parity and word length is assumed to be correct, and the acquisition via an interrupt works too. Because, if I unplug the receiver, the input to the MCU remains constant contrary to "active" signal input with a connected receiver. I checked wether the MCU's clock signal (internal OSC) is maybe too unprecise, switched to the external 8Mhz but still got the same result.

 

I need an 0x0F on the first buffer value to know what follows is most likely SBUS raw data, which will later be converted. I don't get this flag often - but rarely. If I get it, no channel is similar to that of the last useful frame, despite no big movements in the joysticks. If I don't get this flag, the data is completely random aswell.

Instead I receive random and ever changing data on my UART.

As a semi-beginner, this is beyond my understanding honestly.

The HAL_UART_Transmit() blocks for multiple byte times.

Suggest you use it sparingly, and accumulate multiple bytes. Also create a method to resync with the frame byte if you get out of sync or lose bytes from the 25 expected.

The SBUS inverts at a signal level, as I recall, some STM32 have the ability to logic flip as an "advanced" setting for the USART configuration.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..

You are correct about SBUS being inverted, but since the used receiver is made from FrSky, who thought it was funny to invert their own version of SBUS, this should ultimately mean that the SBUS version I am dealing with is uninverted: 1->H, 0->L. For details please see above posts

Yes, my next attempt will be storing three frames at once and outputting them to check if the shift occurs because of overwriting, not some """clock""" (asynchronous, I know) misalignment

The USB<>Serial adapter would just clarify that it is receiving the same data as the STM32. If so, then it's the transmitter that isn't following SBUS protocol. You can also use an Oscilloscope to see if the first byte of the packet is 0x0F.

Tips and Tricks with TimerCallback https://www.youtube.com/@eebykarl
If you find my solution useful, please click the Accept as Solution so others see the solution.

Now that i look at your screen capture of the data, you can see there is a repeating pattern but they are out of sync. Take for instance the first line that starts with 0xE, 0xFC, 0xFE, 0x70, 0x80, 0x12, 0xC.... The same patter can be seen on other lines but 0xE starts at another index. 

 

Now 0x0F isn't seen so something is still not correct. But the first byte of the packet whatever it may be, should be the first in byte[0]. I'd check with an Oscilloscope to see what is the actual first byte

 

I'd get away from using HAL_UART_Transmit as that is blocking code and so you could be missing receiving bytes. Use HAL_UART_Transmit_IT instead.

Tips and Tricks with TimerCallback https://www.youtube.com/@eebykarl
If you find my solution useful, please click the Accept as Solution so others see the solution.

Thank you for pointing that out - I totally should have noticed that!

Bought a simple logic analizer in the meantime that can be used with "sigrok" to make for a 10€ makeshift osci. Nice thing is, that sigrok (the application) can also deal with normal SBUS, so I think this will give me all sorts of possibilites for fault detection. Should arrive by friday.

Will update!

 

Just as a side note in the meantime, on the official sigrok page for Futaba SBUS, it shows 1=High and 0=Low in its diagram. Which, far as I read, would be the other way around. Well, guess I'll soon find out.

Today I got to test the logic analyzer. Unfortunately, that raised more questions than it answered.

Here are a few snaps from a SBUS signal that I acquired directly from the receiver, without the STM32 (solely as power source). Config-window for SBUS decoding:

JGiem1_0-1705092197412.png

These are the SBUS decoding settings, I tried every combination imaginable, first and foremost 100000kbps, 8, even parity, 2 stop bits. Switched Inverted/not inverted. 8/9 bits. Even/uneven. But all that made no difference - what follows are frames taken with several different settings where it's mostly inversion that was changed in the decoding options. Values stay untouched, so the upper "line" is always the raw, unedited signal.

JGiem1_1-1705092386582.png

As you can see in this and some following screenshots, there are some repeating patterns again, yet the same phenomenon, the "wandering", occurs too.

JGiem1_2-1705092458110.png

JGiem1_3-1705092471820.png

JGiem1_4-1705092490600.png

Am I the only one finding those frames a little short for 25bytes?

JGiem1_6-1705092620677.png

I can't even decipher more than two bytes out of most of those frames. Or is that because every byte is transmitted seperately (which, the more thought I give it, sounds somewhat plausible)?

I am 100% sure that the data line is hooked up to the SBUS-Out pin on the Receiver.

Now, there is the option to declare the "SBUS paket length" which I then tried setting to 25, 24 but that did not give me any good results either. I can try it with 16 or other values tomorrow, but as of right now it looks like a dead end.

There's a second, smaller SBUS receiver inbound for a small drone, I could use that to test wether my Rx is maybe bad or not.

In the meantime, I have no idea what to make of this - any ideas?

______

@STea @Karl Yamashita 

 

 

Hello @JGiem.1 ,

any news on you debugging status are you able to visualize the right start frame sequence with the logic analyser ? 

In order to give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.