Count number of transitions on a port

Technical questions regarding the XTC tools and programming with XMOS.
User avatar
octal
XCore Addict
Posts: 228
Joined: Thu Jan 27, 2011 3:30 pm
Location: Argenteuil - France

Count number of transitions on a port

Post by octal »

Hello,
I want to create a simple pulse counter. I'm using this simple code:

Code: Select all

void pulseCounter(server interface pulse_intf s_intf)
{
    char x;

    p_in :> x;
    while (1)
    {
        select {
            case p_in when pinsneq(x) :> x:
            counter++;
            break;

            case s_intf.getCount() -> unsigned int return_val :
            // Set the return value
            return_val = counter;
            break ;
        }
    }
}
Forgot the interface, it's just there to be able to read the counter and print it from another task.

The main pb, is that if my signal on input port is arround 10MHz, the count of pulses is wrong. Seem the chip is too slow to handle states changes at this speed.
Do you see another way to implement states changes counting on a pin?

regards


GerhardNorkus
Active Member
Posts: 55
Joined: Wed Jan 05, 2011 2:15 pm

Post by GerhardNorkus »

The reason you cannot do better than 10 MHz is because of the underlying compiled code. Each machine language instruction takes 10ns to execute. The code below apparently compiles to about 10 commands (meaning 100ns are required). You can inspect the compiled code by
1. Finding your .XE file that gets loaded to XMOS processor
2. Running xobjdump (in the command line) supplying it with the -S flag and the -o flag. This will generate source code and dump it to the desired output file. (Example: xobjdump -S YourProg_Debug.xe -o YourProgDisassembly.txt).

I am assuming you are using a 1 bit port. Each port has a counter associated with it internally. It is accessible using the GETTS assembly language command (see "The XMos Architecture" document from XMos). If you do not feel comfortable using assembly language, this will prove to be difficult to do otherwise.

You can actually see the counter getting updated if you use the "Waves" view. You access that by setting up the "Debug Configurations" to run as a Simulator. But there's a lot more to describe about that if you haven't yet invested the time in it....
User avatar
octal
XCore Addict
Posts: 228
Joined: Thu Jan 27, 2011 3:30 pm
Location: Argenteuil - France

Post by octal »

GerhardNorkus wrote: You can actually see the counter getting updated if you use the "Waves" view. You access that by setting up the "Debug Configurations" to run as a Simulator. But there's a lot more to describe about that if you haven't yet invested the time in it....
Hi GerhardNorkus,
I'm aware of all XMOS tools. I have been using them tow years ago (before XMOS changed the nomenclature of cores/threads to tiles/logic-core). I have left XMOS mainly because of my daily work, and I'm getting back to them mainly because of a special project (a proof of concept mainly). btw, I'm the creator of the French XMOS group (http://www.xcore.com/groups/frenchy-xcore , http://www.xcore.com/wiki/index.php/Frenchy_XCore ;)

As for the timing, I'm checking using the waves view, and I already checked the section of code I posted using XTA. It reports about 160ns for the first case statement, and when I comment the second one, it reports about 120ns (worst case of course).

I'm sorry for not having been precise with my question. What I was asking for is if there were a special feature or trick to do edge counting (using clocks, buffered ports, ...) in accurate manner.
I couldn't find any clever way of doing it. I tought to use buffered ports, and using serialization of 0xFF values on a cloked input port, and then check the number of 0xFF clocked-in in a certain amount of time, but this is usable only if the count of clock edges is multipe of 8....

anyway, I'm going to check how I can do it in assembly.
Thank you for your suggestions.
richard
Respected Member
Posts: 318
Joined: Tue Dec 15, 2009 12:46 am

Post by richard »

My first thought is to use buffered ports. If you take a 1-bit wide port and set the transfer width to 32 then each time you input from the port you get the last 32 sampled values. You can then work out how many transitions are contained in that window and add them to the counter. You can use a lookup table to calculate the number of transitions, for example (warning: untested!):

Code: Select all

// Lookup table for the number of transitions in a 8 bit value.
static char transitionsLookup[256] = {
  0, // 0b00000000 -> 0
  1, // 0b00000001 -> 1
  2, // 0b00000010 -> 2
  1, // 0b00000011 -> 1
  ...
};

void pulseCounter(server interface pulse_intf s_intf, buffered in port:32 p_in) {
  unsigned time;
  unsigned x;
  unsigned counter = 0;
  p_in :> x @ time;
  x >>= 31;
  time += 31;

  while (1) {
    select {
    case p_in @ time when pinsneq(x) :> x:
      // Count the number of transitions.
      counter += transitionsLookup[x >> 24];
      counter += transitionsLookup[(x >> 16) & 0xff];
      counter += transitionsLookup[(x >> 8) & 0xff];
      counter += transitionsLookup[x & 0xff];
      // Add 31 to ensure we don't count the same transition multiple times.
      time += 31;
      x >>= 31;
      break;
    case s_intf.getCount() -> unsigned int return_val :
      // Set the return value
      return_val = counter;
      break;
    }
  }
}
richard
Respected Member
Posts: 318
Joined: Tue Dec 15, 2009 12:46 am

Post by richard »

Another idea is to clock a clock block from the 1-bit port you want count transitions on. Then clock a "dummy" port off that clock block (this can be any port - it doesn't even need to be packaged out). Doing an input with timestamp on the dummy port will give you the number of transitions on the port divided by 2. To determine if the number of transitions on the port is odd or even you can peek on the port to see if the current value is high or low. Since the port counter is only 16 bits you probably also want to event off a timed input on the dummy port every so ofthen so that you can count the number of times the port counter has overflowed.
User avatar
lilltroll
XCore Expert
Posts: 956
Joined: Fri Dec 11, 2009 3:53 am
Location: Sweden, Eskilstuna

Post by lilltroll »

Something like this maybe
You can also add peek if you need the LSB to be correct.

Code: Select all

#include <xs1.h>

in port clockpin = XS1_PORT_1A;
clock clk = XS1_CLKBLK_1;

int main(void) {
    timer tmr;
    int count,startval,t;
    unsigned wraps=0;
    configure_clock_src(clk, clockpin);
    start_clock(clk);
    tmr:>t;
    asm("getts %0, res[%1] ": "=r"(startval): "r"(clockpin));

    while(1){
    select{
        case s_intf.getCount() -> unsigned int return_val :
        asm("getts %0, res[%1] ": "=r"(count): "r"(clockpin));
        return_val =  (wraps+(count-startval))<<1;
        break;
        case tmr when timerafter(t+100000):>t:
        //Check if the counter has wrapped, if true wraps+=1<<16.
        break;
    
        }
    }

    return 0;
}
GerhardNorkus
Active Member
Posts: 55
Joined: Wed Jan 05, 2011 2:15 pm

Post by GerhardNorkus »

By the way...apologies if my reply came off as arrogant. Caught you in the middle of the work day and didn't think the reply completely through...
User avatar
octal
XCore Addict
Posts: 228
Joined: Thu Jan 27, 2011 3:30 pm
Location: Argenteuil - France

Post by octal »

@GerhardNorkus
No pb. This wasn't either my intention when I mentioned my previous experience with XMOS. I only wanted to mention that I know the tools and that I was looking to a technical solution even if it uses very advanced features of the chips and dev tools.

Anyway, going to test various solutins propsed here and come back.
Thank to everyone.