C++ libserial skipping 0x09 - c++

I am attempting to read data over serial from a Pixhawk flight controller which communicates via the Mavlink protocol. It sends 17 bytes, the first three being 0xFE, 0x09 followed by a counter that increments every message. I have confirmed this with GtkTerm.
However when I run the following code, 0x09 (the second byte) is always skipped so only 16 bytes of each 17 byte message is received.
Any ideas?
Thanks, James.
LibSerial::SerialStream pixhawkSerial;
pixhawkSerial.Open("/dev/ttyACM0");
pixhawkSerial.SetBaudRate( LibSerial::SerialStreamBuf::BAUD_57600 ) ;
pixhawkSerial.SetCharSize( LibSerial::SerialStreamBuf::CHAR_SIZE_8 );
pixhawkSerial.SetNumOfStopBits(1);
pixhawkSerial.SetParity( LibSerial::SerialStreamBuf::PARITY_NONE ) ;
pixhawkSerial.SetFlowControl( LibSerial::SerialStreamBuf::FLOW_CONTROL_NONE );
char next_byte [100];
int i = 0;
while (i<100){
if( pixhawkSerial.rdbuf()->in_avail() > 0 ){
pixhawkSerial >> next_byte[i];
i++;
}
else cout << "No data" << endl;
}

Wasn't able to get libserial to work, however I gave temios a go and it worked without issues.
Attached is the working code.
int fd;
struct termios oldAtt, newAtt;
fd = open("/dev/ttyACM0", O_RDWR | O_NOCTTY | O_NDELAY);
tcgetattr(fd, &oldAtt);
memset(&newAtt, 0, sizeof(newAtt));
newAtt.c_cflag = CRTSCTS | CS8 | CLOCAL | CREAD;
newAtt.c_iflag = IGNPAR;
newAtt.c_ispeed = B57600;
newAtt.c_oflag = 0;
newAtt.c_ospeed = B57600;
newAtt.c_lflag = 0;
newAtt.c_cc[VTIME] = 0;
newAtt.c_cc[VMIN] = 1;
tcflush(fd, TCIOFLUSH);
tcsetattr(fd, TCSANOW, &newAtt);
char rBuffer;
char next_byte [100];
int i=0;
int dataReceived;
while (i<100) {
dataReceived = read(fd,&rBuffer,1);
if (dataReceived>0){
next_byte[i] = rBuffer;
i++;
}
}
tcsetattr(fd,TCSANOW,&oldAtt);
close(fd);

Related

Why serial port read() return zero instead of data?

