Sending data to and from XMOS board

Technical questions regarding the XTC tools and programming with XMOS.
SuperDeathMonkey
New User
Posts: 2
Joined: Wed Feb 10, 2010 3:53 am

Sending data to and from XMOS board

Post by SuperDeathMonkey »

Hey guys

This may sound like really simple problem but please bare with me.

All i'm trying to do is send an array of 8-bit values from my computer to my XC-1 board.

Using this http://www.xmoslinkers.org/node/347 I attempted to edit it to receive an array then echo it back. I've been using realterm to send some data to test it however i'm getting back completely different values to what i'm sending. Do I need some kind of handshaking thing?? Any pointers would be greatly appreciated.

Code: Select all

    int main()
    {   
       unsigned char c;
       int i=0,j=0;
       while (1)
       {
          c = rxByte();
          
          if (c == 'R')
          {
             while(j<ARRAY_SIZE)
             {
                i = 0;
                for (i = 0; i < ARRAY_SIZE; i += 1)
                {
                   CompArray[i][j] = rxByte();
                }
                j++;
             }
             i = 0;
             j = 0;
             for (i = 0; i < ARRAY_SIZE; i += 1)
             {
                for (j = 0; j < ARRAY_SIZE; j += 1)
                {
                   txByte(CompArray[i][j]);
                }
             }
          }
       }
       
       return 0;
    }

I'm also trying to write a c# program to handle all the sending data but that's a whole other problem!!


User avatar
Woody
XCore Addict
Posts: 165
Joined: Wed Feb 10, 2010 2:32 pm

Post by Woody »

Firstly, from inspection there looks like theres a bit of a bug in source.xc. rxByte should ensure it sees a stop bit before it looks for the next start bit. So I've added a conditional delay at the start of the function below.

Code: Select all

unsigned char rxByte(void)
{
   unsigned data = 0, time;
   int i;
   unsigned char c;

   //***** Wait for stop bit *****   
   RXD when pinseq (1) :> int _;  
   //***** Stop bit  detected  ***   

   // wait for start bit
   RXD when pinseq (0) :> int _ @ time;  
   time += BIT_TIME + (BIT_TIME >> 1);
   
   // sample each bit in the middle.
   for (i = 0; i < 8; i += 1)
   {
      RXD @ time :> >> data;
      time += BIT_TIME;
   }

   // reshuffle the data.
   c = (unsigned char) (data >> 24);

   return {c};
}
Answering the main question: you shouldn't need any extra handshaking as the UART is self timed. Here's a couple of tips:
1. Try starting off at a slower bit rate: e.g. 9600 rather than 115200. This should avoid any possible electrical problems.
2. Check your terminal emulator settings: They should be 9600, 8 bits, no parity, 2 stop bits (although 1 stop should also work). Also I'd disable flow control.
3. Why not just try a very simple echo program to start off like this one:

Code: Select all

int main (void)
{
  unsigned char c;
  while (1)
  {
    c = rxByte();
    txByte(c);
  }
  return (0);
}
User avatar
leon_heller
XCore Expert
Posts: 546
Joined: Thu Dec 10, 2009 10:41 pm
Location: St. Leonards-on-Sea, E. Sussex, UK.

Post by leon_heller »

That's my code. It did have a problem receiving and sending an array, and your suggestion fixed it. Here is my version of a program that works:

Code: Select all


#include <platform.h>

#define BIT_RATE 115200
#define BIT_TIME XS1_TIMER_HZ / BIT_RATE

void txByte(unsigned char);
unsigned char rxByte(void);

out port TXD = PORT_UART_TX;
in port  RXD = PORT_UART_RX;

unsigned char array[10];

int main()
{	
	//unsigned char c;
	int i;
	
	while (1)
	{
		for (i = 0; i < 10; i++)
			array[i] = rxByte();
		for (i = 0; i < 10; i++)
			txByte(array[i]);			
	}	
	
	return 0;
}

unsigned char rxByte(void)
{
   unsigned data = 0, time;
   int i;
   unsigned char c;
   
   // Wait for stop bit 
   RXD when pinseq (1) :> int _; 

   // wait for start bit
   RXD when pinseq (0) :> int _ @ time;  
   time += BIT_TIME + (BIT_TIME >> 1);
   
   // sample each bit in the middle.
   for (i = 0; i < 8; i += 1)
   {
      RXD @ time :> >> data;
      time += BIT_TIME;
   }

   // reshuffle the data.
   c = (unsigned char) (data >> 24);

   return {c};
}

void txByte(unsigned char c)
{
   unsigned time, data;
   
   data = c;
   
   // get current time from port with force out.
   TXD <: 1 @ time;
   
   // Start bit.
   TXD <: 0;
   
   // Data bits.
   for (int i = 0; i < 8; i += 1)
   {
      time += BIT_TIME;
      TXD @ time <: >> data;         
   }
   
   // two stop bits
   time += BIT_TIME;
   TXD @ time <: 1;
   time += BIT_TIME;
   TXD @ time <: 1; 
}
It's fine at 115k.

