Forum Rule: Always post complete source code & details to reproduce any issue!
Page 3 of 3 FirstFirst 1 2 3
Results 51 to 58 of 58

Thread: Ideas on a T4 parallel library using FlexIO

  1. #51
    Senior Member xxxajk's Avatar
    Join Date
    Nov 2013
    Location
    Buffalo, NY USA
    Posts
    591

    Cool Some polling results

    Been optimizing the parallel display here (polled, 8bit and 16bit) and I thought I would share my results:

    Code:
    8bit
    ILI9341 Test!
    Display Power Mode: 0x9C
    MADCTL Mode: 0x48
    Pixel Format: 0x5
    Image Format: 0x0
    Self Diagnostic: 0xC0
    Benchmark                Time (microseconds)
    Screen fill              40571
    Text                     3860
    Proportional Text        3518
    Lines                    19925
    Horiz/Vert Lines         3395
    Rectangles (outline)     2191
    Rectangles (filled)      83215
    Circles (filled)         16088
    Circles (outline)        15457
    Triangles (outline)      4684
    Triangles (filled)       29904
    Rounded rects (outline)  4834
    Rounded rects (filled)   92047
    Done!
    
    
    16bit
    ILI9341 Test!
    Display Power Mode: 0x9C
    MADCTL Mode: 0x48
    Pixel Format: 0x5
    Image Format: 0x0
    Self Diagnostic: 0xC0
    Benchmark                Time (microseconds)
    Screen fill              19223
    Text                     3568
    Proportional Text        3975
    Lines                    18685
    Horiz/Vert Lines         1689
    Rectangles (outline)     1139
    Rectangles (filled)      39451
    Circles (filled)         11761
    Circles (outline)        15072
    Triangles (outline)      4263
    Triangles (filled)       16499
    Rounded rects (outline)  3893
    Rounded rects (filled)   44945
    Done!
    16bit mode: read/write pixels in one 16bit operation. Both are 16bit 565.
    8 bit does a write in 2 8bit operations, and reads in 3 8bit operations and then has to do a fix-up to get 565.

    Either way, these numbers are quite good, but I think I can still squeeze more out of it.

  2. #52
    Right on, @xxxajk!!! Did you post the code somewhere?

  3. #53
    Senior Member
    Join Date
    Oct 2019
    Posts
    252
    Isn’t this on a Teensy 3.6 & writing to the port register?
    Or did you port your library to a T4.1?

  4. #54
    Senior Member xxxajk's Avatar
    Join Date
    Nov 2013
    Location
    Buffalo, NY USA
    Posts
    591
    T3.6 direct register writing, not released yet, because it's not good enough.

  5. #55
    I figured out a way to combine FlexIO1, FlexIO2, and FlexIO3 together into a single non-blocking parallel interface. This is exciting because it means it should be possible in theory to have a library that enables parallel output on any arbitrary set of FlexIO pins - up to 26 pins on T4.0, 32 pins on MicroMod, and 38 pins on T4.1. Also, it appears that the clock pin can be any arbitrary FlexIO pin as well.

    It's still necessary to use interrupts instead of DMA when FlexIO3 is involved (and if you wanted maximum speed you would want to stick to just one FlexIO). But otherwise I think there could be a lot of freedom to choose any convenient set of pins.

    Here's a proof of concept that ties together all three FlexIOs to make an 8-bit parallel interface. It works fine up to the limit of my test equipment, although I could imagine there could be synchronization issues at really high speeds...
    Code:
    // proof of concept of using FlexIO1, FlexIO2, and FlexIO3 at the same time
    
    #include <Arduino.h>
    #include "FlexIO_t4.h"
    #define SHIFTNUM 4 // number of shifters used (must be 1, 2, 4, or 8)
    #define BYTES_PER_BEAT (sizeof(uint8_t))
    #define BEATS_PER_SHIFTER (sizeof(uint32_t)/BYTES_PER_BEAT)
    #define BYTES_PER_BURST (sizeof(uint32_t)*SHIFTNUM)
    #define SHIFTER_IRQ (SHIFTNUM-1)
    #define TIMER_IRQ 0
    #define FLEXIO_BASE_CLOCK 120000000UL
    #define SHIFT_CLOCK_DIVIDER 10 // shift clock is 120 MHz divided by 10 = 12 MHz
    #define FLEXIO_SHIFT_CLOCK (FLEXIO_BASE_CLOCK/SHIFT_CLOCK_DIVIDER)
    #define FLEXIO_ISR_PRIORITY 64 // interrupt is timing sensitive, so use relatively high priority (supersedes USB)
    
    FlexIOHandler *pFlex1, *pFlex2, *pFlex3;
    IMXRT_FLEXIO_t *p1, *p2, *p3;
    
    uint8_t databuf[32] = {0x05, 0x0A, 0x14, 0x28, 0x50, 0xA0, 0x40, 0x80, 0x05, 0x0A, 0x14, 0x28, 0x50, 0xA0, 0x40, 0x80, 0x05, 0x0A, 0x14, 0x28, 0x50, 0xA0, 0x40, 0x80, 0x05, 0x0A, 0x14, 0x28, 0x50, 0xA0, 0x40, 0x80};
    
    /* variables used by ISR */
    volatile unsigned int bytes_remaining;
    volatile unsigned int bursts_to_complete;
    volatile uint32_t *readPtr1, *readPtr2, *readPtr3;
    uint32_t finalBurstBuffer[SHIFTNUM];
    volatile bool pendingTransfer;
    
    /* 
     * Output  FlexIO  Teensy Pin
     *   D0     2:0     10
     *   D1     2:1     12
     *   D2     2:2     11
     *   D3     1:4     2
     *   D4     1:5     3
     *   D5     1:6     4
     *   D6     3:16    8
     *   D7     3:17    7
     *   CLK    3:2     14
     *   
     *   FlexIO1 outputs 8 bits starting on FlexIO1:1 with no clock output.
     *   FlexIO2 outputs 8 bits starting on FlexIO2:0 with no clock output.
     *   FlexIO3 outputs 8 bits starting on FlexIO3:10 with clock output on FlexIO3:2.
     */
    
    void setup() {
        Serial.begin(115200);
        Serial.print(CrashReport);
        Serial.println("Start setup");
    
        pinMode(15, OUTPUT);
        digitalWriteFast(15, LOW);
    
        FlexIO_Init();
    }
    
    void loop() {
        transmitAsync(databuf, 32);
    
        delay(1000);
    }
    
    void transmitAsync(void *src, uint32_t bytes) {
    
    
        while (pendingTransfer) {
          yield(); // wait until previous transfer is complete
        }
        pendingTransfer = true;
    
        bursts_to_complete = bytes / BYTES_PER_BURST;
    
        int remainder = bytes % BYTES_PER_BURST;
        if (remainder != 0) {
            memset(finalBurstBuffer, 0, sizeof(finalBurstBuffer));
            memcpy(finalBurstBuffer, (uint8_t*)src + bytes - remainder, remainder);
            bursts_to_complete++;
        }
        bytes_remaining = bytes;
      
        /*   Synchronize FlexIO timers by using precise timing.
         *   FlexIO1, FlexIO2, and FlexIO3 are triggered in sequence with precise delay time equal to the burst time.  
         *   The first two bursts (FlexIO1 and FlexIO2 only) are "dummy" bursts of all zeros with no clock signal. 
         *   Then all three FlexIOs output data simultaneously starting with the third burst.
         *   Triggering occurs when data is written to the last shifter SHIFTBUF[SHIFTNUM-1].
         */
    
        uint8_t beats = SHIFTNUM * BEATS_PER_SHIFTER;
        p1->TIMCMP[0] = ((beats * 2U - 1) << 8) | (SHIFT_CLOCK_DIVIDER / 2U - 1U);
        p2->TIMCMP[0] = ((beats * 2U - 1) << 8) | (SHIFT_CLOCK_DIVIDER / 2U - 1U);
        p3->TIMCMP[0] = ((beats * 2U - 1) << 8) | (SHIFT_CLOCK_DIVIDER / 2U - 1U);
    
        uint32_t burst_cycles = (F_CPU_ACTUAL) * ((SHIFTNUM * BEATS_PER_SHIFTER) / ((float) FLEXIO_SHIFT_CLOCK));
        uint32_t cycleStart = ARM_DWT_CYCCNT;
        uint32_t cycleDelay;
    
        // load zeros for dummy burst without triggering yet
        for (int i = 0; i < SHIFTNUM - 1; i++) {
            p1->SHIFTBUF[i] = 0;
        }
    
        // trigger dummy burst
        cycleDelay = burst_cycles;
        __disable_irq();
        while (ARM_DWT_CYCCNT - cycleStart < cycleDelay) ;
        p1->SHIFTBUF[SHIFTNUM - 1] = 0;
        __enable_irq();
        while (0 == (p1->SHIFTSTAT & (1 << (SHIFTNUM - 1)))) ; // wait for dummy burst to start
    
        // load zeros for dummy burst without triggering yet
        for (int i = 0; i < SHIFTNUM - 1; i++) {
            p1->SHIFTBUF[i] = 0;
            p2->SHIFTBUF[i] = 0;
        }
    
        // trigger dummy burst
        cycleDelay += burst_cycles;
        __disable_irq();
        p1->SHIFTBUF[SHIFTNUM - 1] = 0;
        while (ARM_DWT_CYCCNT - cycleStart < cycleDelay) ;
        p2->SHIFTBUF[SHIFTNUM - 1] = 0;
        __enable_irq();
        while (0 == (p2->SHIFTSTAT & (1 << (SHIFTNUM - 1)))) ; // wait for dummy burst to start
    
        // load data for first data burst without triggering yet
        if (bytes_remaining < BYTES_PER_BURST) {
            beats = bytes_remaining / BYTES_PER_BEAT;
            p1->TIMCMP[0] = ((beats * 2U - 1) << 8) | (SHIFT_CLOCK_DIVIDER / 2U - 1U);
            p2->TIMCMP[0] = ((beats * 2U - 1) << 8) | (SHIFT_CLOCK_DIVIDER / 2U - 1U);
            p3->TIMCMP[0] = ((beats * 2U - 1) << 8) | (SHIFT_CLOCK_DIVIDER / 2U - 1U);
            readPtr1 = finalBurstBuffer;
            readPtr2 = finalBurstBuffer;
            readPtr3 = finalBurstBuffer;
            bytes_remaining = 0;
        } else {
            readPtr1 = (uint32_t*)src;
            readPtr2 = (uint32_t*)src;
            readPtr3 = (uint32_t*)src;
            bytes_remaining -= BYTES_PER_BURST;
        }
        for (int i = 0; i < SHIFTNUM - 1; i++) {
            p1->SHIFTBUF[i] = *readPtr1++;
            p2->SHIFTBUF[i] = *readPtr2++;
            p3->SHIFTBUF[i] = *readPtr3++;
        }
    
        // trigger first data burst
        cycleDelay += burst_cycles;
        __disable_irq();
        p1->SHIFTBUF[SHIFTNUM - 1] = *readPtr1++;
        p2->SHIFTBUF[SHIFTNUM - 1] = *readPtr2++;
        while (ARM_DWT_CYCCNT - cycleStart < cycleDelay) ;
        p3->SHIFTBUF[SHIFTNUM - 1] = *readPtr3++;
        __enable_irq();
    
        asm("dsb");
    
        // now that clocks are synchronized, use an interrupt to trigger following bursts
        p3->TIMSTAT = (1 << TIMER_IRQ); // clear timer interrupt signal
        p3->TIMIEN |= (1 << TIMER_IRQ);
        p3->SHIFTSIEN |= (1 << SHIFTER_IRQ);
    
    }
    
    FASTRUN void isr() {
    
        if (p3->TIMSTAT & (1 << TIMER_IRQ)) { // interrupt from end of burst
            p3->TIMSTAT = (1 << TIMER_IRQ); // clear timer interrupt signal
            bursts_to_complete--;
            if (bursts_to_complete == 0) {
                p3->TIMIEN &= ~(1 << TIMER_IRQ); // disable timer interrupt
                pendingTransfer = false;
                asm("dsb");
                transferCompleteCallback();
                return;
            }
        }
    
        if (p3->SHIFTSTAT & (1 << SHIFTER_IRQ)) { // interrupt from empty shifter buffer
            if (bytes_remaining == 0) { // just started final burst, no data to load
                p3->SHIFTSIEN &= ~(1 << SHIFTER_IRQ); // disable shifter interrupt
            } else if (bytes_remaining < BYTES_PER_BURST) { // just started second-to-last burst, load data for final burst
                uint8_t beats = bytes_remaining / BYTES_PER_BEAT;
                p1->TIMCMP[0] = ((beats * 2U - 1) << 8) | (SHIFT_CLOCK_DIVIDER / 2U - 1U);
                p2->TIMCMP[0] = ((beats * 2U - 1) << 8) | (SHIFT_CLOCK_DIVIDER / 2U - 1U);
                p3->TIMCMP[0] = ((beats * 2U - 1) << 8) | (SHIFT_CLOCK_DIVIDER / 2U - 1U);
                readPtr1 = finalBurstBuffer;
                readPtr2 = finalBurstBuffer;
                readPtr3 = finalBurstBuffer;
                bytes_remaining = 0;
                for (int i = 0; i < SHIFTNUM; i++) {
                    p1->SHIFTBUF[i] = *readPtr1++;
                    p2->SHIFTBUF[i] = *readPtr2++;
                    p3->SHIFTBUF[i] = *readPtr3++;
                }
            } else {
                bytes_remaining -= BYTES_PER_BURST;
                for (int i = 0; i < SHIFTNUM; i++) {
                    p1->SHIFTBUF[i] = *readPtr1++;
                    p2->SHIFTBUF[i] = *readPtr2++;
                    p3->SHIFTBUF[i] = *readPtr3++;
                }
            }
        }
    
        asm("dsb");
    }
    
    void transferCompleteCallback() {
        digitalWriteFast(15, HIGH);
        delayNanoseconds(80);
        digitalWriteFast(15, LOW);
        //  Serial.println("d");
    }
    
    
    void FlexIO_Init() {
      
        /* Get FlexIO channels */
        pFlex1 = FlexIOHandler::flexIOHandler_list[0]; // use FlexIO1
        pFlex2 = FlexIOHandler::flexIOHandler_list[1]; // use FlexIO2
        pFlex3 = FlexIOHandler::flexIOHandler_list[2]; // use FlexIO3
    
        /* Pointer to the port structures in the FlexIO channels */
        p1 = &pFlex1->port();
        p2 = &pFlex2->port();
        p3 = &pFlex3->port();
    
        /* Pointer to the hardware structures in the FlexIO channels */
        const FlexIOHandler::FLEXIO_Hardware_t *hw1, *hw2, *hw3;
        hw1 = &pFlex1->hardware();
        hw2 = &pFlex2->hardware();
        hw3 = &pFlex3->hardware();
    
        /* Basic pin setup */
        pinMode(10, OUTPUT); // FlexIO2:0
        pinMode(12, OUTPUT); // FlexIO2:1
        pinMode(11, OUTPUT); // FlexIO2:2
        pinMode(2, OUTPUT);  // FlexIO1:4
        pinMode(3, OUTPUT);  // FlexIO1:5
        pinMode(4, OUTPUT);  // FlexIO1:6
        pinMode(8, OUTPUT);  // FlexIO3:16
        pinMode(7, OUTPUT);  // FlexIO3:17
        pinMode(14, OUTPUT); // FlexIO3:2
        
        /* High speed and drive strength configuration */
        *(portControlRegister(10)) = 0xFF;
        *(portControlRegister(12)) = 0xFF;
        *(portControlRegister(11)) = 0xFF;
        *(portControlRegister(2)) = 0xFF;
        *(portControlRegister(3)) = 0xFF;
        *(portControlRegister(4)) = 0xFF;
        *(portControlRegister(8)) = 0xFF;
        *(portControlRegister(7)) = 0xFF;
        *(portControlRegister(14)) = 0xFF;
    
        /* Set clock */
        switch (FLEXIO_BASE_CLOCK) {
            case 480000000UL:
                pFlex1->setClockSettings(3, 0, 0); // (480 MHz PLL3_SW_CLK clock, CLK_PRED=1, CLK_PODF=1)
                pFlex2->setClockSettings(3, 0, 0); // (480 MHz PLL3_SW_CLK clock, CLK_PRED=1, CLK_PODF=1)
                pFlex3->setClockSettings(3, 0, 0); // (480 MHz PLL3_SW_CLK clock, CLK_PRED=1, CLK_PODF=1)
                break;
            case 240000000UL:
                pFlex1->setClockSettings(3, 1, 0); // (480 MHz PLL3_SW_CLK clock, CLK_PRED=2, CLK_PODF=1)
                pFlex2->setClockSettings(3, 1, 0); // (480 MHz PLL3_SW_CLK clock, CLK_PRED=2, CLK_PODF=1)
                pFlex3->setClockSettings(3, 1, 0); // (480 MHz PLL3_SW_CLK clock, CLK_PRED=2, CLK_PODF=1)
                break;
            case 120000000UL:
            default:
                pFlex1->setClockSettings(3, 1, 1); // (480 MHz PLL3_SW_CLK clock, CLK_PRED=2, CLK_PODF=2)
                pFlex2->setClockSettings(3, 1, 1); // (480 MHz PLL3_SW_CLK clock, CLK_PRED=2, CLK_PODF=2)
                pFlex3->setClockSettings(3, 1, 1); // (480 MHz PLL3_SW_CLK clock, CLK_PRED=2, CLK_PODF=2)
                break;
        }
        // Remark: 120 MHz is the maximum FlexIO frequency shown in the reference manual, but testing shows that 240 MHz works.
        // 480 MHz has also been shown to work but some bugs may occur if CPU speed is less than 600 MHz...
    
        /* Set up pin mux */
        pFlex2->setIOPinToFlexMode(10);
        pFlex2->setIOPinToFlexMode(12);
        pFlex2->setIOPinToFlexMode(11);
        pFlex1->setIOPinToFlexMode(2);
        pFlex1->setIOPinToFlexMode(3);
        pFlex1->setIOPinToFlexMode(4);
        pFlex3->setIOPinToFlexMode(8);
        pFlex3->setIOPinToFlexMode(7);
        pFlex3->setIOPinToFlexMode(14);
    
        /* Enable the clocks */
        hw1->clock_gate_register |= hw1->clock_gate_mask  ;
        hw2->clock_gate_register |= hw2->clock_gate_mask  ;
        hw3->clock_gate_register |= hw3->clock_gate_mask  ;
    
        /* configure FlexIO registers */
        FlexIO_Config(p1, 1, 0xFF);
        FlexIO_Config(p2, 0, 0xFF);
        FlexIO_Config(p3, 10, 2);
    
        /* configure interrupts on FlexIO3 */
        attachInterruptVector(hw3->flex_irq, isr);
        NVIC_ENABLE_IRQ(hw3->flex_irq);
        NVIC_SET_PRIORITY(hw3->flex_irq, FLEXIO_ISR_PRIORITY);
    
        // disable interrupts until later
        p3->SHIFTSIEN &= ~(1 << SHIFTER_IRQ);
        p3->TIMIEN &= ~(1 << TIMER_IRQ);
    }
    
    static void FlexIO_Config(IMXRT_FLEXIO_t *p, uint8_t shifterPin, uint8_t timerPin) {
        // shifterPin and timerPin are FlexIO pin numbers, not Teensy pin numbers
    
        uint8_t beats = SHIFTNUM * BEATS_PER_SHIFTER;
        Serial.printf("Multi Beat Quantity: %d \n", beats);
    
        const uint8_t shiftWidth = 8; // 8 bits
        const uint8_t timerIndex = TIMER_IRQ;
        const uint8_t triggerShifterIndex = SHIFTER_IRQ;
    
        /* Disable and reset FlexIO */
        p->CTRL &= ~FLEXIO_CTRL_FLEXEN;
    
        /* Configure the shifters */
        for (int i = 0; i <= SHIFTNUM - 1; i++)
        {
            p->SHIFTCFG[i] =
                FLEXIO_SHIFTCFG_INSRC * (1U)                                             /* Shifter input from next shifter's output */
                | FLEXIO_SHIFTCFG_SSTOP(0U)                                               /* Shifter stop bit disabled */
                | FLEXIO_SHIFTCFG_SSTART(0U)                                              /* Shifter start bit disabled and loading data on enabled */
                | FLEXIO_SHIFTCFG_PWIDTH(shiftWidth - 1U);            /* Shifter shift width */
        }
    
        p->SHIFTCTL[0] =
            FLEXIO_SHIFTCTL_TIMSEL(timerIndex)                         /* Shifter's assigned timer index */
            | FLEXIO_SHIFTCTL_TIMPOL * (0U)                                            /* Shift on posedge of shift clock */
            | FLEXIO_SHIFTCTL_PINCFG(3U)                                              /* Shifter's pin configured as output */
            | FLEXIO_SHIFTCTL_PINSEL(shifterPin)                    /* Shifter's pin start index */
            | FLEXIO_SHIFTCTL_PINPOL * (0U)                                            /* Shifter's pin active high */
            | FLEXIO_SHIFTCTL_SMOD(2U);               /* shifter mode transmit */
    
        for (int i = 1; i <= SHIFTNUM - 1; i++)
        {
            p->SHIFTCTL[i] =
                FLEXIO_SHIFTCTL_TIMSEL(timerIndex)                         /* Shifter's assigned timer index */
                | FLEXIO_SHIFTCTL_TIMPOL * (0U)                                            /* Shift on posedge of shift clock */
                | FLEXIO_SHIFTCTL_PINCFG(0U)                                              /* Shifter's pin configured as output disabled */
                | FLEXIO_SHIFTCTL_SMOD(2U);               /* shifter mode transmit */
        }
    
        /* Configure the timer for shift clock */
        p->TIMCMP[timerIndex] =
            ((beats * 2U - 1) << 8)                                     /* TIMCMP[15:8] = number of beats x 2  1 */
            | (SHIFT_CLOCK_DIVIDER / 2U - 1U);                          /* TIMCMP[7:0] = shift clock divide ratio / 2 - 1 */
    
        p->TIMCFG[timerIndex] =   FLEXIO_TIMCFG_TIMOUT(0U)                                                /* Timer output logic one when enabled and not affected by reset */
                                  | FLEXIO_TIMCFG_TIMDEC(0U)                                                /* Timer decrement on FlexIO clock, shift clock equals timer output */
                                  | FLEXIO_TIMCFG_TIMRST(0U)                                                /* Timer never reset */
                                  | FLEXIO_TIMCFG_TIMDIS(2U)                                                /* Timer disabled on timer compare */
                                  | FLEXIO_TIMCFG_TIMENA(2U)                                                /* Timer enabled on trigger high */
                                  | FLEXIO_TIMCFG_TSTOP(0U)                                                 /* Timer stop bit disabled */
                                  | FLEXIO_TIMCFG_TSTART * (0U);                                            /* Timer start bit disabled */
    
        if (timerPin != 0xFF) { // output clock signal
    
            p->TIMCTL[timerIndex] =
                FLEXIO_TIMCTL_TRGSEL((triggerShifterIndex << 2) | 1U)                             /* Timer trigger selected as highest shifter's status flag */
                | FLEXIO_TIMCTL_TRGPOL * (1U)                                              /* Timer trigger polarity as active low */
                | FLEXIO_TIMCTL_TRGSRC * (1U)                                              /* Timer trigger source as internal */
                | FLEXIO_TIMCTL_PINCFG(3U)                                                /* Timer' pin configured as output */
                | FLEXIO_TIMCTL_PINSEL(timerPin)                         /* Timer' pin index */
                | FLEXIO_TIMCTL_PINPOL * (1U)                                              /* Timer' pin active low */
                | FLEXIO_TIMCTL_TIMOD(1U);                                                 /* Timer mode 8-bit baud counter */
    
        } else { // no clock output
    
            p->TIMCTL[timerIndex] =
                FLEXIO_TIMCTL_TRGSEL((triggerShifterIndex << 2) | 1U)                             /* Timer trigger selected as highest shifter's status flag */
                | FLEXIO_TIMCTL_TRGPOL * (1U)                                              /* Timer trigger polarity as active low */
                | FLEXIO_TIMCTL_TRGSRC * (1U)                                              /* Timer trigger source as internal */
                | FLEXIO_TIMCTL_PINCFG(0U)                                                /* Timer' pin output disabled */
                | FLEXIO_TIMCTL_TIMOD(1U);                                                 /* Timer mode 8-bit baud counter */
        }
    
        /* Enable FlexIO with fast access */
    
        p->CTRL |= FLEXIO_CTRL_FLEXEN | FLEXIO_CTRL_FASTACC;
    }
    Screenshot of logic analyzer sampling at 24 MHz, showing good synchronization. D7 not shown, since I only have an 8 channel logic analyzer and CLK is connected to D7.
    Click image for larger version. 

Name:	multiFlexIO.jpg 
Views:	21 
Size:	86.8 KB 
ID:	26435

  6. #56
    Senior Member xxxajk's Avatar
    Join Date
    Nov 2013
    Location
    Buffalo, NY USA
    Posts
    591
    Very cool. Note I do not mind if data sent out is polled, I can imagine that DMA could have an advantage in many cases. Keep up the haxxoring!

  7. #57
    Senior Member
    Join Date
    Oct 2019
    Posts
    252
    @easone - amazing work!
    It would be worth hooking this up to one of the ILI displays and trying to send commands/data and see if it can accept anything.
    Now I see how this would work for writing data out from the Teensy, but can we flip it around and read data in from the parallel port?

  8. #58
    Very impressive. Nice work.

Posting Permissions

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