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?

34 REPLIES 34

That is exactly what I was looking for and somehow completely missed it! Thanks a lot!

I'll have to look into ring buffers as I have no experience with them.

A small success:

After doubling the rx buffer up to 50 bytes and looking for the start flag, then transfering the index of the flag in this buffer to the SBUS-Yes/No?-Check I was able to achieve pretty regular lock-ons directly after resetting the MCU by hand. Unfortunately only then. But hey.

JGiem1_1-1707258844613.png

It is far from perfect still, but better than yesterday. Tomorrow I will have the time to read deeper into what you kindly suggested to further improve my concept; Interrupts especially. Any ideas for further lecture?

@StefanRinside my while-loop:

JGiem1_0-1707258811782.png

This could be an easy and combined with other strategies fast way to combat shifting.

I replaced the receive and callback with the functions suggested by Karl earlier and with that it's working rock solid with a 25 byte buffer.

I'll need to look into how to add a ring buffer or the likes to add a layer of buffering before the processing, but that might not even be necessary depending on how the buffer gets overwritten.

In order to check if the received bytes make a valid SBUS packet I simply check the beginning and end:

 

if (buffer[0] == 0x0F && (buffer[24] == 0x00 || (buffer[24] & 0x0F)  == 0x04))

 

 This is also inspired by Bolder Flight Systems SBUS library.

Back after a longer pause with this project. I will look into your code snippet, which looks very promising. I will also most likely work with a ring buffer, as well as an MCU that already supports signal inversion natively (H750 on a custom board).

I have long since finished the library and project and it's working flawlessly so far. Let me know if you run into any more issues and I can try to help.

I added a ping pong buffer between which the reception alternates. Decoding is then only triggered if some other part of my project needs the SBUS data, which blocks that side of the ping pong buffer from getting overwritten during the decoding process. I've also added bit more failsafe functionality, both through validity checks + the SBUS failsafe bit, as well as the WWDG interrupt (I ran out of timers on the F103 and didn't use the WWDG for anything else, so might as well...) which triggers if no valid SBUS packet was received within a set timeframe. That interrupt does not only set a failsafe state, but also reenables (resets) the UART receive interrupt.