Need some help on creating a RS485 library on NXC

Discussion specific to NXT-G, NXC, NBC, RobotC, Lejos, and more.
afanofosc
Site Admin
Posts: 1256
Joined: 26 Sep 2010, 19:36
Location: Nashville, TN
Contact:

Re: Need some help on creating a RS485 library on NXC

Post by afanofosc »

After fiddling with this all night I am happy to report that I am finally able to send data back and forth between two NXTs at baud rates ranging from 1200 to 921600.

One problem was definitely on the receiving side. Every millisecond the firmware would copy whatever it has already received into the Comm module IOMap HsInBuf so the RS485DataAvailable function - which returned a boolean value - would start returning true. But at slower baud rates it was pretty much guaranteed that you did not yet have all the bytes that the sender was trying to send you. To help fix this problem I changed the HSCheckStatus system call function to return DataAvailable as the number of bytes available. So a user program running on a receiving NXT can wait not just until(RS485DataAvailable()); but instead wait until(RS485DataAvailable() >= N);

All I was ever able to see for myself was that my receiving NXT was not getting all the data at slower baud rates - so I couldn't tell for sure if the problem was on the sending end or on the receiving end or both. Andrew reported seeing evidence on a scope that the sender was not actually sending all the bytes. So based on his feedback there probably was also a problem on the sending side. But as I described above it was not at all clear to me how there could be a problem. What I concluded was that if there was a problem on the sending side it had to be due to the way that the code in c_comm.c always called the function to receive RS485 data even though it had just moments before started to send data out via RS485 and may still be in the middle of transmitting. I am not sure whether it ought to be able to call the receive function while still sending data or not. But I added some code to make sure that the receive function is not called while it is still sending out the data from the last RS485 write operation.

Then to make all this work I had to beef up my sender and receiver programs. I needed to add some handshaking and message length information. The new versions of these sample programs are below.

Code: Select all

// RS-485 sender program

inline void WaitForMessageToBeSent()
{
  while(RS485SendingData())
    Wait(MS_1);
}

task main()
{
  // configure the S4 port as RS485
  UseRS485(); 
  // make sure the RS485 system is turned on
  RS485Enable();
  // initialize the UART to default values
  // low level API function call (allows changing UART settings)
  RS485Uart(HS_BAUD_DEFAULT, HS_MODE_DEFAULT);
//  // hi level API function call
//  RS485Initialize();
  Wait(MS_1); // make sure everything gets turned on okay
  int i;
  byte buffer[];
  while (true) {
    string msg;
    msg = "goofy " + NumToStr(i);
    TextOut(0, LCD_LINE1, msg);
    
    // send the # of bytes (5 bytes)
    byte cnt = ArrayLen(msg);
    SendRS485Number(cnt);
    WaitForMessageToBeSent();

    // wait for ACK from recipient
    until(RS485DataAvailable());
    RS485Read(buffer);

    // now send the message
    SendRS485String(msg);
    WaitForMessageToBeSent();

    // wait for ACK from recipient
    until(RS485DataAvailable());
    RS485Read(buffer);

    i++;
  }
  // disable RS485 (not usually needed)
  RS485Disable();
}

Code: Select all

// RS-485 receiver program
inline void WaitForMessageToBeSent()
{
  while(RS485SendingData())
    Wait(MS_1);
}

task main()
{
  byte mlen;
  string buffer;
  // configure the S4 port as RS485
  UseRS485(); 
  // make sure the RS485 system is turned on
  RS485Enable(); 
//  // initialize the UART to default values
//  RS485Initialize();
  // configure the UART (this is equivalent to RS485Initialize)
  RS485Uart(HS_BAUD_DEFAULT, HS_MODE_DEFAULT);

  Wait(MS_1); // make sure everything is turned on
  byte ACK[] = {1};
  while (true) {
    // wait for a message to arrive.

    // read the number of bytes message
    until(RS485DataAvailable() >= 5);

    // read the number of bytes
    RS485Read(buffer);
    long cnt = 0;
    UnflattenVar(buffer, cnt);

    // send out ACK
    RS485Write(ACK);
    WaitForMessageToBeSent();

    // now wait for the real message
    until(RS485DataAvailable() >= cnt);

    // now read the actual message
    RS485Read(buffer);

    // send out ACK
    RS485Write(ACK);
    WaitForMessageToBeSent();

    // display message
    TextOut(0, LCD_LINE1, buffer);
  }
}
A new test release zip containing just the compiler, IDE, and updated firmware image is up on the BricxCC website: http://bricxcc.sourceforge.net/test_releases/

