Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 7 of 7

Thread: Faster way to read in digital inputs into a byte value

  1. #1

    Faster way to read in digital inputs into a byte value

    I have an application capturing both analog and digital data up to a rate of 128ksps.

    At the moment the ISR is taking too much time and making the 128ksps rate unviable for streaming purposes.

    I have determined that the digital input reading and byte assembly is by far the slowest part of the routine (below).

    Note that these inputs are not readable as a single byte (unfortunately).

    void adcDataReadyIsrStream(){
        ultemp = micros() - loggerStatus.logStartTimeMicro;
        //mCurPosValue =;     // taking 
        // update digital inputs here as the ISRs for the digital inputs will be disabled 
        bitWrite(digitalInputs, 0,digitalReadFast(DIN0));
        bitWrite(digitalInputs, 1,digitalReadFast(DIN1));
        bitWrite(digitalInputs, 2,digitalReadFast(DIN2));
        bitWrite(digitalInputs, 3,digitalReadFast(DIN3));
        bitWrite(digitalInputs, 4,digitalReadFast(DIN4));
        bitWrite(digitalInputs, 5,digitalReadFast(DIN5));
        bitWrite(digitalInputs, 6,digitalReadFast(DIN6));
        bitWrite(digitalInputs, 7,digitalReadFast(DIN7));
        myQueueWrite((uint8_t)(0xFF & ultemp));               // elapsed time
        myQueueWrite((uint8_t)(res.chan1_16&0xFF));       // analog channel 1
        myQueueWrite((uint8_t)(res.chan2_16&0xFF));       // analog channel 1
        myQueueWrite((uint8_t)(res.chan3_16&0xFF));       // analog channel 1
        myQueueWrite((uint8_t)(res.chan4_16&0xFF));       // analog channel 1
        myQueueWrite((uint8_t)(mCurPosValue)&0xFF);      // 32 bit encoder counter
        myQueueWrite(digitalInputs);             // digital inputs, automatically update in own ISRs  
        // all added for debugging
       /* myQueueWrite((uint8_t)(myCircBuffer.length)&0xFF);      // 32 bit encoder counter
        myQueueWrite((uint8_t)(myCircBuffer.writeIndex)&0xFF);      // 32 bit encoder counter
        myQueueWrite((uint8_t)(myCircBuffer.readIndex)&0xFF);      // 32 bit encoder counter
    The digitial input read and byte value assignment is taking an average of 206ns out of a total of 375ns so pretty horrible.

    Obviously my code is terribly inefficient but I'm not sure which approach would be significantly faster?

    I have not implemented ISRs to service the digital inputs individually as I need to keep the ADC ISR very high priority and low jitter.

  2. #2
    Found this thread which looks very useful, I'll convert my code and report back on the new time consumed.

  3. #3
    This is roughly the code I'll try out this evening

    #define IMXRT_GPIO6_DIRECT  (*(volatile uint32_t *)0x42000000)
        // read in raw values from single port GPIO6
        register uint32_t rawdata  = IMXRT_GPIO6_DIRECT;  // 0B11111111111111110011000000000000
        // Pin #	bit position	value	  hex value
        // 14	      18	        131072	  20000
        // 15	      19	        262144	  40000
        // 16	      23	        4194304	  400000
        // 17	      22	        2097152	  200000
        // 18	      17	        65536	    10000
        // 19	      16	        32768	    8000
        // 20	      26	        33554432	2000000
        // 21	      27	        67108864	4000000
        // and with the bit mapped to each pin
        digitalInputs = ((rawdata & 0x20000) >> CORE_PIN14_BIT);  // DIN0 is PIN14
        digitalInputs += ((rawdata & 0x40000) >> CORE_PIN15_BIT-1);  // DIN1 is PIN15
        digitalInputs += ((rawdata & 0x400000) >> CORE_PIN16_BIT-2);  // DIN1 is PIN16
        digitalInputs += ((rawdata & 0x200000) >> CORE_PIN17_BIT-3);  // DIN1 is PIN17
        digitalInputs += ((rawdata & 0x10000) >> CORE_PIN18_BIT-4);  // DIN1 is PIN18
        digitalInputs += ((rawdata & 0x80000) >> CORE_PIN19_BIT-5);  // DIN1 is PIN19
        digitalInputs += ((rawdata & 0x2000000) >> CORE_PIN20_BIT-6);  // DIN1 is PIN20
        digitalInputs += ((rawdata & 0x4000000) >> CORE_PIN21_BIT-7);  // DIN1 is PIN21

  4. #4
    Senior Member
    Join Date
    Dec 2013
    East Stroudsburg PA.
    //  T4.1       bit pin
    //01 <-> GPIO6-16 19/A5  AD_B1_00  Data   BIDIR                   Teensy Data BUS 0-7 INPUT & OUTPUT
    //02 <-> GPIO6-17 18/A4  AD_B1_01
    //03 <-> GPIO6-18 14/A0  AD_B1_02
    //04 <-> GPIO6-19 15/A1  AD_B1_03
    //05 <-> GPIO6-20 40/A16 AD_B1_04
    //06 <-> GPIO6-21 41/A17 AD_B1_05
    //07 <-> GPIO6-22 17/A3  AD_B1_06
    //08 <-> GPIO6-23 16/A2  AD_B1_07  Data   BIDIR                   Teensy Data BUS 0-7 INPUT & OUTPUT
    volatile uint32_t GPIO_cs = 0;

    GPIO_cs = GPIO6_PSR >> 16; //sample and shift the bits.
    Last edited by Chris O.; 03-23-2023 at 02:08 AM. Reason: Teensy 4.1 only

  5. #5
    Hi Chris O

    I am still getting my head around (very slowly) the nomenclature and the different labelling levels.

    In the schematic you linked to, what is the 'port' AD_B1 ?

    I need to map my signals in the odd way I've listed as they are wired that way ie in order of the PINS broken o

  6. #6
    Senior Member
    Join Date
    Dec 2013
    East Stroudsburg PA.
    In the schematic you linked to, what is the 'port' AD_B1 ?
    AD_B1_00 basically PORT name similar to Arduino Uno: PORTA, PORTB, PORTC.
    Direct port manipulation will yeld the best performance but you need to connect the wires (pins) correctly so you can read the bits in one go without too many calculations (bit shifting).

  7. #7
    Senior Member+ KurtE's Avatar
    Join Date
    Jan 2014
    For me, the AD_B1_ is the pin name, the GPIO number is closer to the PORTA, B, C, D of the AVR processors.
    For example if you look at my excel sheet in GPIO pin order.
    Click image for larger version. 

Name:	Screenshot.jpg 
Views:	14 
Size:	221.4 KB 
ID:	30688
    You will see a column with name... the AD_B1_ to me is a hint that the pin is likely to be an anlog input pin. some of them that start with SD_... are often used for SDIO (SD), EMC_ for memory...

    Fastest/Best way to do what you want to do? It may depend on how you setup everything. like:

    can you use DMA to do any of this? For example the analog input? The ADC library has examples for doing this. Either as fast as it can go, or by using a clock to govern the interval the conversions happen.

    Digital pins - As Chris mentioned, if you can get the pins in the right order, you might be able to do it with a read in the PSR register and a shift.

    If there is a gap between some of the pins. you might be able to do it with a couple of shifts and an or (might need an and or two).

    If you can get all 8 pins into a consecutive 8 bits but in a scrambled order. you might be able to do it by doing the read in/shift to get them into 8 bits and then use a 256 byte translation (look up) table to convert to the real value.

    And probably lots of other solutions as well.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts