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

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
    532
    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
    532
    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
    532
    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,034
    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.

Posting Permissions

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