Please could I get a few volunteers to try out the new firmware from this test release along with the two programs above. You can test non-default baud rates by changing HS_BAUD_DEFAULT to HS_BAUD_1200 or one of 16 other baud rate constants defined in the online NXC help files.

John Hansen
Multi-platform LEGO MINDSTORMS programming
http://bricxcc.sourceforge.net/
milluzaj
Posts: 31
Joined: 28 Sep 2010, 22:15

Re: Need some help on creating a RS485 library on NXC

Post by milluzaj »

The receiver issue is likely part of it. I will dig through that tonight.

I havent tried the NXT against my logic analyzer in a few weeks now, but I will give it another look to see if it is a sender issue.

One potential issue that could arise would be async variable length messages, though this does seem like a positive change.

FYI I noticed this issue in the NXTBee block as I was making it. I was unable to set the NXTBee to a higher frequency. The NXTBee was not receiving all the commands. (I think that is why I thought it was a sender issue.) Like I said I will work on this tonight/tomorrow. I have a busy day with my shuttle come tomorrow, so we will see how productive I will be.
Blog: 08milluz.wordpress.com
LMS Shuttle: facebook.com/lmsshuttle
afanofosc
Site Admin
Posts: 1256
Joined: 26 Sep 2010, 19:36
Location: Nashville, TN
Contact:

Re: Need some help on creating a RS485 library on NXC

Post by afanofosc »

milluzaj wrote: One potential issue that could arise would be async variable length messages, though this does seem like a positive change.
I am not sure I understand what you mean here. I think everything should still work for asynchronous variable length messages. Do you mean without waiting for ACK responses before sending additional messages and/or sending messages without first sending a message length fixed length message first? These should work just fine but receiving them is harder than the approach I used in my sample code. You would need to combine data read across multiple read operations into a single buffer and then divide it up using some sort of embedded message termination character (such as a null).

John Hansen
Multi-platform LEGO MINDSTORMS programming
http://bricxcc.sourceforge.net/
afanofosc
Site Admin
Posts: 1256
Joined: 26 Sep 2010, 19:36
Location: Nashville, TN
Contact:

Re: Need some help on creating a RS485 library on NXC

Post by afanofosc »

I forgot to mention something I noticed early this AM. It looks like the first time you run the receiver sample program after turning on the brick that it does not work correctly. Aborting the program and then running it again seems to make it work fine. So there may be a bug in the firmware related to starting up the RS485 system - or maybe you need to wait a bit longer than 1 ms for the UART receiver to start. I will see if I can figure out is going on there.

John Hansen
Multi-platform LEGO MINDSTORMS programming
http://bricxcc.sourceforge.net/
afanofosc
Site Admin
Posts: 1256
Joined: 26 Sep 2010, 19:36
Location: Nashville, TN
Contact:

Re: Need some help on creating a RS485 library on NXC

Post by afanofosc »

The problem I mentioned above is resolved by waiting after setting the baud rate for about 5 ms.

John Hansen
Multi-platform LEGO MINDSTORMS programming
http://bricxcc.sourceforge.net/
mattallen37
Posts: 1818
Joined: 02 Oct 2010, 02:19
Location: Michigan USA
Contact:

Re: Need some help on creating a RS485 library on NXC

Post by mattallen37 »

mightor wrote:
mattallen37 wrote:Just curious, why would you want low speeds such as 9600? I guess that if you are interfacing with a uC you might want slowish speeds... but anything less than 9600? I have always used 921,600 (except for the occasional test).
Most, if not all, devices other than the NXT use a fall-back speed of 9600. To configure them for higher baud rates, you need to initially be able to speak to them at the lower rates :)

