Ucom/Uftdi Thru-put

User Tomdean tomdean at speakeasy.org
Tue Aug 30 17:47:44 GMT 2005


Sorry this is long, I have attached the code at the bottom.
ucom_read.c is the FreeBSD code.  UMP2_send.c is the AVR code.

# kldload ucom
# kldload uftdi
power up UMP2 and AVR
In dmesg, I see
  ucom0: FTDI USB HS Serial Converter, rev 1.10/2.00, addr 2

With a scope, on the USB_DATA+ line, I see groups of 3 uSec activity,
every 1 mSec.  Within the groups, I see 100 nSec pulses, or a 10 mBit
rate.

# ./ucom_read

With a scope, on the USB_DATA+ line, I see activity every 1 mSec.
But, the AVR has groups of activity every 2 mSEC!  Just before the 52
uSec of activity caused by the AVR, I see a 3 uSec group of activity.
So, the USB bus has its normal 3 uSec activity every 1 mSec overlayed
by 52 uSec of AVR activity every 2 mSec.  So, ucom_read only gets the
USB bus every 2 msec.

The AVR send loop takes 0.9 to 1.1 uSec.  These happen in bursts of 74
uSec every 2 mSec.  The AVR waits for the UMP2 TX ready signal most of
the time.

>From looking at the USB_DATA+ line and the UMP2 *TXE signal, the *TXE
signal is not true until the buffer is empty.  The doc states 'If this
signal is log.1, the buffer is full'.

10 mSec --+---------+---------+---------+---------
USB     --1---------123-------1---------123------
*TXE    ---------------4-------------------4-----


1 - 3  uSec USB activity from FreeBSD
2 - 10 uSec gap
3 - 52 uSec USB activity from the UMP2
4 - 72 uSec activity on the *TXE line, high otherwise.

The nominal return from the FreeBSD read is 62 bytes.  The UMP2 has a
FT8U245BM chip, which has a 384 byte transmit buffer.

The output from ucom_read,

   Read 1000060 bytes in 32.242824 seconds in chuncks of 62 bytes

This is a thruput of 31017 bytes/second.

Does FreeBSD only request 64 bytes from the UMP2????

tomdean

=== ucom_read =========================================================
/*
 * asus-read.c - read ucom0, doing time measurements
 *
 * $Id$
 */
#include <stdio.h>
#include <termios.h>    /* termios settings */
#include <fcntl.h>      /* open */
#include <sys/types.h>  /* read */
#include <sys/uio.h>    /* read */
#include <unistd.h>     /* read */
#include <sys/time.h>   /* time */

#define USB_BUF_SIZE 20000
#define BYTES_TO_READ 1000000

/*
 * Set up ucom's state
 */
void ucomsetup (int fd) {

  struct termios termios;
  tcgetattr (fd, &termios);

  /* input modes */
  termios.c_iflag = (IGNBRK);
  /* local modes */
  termios.c_lflag = 0;
  /* common modes */
  termios.c_cflag = (CLOCAL|HUPCL|CREAD|CS8);  /* no parity */

  /* since the UMP2 is a USB to parallel device, speed is meaningless */
  if (0) termios.c_ispeed = termios.c_ospeed = B9600;
  if (0) termios.c_ispeed = termios.c_ospeed = B38400;
  if (0) termios.c_ispeed = termios.c_ospeed = B115200;
  if (0) termios.c_ispeed = termios.c_ospeed = B230400;
  if (0) termios.c_ispeed = termios.c_ospeed = B921600;
  
  tcsetattr (fd, TCSANOW, &termios);

  return;
}

/*
 * main
 */