I've updated the Xlinkers project with the new version.

Leon
User avatar
lilltroll
XCore Expert
Posts: 956
Joined: Fri Dec 11, 2009 3:53 am
Location: Sweden, Eskilstuna

Post by lilltroll »

Is the data sent over the FTDI chip??

Can you make the com. work with the XTAG2 yet?
Probably not the most confused programmer anymore on the XCORE forum.
User avatar
leon_heller
XCore Expert
Posts: 546
Joined: Thu Dec 10, 2009 10:41 pm
Location: St. Leonards-on-Sea, E. Sussex, UK.

Post by leon_heller »

Yes, it uses the FTDI chip on the XC-1.

The XTAG-2 could be reprogrammed to provide a similar facility, but I don't think anyone has done it. A driver for the PC will also be required.

Leon
SuperDeathMonkey
New User
Posts: 2
Joined: Wed Feb 10, 2010 3:53 am

Post by SuperDeathMonkey »

Awesome stuff guys, thanks very much
User avatar
otitov
XCore Addict
Posts: 207
Joined: Thu Dec 10, 2009 11:00 pm
Location: Mexico

Post by otitov »

yesterday I got a similar problem with UART implementation - I was unable to receive data from external module, some messages were received good, others came in as garbage. Search brought me to this thread.

Tomorrow I will try to add "RXD when pinseq (1) :> int _;" to my code, but, please could you explain why the end of the stop bit should be detected?

I see, so far, that rx routine waits for beginning of start bit, receives 8 bits, and finishes at the middle of the stop bit (e.g. port is high at this point). Why the detection of low on this port is not enough? Why should be implemented a check for the end of stop bit?

I would quite appreciate a "long" explanation, as the XC "main book" also refers to rx code without this extra check.
User avatar
Woody
XCore Addict
Posts: 165
Joined: Wed Feb 10, 2010 2:32 pm

Post by Woody »

otitov wrote:Tomorrow I will try to add "RXD when pinseq (1) :> int _;" to my code, but, please could you explain why the end of the stop bit should be detected?

I see, so far, that rx routine waits for beginning of start bit, receives 8 bits, and finishes at the middle of the stop bit (e.g. port is high at this point). Why the detection of low on this port is not enough? Why should be implemented a check for the end of stop bit?
Firstly you're right that the code needs to detect the beginning of the start bit. At the end of the rxByte function you'll see that we sample the final bit of the byte at the centre of the byte, and then return. (Not the middle of the stop bit as you thought.) If rxByte is then called again immediately, and the final bit was a 0 then the test for a start bit (0) will be true immediately.

To avoid this situation we need to test for the stop bit (1) first, then move on to the start bit. Only then do we get the exact timing of the -ve edge at the beginning of the start bit.
User avatar
otitov
XCore Addict
Posts: 207
Joined: Thu Dec 10, 2009 11:00 pm
Location: Mexico

Post by otitov »

thanks for your input!

you are quite right about possibility to read last zeroed bit in error. i was mixing my code (a bit different) with one published her.

your suggestion to implement RXD when pinseq(1) :> void; really helped a lot, but this have not solved all issues I have right now.

let me define setup I have right now - GPS module connected to XC-2 card, the card connected to computer via JTAG. I am reading one byte from GPS module and sent it via JTAG, on computer I run HyperTerminal to read output.

if I use following rxByte() function implementation (wait for hi, wait for low, no read stop bit):

Code: Select all

unsigned char rxByte(in port RXD) {
  unsigned data = 0;
  timer t;
  unsigned time;

  RXD when pinseq(1) :> void;
  
  RXD when pinseq(0) :> void;
  
  t :> time;
  
  time += BIT_TIME + ((BIT_TIME) >> 1);
  
  
  // sample each bit in the middle.
     for (int i = 0; i < 8; i++)
     {
    	t when timerafter(time) :> void;
        RXD :> >> data;
        time += BIT_TIME;
     }
     
  return (unsigned char)(data >> 24);   
}
I get:

Code: Select all

$GPGLL,1929.93299,N,09907.82191,W,193Âr‚‚b
                                           ±
                                            ©ºšj
                                                $GPRMC,193409.00,A,1929.93326,N,
09907.82147,W,1.907,,250210,,,A*6E
$GPVTG,,T,©Š)rÊ‚ºbr±šrªšŠbZ±
                            ©’Âj
                                $GPGGA,193409.00,1929.93326,N,09907.82147,W,1,08
,1.22,2256.1,M,-7.5,M,,*6D
$uM±
     ±šb’²b‚ÊbŠ¢b’’bŠÂb’ŠbŠ5,24,,,,,2.07,1.22,1.67*06
$GPGSV,4,1,14,01,02,183,,03,10,310,,06,19,306,,09,&    ÂÂbŠÂRº5
                                                                 $GPGSV,4,2,14,1
