User avatar
Gert van Loo
Posts: 2486
Joined: Tue Aug 02, 2011 7:27 am
Contact: Website

write in C to uart only outputs 16 bytes? [solved]

Wed Aug 06, 2014 8:25 pm

write(uart_file_pnt,data,bytes) (bytes=132)
only outputs 16 bytes. Yes, the uart_file_pnt is from a previously correctly opened /dev/ttyAMA0
yes, the data output is what I expect but only the first 16 bytes come out. (I have scope on the line)
When I send a big file to the device from the command prompt that works.
So this is OK: cat bigfile >/dev/ttyAMA0
In the end I DID get my data out but I have to do a loop where I send max 16 bytes and wait in between.
That suggest it is not my code...
My code now looks like below (There may be typos but you should get the idea)

Code: Select all

send_uart(void *data,int bytes)
{ int b;
  while (bytes)
  { if (bytes>=16)
      b=16;
    else
      b = bytes;
    bytes -= b;
   write(uart0_filepnt,data,b);
   // Flush did not help
   usleep(100000); // wait 0.1 seconds
   data = (void *)((char *)data+b);
  } // while have bytes 
} // write_uart 

User avatar
PeterO
Posts: 5159
Joined: Sun Jul 22, 2012 4:14 pm

Re: write in C to uart only outputs 16 bytes ?

Wed Aug 06, 2014 8:30 pm

What is the return value from write ?
And if it is -1 what is the value of errno ?
PeterO
Discoverer of the PI2 XENON DEATH FLASH!
Interests: C,Python,PIC,Electronics,Ham Radio (G0DZB),1960s British Computers.
"The primary requirement (as we've always seen in your examples) is that the code is readable. " Dougie Lawson

User avatar
Gert van Loo
Posts: 2486
Joined: Tue Aug 02, 2011 7:27 am
Contact: Website

Re: write in C to uart only outputs 16 bytes ?

Wed Aug 06, 2014 8:31 pm

I check if it is NOT -1
I did not check for other values.
Humm, maybe it does return 16.
I have to try that.

Yep! it returns 16.
So my error is that I ignored the return value.

User avatar
PeterO
Posts: 5159
Joined: Sun Jul 22, 2012 4:14 pm

Re: write in C to uart only outputs 16 bytes ?

Wed Aug 06, 2014 8:42 pm

Gert van Loo wrote:I check if it is NOT -1
I did not check for other values.
Humm, maybe it does return 16.
I have to try that.

Yep! it returns 16.
So my error is that I ignored the return value.
Interesting, because the little bit of test code I just wrote here returns 132 :o Which flags did you pass to the open call ?
PeterO
Discoverer of the PI2 XENON DEATH FLASH!
Interests: C,Python,PIC,Electronics,Ham Radio (G0DZB),1960s British Computers.
"The primary requirement (as we've always seen in your examples) is that the code is readable. " Dougie Lawson

User avatar
Gert van Loo
Posts: 2486
Joined: Tue Aug 02, 2011 7:27 am
Contact: Website

Re: write in C to uart only outputs 16 bytes ?

Wed Aug 06, 2014 8:51 pm

c_cflag = B57600 | CS8 | CLOCAL | CREAD ;
c_iflag = IGNPAR;
c_oflag = 0;
c_lflag = 0;

Post edit: my file is a .cpp file as I am linking to QT4.

User avatar
Gert van Loo
Posts: 2486
Joined: Tue Aug 02, 2011 7:27 am
Contact: Website

Re: write in C to uart only outputs 16 bytes ?

Wed Aug 06, 2014 8:55 pm

If I keep pumping in bytes with no delay it looses bytes.
16, then 8 then nothing. I suspect the 8 depends on how much printf I have between.

User avatar
PeterO
Posts: 5159
Joined: Sun Jul 22, 2012 4:14 pm

Re: write in C to uart only outputs 16 bytes ?

Wed Aug 06, 2014 8:56 pm

Those are to tcsetattr ?
PeterO
Discoverer of the PI2 XENON DEATH FLASH!
Interests: C,Python,PIC,Electronics,Ham Radio (G0DZB),1960s British Computers.
"The primary requirement (as we've always seen in your examples) is that the code is readable. " Dougie Lawson

User avatar
PeterO
Posts: 5159
Joined: Sun Jul 22, 2012 4:14 pm

Re: write in C to uart only outputs 16 bytes ?

Wed Aug 06, 2014 9:04 pm

