One bit off when receiving ARINC429 with FlexIO

guilhembn

New member
Hello all!
This thread is a new question following this one: https://forum.pjrc.com/index.php?th...rinc429-with-bits-on-two-separate-pins.76239/
I implemented the solution proposed by jmarsh, and it is almost working (code at the end of the post).

Quick sum up: I have a signal (ARINC429) arriving on two different pins: channel A, and channel B. Channel A high and B low means a 1; Channel A low and B high means a 0; both low means no data and both high should not happen. Bits are return to zero encoded (each channel returns to low before the same channel or the other goes high).

The solution proposed by jmarsh is as follows and uses FlexIO. I have two timers (0 and 1) and three shifters (0, 1 and 2).
Timer 0 is simply plugged on FlexIO clock.
Shifter 0 and 1 are in state mode and uses Timer 0: the state represented by the shifter0 is on when both channels are low or when both channels are high; it transitions to state represented by shifter1 when one of the channels (and only one) goes high.
Timer 1 has its trigger set on shifter1 active, decrements on trigger, and compare to 63 (ARINC429 words are 32 bits long), shift clock is set to trigger input.
Shifter 2 is in receive mode, uses Timer 1 and has the Channel A as input.

Everything is almost working as planned except that the first bit in each message is 0 whatever its real value (see screenshots attached).
The state machine is working perfectly, the trigger for Timer1 is generated when one channel goes high or low, I think the issue comes from either the Timer1 or Shifter2.
Indeed, the timer expires (and content of Shifter2 is loaded into the buffer) on the rising of the next message bit, which I think, causes the reading of the channel A to be wrong. I tried to tweak the settings of the Timer1 and Shifter2 but I still can't find the issue.
Have you any idea on how to efficiently debug this problem and maybe correct it?

When I try with 32 bits messages containing only ones (not a valid ARINC message but CRC check will be done later), and reading the FLEXIO2_SHIFTBUFBIS2 buffer when FLEXIO2_SHIFTSTAT & (1 << 2) (by polling, interrupt or DMA will be the problem for another day :D), the result I have is "0x7fffffff" i.e. one zero and 31 ones.

Thanks!

Here is the code:
C++:
// Channel A is plugged in FlexIO2:1 pin (Teensy 4.1 pin 12); Channel B in FlexIO2:0 pin (pin 10)

CCM_CCGR3 |= CCM_CCGR3_FLEXIO2(CCM_CCGR_ON);
FLEXIO2_CTRL |= FLEXIO_CTRL_FLEXEN;
IOMUXC_SW_MUX_CTL_PAD_GPIO_B0_00 = 4;
IOMUXC_SW_MUX_CTL_PAD_GPIO_B0_01 = 4;
// IOMUXC_SW_MUX_CTL_PAD_GPIO_B0_02 = 4;
IOMUXC_SW_MUX_CTL_PAD_GPIO_B0_03 = 4;

// Timer0 Configuration
FLEXIO2_TIMCTL0 = FLEXIO_TIMCTL_TRGSEL(0) | 
    FLEXIO_TIMCTL_PINCFG(0) |  // timer pin output disabled
    FLEXIO_TIMCTL_PINSEL(0) |
    FLEXIO_TIMCTL_TIMOD(3);                              // timer mode 16bit   
FLEXIO2_TIMCFG0 = FLEXIO_TIMCFG_TIMOUT(0) | FLEXIO_TIMCFG_TIMDEC(0) |
    FLEXIO_TIMCFG_TIMRST(0) |                           
    FLEXIO_TIMCFG_TIMDIS(0) |                           
    FLEXIO_TIMCFG_TIMENA(0) |                           
    FLEXIO_TIMCFG_TSTOP(0);                             
FLEXIO2_TIMCMP0 = 0;

// Shifter0 configuration (State0, both channels are low or both are high)
FLEXIO2_SHIFTCTL0 = FLEXIO_SHIFTCTL_TIMSEL(0) |
    FLEXIO_SHIFTCTL_PINCFG(0) |
    FLEXIO_SHIFTCTL_PINSEL(0) |     // Input pins are 0,1,2
    FLEXIO_SHIFTCTL_SMOD(6);        // State mode
FLEXIO2_SHIFTCFG0 = FLEXIO_SHIFTCFG_PWIDTH(0x1F) |  // In state mode FLEXIO2_SHIFTCFG masks output pins.
    FLEXIO_SHIFTCFG_SSTOP(3) | FLEXIO_SHIFTCFG_SSTART(3);  // We don't need any output pins.