GOAL:
Configure a serial port /dev/ttyTHS1 on Linux 18 Jetson NANO with interrupter and non-standard baud rate for Sbus. The funny part is that it worked perfectly until today. The backup had no effect.
PS: the code was combined from several files for testing purposes, so i could make a few mistakes.
#include <iostream>
#include <asm/termios.h>
#include <asm/ioctls.h>
#include <sys/signal.h>
#include <stropts.h>
#include <unistd.h>
using namespace std;
bool Ports::setup_port_Sbus(Info* port)
{
//> check descriptor
if (!isatty(fd)) { throw "File description is NOT a serial port!"; }
//> read fole descriptor config
struct termios2 config = { 0 };
//> for interrupt
struct sigaction saio;
sigset_t mskvar;
sigfillset(&mskvar);
sigprocmask(SIG_SETMASK, &mskvar, NULL);
sigdelset(&mskvar, SIGIO);
saio.sa_handler = signal_io_handler;
saio.sa_flags = 0;
saio.sa_restorer = NULL;
sigaction(SIGIO, &saio, NULL);
if (ioctl(fd, TCGETS2, &config) < 0) { throw "Could not read config of FD!"; }
config.c_cflag |= PARENB; // enable parity
config.c_cflag &= ~PARODD; // even parity
config.c_cflag |= CSTOPB; // enable 2 stop bits
config.c_cflag &= ~CSIZE; // clear character size mask
config.c_cflag |= CS8; // 8 bit characters
config.c_cflag &= ~CRTSCTS; // disable hardware flow control
config.c_cflag |= CREAD; // enable receiver
config.c_cflag |= CLOCAL; // ignore modem lines
config.c_lflag &= ~ICANON; // receive characters as they come in
config.c_lflag &= ~ECHO; // do not echo
config.c_lflag &= ~ISIG; // do not generate signals
config.c_lflag &= ~IEXTEN; // disable implementation-defined processing
config.c_iflag &= ~(IXON | IXOFF | IXANY); // disable XON/XOFF flow control
config.c_iflag |= IGNBRK; // ignore BREAK condition
config.c_iflag |= INPCK; // enable parity checking
config.c_iflag |= IGNPAR; // ignore framing and parity errors
config.c_iflag &= ~ISTRIP; // do not strip off 8th bit
config.c_iflag &= ~INLCR; // do not translate NL to CR
config.c_iflag &= ~ICRNL; // do not translate CR to NL
config.c_iflag &= ~IGNCR; // do not ignore CR
config.c_oflag &= ~OPOST; // disable implementation-defined processing
config.c_oflag &= ~ONLCR; // do not map NL to CR-NL
config.c_oflag &= ~OCRNL; // do not map CR to NL
config.c_oflag &= ~(ONOCR | ONLRET); // output CR like a normal person
config.c_oflag &= ~OFILL; // no fill characters
// Apply baudrate
speed_t br = 100000;
config.c_ispeed = br;
config.c_ospeed = br;
config.c_cc[VMIN] = 0;
config.c_cc[VTIME] = 0;
//> Finally, apply the configuration
if (ioctl(fd, TCSETS2, &config) < 0) { throw "Could not set configuration of fd!"; }
// Done!
return true;
}
void port_init(){
const char* _name = "/dev/ttyTHS1";
int fd = -1;
fd = open(_name, O_RDWR | O_NOCTTY );
if (fd < 0) { throw "File is not open!"; }
else{
fcntl(fd, F_SETFL, O_NONBLOCK|O_ASYNC);
}
bool setup = setup_port_Sbus(fd);
if (!setup) { throw "Could not configure port"; }
if (fd <= 0) { throw "Connection attempt to port failed, exiting"; }
}
struct Sbus_data{
bool lost_frame;
int failsafe;
bool ch17;
bool ch18;
static int8_t SBUS_NUM_CH = 16;
int last_ch[SBUS_NUM_CH] = {};
int ch[SBUS_NUM_CH] = {};
};
int main(){
try{
port_init();
}
catch(const char* err){
cout << "ERR: " << err << endl;
}
uint8_t byte;
uint8_t sb_buf[SBUS_PACKET_LEN] = {};
const int8_t SBUS_PACKET_LEN = 25;
const int8_t SBUS_NUM_SBUS_CH = 16;
const uint8_t SBUS_HEADER = 0x0F;
const uint8_t SBUS_FOOTER = 0x00;
const uint8_t SBUS_FOOTER2 = 0x04;
const uint8_t SBUS_CH17_MASK = 0x01;
const uint8_t SBUS_CH18_MASK = 0x02;
const uint8_t SBUS_LOST_FRAME_MASK = 0x04;
const uint8_t SBUS_FAILSAFE_MASK = 0x08;
Sbus_data sb_data;
int sb_state = 0;
do{
count_read_symb = read(port->file_descriptor, &byte, 1);
if(count_read_symb <= 0)
{
cout << "byte: " << byte << " | errno: "<< errno << endl;
continue;
}
//> wrong start
if(sb_state == 0 && byte != SBUS_HEADER)
{
continue;
}
sb_buf[sb_state++] = byte;
//> index done
if(sb_state == SBUS_PACKET_LEN)
{
sb_state = 0;
if(sb_buf[24] != SBUS_FOOTER)
{
continue;
}
sb_data.ch[0] = ((sb_buf[1] |sb_buf[2]<<8) & 0x07FF);
sb_data.ch[1] = ((sb_buf[2]>>3 |sb_buf[3]<<5) & 0x07FF);
sb_data.ch[2] = ((sb_buf[3]>>6 |sb_buf[4]<<2 |sb_buf[5]<<10) & 0x07FF);
sb_data.ch[3] = ((sb_buf[5]>>1 |sb_buf[6]<<7) & 0x07FF);
sb_data.ch[4] = ((sb_buf[6]>>4 |sb_buf[7]<<4) & 0x07FF);
sb_data.ch[5] = ((sb_buf[7]>>7 |sb_buf[8]<<1 |sb_buf[9]<<9) & 0x07FF);
sb_data.ch[6] = ((sb_buf[9]>>2 |sb_buf[10]<<6) & 0x07FF);
sb_data.ch[7] = ((sb_buf[10]>>5|sb_buf[11]<<3) & 0x07FF);
sb_data.ch[8] = ((sb_buf[12] |sb_buf[13]<<8) & 0x07FF);
sb_data.ch[9] = ((sb_buf[13]>>3|sb_buf[14]<<5) & 0x07FF);
sb_data.ch[10] = ((sb_buf[14]>>6|sb_buf[15]<<2|sb_buf[16]<<10) & 0x07FF);
sb_data.ch[11] = ((sb_buf[16]>>1|sb_buf[17]<<7) & 0x07FF);
sb_data.ch[12] = ((sb_buf[17]>>4|sb_buf[18]<<4) & 0x07FF);
sb_data.ch[13] = ((sb_buf[18]>>7|sb_buf[19]<<1|sb_buf[20]<<9) & 0x07FF);
sb_data.ch[14] = ((sb_buf[20]>>2|sb_buf[21]<<6) & 0x07FF);
sb_data.ch[15] = ((sb_buf[21]>>5|sb_buf[22]<<3) & 0x07FF);
((sb_buf[23]) & 0x0001) ? sb_data.ch[16] = 2047: sb_data.ch[16] = 0;
((sb_buf[23] >> 1) & 0x0001) ? sb_data.ch[17] = 2047: sb_data.ch[17] = 0;
if ((sb_buf[23] >> 3) & 0x0001) { sb_data.failsafe = 1; }
else { sb_data.failsafe = 0; }
cout << "DONE!" << endl;
}
}
while(count_read_symb > 0);
}
I checked ports buffer with sudo sh 'cat < /dev/ttyTHS1' and Putty, and all data was there but the read() returns zero.
Port is in dialout group to which i have access, it is configured for -rw-, and no error in port initialization stage was caught.
Moreover, i have /dev/ttyUSB1 and ../ttyUSB0 with slightely different flags (no parity/ br=115200/ 1 stop bit) for TTL but they are working perfectly.
Thanks to #SKi, I checked the flags.
The solution:
// Apply baudrate
speed_t br = 100000;
config.c_ispeed = br;
config.c_ospeed = br;
config.c_cflag &= ~CBAUD; // !!!!!
config.c_cflag |= BOTHER; // !!!!!
config.c_cc[VMIN] = 0;
config.c_cc[VTIME] = 0;
For some reason, the code used to work without those 2 lines. They are required now.

