Errata Sheet for XS1-G4A-FB512-C4 0835 ES N65285.00

Technical discussions around xCORE processors (e.g. xcore-200 & xcore.ai).
richard
Respected Member
Posts: 318
Joined: Tue Dec 15, 2009 12:46 am

Post by richard »

Edit: We are still investigating and checking other solutions.


User avatar
segher
XCore Expert
Posts: 844
Joined: Sun Jul 11, 2010 1:31 am

Post by segher »

Would it work to run the timer event on another thread, or will that run into
the same problem?


Segher
richard
Respected Member
Posts: 318
Joined: Tue Dec 15, 2009 12:46 am

Post by richard »

A second possibility is to use a combination of a timer and an unbuffered port. Since the UART RX port is clocked off the undivided reference clock the number of timer ticks before a timed input on the port becomes ready is equal to the number of port counter increments before the port time is met. You can use this to implement the UART as follows.

When you want to sample the value of the port at a time in the future use the setpt instruction with the desired time as before. Instead of enabling events on the port, input the current time on a timer and configure the timer to event after uart bit time timer ticks have elapsed (or 1.5 bit times if you have just had the start bit). Finally enable events on thread.

When the timer event is taken the port time is guaranteed to have been met. The port will have sampled the pins at this time and will hold this value until it is read. An in instruction can be used to read the value. Once you have read the value you can configure the time and the port for the bit in the same way and enable events on the thread again.

I've written a XC and a modified assembly version of the UART to illustrate this idea.

Code: Select all

#include "xs1.h"

#define UART_TICKS 868
#define UART_TICKS_1_5 1302

static void setpt(port p, unsigned time)
{
  asm("setc res[%0], 1" : : "r"(p)); // XS1_SETC_COND_NONE
  asm("setpt res[%0], %1" : : "r"(p), "r"(time));
}

static unsigned portin(port p)
{
  unsigned value;
  asm("in %0, res[%1]" : "=r"(value) : "r"(p));
  return value;
}

unsigned uart_rx_count;
unsigned uart_rx_val;

void uart_rx(port p) {
  timer t;
  timer periodicTimer;
  unsigned periodicTime;
  unsigned time;
  unsigned timerTime = 0;
  unsigned portTime = 0;
  unsigned portValue = 0;
  unsigned byte;
  unsigned bit = 0;
  int timedInput = 0;
  periodicTimer :> periodicTime;
  periodicTime += 434;
  while (1) {
    select {
    case periodicTimer when timerafter(periodicTime) :> void:
      periodicTime += 434;
      break;
    case !timedInput => p when pinseq(portValue) :> void @ portTime:
      if (portValue) {
        // Wait for start condition
        portValue = 0;
      } else {
        // Wait for first bit.
        t :> timerTime;
        timerTime += UART_TICKS_1_5;
        portTime += UART_TICKS_1_5;
        setpt(p, portTime);
        timedInput = 1;
        bit = 0;
        byte = 0;
      }
      break;
    case timedInput => t when timerafter(timerTime) :> void:
      portValue = portin(p);
      if (bit == 8) {
        unsigned tmp;
        // Read stop bit
        timedInput = 0;
        // If bit is 0 wait for high, otherwise wait for start condition.
        if (portValue) {
          portValue = 0;
          uart_rx_count++;
          uart_rx_val = byte;
        } else {
          portValue = 1;
        }
      } else {
        byte |= portValue << bit;
        bit++;
        timerTime += UART_TICKS;
        portTime += UART_TICKS;
        setpt(p, portTime);
      }
      break;
    }
  }
}

Code: Select all

#include <xs1.h>

.section .dp.data, "awd", @progbits
.align 4
RXrecord:
  .int 0           // bit number
  .int XS1_PORT_1B // portID
  .int 0           // timerID
  .int 0           // port time
  .int 868         // del10bit (115200 bps)
  .int 1302        // del15bit
  .int 0           // shiftreg
  .int 0           // datareg
  .int 0           // dataready

