Created Mon, 07 Sep 2015 21:50:10 +0000 by 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.
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! :)
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...?
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! )
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.
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:
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?
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. :)