I missed that (didn't see that the code box had a scroll handle). Thanks, I will give it a try.
Again, I'm most interested in 1) code that works (we all are), and 2) code that is not overly-optimized to the point of being intimidating. I have been published in dozens of magazine articles and my code is known to be easy for newcomers to understand. That being the case, I will sometimes make code more verbose so that it is easy for others to understand.
Thanks, again, for all the great feedback. I mentioned you and Evan in the Parallax zoom call after showing my custom DEBUG PLOT window for visualizing the live data from the receiver.
@JonnyMac said:
Again, I'm most interested in 1) code that works (we all are), and 2) code that is not overly-optimized to the point of being intimidating. I have been published in dozens of magazine articles and my code is known to be easy for newcomers to understand. That being the case, I will sometimes make code more verbose so that it is easy for others to understand.
Jon,
I really like the way you use the simple instructions to make it easy for newbies to understand. I many cases we're not interested in speed, or for that matter code density. It's much easier to pick up a simple program and instantly understand what's happening.
Going into the project I honestly didn't know how long it would take to decode the packet and write it to the hub. I was worried for nothing. In fast S.BUS there is about a 4 millisecond gap between packets. My decode-write-to-hub code, even with easy-to-understand instructions, consumes about 4 microseconds. I was worried for nothing. Things won't be so cheery on the P1, but I'm comfortable I'm not going to have any problems.
Going into the project I honestly didn't know how long it would take to decode the packet and write it to the hub. I was worried for nothing. In fast S.BUS there is about a 4 millisecond gap between packets. My decode-write-to-hub code, even with easy-to-understand instructions, consumes about 4 microseconds. I was worried for nothing. Things won't be so cheery on the P1, but I'm comfortable I'm not going to have any problems.
From one of the PST displays a number of posts ago, it's 230_400 baud so P1 should be fine. It will need the fullduplexserial cog to do the receiving as usual. Just use the invert option.
I've already written the driver in PASM -- need to test now. The P1 code matches the P2 code as closely as I can. Hope to finish the P1 version this weekend.
@evanh said:
Bugger, you're right. And I've led you up the garden path too. Certainly can't go embedding maths in an assembly line for variables/registers. That only works for constants/immediates.
Both our code shrinks are broken.
I think my code will work.
Huh, you're right. I've hacked up a quick test and it works as you say. In hindsight it does make sense sense that that's legal. It is still a constant register number in the end.
Learn some new every day.
PS: Here's my test code. It uses my own debug calls that I've had from the day dot. Chip's debug calls could be substituted when using Pnut.
mov bcdlen, #8
mov pa, #table
call #itod
mov pa, #table+2
call #itod
mov pa, table
call #itod
mov pa, table+2
call #itod
call #putnl
jmp #$
table
long 2
long 4
long 6
long 8
long 10
Hi, I've been studying the Futaba S.Bus for a couple of months and I believe I can throw some light on what appears to be much confusion on the internet in general about the format of S.Bus packets. Some people say the header byte is 0x0F whilst others say it is 0xF0. Some will say the bus is inverted and you need an external inverter, others will not. Here's what I have observed.
Using both my oscilloscope and my logic analyzer I can definitely confirm that the idle bus is low, i.e. 0 volts or thereabouts. The packets start with a start bit which goes high (3.3 Volts of thereabouts). Now whether the first packet header byte is read as a 0x0F or a 0xF0 depends on how your logic analyzer Serial Bus interpreter is configured. If you configure the interpreter to read LSB first, it reads as 0x0F. If you configure the interpreter to read MSB first, it reads as 0xF0.
The normal convention for microcontroller UARTs is that they read LSB first, in which case you should expect the first byte to read 0x0F. However many folks report that Futaba, in their infinite and obfuscating wisdom, decided to transmit S.Bus packets MSB first. Many microcontroller UARTS can be configured to read MSB first, so the Initial header byte would read as 0xF0, not 0x0F as many folks have reported and as has been assumed in this thread.
However, because of this, if you are receiving S.Bus packets on your own device, you will need to reverse the data bytes bit order since Futaba transmits them reversed that way. You can do that simply here:
uint8_t ByteReverseBits(uint8_t b)
{
b = (b & 0xF0) >> 4 | (b & 0x0F) << 4;
b = (b & 0xCC) >> 2 | (b & 0x33) << 2;
b = (b & 0xAA) >> 1 | (b & 0x55) << 1;
return b;
}
I have verified all this is true using a genuine Futaba S.Bus transmitter and receiver to control my own S.Bus device, an advanced RC sound system module.
Additionally, I see a lot of folks use unnecessarily complex bit handling to separate out the 16 x 11 bit channels from the 22 bytes (176 bits) of incoming S.Bus channel data.
I have used unions and 11 bit wide bit-fields to simplify the parsing out of those 16 x 11 bit channels using the data structure as shown here:
typedef union
{
uint8_t Byte;
struct
{
uint8_t EncodedChannel17 : 1;
uint8_t EncodedChannel18 : 1;
uint8_t FrameLost : 1;
uint8_t FailsafeActivated : 1;
uint8_t Bit3 : 1;
uint8_t Bit2 : 1;
uint8_t Bit1 : 1;
uint8_t Bit0 : 1;
};
} SBusErrorFlagsStruct;
// Futaba S.BUS packets are always 25 bytes.
typedef struct
{
uint8_t SerialBusID; // Will be 0xFO for FUTABA SBUS
SBusErrorFlagsStruct ErrorFlags;
uint8_t SBusFinalByte; // Always set to 0x00
} PACKED FutabaSBusPacketStruct;
This does rely on your particular compiler respecting bit-field positions absolutely and also allowing PACKED data structures. I am using the GCC ARM toolchain. which does allow this.
I hope this helps to clarify this very obscure and convoluted S.Bus format.
OK, so I might not be a smart assembler programmer like you guys and I do not know the Parallax products. My implementation of ByteReverseBits will work in any C compiler. And my application code works, so all is well as far as I am concerned!
Comments
@JonnyMac
Did you look at my code? If not, two main points are (1) subx t2,t2 and (2) wrlong #0,...
(1) is an old trick, e.g. sbc a,a (Z80) or sbb ax,ax (8086).
I missed that (didn't see that the code box had a scroll handle). Thanks, I will give it a try.
Again, I'm most interested in 1) code that works (we all are), and 2) code that is not overly-optimized to the point of being intimidating. I have been published in dozens of magazine articles and my code is known to be easy for newcomers to understand. That being the case, I will sometimes make code more verbose so that it is easy for others to understand.
Thanks, again, for all the great feedback. I mentioned you and Evan in the Parallax zoom call after showing my custom DEBUG PLOT window for visualizing the live data from the receiver.
Jon,
I really like the way you use the simple instructions to make it easy for newbies to understand. I many cases we're not interested in speed, or for that matter code density. It's much easier to pick up a simple program and instantly understand what's happening.
Thanks, Ray.
Going into the project I honestly didn't know how long it would take to decode the packet and write it to the hub. I was worried for nothing. In fast S.BUS there is about a 4 millisecond gap between packets. My decode-write-to-hub code, even with easy-to-understand instructions, consumes about 4 microseconds. I was worried for nothing. Things won't be so cheery on the P1, but I'm comfortable I'm not going to have any problems.
From one of the PST displays a number of posts ago, it's 230_400 baud so P1 should be fine. It will need the fullduplexserial cog to do the receiving as usual. Just use the invert option.
I've already written the driver in PASM -- need to test now. The P1 code matches the P2 code as closely as I can. Hope to finish the P1 version this weekend.
Huh, you're right. I've hacked up a quick test and it works as you say. In hindsight it does make sense sense that that's legal. It is still a constant register number in the end.
Learn some new every day.
PS: Here's my test code. It uses my own debug calls that I've had from the day dot. Chip's debug calls could be substituted when using Pnut.
Terminal output was:
19 21 2 6
Hi, I've been studying the Futaba S.Bus for a couple of months and I believe I can throw some light on what appears to be much confusion on the internet in general about the format of S.Bus packets. Some people say the header byte is 0x0F whilst others say it is 0xF0. Some will say the bus is inverted and you need an external inverter, others will not. Here's what I have observed.
Using both my oscilloscope and my logic analyzer I can definitely confirm that the idle bus is low, i.e. 0 volts or thereabouts. The packets start with a start bit which goes high (3.3 Volts of thereabouts). Now whether the first packet header byte is read as a 0x0F or a 0xF0 depends on how your logic analyzer Serial Bus interpreter is configured. If you configure the interpreter to read LSB first, it reads as 0x0F. If you configure the interpreter to read MSB first, it reads as 0xF0.
The normal convention for microcontroller UARTs is that they read LSB first, in which case you should expect the first byte to read 0x0F. However many folks report that Futaba, in their infinite and obfuscating wisdom, decided to transmit S.Bus packets MSB first. Many microcontroller UARTS can be configured to read MSB first, so the Initial header byte would read as 0xF0, not 0x0F as many folks have reported and as has been assumed in this thread.
However, because of this, if you are receiving S.Bus packets on your own device, you will need to reverse the data bytes bit order since Futaba transmits them reversed that way. You can do that simply here:
uint8_t ByteReverseBits(uint8_t b)
{
b = (b & 0xF0) >> 4 | (b & 0x0F) << 4;
b = (b & 0xCC) >> 2 | (b & 0x33) << 2;
b = (b & 0xAA) >> 1 | (b & 0x55) << 1;
return b;
}
I have verified all this is true using a genuine Futaba S.Bus transmitter and receiver to control my own S.Bus device, an advanced RC sound system module.
Additionally, I see a lot of folks use unnecessarily complex bit handling to separate out the 16 x 11 bit channels from the 22 bytes (176 bits) of incoming S.Bus channel data.
I have used unions and 11 bit wide bit-fields to simplify the parsing out of those 16 x 11 bit channels using the data structure as shown here:
typedef union
{
uint8_t Byte;
struct
{
uint8_t EncodedChannel17 : 1;
uint8_t EncodedChannel18 : 1;
uint8_t FrameLost : 1;
uint8_t FailsafeActivated : 1;
uint8_t Bit3 : 1;
uint8_t Bit2 : 1;
uint8_t Bit1 : 1;
uint8_t Bit0 : 1;
};
} SBusErrorFlagsStruct;
// Futaba S.BUS packets are always 25 bytes.
typedef struct
{
uint8_t SerialBusID; // Will be 0xFO for FUTABA SBUS
// This channel data is 11 bits per channel (2048 bits resolution) - 176 bits packed into 22 Bytes
union
{
uint8_t ChannelDataBytes[22];
struct SBUSChannelData
{
uint16_t Channel1 : 11;
uint16_t Channel2 : 11;
uint16_t Channel3 : 11;
uint16_t Channel4 : 11;
uint16_t Channel5 : 11;
uint16_t Channel6 : 11;
uint16_t Channel7 : 11;
uint16_t Channel8 : 11;
uint16_t Channel9 : 11;
uint16_t Channel10 : 11;
uint16_t Channel11 : 11;
uint16_t Channel12 : 11;
uint16_t Channel13 : 11;
uint16_t Channel14 : 11;
uint16_t Channel15 : 11;
uint16_t Channel16 : 11;
} PACKED EncodedPulseWidths;
} PACKED;
SBusErrorFlagsStruct ErrorFlags;
uint8_t SBusFinalByte; // Always set to 0x00
} PACKED FutabaSBusPacketStruct;
This does rely on your particular compiler respecting bit-field positions absolutely and also allowing PACKED data structures. I am using the GCC ARM toolchain. which does allow this.
I hope this helps to clarify this very obscure and convoluted S.Bus format.
OK, so I might not be a smart assembler programmer like you guys and I do not know the Parallax products. My implementation of ByteReverseBits will work in any C compiler. And my application code works, so all is well as far as I am concerned!