FLEXIO2_SHIFTBUF0 = 0x00048048;                                            // First byte set all output to low (masked via SHIFTCFG anyway)
                                                                               // Then next states (group of three bits, starting with input = 7 (0b111); ending at input = 0 (0b000))
                                                                               // are state0 for inputs ending with x11 (should not happen) or x00
                                                                               // and state1 for inputs ending with x10 or x01

// Shifter 1 configuration (State1, channel A xor channel B is high)
FLEXIO2_SHIFTCTL1 = FLEXIO_SHIFTCTL_TIMSEL(0) |
    FLEXIO_SHIFTCTL_PINCFG(0) |     // Open drain and bidirecitonal output
    FLEXIO_SHIFTCTL_PINSEL(0) |     // Input pins are 0,1,2
    FLEXIO_SHIFTCTL_SMOD(6);        // State mode
FLEXIO2_SHIFTCFG1 = FLEXIO_SHIFTCFG_PWIDTH(0x1F) |  // In state mode FLEXIO2_SHIFTCFG masks output pins.
    FLEXIO_SHIFTCFG_SSTOP(3) | FLEXIO_SHIFTCFG_SSTART(3);  // We don't need any output pins.
FLEXIO2_SHIFTBUF1 = 0x00048048;  // First byte sets all pins LOW (they are masked via SHIFTCFG anyway).
// Then next states (group of three bits, starting with input = 7 (0b111); ending at input = 0 (0b000))
// are state0 for inputs ending with x11 (should not happen) or x00
// and state1 for inputs ending with x10 or x01

// Timer1 configuration
FLEXIO2_TIMCTL1 = FLEXIO_TIMCTL_TRGSEL(5) |                            // Set to Shifter 1 status flag : 4*1+1
    FLEXIO_TIMCTL_TRGSRC |                               // Trigger source : internal
    FLEXIO_TIMCTL_PINSEL(3) | FLEXIO_TIMCTL_PINCFG(3) |  // Output on FlexIO2:3 for debugging purposes
    FLEXIO_TIMCTL_TIMOD(3);                              // Single 16-bit counter
FLEXIO2_TIMCFG1 = FLEXIO_TIMCFG_TIMOUT(0) |                           
    FLEXIO_TIMCFG_TIMDEC(3) |                            // Decrement on trigger input; shift clock also on trigger input.
    FLEXIO_TIMCFG_TIMRST(0) |                            // Never reset
    FLEXIO_TIMCFG_TIMDIS(0) |                            // Never disabled
    FLEXIO_TIMCFG_TIMENA(0) |                            // Always enabled
    FLEXIO_TIMCFG_TSTOP(0);                              // No stop bit
FLEXIO2_TIMCMP1 = 63;                                    // ARINC "words" are 32 bits wide. But we decrement on both

// Shifter2 configuration
FLEXIO2_SHIFTCTL2 = FLEXIO_SHIFTCTL_TIMSEL(1) |  // Use timer 1
    FLEXIO_SHIFTCTL_PINCFG(0) |  // output disabled
    FLEXIO_SHIFTCTL_PINSEL(1) |  // Read pin 1 (flexio2:1, Teensy pin 12, ARINC Channel A)
    FLEXIO_SHIFTCTL_SMOD(1);     // Receive mode
FLEXIO2_SHIFTCFG2 = FLEXIO_SHIFTCFG_PWIDTH(0) |  // Read 1 bit at a time
    FLEXIO_SHIFTCFG_SSTOP(0) |   // Stop bit disabled
    FLEXIO_SHIFTCFG_SSTART(0);   // Start bit disabled

And logic analyzer outputs:
1734517696962.png
 
It looks like timer1 is out of sync with the incoming data, I would expect it to toggle state at the end of the word rather than the beginning of the next one.
What happens if it is set to enable on the trigger rising edge and disable on compare?

It's unclear from the 0x7FFFFFFF output exactly which bit is missing; it's either the first or the last, it just indicates that the shift register is only shifting in 31 bits before storing the contents. It can't shift and store on the same "tick", but that shouldn't be a problem because it should be shifting on the rising edges and storing should happen on the falling edge of the last bit.

(Also: what happened to the other thread? It was recent enough that I vaguely remember it, but it seems to have been scrubbed from the forum.)
 
