Re: Need some help on creating a RS485 library on NXC
Posted: 07 Jul 2011, 12:20
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.
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
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);
}
}
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