4,41,223,14,15,11,037,11,18,47,356,27,21,69,029,29*7F
$GPGSV,ibŠ¢b’’bšºbš‚ºbš‚b’¢bªÊb‚Â’b’Êb’²b‚b’¢²bšŠb’ºb’Êb‚º¢bRº‚j
                                                                  $GPGSV,4,4,14,
29,26,174,,30,00,163,*76
if i use (wait for low, end at middle of stop bit):

Code: Select all

unsigned char rxByte(in port RXD) {
  unsigned data = 0;
  timer t;
  unsigned time;

  RXD when pinseq(0) :> void;
  
  t :> time;
  
  time += BIT_TIME + ((BIT_TIME) >> 1);
  
  // sample each bit in the middle.
     for (int i = 0; i < 8; i++)
     {
    	t when timerafter(time) :> void;
        RXD :> >> data;
        time += BIT_TIME;
     }
     
     /* input stop bit */
     t when timerafter ( time ) :> void ;
     
  return (unsigned char)(data >> 24);   
}
I get:

Code: Select all

$GPGLL,1929.93407,N,˜œœ˜›—œ™š™›–«–˜œ™›˜›—˜˜– –PJ“SHø$GPRMC,193608.00,A,1929.9340
3,N,09907.82438,W,0.616,–™š˜™˜˜––– •›¢†…’£¨«ª£––ª––SKLKMLMKSKLKLMLK)¥(%¦SHˆé
                                                                            êê*Š
))š²‚Âr‚‚bŠÊ’ÊrÊš¢‚šbrb‚ÊÊ‚ºrÂ’¢šÂbº±Å±Áå±Å¹ÁͱÉÉÕݹå±5±µÝ¹Õ±5±±©Ùá5)‘AM±±Í±ÉÙ
±Áå±ÅÑXddXdnXdrXbpXdbXdhXXXXd\bp,1.03,1.93*0A
$GPGSV,4,1,14,01,02,182,,03,11,309,,0›–™˜–™˜š––˜œ–™š–˜œ›–˜š•›¢†…’ÕÔ•‰‰I‰)‰‰)‰‰
‰I‰II‰‰)i‰)©‰)  ‰       šÂbbŠÂb¢ºbšªºb’ºb’Šb²Êb‚šŠbš‚Rº’jR":AMY±Ñ±Í±ÅѱÉɱÍݱÍÁ
å±ÍÁ±ÉѱÕå±ÁáѱÍÁ±ÉÙ±áűÉÕͱÉá±ÉnXdrX`nfXbjTnŠHŽ Ž¦¬XhXh,14,29,25,174,14,30,00
,162,*71
if I use (wait for low, end at stop bit's end):

Code: Select all

unsigned char rxByte(in port RXD) {
  unsigned data = 0;
  timer t;
  unsigned time;

  //RXD when pinseq(1) :> void;
  
  RXD when pinseq(0) :> void;
  
  t :> time;
  
  time += BIT_TIME + ((BIT_TIME) >> 1);
  
  
  // sample each bit in the middle.
     for (int i = 0; i < 8; i++)
     {
    	t when timerafter(time) :> void;
        RXD :> >> data;
        time += BIT_TIME;
     }
     
     /* input stop bit */
     time += (BIT_TIME >> 1) ;
     t when timerafter ( time ) :> void ;
     
  return (unsigned char)(data >> 24);   
}
I get:

Code: Select all

$GPRMC,193811.00,A,1929.œ™›œ˜–§–˜œœ˜›—œ™š™œ–«–˜—™‰Iª‚’Š‚bbb
                                                              ©ÙÁ5)‘AYQ±±Q±±5±
Á¹ÉÝѱœX`\j`pX–X‚TdŒHŽ ŽŽ‚Xb93811.00,1929.93691,N,09œ˜›—œ™š™œ–«–˜–˜›–˜—™™–™™›L
ébj±µÝ¹Õ±5±±©ÙÁ5)‘AM±±ÍXdlXbhXddXdnXbpXdbXdhXXX,,,2.64,1.33,2.28*03
5)‘AMY±Ñ±É±ÅѱÅѱÑͱÉÉjXdfXbjXb`X`fpX`pXbpXhnX359,28,21,70,034,25*71
’£¨£©«–š–™–˜š–™™–™œ–™˜˜–¦&I¢bªÊb‚²b’ºb’²bŠb’²Šb’º±ÉݱÉå±ÁÝɱÅÁ©ÝÙ5)‘AMY±Ñ±Ñ±
ÅѱÉå±ÉÕ±ÅÝѱ±Í`X``XblbXTnnHŽ Ž˜˜Xbrd9.93691,N,09907.82428,W,˜œ™œ˜˜—˜˜– – •›¡†
…
I have tested GPS module by directly connecting module to TTL UART to USB FTDI adapter. Works just fine.

Please, let me know if I can provide any useful info.

Any comments are quite welcome as I really would like to learn XMOS very good.