Sendng CAN BCM Cyclic Message Has No Frame Contents

I need to transmit 1200 identical CAN messages, with 5ms between each message. This is to arm a motor to start. Because of the timing required, I switched from
sockfd = socket(PF_CAN, SOCK_RAW, CAN_RAW);
to
sockfd = socket(PF_CAN, SOCK_DGRAM, CAN_BCM);
Using a CAN sniffer, the 1200 messages are being sent at 5ms intervals. The data field has the correct data that I specified, but the 32-bit CAN_ID field is 0x00000000 instead of 0x00000201.
The code I wrote to send a TX_SETUP is shown below.
// these are placed here for testing
unsigned char priority = 0;
unsigned char srcaddr = 0;
unsigned char destaddr = 2;
unsigned objaddr = ESC::enumPWM;
struct {
struct bcm_msg_head msg_head;
struct can_frame frame[4];
} txmsg;
txmsg.msg_head.opcode = TX_SETUP;
txmsg.msg_head.nframes = 1;
// set flags first, set EFF for extended frame, no
// RTR, no ERR.
txmsg.frame[0].can_id = CAN_EFF_FLAG;
txmsg.frame[0].can_id |= ((0x1F & priority) << 24);
txmsg.frame[0].can_id |= (srcaddr << 16);
txmsg.frame[0].can_id |= (destaddr << 8);
txmsg.frame[0].can_id |= objaddr;
txmsg.msg_head.flags = SETTIMER | STARTTIMER | TX_CP_CAN_ID;
txmsg.msg_head.count = 1200;
txmsg.msg_head.ival1.tv_sec = 0;
txmsg.msg_head.ival1.tv_usec = 5000;
txmsg.msg_head.ival2.tv_sec = 0;
txmsg.msg_head.ival2.tv_usec = 0;
// configure the data to send
txmsg.frame[0].can_dlc = 2;
txmsg.frame[0].data[0] = 0x04;
txmsg.frame[0].data[1] = 0x4C;
txmsg.frame[0].data[2] = 0;
txmsg.frame[0].data[3] = 0;
txmsg.frame[0].data[4] = 0;
txmsg.frame[0].data[5] = 0;
txmsg.frame[0].data[6] = 0;
txmsg.frame[0].data[7] = 0;
int err = write(can->sockfd, &txmsg, sizeof(txmsg));
Any idea why the message is transmitting incorrectly?