Last edited:
Having a closer look at the code, you should be setting the TIMCTL and SHIFTCTL registers last (after configuring the other registers); setting the operating modes is what activates the timers/shifters and starts them running.
 
Had a bit of a re-think, this can be done simpler with a logic shifter rather than two state shifters:
Code:
  // Channel A is plugged in FlexIO2:1 pin (Teensy 4.1 pin 12); Channel B in FlexIO2:0 pin (pin 10)

  CCM_CCGR3 |= CCM_CCGR3_FLEXIO2(CCM_CCGR_ON);
  FLEXIO2_CTRL |= FLEXIO_CTRL_FLEXEN;
  IOMUXC_SW_MUX_CTL_PAD_GPIO_B0_00 = 4;       // D0 / Channel B
  IOMUXC_SW_MUX_CTL_PAD_GPIO_B0_01 = 4;       // D1 / Channel A
  IOMUXC_SW_MUX_CTL_PAD_GPIO_B0_03 = 4;       // D3 / Timer output (toggles when word completes)

  // Shifter 0 - logic mode, asserts D4 when inputs are 01 or 10
  FLEXIO2_SHIFTCFG0 = FLEXIO_SHIFTCFG_SSTOP(3);    // mask D2+D3
  FLEXIO2_SHIFTBUF0 = 0x66666666;                  // D4 = D0 XOR D1
  FLEXIO2_SHIFTCTL0 = FLEXIO_SHIFTCTL_SMOD(7) |    // logic mode, timer is irrelevant
                      FLEXIO_SHIFTCTL_PINCFG(3);   // drive D4 (not connected / mux not set to FlexIO)

  // Shifter2 configuration
  FLEXIO2_SHIFTCFG2 = FLEXIO_SHIFTCFG_PWIDTH(0) |  // Read 1 bit at a time
                      FLEXIO_SHIFTCFG_SSTOP(0) |   // Stop bit disabled
                      FLEXIO_SHIFTCFG_SSTART(0);   // Start bit disabled
  FLEXIO2_SHIFTCTL2 = FLEXIO_SHIFTCTL_TIMSEL(0) |  // Use timer 0
                      FLEXIO_SHIFTCTL_PINCFG(0) |  // output disabled
                      FLEXIO_SHIFTCTL_PINSEL(1) |  // Read pin 1 (flexio2:1, Teensy pin 12, ARINC Channel A)
                      FLEXIO_SHIFTCTL_SMOD(1);     // Receive mode

  FLEXIO2_TIMCFG0 = FLEXIO_TIMCFG_TIMDEC(3);       // Decrement on trigger input, shift clock on trigger input
  FLEXIO2_TIMCMP0 = (32*2) - 1;                    // word size is 32 bits
  FLEXIO2_TIMCTL0 = FLEXIO_TIMCTL_TRGSEL(4*0+1) |  // trigger is shifter 0's state (could also use pin D4)
                    FLEXIO_TIMCTL_TRGSRC |
                    FLEXIO_TIMCTL_PINCFG(3) | FLEXIO_TIMCTL_PINSEL(3) | // output timer status on D3
                    FLEXIO_TIMCTL_TIMOD(3);        // 16-bit counter

Note that logic shifters are more picky regarding their inputs/outputs; they are fixed depending on which shifter is used, e.g. shifter 0 in logic mode always uses D0-D3 as inputs and D4 as output. On Teensy 4.1 the only FlexIO2 shifter capable of operating in logic mode with a physical output pin is shifter 4, which uses D8-D11 as inputs and D12 as output (pin 32).
 
Having a closer look at the code, you should be setting the TIMCTL and SHIFTCTL registers last (after configuring the other registers); setting the operating modes is what activates the timers/shifters and starts them running.
It works! Thanks a lot! Indeed, I was not really thinking about how everything started... I set all the TIMCTL and SHIFTCTL registers last and activate Timer0 only when everything else is configured (as you have done in your last example, so thanks again!).
I tried to set the Timer1 "to enable on the trigger rising edge and disable on compare" for the sake of completeness and for my understanding, but when everything is setup in the right order, one bit is off again.

I will try your logic mode solution also for my knowledge, but now I am going to try to set the interrupt on store of the Shifter2.

Thanks!

(Indeed I can't see the last thread on the forum anymore. I checked it via the link and it is displayed as "waiting for approval", probably because it is my first post on this forum ?)
 
Back
Top