This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Capturing GPIO transitions of a 4kHz signal with BLE enabled

I need to capture the time between rising transition of a GPIO pin in order to integrate a Manchester decoder of an RFID reader chip. In my particular case, the reader chip emits a waveform where the minimum time between the rising edges is ~256uS. The device I'm working on is a BLE peripheral and ideally, I'd like to run both interfaces concurrently.

This is all running on an nRF52840-DK board with FreeRTOS.

I hacked together an initial prototype where

  1. I linked a PPI with GPIOE and TIMER1 where the rising edge causes the timer count to be captured
  2. An IRQ on the GPIO rising edge to cache the last capture (thus getting a very accurate measurement)

This all works fine when BLE is disabled, however as soon as enable it (the device starts advertising), I appear to be missing transitions.

I'm yet to really drill down to identify how/when the transitions are missed, however I thought I might check to see if anyone can suggest a better scheme to capture the timing.

Thanks.

DJ

Parents
  • If you know the clock frequency and length you can set up a TIMER to trigger a SAADC sample task in the middle of each positive clock period. You start the TIMER on a GPIOTE pin change. That way you can capture a waveform and store it in RAM without using the CPU at all, and then process the data whenever the CPU is available. 

    Since the signal is digital it should be fairly easy to convert from analog to digital, I suppose you can right-shift the analog 16-bit integer down to msb, then XOR with 1 to get the original data bit. 

    ex:
    At 10-bit accuracy, say the SAADC samples yield between 512-1023dec for '1's and 0-511dec for '0's. Then right shifting the samples by 9 bits will leave you with the manchester-encoded bit. 

    The samples are stored as an array, so for a 32-bit transmission, you will need a buffer size of 16bit x 32 = 64bytes

    #define BufSize 32
    
    int16_t     MyBuffer[BufSize];
    uint32_t    Data = 0;
    
    //After the data is captured:
    for(uint16_t i=0; i < BufSize; i++)
    {
        My_Buffer[i] &= 0x3FF;          // Remove sign bit if a '0' is registered as negative number
        
        MyBuffer[i] = (MyBuffer >> 9);  /* '9', because at 10-bit precision with signed value 
                                        the 9th bit is half of max value*/
                                        
        Data |= (MyBuffer[i] << i);        // OR-in the Manchester-encoded bit into a data buffer
    }
    Data ^= 0xFFFFFFFF; //XOR with the clock signal, represented by '1's. 
    
    //Repeat for however many 32-bit words your transfers are.
    
    .



Reply
  • If you know the clock frequency and length you can set up a TIMER to trigger a SAADC sample task in the middle of each positive clock period. You start the TIMER on a GPIOTE pin change. That way you can capture a waveform and store it in RAM without using the CPU at all, and then process the data whenever the CPU is available. 

    Since the signal is digital it should be fairly easy to convert from analog to digital, I suppose you can right-shift the analog 16-bit integer down to msb, then XOR with 1 to get the original data bit. 

    ex:
    At 10-bit accuracy, say the SAADC samples yield between 512-1023dec for '1's and 0-511dec for '0's. Then right shifting the samples by 9 bits will leave you with the manchester-encoded bit. 

    The samples are stored as an array, so for a 32-bit transmission, you will need a buffer size of 16bit x 32 = 64bytes

    #define BufSize 32
    
    int16_t     MyBuffer[BufSize];
    uint32_t    Data = 0;
    
    //After the data is captured:
    for(uint16_t i=0; i < BufSize; i++)
    {
        My_Buffer[i] &= 0x3FF;          // Remove sign bit if a '0' is registered as negative number
        
        MyBuffer[i] = (MyBuffer >> 9);  /* '9', because at 10-bit precision with signed value 
                                        the 9th bit is half of max value*/
                                        
        Data |= (MyBuffer[i] << i);        // OR-in the Manchester-encoded bit into a data buffer
    }
    Data ^= 0xFFFFFFFF; //XOR with the clock signal, represented by '1's. 
    
    //Repeat for however many 32-bit words your transfers are.
    
    .



Children
  • Can you specify exactly what kind of Manchester encoding you're using?
    Can you ensure that each transfer starts with a low-to-high or optionally high-to-low transition? 

  • Hi Thanks very much for your response.

    That's an interesting idea... I hadn't considered using the ADC to manually sample a waveform. However, I'm a bit confused with your suggestion to start the timer on the rising edge. Did you mean the *first* rising edge of the signal or *every* rising edge?

  • This is a bit tricky to answer. I'm interfacing with an HTRC110 reader chip and none of the documentation clearly states what Type of Manchester it is. The only reason I believe it's Manchester is because a sample driver found here mentions it.

    I had a look at a waveform of the RF chip on an existing product (I don't have the source for it) and it's a waveform with a minimum duration of 256us between two rising edges. This tallies with the comments in the sample code.

  • Only the first rising edge (or low, as long as it's consistent), we can use the first rising edge to trigger the start of a TIMER that in turn triggers SAADC sampling in the middle of the positive clock periods. 


  • The HTRC110 does not appear to be using a manchester encoded protocol since it has a separate clock signal. The defining attribute of a manchester encoded signal is that it's self-clocking, where the clock signal is modulated into the signal itself. 

    But this does not really change much in your case, it actually makes things a lot easier since the MCU controls the SCLK and DIN lines. Now we can use the SCLK timings to trigger SAADC sampling of the DOUT line on positive clock periods. 

    See "Fig 4. Serial signaling" in https://www.nxp.com/docs/en/data-sheet/037031.pdf.


    What you need to do:

    1. Create a clock signal with a TIMER and GPIOTE. 

    2. Create a driver for the digital input line, DIN, with manual SW GPIO toggling or maybe even use the PWM peripheral for that. I'm not 100% sure we can use the PWM for this, but if we can then you will be able to send commands to the HTRC110 without using the CPU to control the GPIO for the DIN line, as the PWM peripheral can be configured to use a pre-defined 'sequence' in RAM with EasyDMA. 

    3. Setup the SAADC to sample on the SCLK's positive flank changes, based on the TIMER it runs on. 

    4. Run the process I described earlier on the samples to get the data. 
Related