Making a blocking read() from UART on Linux

I am trying to write to the serial port (sending a handshake) and then subsequently I try to read the serial port. When reading the port, I notice I am getting garbage reads (even if there is nothing connected to the RX line) or part of the write string I am sending to the TX line. Why am I getting part of that string? I am not supposed to be seeing that!
Here is my code:
class UART{
public:
UART();
~UART();
int open_port();
int configure_port(); // All port configurations such as parity, baud rate, hardware flow, etc
int uart_write(std::string); // Send characters to the serial port
int uart_read(std::string*, int); // Read from serial port
// Close
void close_port();
private:
int fd;
uart.cpp:
UART::UART(){
open_port();
configure_port();
}
UART::~UART(){
close_port();
}
int UART::open_port()
{
// Open ttys4
fd = open("/dev/ttyS4", O_RDWR | O_NOCTTY | O_NDELAY);
if(fd == -1) // if open is unsucessful
{
//perror("open_port: Unable to open /dev/ttyS0 - ");
printf("open_port: Unable to open /dev/ttyS4. \n");
}
else
{
fcntl(fd, F_SETFL, 0);
printf("port is open.\n");
}
return(fd);
} //open_port
// configure the port
int UART::configure_port()
{
struct termios port_settings; // structure to store the port settings in
cfsetispeed(&port_settings, B9600); // set baud rates
cfsetospeed(&port_settings, B9600);
port_settings.c_cflag &= ~PARENB; // set no parity, stop bits, data bits
port_settings.c_cflag &= ~CSTOPB;
port_settings.c_cflag &= ~CSIZE;
port_settings.c_cflag |= CS8;
port_settings.c_cflag |= CREAD | CLOCAL; // turn on READ & ignore ctrl lines
port_settings.c_cc[VTIME] = 10; // n seconds read timeout
port_settings.c_iflag &= ~(IXON | IXOFF | IXANY); // turn off s/w flow ctrl
port_settings.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); // make raw
port_settings.c_oflag &= ~OPOST; // make raw
tcsetattr(fd, TCSANOW, &port_settings); // apply the settings to the port
return(fd);
}
// Write to serial port
int UART::uart_write(string data)
{
int buffer_size = data.length();
char * data_write = new char[data.length()+1];
strcpy (data_write, data.c_str());
int n = write(fd, data_write, buffer_size); //Send data
usleep(1000);
tcdrain(fd);
printf("Wrote the bytes. \n");
/* Error Handling */
int status = 0;
if (n < 0)
{
cout << "Error Writing: " << strerror(errno) << endl;
status = 0;
}else{
status = 1;
}
delete[] data_write;
return status;
}
int UART::uart_read(string *data,int buffer_size)
{
// Buffer
char * buf = new char[buffer_size+1];
usleep(1000);
tcflush(fd, TCIOFLUSH);
// Read
/*I NEED THIS PART TO BE BLOCKING*/
int n = read( fd, buf , buffer_size );
/* Error Handling */
if (n < 0)
{
cout << "Error reading: " << strerror(errno) << endl;
}
// String received
string data_received(buf,buffer_size);
*data = data_received;
delete[] buf;
cout << "data_received: " << *data << endl;
// Did we get blank data?
if( data_received.length() == 0 )
return 0;
else
return 1;
}
main
int main()
{
UART uart_connection;
string handshake = "handshake!";
uart_connection.uart_write(handshake);
string data;
string *data_ptr = &data;
uart_connection.uart_read(data_ptr );
cout << data << endl;
}
When printing the received data, I usually get part of the sent data. So on cout << data << endl I am getting the following:
dshake
along with some weird characters after it, or if I don't write anything to the serial port then I just get random characters.
Specifically I want int n = read( fd, buf , buffer_size ); to be a blocking function, which apparently it's not happening... It just goes through and it returns a bunch of weird characters or it reads part of the string sent with write.
Please note that the code works and when I do actually send something to the RX line, I can read it just fine. However, I am finding it difficult to send large chunks of data without getting bad reads.
I believe this could all be solved if I could make the read() function a blocking function, and avoid it reading those weird characters.
Read is always allowed to read less than what you asked for. To make it "block" until you have read enough characters, you need to wrap it in a loop and call it until you've read however many bytes you wanted.
In your code, n is the number of bytes that were read successfully. You only ever check that it is non-negative.
The loop would probably look like this:
size_t read_count = 0;
while (read_count < buffer_size)
{
ssize_t read_result = read(fd, buf + read_count, buffer_size - read_count);
if (read_result < 0)
{
cout << "Error reading: " << strerror(errno) << endl;
break;
}
read_count += read_result;
}
Note that generally speaking, read is a low-level interface with lots of easy-to-miss subtleties. For instance, on error, it's worth checking for EINTR and maybe a few others.
Off the top of my head, FILE* functions don't have these issues, and you may be able to use fdopen and fread to consistently get what you want.
Although it appears that you haven't had that problem yet, write has the same set of issues. It is also allowed to write fewer bytes than you gave it, and it can be interrupted too. However, this rarely happens with small writes.

