Forum Rule: Always post complete source code & details to reproduce any issue!
Page 3 of 3 FirstFirst 1 2 3
Results 51 to 59 of 59

Thread: SBUS Library

  1. #51
    Junior Member
    Join Date
    Apr 2019
    Posts
    10
    Hi Brian,

    how many SBUS objects can I create? I need to use Serial1 for serial communication, and serial 2 and 3 for SBUS communication. Thing is I create

    "
    SBUS x8r_gimbal(Serial2);
    SBUS x8r_camera(Serial3);

    void setup()
    {
    pinMode(led_pin, OUTPUT);
    pinMode(reset_pin, OUTPUT);
    Serial.begin(baud); // USB, communication to PC or Mac
    HWSERIAL.begin(baud); // communication to hardware serial
    x8r_gimbal.begin();
    x8r_camera.begin();
    }

    void loop()

    if(x8r_gimbal.read(&gimbal[0], &failSafe, &lostFrame))
    x8r_gimbal.write(&gimbal[0]);
    "
    If I do x8r_camera.begin(), tx2 won't transmit data. rx2 will still receive SBUS data though. And tx3 also works fine.

    Any clue why only one tx works?
    Ps: I'm using serial1 for serial communication and it works fine

  2. #52
    Senior Member brtaylor's Avatar
    Join Date
    Mar 2016
    Location
    Portland, OR
    Posts
    537
    Which Teensy are you compiling and testing on? For Teensy 3.0 and 3.1/3.2, this would be expected behavior - I have to emulate two stop bits and define some timers to help with that, which would only allow for 1 Teensy object to send data. For other Teensy devices (i.e. LC, 3.5, and 3.6), this would not be expected behavior.

  3. #53
    Junior Member
    Join Date
    Apr 2019
    Posts
    10
    Thanks for the reply. Unfortunately it's a teensy 3.2. Is there a way to get around that limitation?

  4. #54
    Senior Member brtaylor's Avatar
    Join Date
    Mar 2016
    Location
    Portland, OR
    Posts
    537
    It's not flexible, which is why it's not implemented, but yes, you can work around it.

    In SBUS.cpp, you would change this (lines 26 - 33):
    Code:
    #if defined(__MK20DX128__) || defined(__MK20DX256__)
    	// globals needed for emulating two stop bytes on Teensy 3.0 and 3.1/3.2
    	IntervalTimer serialTimer;
    	HardwareSerial* SERIALPORT;
    	uint8_t PACKET[25];
    	volatile int SENDINDEX;
    	void sendByte();
    #endif
    To the following, basically creating two of everything:
    Code:
    #if defined(__MK20DX128__) || defined(__MK20DX256__)
    	// globals needed for emulating two stop bytes on Teensy 3.0 and 3.1/3.2
    	IntervalTimer serialTimer1, serialTimer2;
    	HardwareSerial *SERIALPORT1, *SERIALPORT2;
    	uint8_t PACKET1[25], PACKET2[25];
    	volatile int SENDINDEX1, SENDINDEX2;
    	void sendByte1(), sendByte2();
    #endif
    Then in the rest of the code, we need to update the variables and functions used. This starts with the begin method and assigning the serial port pointers:
    Code:
    		_bus->begin(_sbusBaud,SERIAL_8E1_RXINV_TXINV);
    		if (_bus == &Serial2) {
    			SERIALPORT1 = _bus;
    		} else if (_bus == &Serial3) {
    			SERIALPORT2 = _bus;
    		}
    You'll notice right away, that we need to check the Serial port value before assignment since the object could have been created for either, but we're assigning to a global variable, so we're already reducing flexibility and assigning the port numbers specific for your setup. This would need to change if your serial port numbers ever change.

    Then in the write method would get modified to:
    Code:
    		if (_bus == &Serial2) {
    			noInterrupts();
    			memcpy(&PACKET1,&packet,sizeof(packet));
    			interrupts();
    			serialTimer1.priority(255);
    			serialTimer1.begin(sendByte1,130);
    		} else if (_bus == &Serial3) {
    			noInterrupts();
    			memcpy(&PACKET2,&packet,sizeof(packet));
    			interrupts();
    			serialTimer2.priority(255);
    			serialTimer2.begin(sendByte2,130);
    		}
    Note that I had to hard code a check to see whether it's Serial2 or Serial3. This is specific to your setup and would need to be modified if it changes. Finally, the logic of the interrupt routine needs to be updated
    Code:
    	void sendByte1()
    	{
    		if (SENDINDEX1 < 25) {
    			SERIALPORT1->write(PACKET1[SENDINDEX1]);
    			SENDINDEX1++;
    		} else {
    			serialTimer1.end();
    			SENDINDEX1 = 0;
    		}
    	}
    	void sendByte2()
    	{
    		if (SENDINDEX2 < 25) {
    			SERIALPORT2->write(PACKET2[SENDINDEX2]);
    			SENDINDEX2++;
    		} else {
    			serialTimer2.end();
    			SENDINDEX2 = 0;
    		}
    	}

  5. #55
    Junior Member
    Join Date
    Apr 2019
    Posts
    10
    Thanks, it works! However delay is noticeable and data gets corrupted more easily. Is it supposed to happen? If yes, I guess I can work out a solution the way it is right now

  6. #56
    Senior Member brtaylor's Avatar
    Join Date
    Mar 2016
    Location
    Portland, OR
    Posts
    537
    Quote Originally Posted by VascoSampaio View Post
    Thanks, it works! However delay is noticeable and data gets corrupted more easily. Is it supposed to happen? If yes, I guess I can work out a solution the way it is right now
    I'm not sure, hasn't been tested other than what you've been doing.

    If you're fine with the two write methods being called at the same time, an alternative approach is to use one timer and write out the two packets back to back. In that case you still need two serial port pointers and two buffers, but that's it:

    Code:
    	IntervalTimer serialTimer;
    	HardwareSerial *SERIALPORT1, *SERIALPORT2;
    	uint8_t PACKET1[25], PACKET2[25];
    	volatile int SENDINDEX;
    	void sendByte();
    The begin method would still be:
    Code:
    		_bus->begin(_sbusBaud,SERIAL_8E1_RXINV_TXINV);
    		if (_bus == &Serial2) {
    			SERIALPORT1 = _bus;
    		} else if (_bus == &Serial3) {
    			SERIALPORT2 = _bus;
    		}
    The write method would then be:
    Code:
    		if (_bus == &Serial2) {
    			noInterrupts();
    			memcpy(&PACKET1,&packet,sizeof(packet));
    			interrupts();
    		} else if (_bus == &Serial3) {
    			noInterrupts();
    			memcpy(&PACKET2,&packet,sizeof(packet));
    			interrupts();
    			serialTimer.priority(255);
    			serialTimer.begin(sendByte,130);
    		}
    Notice that actually sending the commands out is now tied to calling the write method on Serial3. Finally, the send function would be:
    Code:
    	void sendByte()
    	{
    		if (SENDINDEX < 25) {
    			SERIALPORT1->write(PACKET1[SENDINDEX]);
    			SENDINDEX++;
    		} else if (SENDINDEX < 50) {
    			SERIALPORT2->write(PACKET2[SENDINDEX - 25]);
    			SENDINDEX++;
    		} else {
    			serialTimer.end();
    			SENDINDEX = 0;
    		}
    	}
    I haven't tested it, but it should work a little better using just one timer and sending both packets back to back.

    Brian

  7. #57
    Senior Member+ KurtE's Avatar
    Join Date
    Jan 2014
    Posts
    5,584
    Not sure if you are losing data, and have some freedom in your choosing of Serial objects are used...
    On Teensy 3.2, Serial1 and Serial2 have larger hardware buffers than does Serial3, so depending on what you are using Serial1 for now, might help to swap 1 with 3?

    But I have no knowledge of SBus and the like.

  8. #58
    Junior Member
    Join Date
    Sep 2019
    Posts
    4
    Hi Brian;

    I have been trying on the following code modified from your bolderflight github for reading SBUS input from a frsky receiver on teensy4:
    #include "Wire.h"
    #include "SBUS.h"

    // a SBUS object, which is on hardware
    // serial port 1
    SBUS x8r(Serial1);

    // channel, fail safe, and lost frames data
    uint16_t channels[16];
    bool failSafe;
    bool lostFrame;

    void setup() {
    Wire.begin();
    Serial.begin(115200);
    // begin the SBUS communication
    x8r.begin();
    }

    void loop() {
    int i = 1;
    // look for a good SBUS packet from the receiver

    Serial.println("h");
    if(x8r.read(&channels[0], &failSafe, &lostFrame)){
    Serial.println("h234 ");
    // write the SBUS packet to an SBUS compatible servo
    for (i=0; i < 8; i++) {
    Serial.print(i);
    Serial.print(" :");
    Serial.print(channels[i]);
    Serial.print(" "); };
    Serial.println();

    x8r.write(&channels[0]);
    }
    }

    I am using Pin0 (RX1) (and also tried RX5) on Teensy4 as input and the SBUS signal from the receiver passes through an inverter circuit. This code and setup works on an Arduino Mega 2560 board, but not on the teensy4. I have tried using 3.3V or 5V, lowering the CPU speed to 24MHz, using #include <I2C_t3.h>. All not working on teensy4. Not sure why it works on Mega 2560 but not on a teensy4. Please help.

  9. #59
    Senior Member brtaylor's Avatar
    Join Date
    Mar 2016
    Location
    Portland, OR
    Posts
    537
    Hi Funwey,

    Have you downloaded the library recently? I only recently edited it to enable the Teensy 4.
    https://github.com/bolderflight/SBUS

    Also:
    1. Don't use the inverter circuit. The Teensy 3.x, LC, and 4.0 read the inverted signal directly.
    2. I2C isn't used for SBUS, it's strictly a Serial library.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •