chipKIT® Development Platform

Inspired by Arduino™

HardwareSerial reading issues - nothing happens...

Created Mon, 07 Sep 2015 21:50:10 +0000 by rasmadrak


rasmadrak

Mon, 07 Sep 2015 21:50:10 +0000

Hi there,

In the spirit of "two steps forward, one step backward" my serial communication reading has stopped working at some point, and I'm baffled why. I have only transfered data from the Chipkit to this point and noticed when I was about to receive that it didn't work.

  • I am using DSPI and have thus "removed" the interrupt routines in DSPI.cpp as these caused the program to crash (see this old thread: [url]http://chipkit.net/forum/viewtopic.php?f=17&t=1547&p=6800&hilit=hardware+crash+dspi#p6800[/url]).
  • None of the four hardware serial ports can receive data (using different devices). They all work correctly while sending.
  • I am using interrupts for rendering - tried both timer3 and timer5 but it makes no difference on serial com.
  • The built-in (hardware) servo library is experiencing issues as well, can this be related? Or at least a pointer to where the problem can be?

What timers and interrupts could interfere with the hardware serial ports?

Are there any libraries that I can use instead of HardwareSerial, that plays nicely with other interrupt-routines? I have only tried SoftwareSerial so far, but on the very same pins as the hardware serial. It didn't work out... I have only the need for a single receivable port, but need at least two for sending. Speed is preferably 57600 baud (for sending, receiving can be much much lower) but can be lowered in case it must be. I can live with a 100 byte/sec receive-rate...

I have tried to check the pin layout and even source code, but I can't say I'm a lot wiser now... I would very much appreciate any help I can get on the matter! :)


rasmadrak

Mon, 07 Sep 2015 22:05:13 +0000

I haven't tried a very low hardware setting like 9600 yet, since the transmission from the Max32 works great and the reconfiguration of the external device is cumbersome. But I suspect a slower speed would be more resistant to interference and long delays... or would it? Also - Considering sending to the external device works great and that I only ever need to receive data immediately after talking to it - wouldn't it be possible to use a non-interrupt driven method to read back the data, i.e a blocking approach?

Update: I just tried 9600. Same issue, sending works fine but receiving doesn't :( Any point in trying even lower, or is the problem elsewhere...?


rasmadrak

Thu, 10 Sep 2015 10:19:18 +0000

Ok, I found the reason why it's not working to recieve - and I believe it might be a bug. I'm creating an instance of the hardware serial port to avoid using "Serial3.write" etc, like so:

HardwareSerial soundSerial = Serial3;
   //or
HardwareSerial soundSerial = HardwareSerial(Serial3);
  //or even
HardwareSerial soundSerial(Serial3);

This creates a perfectly valid serial object that can write - BUT - not receive!

However -

//PSEUDO CODE
//If I use the Serial3 directly, both sending and receiving works. 
Serial3.begin()
Serial3.write()
Serial3.read()

//It also works when sending on the instanced object and receiving on Serial3.
soundSerial.begin()
soundSerial.write()
Serial3.read()

I've also tried using Serial3.end() to (possibly) free the recieve interrupt routine and be reused for the soundSerial.begin(), but that made no difference. Either this is not supposed to work, and wasn't meant too - or is the constructor somewhat broken in the HardwareSerial class? I believe it's not forwarding the interrupt routine correctly, or something like that.

Any thoughts? :)

(Btw, thanks Majenko for your TimerSerial class. It made me discover the situation described above! )


majenko

Thu, 10 Sep 2015 10:55:32 +0000

It's not broken - it's just the way it works.

When Serial3 is instantiated it grabs the interrupt and all received data goes into the receive buffer inside the Serial3 object.

However, due to the way that the interrupt system receives the ISR to use, and the fact that what wants to handle the interrupt is inside an object, the two cannot work together (the interrupt system expects a "void func()" but would be sent a "void (HardwareSerial *this)") the ISR itself has to be outside the Serial3 object completely.

Thus it looks like this:

#if defined(__PIC32MZXX__)
void __attribute__((nomips16,at_vector(_SER3_VECTOR),interrupt(_SER3_IPL_ISR))) IntSer3Handler(void)
#else
void __attribute__((interrupt(), nomips16)) IntSer3Handler(void)
#endif
{
    Serial3.doSerialInt();
}
#endif

So the interrupt hander for Serial3 can only ever point to the specific Serial3 object.

If you want to "rename" the Serial3 device to something else you would be better off using a reference pointer to it:

HardwareSerial &foo = Serial3;

void setup() {
    foo.begin(115200);
}

void loop() {
    if (foo.available()) {
        foo.println(foo.read());
    }
}

You're still using the Serial3 object (not creating a new one which is what you were doing), so the receive buffer used is the one inside Serial3 - you just call it something else.


rasmadrak

Thu, 10 Sep 2015 11:32:47 +0000

Creating a reference pointer is of course the right way to do it, that makes perfect sense, thanks! It's just that I've seen the serial ports be "renamed" like in my post in many many tutorials and libraries. Somebody got it wrong somewhere and it multiplied, I guess. :)

Working now, and I'm a happy camper. :ugeek:


majenko

Thu, 10 Sep 2015 12:22:26 +0000

It's not something I have ever come across before. Are you sure they aren't (in the libraries, anyway) using reference pointers passed through the parameters of a member function or constructor? Do you have an example where you have seen it?


rasmadrak

Mon, 14 Sep 2015 08:50:44 +0000

Do you have an example where you have seen it?

Can't find a lot of them now (naturally...) but I have seen them. :P One example is in the AdaFruit GPS Library thou:

// If using hardware serial (e.g. Arduino Mega), comment out the
// above SoftwareSerial line, and enable this line instead
// (you can change the Serial number to match your wiring):

//HardwareSerial mySerial = Serial1;

I did start on Arduino and then changed to Chipkit, perhaps the code above is perfectly valid on an Arduino. Anyhow, problem solved with reference pointers and a added bonus of a little more available RAM/flash. :)