serial communication with arm microcontroller

I am trying to send data from the arm cortrx m4 microcontroller to pc through usb. There is a program written in C++ language in codeblocks ide. Basically the program sets the serial communication settings and read data using ReadFile function.
The problem is I am getting garbage values at the output even if the baud rate in pc proogram and microcontroller is same.
How can I solve this problem?
The pc program is shown below.
#include <Windows.h>
#include <stdio.h>
int main(void)
{
HANDLE hComm; // Handle to the Serial port
char ComPortName[] = "\\\\.\\COM51"; // Name of the Serial port to be opened,
BOOL Status; // Status of the various operations
DWORD dwEventMask; // Event mask to trigger
char TempChar; // Temperory Character
char SerialBuffer[26]; // Buffer Containing Rxed Data
DWORD NoBytesRead; // Bytes read by ReadFile()
int i = 0;
printf("\n\n +==========================================+");
printf("\n | Serial Port Reception (Win32 API) |");
printf("\n +==========================================+\n");
/*---------------------------------- Opening the Serial Port -----------*/
hComm = CreateFile( ComPortName, // Name of the Port to be Opened
GENERIC_READ | GENERIC_WRITE, // Read/Write Access
0, // No Sharing
NULL, // No Security
OPEN_EXISTING, // Open existing port only
0, // Non Overlapped I/O
NULL); // Null for Comm Devices
if (hComm == INVALID_HANDLE_VALUE)
printf("\n Error! - Port %s can't be opened\n", ComPortName);
else
printf("\n Port %s Opened\n ", ComPortName);
DCB dcbSerialParams = { 0 }; // Initializing DCB structure
dcbSerialParams.DCBlength = sizeof(dcbSerialParams);
Status = GetCommState(hComm, &dcbSerialParams); //retreives the current settings
if (Status == FALSE)
printf("\n Error! in GetCommState()");
dcbSerialParams.BaudRate = 115200; // Setting BaudRate = 115200
dcbSerialParams.ByteSize = 8; // Setting ByteSize = 8
dcbSerialParams.StopBits = ONE5STOPBITS; // Setting StopBits = 1
dcbSerialParams.Parity = NOPARITY; // Setting Parity = None
Status = SetCommState(hComm, &dcbSerialParams); //Configuring the port according to settings in DCB
if (Status == FALSE)
{
printf("\n Error! in Setting DCB Structure");
}
else //If Successfull display the contents of the DCB Structure
{
printf("\n\n Setting DCB Structure Successfull\n");
printf("\n Baudrate = %ld", dcbSerialParams.BaudRate);
printf("\n ByteSize = %d", dcbSerialParams.ByteSize);
printf("\n StopBits = %d", dcbSerialParams.StopBits);
printf("\n Parity = %d", dcbSerialParams.Parity);
}
//----------------- Setting Timeouts ----------------------------
COMMTIMEOUTS timeouts = { 0 };
timeouts.ReadIntervalTimeout = 50;
timeouts.ReadTotalTimeoutConstant = 50;
timeouts.ReadTotalTimeoutMultiplier = 10;
timeouts.WriteTotalTimeoutConstant = 50;
timeouts.WriteTotalTimeoutMultiplier = 10;
if (SetCommTimeouts(hComm, &timeouts) == FALSE)
printf("\n\n Error! in Setting Time Outs");
else
printf("\n\n Setting Serial Port Timeouts Successfull");
//-------------- Setting Receive Mask -------------------------------
if (!SetCommMask(hComm, EV_RXCHAR))
printf("\n\n Error! in Setting CommMask"); // Error setting communications event mask
else
printf("\n\n Setting CommMask successfull");
i = 0;
printf("\n\n Waiting for Data Reception");
if (WaitCommEvent(hComm, &dwEventMask, NULL))
{
printf("\n\n Characters Received\n");
do
{
if (ReadFile(hComm, &TempChar, 1, &NoBytesRead, NULL))
{
// A byte has been read; process it.
SerialBuffer[i] = TempChar;
//printf("\n%c\n", TempChar);
if(TempChar == 's')
printf("\ndone\n");
i++;
}
else
{
// An error occurred in the ReadFile call.
break;
}
} while (NoBytesRead);
}
int j =0;
for (j = 0; j < i-1; j++) // j < i-1 to remove the dupliated last character
printf("%c", SerialBuffer[j]);
CloseHandle(hComm);//Closing the Serial Port
printf("\n +==========================================+\n");
}
Here image showing the garbage value printed when the char s is continuosly sent on the port.
The microcontroller code goes below.
#include "PLL.h"
#include "UART.h"
#define GPIO_PORTF_DATA_R (*((volatile unsigned long *)0x400253FC))
#define GPIO_PORTF_DIR_R (*((volatile unsigned long *)0x40025400))
#define GPIO_PORTF_AFSEL_R (*((volatile unsigned long *)0x40025420))
#define GPIO_PORTF_PUR_R (*((volatile unsigned long *)0x40025510))
#define GPIO_PORTF_DEN_R (*((volatile unsigned long *)0x4002551C))
#define GPIO_PORTF_LOCK_R (*((volatile unsigned long *)0x40025520))
#define GPIO_PORTF_CR_R (*((volatile unsigned long *)0x40025524))
#define GPIO_PORTF_AMSEL_R (*((volatile unsigned long *)0x40025528))
#define GPIO_PORTF_PCTL_R (*((volatile unsigned long *)0x4002552C))
#define SYSCTL_RCGC2_R (*((volatile unsigned long *)0x400FE108))
unsigned long In; // input from PF4
// time delay
void delay(int value)
{
while(value){
value--;}
}
//debug code
int main(void)
{
unsigned char i;
char string[20]; // global to assist in debugging
unsigned long n;
unsigned char c;
char text[10] = "Hello!";
unsigned long count;
SYSCTL_RCGC2_R |= 0x00000020; // 1) F clock
//delay = SYSCTL_RCGC2_R; // delay
GPIO_PORTF_LOCK_R = 0x4C4F434B; // 2) unlock PortF PF0
GPIO_PORTF_CR_R = 0x1F; // allow changes to PF4-0
GPIO_PORTF_AMSEL_R = 0x00; // 3) disable analog function
GPIO_PORTF_PCTL_R = 0x00000000; // 4) GPIO clear bit PCTL
GPIO_PORTF_DIR_R = 0x0E; // 5) PF4,PF0 input, PF3,PF2,PF1 output
GPIO_PORTF_AFSEL_R = 0x00; // 6) no alternate function
GPIO_PORTF_PUR_R = 0x11; // enable pullup resistors on PF4,PF0
GPIO_PORTF_DEN_R = 0x1F; // 7) enable digital pins PF4-PF0
PLL_Init();
UART_Init(); // initialize UART
n = 0;
while(n < 10)
{
UART_OutChar('s');
delay(10000);
n++;
}
}
UART_OutChar('s');
delay(10000);
This code is not correct. I suspect you keep overwriting the UART tx buffer over and over, long before the UART is given a chance to send anything at all.
First of all, you can't write the delay function like that. The compiler is free to optimize it all away, as it can't spot any side-effects. Generally, you should away "burn-away time" loops as poor man's delays, but if you for some reason must use them, they have to be written like this:
void delay(int value)
{
for(volatile int i=0; i<value; i++)
{}
}
The volatile keyword prevents the compiler from optimizing away the whole function.
The correct way to do this though, is not to use such blunt delays at all, but instead watch the transmitter busy flag of your UART hardware. It is found in the UART status register, whatever that one is called for your specific microcontroller.
Pseudo code:
n = 0;
while(n < 10)
{
if((UART_SR & TX_BUSY) == 0)
{
UART_OutChar('s');
n++;
}
/* can do other things here in the meantime */
}