#define BIT_OFFSET 0
#define PORTID_OFFSET 1
#define TIMERID_OFFSET 2
#define PORTTIME_OFFSET 3
#define BITTIME_OFFSET 4
#define BITTIME1_5_OFFSET 5
#define SHIFT_OFFSET 6
#define DATA_OFFSET 7
#define DATAREADY_OFFSET 8

.text
.globl UART
.globl UART.nstackwords
.linkset UART.nstackwords, 0

.align 2
UART:
  ldaw   r0, dp[RXrecord]
  // Allocate and initialise periodic timer
  getr   r1, XS1_RES_TYPE_TIMER
  setc   res[r1], XS1_SETC_COND_AFTER
  ldap   r11, TimerHandler
  setv   res[r1], r11
  in     r2, res[r1]
  ldc    r3, 434
  add    r2, r2, r3
  setd   res[r1], r2
  eeu    res[r1]

  // Allocate and initialise rx timer
  getr   r1, XS1_RES_TYPE_TIMER
  setc   res[r1], XS1_SETC_COND_AFTER
  stw    r1, r0[TIMERID_OFFSET]
  ldap   r11, RXTimerHandler
  setv   res[r1], r11
  mov    r11, r0
  setev  res[r1], r11

  // Initialise port
  ldw    r1, r0[PORTID_OFFSET]
  setc   res[r1], XS1_SETC_INUSE_ON
  ldap   r11, RXHandler
  setv   res[r1], r11
  mov    r11, r0
  setev  res[r1], r11
  
  // setup port to event when high
  setc   res[r1], XS1_SETC_COND_EQ
  ldc    r2, 1
  setd   res[r1], r2
  eeu    res[r1]
  waiteu

RXHandler:
  get    r11, ed            //  get environment vector = RXrecord
  ldw    r0, r11[PORTID_OFFSET]
  getts  r1, res[r0]
  in     r2, res[r0]
  bt     r2, waitstartbit

startbitfound:
  ldw    r2, r11[TIMERID_OFFSET]
  in     r3, res[r2]
  ldw    r4, r11[BITTIME1_5_OFFSET]
  edu    res[r0] // disable port events
  setc   res[r0], XS1_SETC_COND_NONE // unset port condition
  add    r1, r1, r4
  setpt  res[r0], r1 // set port time
  stw    r1, r11[PORTTIME_OFFSET]
  add    r3, r3, r4
  setd   res[r2], r3 // set timer time
  eeu    res[r2] // enable timer events
  ldc    r1, 0
  stw    r1, r11[BIT_OFFSET] // store bit = 0
  stw    r1, r11[SHIFT_OFFSET] // clear shift register
  waiteu

waitstartbit:
  ldc    r2, 0
  setd   res[r0], r2
  waiteu

RXTimerHandler:
  get    r11, ed            //  get environment vector = RXrecord
  ldw    r0, r11[TIMERID_OFFSET]
  in     r1, res[r0]
  ldw    r1, r11[PORTID_OFFSET]
  ldw    r2, r11[BIT_OFFSET]
  eq     r3, r2, 8
  bt     r3, checkstopbit
  ldw    r3, r11[SHIFT_OFFSET]
  inshr  r3, res[r1]
  stw    r3, r11[SHIFT_OFFSET]
  add    r2, r2, 1
  stw    r2, r11[BIT_OFFSET]
  ldw    r2, r11[BITTIME_OFFSET]
  getd   r3, res[r0]
  add    r3, r3, r2
  setd   res[r0], r3 // set timer time
  ldw    r3, r11[PORTTIME_OFFSET]
  add    r3, r3, r2
  setpt  res[r1], r3 // set port time
  stw    r3, r11[PORTTIME_OFFSET]
  waiteu

