conditionally read a buffered input Topic is solved

Technical questions regarding the XTC tools and programming with XMOS.
DemoniacMilk
XCore Addict
Posts: 191
Joined: Tue Jul 05, 2016 2:19 pm

conditionally read a buffered input

Post by DemoniacMilk »

First of all: Sorry for asking so many questions.

Im trying to write a 'library' for an SSC interface. Sending data is working well, but I don't understand how receiving data may work in this case.

Setup is the following:
  • Data needs to be read from a bus (1,2,4or8 bits wide).
  • Data is sent in 16 bit wide words
  • Each data line provides one word serialized, so after 16 clock cycles a transfer of n = 1,2,4or8 (depending on bus width) words is completed.
  • Input port is clocked by an external clock.
  • Clock is generated permanently
  • Start of a new word transmit is indicated by an additional SYNC signal on a 1-bit-port being set to high for the first valid clock cycle
I know that sampling/shifting(on buffered ports) is only active when driven by a clock, but as a continous clock is used here, I cannot rely on that. Strobing/ready signals are not an option either from what I understand, as the ready-signal has to remain high during sampling.

From reading documentation I understood that clocked, buffered inputs will right-shift (resulting in an LSB first transmission) the input values into a shift register on a falling port clock edge. If the shift register is filled, it is copied to another register the CPU can read from (correct?). If the previous value has not been read by the CPU, its lost.
Was thinking about adding a flag and use a conditional port input event that is triggered by the SYNC signal being high. If the flag is set, data is read from the input port (case flag => port :> bla:) and reset on having read (16*n, n = bus width) bits to then wait for another SYNC. But if the data sampling/shift registers work as I think, then its undefined how much of the shift register is filled on receiving the SYNC signal and i will read invalid data.

Is there a way to react to the SYNC signal with reading for exactly 16 clock cycles, including the clock cycle the SYNC signal is set to 'high' on?


View Solution
DemoniacMilk
XCore Addict
Posts: 191
Joined: Tue Jul 05, 2016 2:19 pm

Post by DemoniacMilk »

From "Introduction to XS1 ports" (XM004136A), page 4
On each rising edge, data is transferred from the FIFO to the transfer register
starting with the least significant bit (nibble, byte or 16-bit entity).
Does this mean, that providing a clock signal and sending 0xA 0xB 0xC 0xD to a 4-bit 16-bit-buffer port, continous reading results in
0xAXXX, 0xBAXX, 0xCBAX, 0xDCBA, 0xXDCB, ...
or
0xXXXX, 0xXXXX, 0xXXXX, 0xDCBA, 0xXXXX,
DemoniacMilk
XCore Addict
Posts: 191
Joined: Tue Jul 05, 2016 2:19 pm

Post by DemoniacMilk »

Wrote a test software performing an 8 bit data output onto an 8-bit-buffered 1-bit-port and continous reads on another 8-bit-buffered 1-bit-port. The two ports are connected and both clocked continously by an internal clock.

Data output timings are randomized. Output value is ..xx11110..

the main function for data input/output looks like this

Code: Select all

while(1){
        select{
            case t when timerafter(uiTime) :> void:
                portOut <: 0x0F;
                t :> uiTime;
                uiTime += 500 + (rand() % 1000);
                break;
            case portIn :> inTemp:
                input[location] = (unsigned char)inTemp;
                location += 1;
                location = location % 100;
                if (!location){
                    asm("nop");   // for debug
                }
            break;
        }
    }
and creates the following result:
input[33] 0b10000000
input[34] 0b111
input[35] 0b0
input[36] 0b0
input[37] 0b0
input[38] 0b0
input[39] 0b0
input[40] 0b11110000
input[41] 0b0
input[42] 0b0
input[43] 0b0
input[44] 0b11000000
input[45] 0b11
So the buffer is fully filled and then stored into the transmit register for CPU access (what makes perfect sense for most scenarios).

Is there a way of forcing the shift register to be stored in the transmit register, resulting in an empty port buffer and a new read out? That would allow me to set the systm into a defined state on receiveing data.

Edit: Just found "clearbuff()". Semms like thats what I needed. Thank you in case you are reading this.
User avatar
larry
Respected Member
Posts: 275
Joined: Fri Mar 12, 2010 6:03 pm

Post by larry »

One way you could read a de-serialising data port off a sync signal that doesn't stay high would be to get the time of sync rising edge and input data at that time plus 31. Subsequent data inputs will be aligned to this first timed one as long as you are keeping up with data rate. In pseudocode:

p_sync when pinseq(1) :> void @ t
p_data @ (t + 31) :> x
p_data :> x
...

I don't remember if 31 is the correct offset, it might be 30 or 32, which you can check easily in simulation or by experimentation, sending a known pattern such as 0xFF00FF00.

Remember that you can only have de-serialising ("buffered") of 8 or 32, 16 isn't supported.
User avatar
larry
Respected Member
Posts: 275
Joined: Fri Mar 12, 2010 6:03 pm

Post by larry »

I2S slave code in XMOS I2S library uses the technique I described. From i2s_slave_impl.h in lib_i2s on Github:

Code: Select all

        p_lrclk when pinseq(0x80000000) :> int @ port_time;
        port_time += (m == I2S_MODE_I2S);

        for(size_t i=0;i<num_out;i++)
            p_dout[i] @ port_time + 32+32  <: bitrev(i2s_i.send(i*2));

        i2s_slave_send(i2s_i, p_dout, num_out, 1);

        for(size_t i=0;i<num_in;i++)
            asm volatile("setpt res[%0], %1"::"r"(p_din[i]), "r"(port_time + 64+32-1):"memory");
DemoniacMilk
XCore Addict
Posts: 191
Joined: Tue Jul 05, 2016 2:19 pm

Post by DemoniacMilk »

Thank you for your answer. I will give it a try.
I am interested in how the deserializing/port events work.
It sounds like the deserializing is just a shift register, that new values are being shifted into on every falling clock edge, so I can basically read a different value every clock cycle?

But to allow something like

Code: Select all

case port_in :> some_var
is there a counter attached, that triggers an event when n bits, where n is the buffer size, have been shifted into the register?
User avatar
larry
Respected Member
Posts: 275
Joined: Fri Mar 12, 2010 6:03 pm

Post by larry »

I will point you to the XS2 architecture document, section 15.10, Buffered Transfers (also XMOS Programming Guide, section 6.12 Deserializing input data using a port).

A n-bit port has a shift register. Each application clock tick, n-bits are moved into the shift register. Say the port is buffered to m bits, typically 32. Once m bits have been collected in the shift register, it is copied to another register, the transfer register. An input instruction or xC statement gives you contents of the transfer register.