Wrong data transmission in serial communication between Arduino and Raspberry

I'm trying to sendo datas from Arduino Uno to RaspberryPi 3B. I need to send 14 int (max value: 6000) from Arduino as soon as Raspberry ask for them. Each one of this 14 number came from ad ADC (SPI communication).
ARDUINO SIDE
#include "SPI.h"
byte incomingByte = 0; // for incoming serial data
const int N_SENSORI=14;
const int DATAOUT = 11;
const int DATAIN = 12;
const int SPICLOCK = 13;
const int SLAVESELECT = 10;
//===============SPI COMMUNICATION================
short write_read_spi16(short what) {
digitalWrite(SS, LOW);
short res = SPI.transfer16(what);
digitalWrite(SS, HIGH);
return res;
}
//===============CONVERT INT IN BYTE AND SEND IT================
void longInt2Byte( int x){
unsigned char buf[sizeof( int)];
memcpy(buf,&x,sizeof(int));
Serial.write(buf,sizeof(buf));
}
//=======================================
void setup() {
Serial.begin(115200);
SPI.begin();
pinMode(DATAOUT, OUTPUT);
pinMode(DATAIN, INPUT);
pinMode(SPICLOCK,OUTPUT);
pinMode(SLAVESELECT,OUTPUT);
}
void loop() {
if (Serial.available() > 0) {
incomingByte= Serial.read();
if (incomingByte=='E') {
write_read_spi16(0b1000001101110000); //THIS IS FOR THE ADC COMMUNICATION
for (int i = 1; i<N_SENSORI+1; i++) { //DONE 14 TIMES.
short s = write_read_spi16(0b1000001101110000 | (i<<10));
int Data = s&0xFFF;
longInt2Byte(Data);
}
}
}}
// C++ SIDE
void stimulationController::SetupDario(){
cout<<"Dentro al setupDario"<<endl<<flush;
buffer=new char [1000];
const char* _portNameSensorsDario="/dev/ttyACM1";
//SERIAL PORT FOR HAND SENSORS
struct termios options;
SerialHandleSensors=open(_portNameSensorsDario, O_RDWR | O_NOCTTY | O_NDELAY); //SerialHandleSensors=open(_portNameSensors, O_RDWR | O_NOCTTY | O_NDELAY); non blocking
if (SerialHandleSensors == -1 )
{
cout<<endl<<"......ERROR: Unable to open: "<<_portNameSensorsDario<<endl;
return;
}
else
{
fcntl(SerialHandleSensors, F_SETFL,0);
cout<<"......OPENED PORT: Succesfully opened: "<<_portNameSensorsDario<<endl;
}
//GET THE OPTIONS, MODIFY AND SET
tcgetattr(SerialHandleSensors,&options);
cfsetispeed(&options,B115200); //BAUD RATE IN
cfsetospeed(&options,B115200); //BAUD RATE OUT
// options.c_lflag |= (ICANON | ECHO | ECHOE);
options.c_cflag |= (CLOCAL | CREAD);
options.c_cflag &= ~PARENB;
options.c_cflag |= CSTOPB;
options.c_cflag &= ~CSIZE;
options.c_cflag |= CS8;
tcsetattr(SerialHandleSensors,TCSANOW,&options);
usleep(3000000);
cout<<"Fine Setup"<<endl<<flush;
}
int stimulationController::Dario( )
{
{
cout<<" NUOVA FUNZIONE"<<endl;
unsigned char bytes[4];
bytes[0]=0x45; // 'E'
int tempWrite=write(SerialHandleSensors,bytes,1);
if(tempWrite==-1)
{
cout<<"......ERROR: PROBLEM WRITING TO ROBOTIC HAND"<<endl;
failure=true;
return 0;
}
int value=0;
int tempRead=read(SerialHandleSensors,buffer,28);
if(tempRead==-1)
{
cout<<"......ERROR: PROBLEM READING FROM ROBOTIC HAND"<<endl;
failure=true;
return 0;
}
int j=0;
for( int i=0; i<28; i=i+2){
value= buffer[i] | ((int)buffer[i+1]<<8);
//ensorDataFoot.push_back(value); //Aggiunge un elemento
j=j+1;
cout<<"Dato "<<j <<"vale: "<<value<<endl<<flush;
}
return value;
}
}
The problem is that or the raspberry side some time it prints the right values, some time (the most of the times, actually) it doesn't. Data seems to be repeated or (2500 insted of 2000 for example).
I can't figure it out the problem.Could it be a matter of timing between the request of sending data and the reading? if so, there is a way to get rid of it?
I've added a do-while cycle in order to be sure that all the 28 bytes are read
int TotByte=28;
int ByteRead=0;
int TempRead=0;
do{ TempRead= read(SerialHandleSensors, buffer, (TotByte-ReadByte));
ReadByte= ReadByte+TempRead;
cout<<"ReadByte is: "<<ReadByte<<endl<<flush;
}while(ByteRead<TotByte);
Output:
ReadByte is: 5
ReadByte is: 15
ReadByte is: 25
and then it stay like that without doing anything
(Posted answer on behalf of the OP):
I figured it out; the problem were the settings of the serial port. For future reference, here is the working version.
bufferTemp=new char [1000];
bufferDEF = new char[1000];
const char* _portNameSensorsBT="/dev/rfcomm0";
struct termios options;
SerialHandleSensorsFoot=open(_portNameSensorsBT, O_RDWR ); //SerialHandleSensors=open(_portNameSensors, O_RDWR | O_NOCTTY | O_NDELAY); non blocking
if (SerialHandleSensorsFoot == -1 )
{
cout<<endl<<"......ERROR: Unable to open: "<<_portNameSensorsBT<<endl;
return 0;
}
else
{
fcntl(SerialHandleSensorsFoot, F_SETFL,0);
cout<<"......OPENED PORT: Succesfully opened: "<<_portNameSensorsBT<<endl;
}
//GET THE OPTIONS, MODIFY AND SET
tcgetattr(SerialHandleSensorsFoot,&options);
cfsetispeed(&options,B115200); //BAUD RATE IN
cfsetospeed(&options,B115200); //BAUD RATE OUT
// options.c_lflag |= (ICANON | ECHO | ECHOE);
options.c_iflag = IGNBRK | IGNPAR;
options.c_oflag = 0;
options.c_lflag = 0;
options.c_cflag |= (CLOCAL | CREAD);
options.c_cflag &= ~PARENB;
options.c_cflag |= CSTOPB;
options.c_cflag &= ~CSIZE;
options.c_cflag |= CS8;
tcsetattr(SerialHandleSensorsFoot,TCSAFLUSH,&options);
usleep(5000000);
with these setting I'm able to communicate with bluetooth even though there might be some velocity problem.