checkstopbit:
  edu res[r0]      // disable port events
  in r2, res[r1]
  setc   res[r1], XS1_SETC_COND_EQ
  eq r2, r2, 0
  setd res[r1], r2 // if 1 was sampled wait for 0, if 0 was sampled wait for 1
  eeu res[r1]      // enable port events
  waitet r2        // don't store data if stop bit wasn't 1
  ldw r2, r11[SHIFT_OFFSET]
  shr r2, r2, 24   // shift data to least significant bits
  stw r2, r11[DATA_OFFSET] // store data
  ldc r2, 1
  stw r2, r11[DATAREADY_OFFSET] // set dataready
  waiteu

TimerHandler:
  get    r11, ed            //  get environment vector = timerID
  in     r0, res[r11]
  getd   r0, res[r11]       //  load previous due time
  ldc    r10, 434           //  TIMER period = 434 REF cycles
  add    r9, r9, r10
  setd   res[r11], r9       //  set new due time
  waiteu
richard
Respected Member
Posts: 318
Joined: Tue Dec 15, 2009 12:46 am

Post by richard »

segher wrote:Would it work to run the timer event on another thread, or will that run into
the same problem?

Segher
Yes, this would be OK as well. It will work correctly so long as you are guaranteed not to get another event at the same time as the event on the port.
va3ttn
Member
Posts: 12
Joined: Sat Jul 03, 2010 1:46 pm

Post by va3ttn »

dave wrote:We have checked that XC programs are not affected by this behavior - the instruction sequences compiled can not give rise to it.
True, XC has no equivalent construct.
That's why I had to use assembly to get to the full potential of this wonderful technology.
dave wrote: Thank you for finding this issue and pointing it out to us.
Can I offer you a reward - a free XC-1A or equivalent?
Unexpected, and gladly accepted :-)
An equivalent in the form of XK-1 with XTAG-2 fits my immediate needs perfectly.
I sent contact details in a private message. Thank you!
Last edited by va3ttn on Thu Jul 29, 2010 10:43 am, edited 1 time in total.
va3ttn
Member
Posts: 12
Joined: Sat Jul 03, 2010 1:46 pm

Post by va3ttn »

richard wrote:As Dave says you have encountered a limitation of the port hardware...
Let me first thank all of you nice people from XMOS for considering my problem so carefully and promptly.

In the actual application, a single thread was to implement 8 UART receivers,
10 UART transmitters plus some additional gadgets.

Other threads (on Core 2) have their own duties, such as generating two RGB video signals (640 x 400, 8 colors each), rendering, etc.
But, happily enough, a few spare threads still remained. Eight threads (per core) can really go a long way :-)

So, I could reproduce the problem without a timer, just by using two or more UART receivers simultaneously.
richard wrote:...The issue concerns waiting for events on a unbuffered port configured to become ready at a port time with no condition. If the port becomes ready at the same time as another resource and the event for the other resource is taken then the port will not generate another event until its configuration is changed.
What is the exact extent of this limitation?
Does it also apply to ports in interrupt mode?

It would be very nice if this limitation could be removed in future versions of silicon.
This may be unimportant for XC, but it would certainly enable more effective use
of the available resources in some applications.
richard wrote:One possibility is to instead configure the port as a buffered port...
Thank you very much for the suggestion, it worked!

The timing uncertainty wasn't small with all the burden I've placed on the poor thread.
But it was easy to rearrange things so that only 8 UART receivers remained, with the rest placed on a spare thread.

At 115200 bps the timing uncertainty now amounted to about 24 % of the bit period,
so I've shifted the sampling point to distribute this uncertainty symmetrically
about bit center. The resulting +/- 12 % seem to have no ill effect at all.
richard wrote:A second possibility is to use a combination of a timer and an unbuffered port.
This solution has a great virtue of preserving the precise input sampling.
But I feared that for 8 concurrent receivers the necessary time bookkeeping may turn too complex.
So, I stayed with the first solution, but will have this in mind.

Thank you very much for bringing my project back to tracks!
richard
Respected Member
Posts: 318
Joined: Tue Dec 15, 2009 12:46 am

Post by richard »

va3ttn wrote:Does it also apply to ports in interrupt mode?
Yes, the same applies to interrupts.