- Xander
Oh, right.

@John, so does that mean all the known issues with low speeds are taken care of, or just a specific issue (only working on second+ run)?
Matt
http://mattallen37.wordpress.com/

I'm all for gun control... that's why I use both hands when shooting ;)
afanofosc
Site Admin
Posts: 1256
Joined: 26 Sep 2010, 19:36
Location: Nashville, TN
Contact:

Re: Need some help on creating a RS485 library on NXC

Post by afanofosc »

Well, now I am annoyed with myself. I stayed up all night working on a firmware problem that did not exist... Frustrating. Oh, well.

I just ran a test with a slightly modified form of the above two RS485 programs with both my NXTs running a version of the 1.31 firmware from October 19, 2010 (test_release20101019.zip) and it worked perfectly at 1200 baud.

Since back then you could not tell how many bytes were available (DataAvailable was a boolean value - either zero or 1) I added brief waits to the Sender program above when it was waiting on the ACK response (1 byte) from the receiver. Also increased the wait after configuring the UART from 1 ms to 5 ms. On the receiving side since the first message is 5 bytes long and the second is at least 7 bytes long ("goofy 1") I arbitrarily increased the miminum wait to 100 ms and then arbitrarily waited an additional 250 ms before trying to read the incoming data. Many different, aka better, approaches could be used with older 1.31 firmware versions to wait long enough or read repeatedly until there is nothing left to read, etc... These alternatives are left as an exercise for the reader. I would love to see what you guys come up with.

Code: Select all

// RS-485 sender program

inline void WaitForMessageToBeSent()
{
  unsigned long tick = CurrentTick();
  while(RS485SendingData())
    Wait(MS_1);
  NumOut(0, LCD_LINE8, CurrentTick()-tick);
}

task main()
{
  // configure the S4 port as RS485
  UseRS485(); 
  // make sure the RS485 system is turned on
  RS485Enable();
  // initialize the UART to default values
  // low level API function call (allows changing UART settings)
  RS485Uart(HS_BAUD_1200, HS_MODE_DEFAULT);
//  // hi level API function call
//  RS485Initialize();
  Wait(MS_5); // make sure everything gets turned on okay
  int i;
  byte buffer[];
  while (true) {
    string msg;
    msg = "goofy " + NumToStr(i);
    TextOut(0, LCD_LINE1, msg);
    
    // send the # of bytes (5 bytes)
    byte cnt = ArrayLen(msg);
    SendRS485Number(cnt);
    WaitForMessageToBeSent();

    // wait for ACK from recipient
    until(RS485DataAvailable()) Wait(5);
    RS485Read(buffer);

    // now send the message
    SendRS485String(msg);
    WaitForMessageToBeSent();

    // wait for ACK from recipient
    until(RS485DataAvailable()) Wait(5);
    RS485Read(buffer);

    i++;
  }
  // disable RS485 (not usually needed)
  RS485Disable();
}

Code: Select all


// RS-485 receiver program
inline void WaitForMessageToBeSent()
{
  unsigned long tick = CurrentTick();
  while(RS485SendingData())
    Wait(MS_1);
  NumOut(0, LCD_LINE8, CurrentTick()-tick);
}