I guess you are repeatedly calling write ? I just tried that , First 30 writes return 132, then......
n= 19 loops=31
n= 8 loops=32
n= 16 loops=33
n= 8 loops=34
n= 8 loops=35
n= 16 loops=36
n= 8 loops=37
n= 16 loops=38
n= 8 loops=39
n= 8 loops=40
n= 8 loops=41
n= 16 loops=42
n= 16 loops=43
n= 16 loops=44
n= 16 loops=45
n= -1 loops=46
n= -1 loops=47
n= -1 loops=48
n= -1 loops=49
n= -1 loops=50

31x132 = 4092
If I write 80 bytes at a time it works for first 50 times... 50 * 80 = 4000, so it looks l ike there is a 4096 byte buffer some where !
PeterO
Discoverer of the PI2 XENON DEATH FLASH!
Interests: C,Python,PIC,Electronics,Ham Radio (G0DZB),1960s British Computers.
"The primary requirement (as we've always seen in your examples) is that the code is readable. " Dougie Lawson

User avatar
Gert van Loo
Posts: 2486
Joined: Tue Aug 02, 2011 7:27 am
Contact: Website

Re: write in C to uart only outputs 16 bytes ?

Wed Aug 06, 2014 9:06 pm

Yes,
I just checked my rasbian version: 3.6.11+ (Aug 2013)
Seems this is a very old version.
My SD-card failed and I randomly grabbed another I had laying around.
Time for an upgrade!

But first time for bed. It is late here.

User avatar
Gert van Loo
Posts: 2486
Joined: Tue Aug 02, 2011 7:27 am
Contact: Website

Re: write in C to uart only outputs 16 bytes ?

Mon Aug 11, 2014 7:31 pm

I have given up on trying to solve this.
I can't find anything wrong with what I am doing but the Pi keeps outputting only 16 bytes
although it reports it writes all of them. (it prints a=64 but only 16 bytes go out)
I even went in the minicom source code to see what they do
(as it works for them) but their open and init code gives me the same result.
I'll use my workaround which uses a usleep and is good enough for my application.
I can't spend anymore time on this

Code below: write_uart1 fails, write_uart2 is my workaround and is fine.

Code: Select all

//
// Raspberry-Pi UART access from C
//
// Code based on
//  http://www.raspberrypi.org/phpBB3/viewtopic.php?t=7500&p=93257
//  mixed with minicom code 
//

#include <unistd.h>   //Used for UART
#include <fcntl.h>    //Used for UART
#include <termios.h>  //Used for UART

int  open_uart(int low);
int  write_uart1(void *data,int bytes);
int  write_uart2(void *data,int bytes);
void close_uart();

// debug:
#include <stdio.h>

char pattern[65] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz\015\012";
// test
int main()
{
  if (open_uart(0)!=0)
  { fprintf(stderr,"Could not open UART\n");
    return 1;
  }
  while (1)
  {
    write_uart2(pattern,64);
    sleep(2);
  }
  return 0;
} // main 

int uart0_filestream = -1;

//
// Setup Raspberry-Pi UART
// return 0 on success
// return 1 on failure
//
// Code based on http://www.raspberrypi.org/phpBB3/viewtopic.php?t=7500&p=93257
//
int open_uart(int low)
{ int n;
  struct termios options;
  if (uart0_filestream!=-1)
    return 0; // assume already opened 
  uart0_filestream = open("/dev/ttyAMA0", O_RDWR | O_NOCTTY | O_NDELAY);  //Open in non blocking read/write mode
  if (uart0_filestream == -1)
  {
    fprintf(stderr,"Error - Unable to open UART. Ensure it is not in use by another application\n");
    fflush(stderr);
    return 1;
  }
  // cancel the O_NDELAY flag
  // (copied from minicom)
  n = fcntl(uart0_filestream, F_GETFL, 0);
  fcntl(uart0_filestream, F_SETFL, n & ~O_NDELAY);

  // CONFIGURE THE UART
  // The flags (defined in /usr/include/termios.h - 
  // see http://pubs.opengroup.org/onlinepubs/007908799/xsh/termios.h.html):
  tcgetattr(uart0_filestream, &options);
  cfsetospeed(&options,B57600);
  cfsetispeed(&options,B57600);
  options.c_cflag =  (options.c_cflag & ~CSIZE) | CS8; // 8 bits
  options.c_cflag |=  CLOCAL | CREAD;  // ignore mode status, enable rec.
  options.c_cflag &=  ~(PARENB | PARODD | CSTOPB); // No parity, 1 stop bit
  
  options.c_iflag = IGNBRK;
  options.c_iflag &= ~(IXON|IXOFF|IXANY);

  options.c_oflag = 0;
  options.c_lflag = 0;
  tcsetattr(uart0_filestream, TCSANOW, &options); // set the options NOW
  return 0;
} // setup_uart

