You are here

"Artificial" SPI when using GPIF-II 32-bit mode | Cypress Semiconductor

"Artificial" SPI when using GPIF-II 32-bit mode

Summary: 3 Replies, Latest post by MyDirtIsRed on 04 Jun 2015 09:22 AM PDT
Verified Answers: 0
Last post
Log in to post new comments.
MyDirtIsRed's picture
10 posts


Please bear with my multi-threaded ignorance...

For our current application, we're using the 32-bit GPIF-II mode, and thus the SPI peripheral is not available.  We have another device off to the side that we've connected to three GPIO on the FX3 to act as chip select, clock, and data (we did basically the same thing with a project we did that used the FX2 chip).  We want this interface to work at close to its maximum speed, which is 20MHz according to the interfacing component's data sheet.  In our previous iteration, we'd drive chip select and the clock low, drive the data to its desired value, run a couple of 'nop' calls for setup time, bring the clock high, run a couple of 'nop' calls for hold time, and then bring the clock signal low again, all in a loop until the message was finished.  I tried to implement something similar on the FX3, but it runs quite a bit slower than I anticipated.  I'm thinking it's due to the multi-threaded nature of the underlying OS, but I'm not an expert on this, so I've come to the forums.  Here's my code:

SwXTimesFiveNsDelay( uint8_t x )
    int i;
    for (i = 0; i < x; i++)

SwSpiWriteToDac( uint16_t val )
    signed char b;
    /* Don't let anything get in the way of this routine; disable all
     * interrupts, but make sure we know which interrupts were enabled before we
     * disabled them. */
    uint32_t    currentIRQs = CyU3PVicDisableAllInterrupts();

    /* Turn on the chip select */
    CyU3PGpioSetValue( GPIO_HVCTRLCS_L, CyFalse );
    /* Force clock low if it isn't already */
    CyU3PGpioSetValue( GPIO_HVCTRLSCK, CyFalse );

    for(b = 15; b >= 0; b--)
        if (val & (1 << b))
            CyU3PGpioSetValue( GPIO_HVCTRLSDI, CyTrue );
            CyU3PGpioSetValue( GPIO_HVCTRLSDI, CyFalse );
        SwXTimesFiveNsDelay(6);  // 50% duty cycle clock, ~16.8MHz
        CyU3PGpioSetValue( GPIO_HVCTRLSCK, CyTrue );  // Bring clock high
        SwXTimesFiveNsDelay(6);  // Hold high for the rest of the duty cycle
        CyU3PGpioSetValue( GPIO_HVCTRLSCK, CyFalse );  // Bring clock low
    /* Disable DAC */
    CyU3PGpioSetValue( GPIO_HVCTRLCS_L, CyTrue );

    /* Re-enable previously disabled interrupts */
    CyU3PVicEnableInterrupts( currentIRQs );

The actual logic of the code is fine; it does exactly what I expect it to logically on the scope.  However, the calls to CyU3PGpioSetValue appear to take ~1.2us, and the __nop's take ~63ns.  I didn't really now how long the CyU3PGpioSetValue call was going to take, and my calculations were that a __nop would take 4.96ns when using a system clock of 403.2MHz (CPU clock is half the system clock).

Thread priority is '8', and it's one of two threads running, the other being a low-priority debug thread.

Thanks in advance.

mady's picture
Cypress Employee
964 posts


It is impossible to achieve 20 MHz using Bit Banging. To increase the speed, pls use CyU3PGpioSimpleSetValue instead of CyU3PGpioSetValue.

To increase the speed further, you can toggle the GPIOs by writing to the GPIO registers directly instead of APIs.


GPIO->lpp_gpio_simple[21] = GPIO->lpp_gpio_simple[21] ^ 1;

//This toggles GPIO 21. The last bit of this register is the output value of the correspnding GPIO (21 in this case)

For accessing the registers directly, add #include "gpio_regs.h" in your project


- Madhu Sudhan



Dtimon's picture
5 posts

This is very interesting approach. Thanks for posting the suggestion. Out of curiosity, what maximum clocking frequency could be achieved using this approach?

MyDirtIsRed's picture
10 posts


I essentially implemented the code that was suggested.  I am able to achieve a little over 1MHz using the suggested method, which is plenty fast enough for my application.  YMMV.

Log in to post new comments.