int main(int argc, char **argv) {
  int fd;  /* file descriptor */
  int numRead;
  size_t bytes;
  uint8_t *buf[USB_BUF_SIZE];
  
  struct timeval  start, stop;
  struct timezone tz;
  long sec, usec;
  double elapsed, mb_sec, nsec;

  if ((fd = open("/dev/ucom0", O_RDONLY)) < 0) {
	perror("Open /dev/ucom0");
	return -1;
  }

  /* need to do this */
  ucomsetup(fd);

  numRead = 0;

  /*
   * get the start time
   */
  gettimeofday(&start, &tz);
  
  /*
   * read a large number of bytes and keep track of time
   */
  while (numRead < BYTES_TO_READ) {
	bytes = read(fd, buf, USB_BUF_SIZE);
	if (0) printf("Read %d bytes\n", bytes);
	numRead += bytes;
  }

  /*
   * get the end time
   */
  gettimeofday(&stop, &tz);

  /*
   * calculate the time, etc.
   */
  sec  = stop.tv_sec  - start.tv_sec;
  if (sec < 0) sec++;
  usec = stop.tv_usec - start.tv_usec;
  if (usec < 0) {
        sec--;
        usec += 1000000L;
  }
  elapsed = (double)sec + ((double) usec)/1000000.0;

  printf("Read %d bytes in %f seconds in chuncks of %d bytes\n",
		 numRead, elapsed, bytes);

  close(fd);

  return 0;
}

== UMP2_send ========================================================
/*
 * UMP2-send.c - provide loopback for the UMP2 module
 *
 * Connections
 *   PORTA
 *     <7> UMP2 RD#   =0 to read data
 *     <6> UMP2 WR    =1 to write data
 *     <5> UMP2 TXE#  =0 TX is available to accept data
 *     <4> UMP2 RXF#  =0 RX has data available
 *     <3> UMP2 PWE#  =0 if device is configured via USB
 *     <2>
 *     <1>
 *     <0>
 *   PORTB LEDs
 *     <7> Init OK
 *     <6> 
 *     <5>
 *     <4>
 *     <3> Wait Tx ready
 *     <2> Wait Rx data
 *     <1> Writing data to UMP2
 *     <0> Reading data from UMP2
 *   PORTC
 *     <7:0> UMP2 data
 *
 * $Id$
 */

#include <avr/io.h>          /* io definitions like PORTB, etc */
#include <libasus.h>         /* prototypes */
#include <avr/interrupt.h>   /* cli */
#include <stdint.h>          /* uint8_t, etc */

/* led 0 is the first led, or bit 0 */
/* PORTB is at 0x18 */
#define LED_PORT 0x18
#define LED_ON(n)  asm("cbi %0,%1"::"i"(LED_PORT),"i"(n))
#define LED_OFF(n) asm("sbi %0,%1"::"i"(LED_PORT),"i"(n));

/*
 * UMP2 bit definitions
 */
#define UMP2_CTL PORTA
#define UMP2_CTL_PIN PINA
#define UMP2_RD  7
#define UMP2_WR  6
#define UMP2_TXE 5
#define UMP2_RXF 4
#define UMP2_PWE 3

#define UMP2_DATA PORTC
#define SET_READ  DDRC=0x00
#define SET_WRITE DDRC=0xff

int main() {
  uint8_t c;
  uint8_t r;

  asm("cli");
  
  DDRA = (1<<UMP2_RD) | (1<<UMP2_WR);
  DDRB=0xff;  /* all output */
  DDRC=0x00;  /* all input */
  PORTC=0x00; /* make sure no pullups */

  /* ser UMP2_RD high */
  PORTA |= (1<<UMP2_RD);
  /* pull up the low signals */
  PORTA |= (1<<UMP2_TXE) |(1<<UMP2_RXF) |(1<<UMP2_PWE);
  
  PORTB = 0xff;  /* all led's off */

  serial_init();
  /*
   * set the UART baud rate
   */
  UBRRL = 8;  /* 115.2k at 16.0000Mhz */

  PORTB = 0;          /* all led's on */
  if (0) r = serial_recv();  /* get in sync */
  PORTB = 0xff;       /* all led's off */
  LED_ON(7);
  LED_OFF(7);

  c = 'a';
  
  /* set the data port direction to out */
  SET_WRITE;

  while(1) {
	/* visual output and scope trigger */
	LED_ON(0);
	/* Write data to UMP2 */
	while (UMP2_CTL_PIN & (1<<UMP2_TXE)) ;
	/* WR up */
	UMP2_CTL |=  (1<<UMP2_WR);
	/* present data */
	UMP2_DATA = c;
	/* WR down */
	UMP2_CTL &= ~(1<<UMP2_WR);
	/* the loop is done */
	LED_OFF(0);
  }

  return 0;
}


More information about the freebsd-usb mailing list