// what it says 
void close_uart()
{
  if (uart0_filestream!=-1)
    close(uart0_filestream);
}


//
// transmit data to uart 
// This is how it should work 
//
// return 0 on failure
// return 1 on success
//
int write_uart1(void *data,int bytes)
{ int a;
  while (bytes)
  { 
    a = write(uart0_filestream, data, bytes);
    if (a==-1)
    { fprintf(stderr,"UART WRITE ERRROR!!\n");
      return 0;
    }
    bytes -= a;
    printf("a=%d\n",a);
    data = (void *)((char *)data + a);
  }
  tcflush(uart0_filestream,TCOFLUSH); 
  return 1;
} // tx_uart


//
// transmit data to uart 
// max 16 at a time 
// wait for 16 charac to leave before pushing more out
//
// return 0 on failure
// return 1 on success
//
int write_uart2(void *data,int bytes)
{ int b,a;
  while (bytes)
  { 
    b = bytes>=16 ? 16 : bytes;
    a = write(uart0_filestream, data, b);
    if (a==-1)
    { fprintf(stderr,"UART WRITE ERRROR!!\n");
      return 0;
    }
    bytes -= a;
    printf("a=%d\n",a);
    data = (void *)((char *)data + a);
    usleep(30000); // > 16charsx10bits/57600
  }
  tcflush(uart0_filestream,TCOFLUSH); 
  return 1;
} // tx_uart

User avatar
PeterO
Posts: 5159
Joined: Sun Jul 22, 2012 4:14 pm

Re: write in C to uart only outputs 16 bytes ?

Mon Aug 11, 2014 8:08 pm

Bit busy at the moment (trying to find a missing vertex in a 3D object !) but I'll try your code when I get a few minutes....
PeterO
Discoverer of the PI2 XENON DEATH FLASH!
Interests: C,Python,PIC,Electronics,Ham Radio (G0DZB),1960s British Computers.
"The primary requirement (as we've always seen in your examples) is that the code is readable. " Dougie Lawson

RaspISteve
Posts: 98
Joined: Wed Oct 24, 2012 9:15 pm
Location: Cheltenham, UK

Re: write in C to uart only outputs 16 bytes ?

Mon Aug 11, 2014 8:53 pm

Guys,

I remember years ago there was a UART which came with a 16 byte FIFO buffer. Very useful if you couldn't always get to it on time as you could whack a load of characters at it then go off and do something else.

If you didn't check the right flags and waited for characters to flush out correctly via the serial bit any character(s) written after the 17th all went to the same place and corrupted and I guess confused the thing. Maybe the Pi chip set has a similar feature.

Check you are testing the right status flags.
Share and Enjoy.

User avatar
jojopi
Posts: 3089
Joined: Tue Oct 11, 2011 8:38 pm

Re: write in C to uart only outputs 16 bytes ?

Mon Aug 11, 2014 9:21 pm

Gert van Loo wrote:tcflush(uart0_filestream,TCOFLUSH);
This flushes data written but not transmitted. So yes, you can successfully write 64 bytes but then discard most of them, sending only the 16 that were already in the FIFO.

Perhaps you meant tcdrain(), though in most cases you do not need that. Writes will start to block or return short once the output buffer is full.

User avatar
PeterO
Posts: 5159
Joined: Sun Jul 22, 2012 4:14 pm

Re: write in C to uart only outputs 16 bytes ?

Mon Aug 11, 2014 9:37 pm

Just got to look at this , and came to same conclusion and jojopi..... tcflush is not what you want .... "man termios" is your friend :D

Code: Select all

   tcflush() discards data written to the object referred to by fd but not
       transmitted,  or  data received but not read, depending on the value of
       queue_selector:

Code: Select all

     tcdrain()  waits  until all output written to the object referred to by
       fd has been transmitted.
PeterO
Discoverer of the PI2 XENON DEATH FLASH!
Interests: C,Python,PIC,Electronics,Ham Radio (G0DZB),1960s British Computers.
"The primary requirement (as we've always seen in your examples) is that the code is readable. " Dougie Lawson

User avatar
Gert van Loo
Posts: 2486
Joined: Tue Aug 02, 2011 7:27 am
Contact: Website

Re: write in C to uart only outputs 16 bytes ?

Tue Aug 12, 2014 8:26 am

Yes! thanks guys. It is now working.
My error was the usual: knowing fflush I assumed tcflush was the same.

Return to “Advanced users”