It turns out that SoftwareSerial is not only expectably slow, but also causes the board to freeze spontaneously for some reason.
Since there are 2 UART blocks available in the PIC, lets switch to HardwareSerial. The second UART on the DP32 chip (PIC32MX250F128B) is on the PPS pins for RB14 and RA1. So we only need to move one pin, HC05/RXD from 18/RA4 to 7/RB14:
The updated pin assignment is this:
Usage Pin (Arduino/PIC) Notes
------------------------------------------------------------------
REF 0/RB5
AM2303 1/RB7
BMP180 2/RB8 all I2C devices - not just BMP any more
BMP180 3/RB9 all I2C devices - not just BMP any more
USB+ 4/RB10
USB- 5/RB11
6/RB13
HC05/RXD 7/RB14
8/RB15
9/RA0
HC05/TXD 10/RA1
MEAS1 11/RB0 LED4
12/RB1 LED3
MEAS2 13/RB2 LED2
MEAS3 14/RB3 LED1
CLOCK 15/RA2
16/RA3
HC05/EN 17/RB4
18/RA4
And then we need a software update.
Serial.println() is a blocking call and the hardware FIFO buffer is only 8 bytes deep, so if we send the whole data string at once we will wait until the transfer is complete instead of being able to handle the stream to the USB serial connection. The default rate of the HC05 is pretty slow, but regardless of its' speed, we don't want to block on the FIFO. The solution is as follows:
1. declare a buffer for the current data. If new data is available before this buffer has been transmitted, we skip the new sample
2. write a function that takes characters from the buffer and puts it into any available space in the FIFO, but does not block
3. Call that function frequently
For 1,
#include <CircularBuffer.h>
[...]
CircularBuffer<char> bluetoothBuffer(300); // make some space for hardware accelerated output
[...]
buffer[offset15-1]=0; // terminate message buffer
Serial.println(buffer);
if (0==bluetoothBuffer.available())
{
for (int i=0;i<strlen(buffer);i++)
bluetoothBuffer.write(buffer[i]);
bluetoothBuffer.write('\r');
bluetoothBuffer.write('\n');
}
// update queue
if ((FIFO_SIZE-1)==tail) // check for wrap around
tail = 0; // update tail location
else
tail = tail +1; // update tail location
}
[...]
For 2,
void SendBluetoothData()
{ // direct to hardware FIFO
if (bluetoothBuffer.available())
{
if (U2STAbits.UTXBF == 0)
{
U2TXREG = bluetoothBuffer.read();
}
}
}
this part was quite frustrating to get right. Thanks to Matt at UECIDE.org:
http://www.uecide.org/forum/viewtopic.php?f=13&t=685&sid=884bd83863c9acc2932434a61170895a
For 3,
void convertToAscii( INT64 value,int offset)
// constant time version of string conversion. For speed, not all are considered
// with 15 divisions by 10, and at 10 MHz that is about 30 years of continuous operation
// 64 bits can be done with 19 divisions
{
int i;
SendBluetoothData(); // needs to be called periodically, so I am doing it in this frequently run routine
if (value<0)
{
buffer[0+offset]='-';
value = -value;
}
else
{
buffer[0+offset]='+';
}
for(i=numbersize-2; i>=1;i--)
{
buffer[i+offset] = (value % 10) +'0';
value = value / 10;
}
buffer[numbersize-1+offset]= ' ';
SendBluetoothData(); // needs to be called periodically, so I am doing it in this frequently run routine
}
[...]
void loop()
{
sensorCounter++; // cycle through the different sensors
SendBluetoothData();
if (head != tail) // only send a new data packet if the queue is not empty; probably superfluous since serial.println blocks :/
{
[...]
That works quite well, but I should probably make the data transfer interrupt driven in the future....