Reputation: 1002
I am trying to make a simple program which sends 9 bytes of data over a COM port to a microcontroller, then waits for 11 bytes of data from the microcontroller. The entire process has to occur within 500µs, which is feasible at 115200 bauds (edit: sorry, feasible at 500kbauds, but this test is done at 115.2k).
However, I have measured the duration of an iteration (which yields correct results) using QueryPerformanceCounter and the total duration (dominated by reading) varies wildly between 4 and 6ms instead of 1.7ms - even at 500kbauds the duration stays around 4-5ms! How is this possible? How can I remedy to this?
I have tested ALL libraries I could find out there, they all yield similar results (or do not work at all when reading), but here is an example with Boost on MSVC. I am all ears if you have tested anything on your side which works.
PC:
#include "stdafx.h"
#include <iostream>
#include <boost/asio/serial_port.hpp>
#include <boost/asio.hpp>
using namespace std;
int main()
{
try
{
boost::asio::io_service io;
boost::asio::serial_port arduino(io, "COM3");
arduino.set_option(boost::asio::serial_port_base::baud_rate(115200));
LARGE_INTEGER frequency;
QueryPerformanceFrequency(&frequency);
LARGE_INTEGER start;
QueryPerformanceCounter(&start);
//Send first set of duty cycles first
char dc[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
boost::asio::write(arduino, boost::asio::buffer(dc, 9));
char buf[11] = { 0 };
boost::asio::read(arduino, boost::asio::buffer(buf, 11));
for (unsigned int i = 0; i < 11; ++i) {
printf("%d ", buf[i]);
}
LARGE_INTEGER end;
QueryPerformanceCounter(&end);
double interval = static_cast<double>(end.QuadPart - start.QuadPart) / frequency.QuadPart * 1000000; // in seconds
printf("(%f us)\n", interval);
}
catch (boost::system::system_error& e)
{
cout << "Error: " << e.what() << endl;
return 1;
}
return 0;
}
/* Output:
0 1 2 3 4 5 6 7 8 -1 7 (6234.500000 us)
*/
Arduino:
#include <Arduino.h>
#define BAUDRATE 115200
#define N_BYTES_IN 9
#define PERIOD_US 1200
unsigned int ssiDummyVal = 2047;
void setup() {
Serial.begin(BAUDRATE);
while(Serial.available()); //Flush buffer (need to reset the arduino after connection and before transmission of bytes).
pinMode(LED_BUILTIN, OUTPUT); //Dummy output
}
unsigned long t;
void loop() {
t = micros();
while(Serial.available() < N_BYTES_IN); //Wait for duty cycles
//Receive duty cycles
unsigned char dc[N_BYTES_IN];
for(unsigned int i = 0 ; i < N_BYTES_IN ; ++i)
{
dc[i] = Serial.read();
analogWrite(LED_BUILTIN, dc[i]);
}
//Send dummy current values
for(unsigned int i = 0 ; i < N_BYTES_IN ; ++i)
{
unsigned int val = float(analogRead(A0))/1023*255;
Serial.write(i);
}
//Bit-bang SSI interface TODO
//Finally send SSI value as 2 bytes
unsigned char ssiValLSB = ssiDummyVal & 255;
unsigned char ssiValMSB = (ssiDummyVal >> 8) & 255;
Serial.write(ssiValLSB); //LSByte first
Serial.write(ssiValMSB); //MSByte second
unsigned long dt;
//Only for the 10 first samples to avoid clogging the screen
static unsigned int sample = 0;
while((dt = abs(micros()-t)) < PERIOD_US) //Estimate how much time margin we have
{
if(sample < 10) {
//Serial.write(int(float(dt)/PERIOD_US*255)); //Gives the fraction of the period_us used to do the iteration
}
}
sample++;
}
Upvotes: 0
Views: 1090
Reputation: 283803
Your math is wrong.
200 serial symbols (110 out, 90 back, because your 8-N-1 configuration uses 10 timeslices per byte... 1 start, 8 data, 1 stop) at 115200 baud will take over 1.7 milliseconds just for the data transfer. That allows no time for interrupt handling and thread scheduling or for the microcontroller to receive its message and compose a response.
Upvotes: 2