task main()
{
  byte mlen;
  string buffer;
  // configure the S4 port as RS485
  UseRS485(); 
  // make sure the RS485 system is turned on
  RS485Enable(); 
//  // initialize the UART to default values
//  RS485Initialize();
  // configure the UART (this is equivalent to RS485Initialize)
  RS485Uart(HS_BAUD_1200, HS_MODE_DEFAULT);

  Wait(MS_5); // make sure everything is turned on
  byte ACK[] = {1};
  while (true) {
    // wait for a message to arrive.

    // read the number of bytes message
    until(RS485DataAvailable()) Wait(100);
    // now wait a bit more
    Wait(250);

    // read the number of bytes
    RS485Read(buffer);
    long cnt = 0;
    UnflattenVar(buffer, cnt);

    // send out ACK
    RS485Write(ACK);
    WaitForMessageToBeSent();

    // now wait for the real message
    until(RS485DataAvailable()) Wait(100);
    // now wait a bit more
    Wait(250);

    // now read the actual message
    RS485Read(buffer);

    // send out ACK
    RS485Write(ACK);
    WaitForMessageToBeSent();

    // display message
    TextOut(0, LCD_LINE1, buffer);
  }
}
What this test shows is that there was not ever a problem in the firmware with either sending or receiving RS485 at baud rates slower than the default rate of 921600. There was a deficiency in clearly reporting to user programs how much data was available and, similarly, a deficiency with reporting that the data had been sent when it may not have been completely sent at slower baud rates. The output on line 8 from the modified WaitForMessageToBeSent routine is always 1ms with older firmware versions - which is wrong - while with the latest 1.31 version (20110707 0630) the value varies between 28 (for the 5 byte message) and 70 (for "goofy 236"). So with older 1.31 firmwares you could cause problems in a user program by trying to send another message before the previous message had truly been sent if you were using slower baud rates. The more likely problem with older 1.31 firmware versions at slower baud rates, though, was assuming that as soon as DataAvailable was non-zero that you could read the data and get everything that the remote device was trying to send you.

What I will do is back out the unneeded changes and keep the ones that allow you to know how many bytes are available and to properly report that data is still being sent until the transmission is properly completed.

John Hansen
Multi-platform LEGO MINDSTORMS programming
http://bricxcc.sourceforge.net/
ronmcrae
Posts: 33
Joined: 28 Sep 2010, 14:56

Re: Need some help on creating a RS485 library on NXC

Post by ronmcrae »

afanofosc wrote:Well, now I am annoyed with myself. I stayed up all night working on a firmware problem that did not exist... Frustrating. Oh, well.
John Hansen
I had been following this thread with interested, and am annoyed that I didn't chime in a bit earlier. During 2010 I played with some code to implement Modbus communications between two NXT's. Unfortunately I lost interest a bit, so it is a somewhat incomplete project, but I did get as far as passing data from an NXC array (aka registers) back and forth. I ran this at 9600 baud for several hours and never got a report of any missed packets (checksum errors, timeout etc.).

The reason that code works fine is most likely the fact that the NXC program constantly gathers any available characters from the firmware until it sees the Modbus framing character. Only once that character is received does it process the packet, so it can't proceed until it sees a full message at the user program level. I do have an overall message timeout that eventually kicks in, but in normal operation the program can't proceed until it has gathered the entire message so it wouldn't be affected by the firmware prematurely reporting buffer empty conditions.

Ron.
nxtreme
Posts: 246
Joined: 29 Sep 2010, 03:53
Location: 192.168.1.2

Re: Need some help on creating a RS485 library on NXC

Post by nxtreme »

afanofosc wrote:Well, now I am annoyed with myself. I stayed up all night working on a firmware problem that did not exist... Frustrating. Oh, well.
You didn't forget to update to the latest test release and firmware version now, did you? ;)

Thank you very much for working this out! I just purchased some RS485 converter chips and once they arrive (and when I finish some other projects that need finishing...) I'm going to see if I can get my NXT talking to my computer. Since I mainly want to use speeds around 4800 baud, your findings really come in handy. Thanks again!
One King to rule them all, One King to find them,
One King to bring them all and in the darkness bind them
On Earth where Shadows lie.
HaWe
Posts: 2500
Joined: 04 Nov 2014, 19:00

Re: Need some help on creating a RS485 library on NXC

Post by HaWe »

just an unimportant suggestion for further developments:
to my HO it would be very fine to work out a communication protocol for several attached NXTs that either
a) mimicri the BT Mailbox protocol
- or -
b) apply to a common network protocol, such as Aloha or TCP/IP

- just IMHO, just my .5ct^^
Post Reply

Who is online

Users browsing this forum: No registered users and 4 guests