This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

High Speed GPIO Operation

Hello , everyone

I am using MV4 on DM355 EVM.

I want to use multiple GPIO pins for high speed clock generation and high speed data capture simultaneously.

I want to do these operations on 4-5 MHz.For eg. generating 4-5 MHz square wave from 2 pins and reading other 2 pins @ the same time with the same speed.

For my this kind of application ,

1-Is this really possible on such high speed?

2- Will multi threading be beneficial if I use the GPIO pins form the same GPIO Bank?

3- Do you have any smarter way to write a “LIGHT WEIGHT” driver + application??

I have tried writing an application to generate a square wave using “gpio_set_value()”.(from gpio.c),I have gained approx 5 MHz speed on single pin but while using pthreads in application I am not getting  both the waves simultaneously !

Now I want to toggle and read multiple pins around 4-5 MHz …what should I do ???? H E L P !!  ; )

 

  • Digant Desai said:
    1-Is this really possible on such high speed?

    This is really pushing the limits of what is practical to do on a device like this, 5MHz is fairly fast for a 216MHz device to be servicing a piece of hardware, as this means you have only 21 cycles (216MHz / 5MHz * 2 GPIO transitions per period) on the ARM in between each GPIO access in which to manage everything else in the system. Having just 21 cycles available means that almost all of your CPU time will be used by overhead, so any time you had a timer interrupt or needed to do something else other than service the GPIO your GPIO waveform would suffer, this is not something that seems very practical to do in a Linux environment.

    Digant Desai said:
    2- Will multi threading be beneficial if I use the GPIO pins form the same GPIO Bank?

    In general if you can do all the GPIO transactions at the same time without the overhead of having multiple threads that would probably be most efficient.

    Digant Desai said:
    3- Do you have any smarter way to write a “LIGHT WEIGHT” driver + application??

    If at all possible you will probably want to generate your 5MHz clock with external hardware, as mentioned above doing this from software is very taxing on the system. What are you trying to interface to that requires the 5MHz clock and reading from multiple pins? Perhaps this is something you could adapt to interface through the EMIF or serial port using a CPLD or FPGA?

  • Ok  you are absolutely  correct,

    I am having problem of waveform distortion @ 5MHz,

    & thx for the quick reply..:)

    Now if I tell you my application little more specifically,

    I am using an IC in which I am suppose to give it 1-4 MHz clock and read 8 bit data from it on around 4 Mhz !!The data comming out is in SYNC with the clock I am giving .So, Dm355 must aware of  the clock in order to read the data!

    Can I use VPFE for the same ?? If I use PCLK and raw data capture mode for 8-14 bits ???Is it possible to lower down the frequency of VPFE to 4-5 MHz for my application.It would be gr8 if I can do so !!!!!!

    Or any other way  using any internal harware,I mean like VPFE , I can do so ??

    How can I use EMIF for the same ??

    Please HELP ....!!!

  • Digant Desai said:

    Can I use VPFE for the same ?? If I use PCLK and raw data capture mode for 8-14 bits ???Is it possible to lower down the frequency of VPFE to 4-5 MHz for my application.It would be gr8 if I can do so !!!!!!

    The VPFE is not really an option at these speeds, the PCLK speed is specified to be a minimum of 10MHz in the datasheet, so going to 5MHz is not tested and may cause malfunction in the VPFE. Even if it was able to operate at the low frequency, the VPFE is designed to capture image/video like signals, so it needs to have periodic sync signals to operate properly.

    Digant Desai said:
    How can I use EMIF for the same ??

    The EMIF could not be used directly in this case, however if you had some sort of FIFO externally (perhaps in a FPGA/CPLD) that you could connect up to the EMIF to act as a buffer than the EMIF could be a possibility.

  • Thank you very much Bernie..after asking to you yesterday I did find that VPFE is not exactly designed for my kind of application :(

    Now I thing I have to use generic GPIOs for my purpose...I am planning to use EDMA..to copy the data from the GPIO's INDATA resistor to internal memory or to DDR Memory ...To use EDMA for byte by byte transfer is the good way to reduce overheads from arm ?? or is there any other better way ?

    I am thinking I should go like this way...

    1- read the data from INDATA

    2- put it into a local buffer

    3- as the buffer is filled copy it to memory using EDMA

    4-process that data using arm/ipipe once this receive mechanism is finished .

    Will it work ??

    I will be having around 4-6 MB data coming at around 4 MHz...

    If I want to process these data using IPIPE ..where should I copy it using EDMA so it will be best suitable for IPIPE to use..I have read IPIPE & there is a specific buffer for this purpose on SDRAM or DDRAM ..

    Can i access that specific buffer using EDMA directly ???

    Thank you very much bernie for your time.    :)

  • Digant Desai said:
    Now I thing I have to use generic GPIOs for my purpose...I am planning to use EDMA..to copy the data from the GPIO's INDATA resistor to internal memory or to DDR Memory ...To use EDMA for byte by byte transfer is the good way to reduce overheads from arm ?? or is there any other better way ?

    This is a possibility, as long as your data coming in is contiguous enough for your purposes in the INDATA register, and you can synchronize your EDMA somehow. I suppose if your device was the clock slave you could feed the clock into a GPIO pin to trigger the EDMA event, and if your device was the master you could have a timer event trigger the EDMA and have part of the transfer toggle a GPIO to act as the clock. This is still a bit unusual usage for the EDMA and GPIO though, and there may be unforeseen issues (a.k.a. I have not seen this done before).

    Digant Desai said:

    If I want to process these data using IPIPE ..where should I copy it using EDMA so it will be best suitable for IPIPE to use..I have read IPIPE & there is a specific buffer for this purpose on SDRAM or DDRAM ..

    Can i access that specific buffer using EDMA directly ???

    Anywhere in DDR that you have contiguous space available should be fine, the IPIPE reads from DDR memory based on the address put into the ADDRU and ADDRL registers.

  • The peripheral you are talking about here is the SPI interface - the ARM generates the SPI clock to a slave, which then synchronously clocks data back to the ARM (please see the SPI specification, or the SPI datasheet for your Davinci part). This can be serviced by DMA, in which case you can run at any speed on the SPI lanes (1Mhz to 60Mhz i believe)

    Using GPIO to do what you are trying to achieve is not the correct approach on a SoC like the Davinci - that is why they give you so many different kinds of peripherals on these chips :)

    Hope it helps,

    Jerry

  • JerryJohns said:
    The peripheral you are talking about here is the SPI interface

    This is certainly the case for a single data line, I was under the impression that this was capturing several individual lines per cycle, like an 8 bit synchronous bus, though Digant Desai can probably clarify.

  • yes thats what it is, I have data comming through 8 bit wide data bus...so cant use SPI ,  tne ways thx jerry

    Ne how I have to give it a try ….thx for help will definitely let you know my progress :) & I  will ask if I need ur expertise

    right now I am trying to do this by the way  u were telling bernie but with little different approch ...

    & yes The device is generating clock & i have mapped a GPIO interrupt to it.On each rising pulse the 8 bit data is copied to a local buffer ...I am getting around 1.4 MHz spped.

    I ve used ..

    ---------------------------------------------------------------------------------------------

    static unsigned long a[10000];

    static int i;

    irq_function_gpio

    {

    if(i<10000){

    a[i]=0xFE0000000 & --raw_readl(&g->in_data);

    i++;

    }else printk("Buffer overflow ...!!");

    }

    ------------------------------------------------------------------------------

    & i am thinking of using the another buffer when this one is overflown and mean while put this buffer to ddr using DMA..and then  similar wqay for another buffer and keep on switching the buffers..

    Is this a right approch ??

    bcos my data size would around 5-7 MB & still want high frequency...ard 4 MHz

    1- is there any other special approch to reduce memory write overhead...each time ??

    2- What will be approx speed if  i use EDMA event triggering and copy the indata resistor directly to DDR or any othe linear memory ??

    3- How can I check where is my local buffer apart from printing the addresses ...will the same address assigned each time 

    4-For local buffer's  memory allocation is there any other standard way with least overhead...

    Thank you very much bernie for you time and support :)

  • Hello ,

    I am trying using EDMA3.....

    I have done the following steps,

    1- Allocate a buffer through an API from dma-mapping.h

    2-request a channel for any GPIO pin on which I am receiving my clock**( <<problem getting few channels...:(   )

    3- map source address as the GPIO bank on which I am getting the data , and set INCR addressing mode & 8 bit WIDE buffer

    4- start the dma

    Now, As per my knowledge , 

    It should automatically enable event and copy byte by byte on each rising pulse and copy the data to the allocated buffer (Buffer has been passed via destination port address).We dont need to separately enable / request as in IRQ ..m I correct ??? 

    **But now My problem is...

    I am not able to get few particular channels,

    They are ..

     

    #define DAVINCI_DMA_GPIO_GPINT5 37

    #define DAVINCI_DMA_GPIO_GPINT6 38

    #define DAVINCI_DMA_GPIO_GPINT7 39

    #define DAVINCI_DMA_GPIO_GPBNKINT0 40

    #define DAVINCI_DMA_GPIO_GPBNKINT1 41

    #define DAVINCI_DMA_GPIO_GPBNKINT2 42

    #define DAVINCI_DMA_GPIO_GPBNKINT3 43

     

    but I can successfully get following channels...

     

    #define DM355_DMA_GPIO_GPINT9 25

    #define DM355_DMA_MCBSP1_RX 9

    #define DM355_DMA_GPIO_GPINT8 47

    What could be the problem ....No one from the da-vinci pool of channels worked yet :(

    Do we need to request GPIOs. or set direction or demux pins prior to that??

    It was all not worked I have tried demuxing and setting the direction bits for GPIO7.

    Please help , and also tell me can we directly allocate 20 M x 1 byte buffer using "dma_alloc_coherent"???

    If yes than after filling it up can we directly map it to IPIPE ????

    Pleaste reply ..ASAP..

  • I can copy data from GPIO INDATA to the dedicated buffer but I am not able to trigger the EDMA event on rising edge on GPIO , I have mapped GPIO 9!

    Normal ARM interrupt on this pin "IRQ 53" is working fine !!

    Please reply ASAP !

  • This sounds like something that needs to be debugged a bit within the EDMA module, I assume you have the EDMA setup as per SPREE4a, are you getting the event bit set in the ER register? Can you trigger the EDMA to run manually by setting the ESR bit for your transfer?

  • Let me try that way...N thx for quick reply

  • I have kept the debug msges of dma.c file on.

    And I have got this,

    -----------------------------------------------------------------------------------------------

    Request_dma...core

    [davinci_request_dma]: start

    <alloc_resource><714>: drae = ce030000

    <davinci_request_dma><1414>: DMA channel 25 allocated

    <davinci_request_dma><1422>: PaRAM Set 25 allocated

    <davinci_request_dma><1431>: TCC 25 allocated

    <register_callback><589>: ier = ce030000 

    [davinci_request_dma]: end

    [davinci_set_dma_transfer_params]: start

    <davinci_set_dma_transfer_params><2044>: lch = 25, param_id = 25

    [davinci_set_dma_transfer_params]: end

    [davinci_set_dma_src_params]: start

    [davinci_set_dma_src_params]: end

    [davinci_set_dma_dest_params]: start

    [davinci_set_dma_dest_params]: end

    [davinci_set_dma_src_index]: start

    <davinci_set_dma_src_index><1965>: lch = 25, param_id = 25

    [davinci_set_dma_src_index]: end

    [davinci_set_dma_dest_index]: start

    <davinci_set_dma_dest_index><2002>: lch = 25, param_id = 25

    [davinci_set_dma_dest_index]: end

    [davinci_start_dma]: start

    <davinci_start_dma><2141>: lch 25 edma_max_logical_ch 520

    <davinci_start_dma><2145>: davinci_dma_ch_hw_event_map 0xfdff0ffc 

    <davinci_start_dma><2146>: lch/32u  0  lch-32u 25

     I am in Callback !

    <6>[davinci_free_dma]: start

    <davinci_free_dma><1787>: lch = 25

    [davinci_stop_dma]: start

    <davinci_stop_dma><2261>: ESR=0

    [davinci_stop_dma]: end

    [unregister_callback]: start

    <unregister_callback><616>: lch = 25

    <unregister_callback><621>: mapped tcc for DMA channel = 25

    [unregister_callback]: end

    <davinci_free_dma><1804>: Free ParamSet 25

    <davinci_free_dma><1810>: Free TCC 25

    <davinci_free_dma><1816>: Free DMA channel 25

    [davinci_free_dma]: end

    [davinci_start_dma]: end

     davinci_recv_buffer: after wait_for_completion

     GPIO IN_DATA bank 4 and 5: 0x3

    BUFFER DATA=3

     Transfer Successfully Completed !

    -------------------------------------------------------------------------------------------------------------

    Now I have following questions,

    1- I have copied one byte successfully into memory form GPIO, it is because i have called "dma_start "..M I right ??

     

    2- In dma.c , there is a function for dma_start.....here is its code...

    --------------------------------------------------------------------------------------------------

    int davinci_start_dma(int lch)

    {

        int ret_val = 0;

        DMA_FN_IN;

        DMA_PRINTK ("lch %d edma_max_logical_ch %d\n", lch,edma_max_logical_ch);

        if (lch < edma_max_logical_ch)   {

            if (lch >= 0 && lch < EDMA_NUM_DMACH)   {

                /* DMA Channel */

                    DMA_PRINTK ("davinci_dma_ch_hw_event_map 0x%8x \n",davinci_dma_ch_hw_event_map[lch/32u]);

                    DMA_PRINTK ("lch/32u  %i  lch-32u %i\n",lch/32u,(lch % 32u));

                if (((davinci_dma_ch_hw_event_map[lch/32u]) &

                        (1u << (lch % 32u))) != 0)    {

                   DMA_PRINTK ("Event mapped\n");

                    /* Event Mapped */

                    if (lch < 32)   {

                        DMA_PRINTK ("ER = %x\r\n", ptr_edmacc_shadow_regs->er);

                        /* Clear any SER */

                        ptr_edmacc_shadow_regs->secr = (1UL << lch);

                        /* Clear any pending error */

                        ptr_edmacc_regs->emcr = (1UL << lch);

                        /* Set EER */

                        ptr_edmacc_shadow_regs->eesr = (1UL << lch);

                        ptr_edmacc_shadow_regs->ecr = (1UL << lch);

                    } else {

                        DMA_PRINTK ("ERH = %x\r\n", ptr_edmacc_shadow_regs->erh);

                        /* Clear any pending error */

                        ptr_edmacc_regs->emcrh = (1UL << (lch-32));

                        /* Clear any SERH */

                        ptr_edmacc_shadow_regs->secrh = (1UL << (lch-32));

                        /* Set EERH */

                        ptr_edmacc_shadow_regs->eesrh = (1UL << (lch-32));

                        ptr_edmacc_shadow_regs->ecrh = (1UL << (lch-32));

                    }

                } else {

                    /* Manual Triggered */

                    if (lch < 32)   {

                        ptr_edmacc_shadow_regs->esr = (1UL << lch);

                    } else {

                        ptr_edmacc_shadow_regs->esrh = (1UL << (lch-32));

                    }

                }

            } else {

                /* QDMA Channel */

                ptr_edmacc_shadow_regs->qeesr =

                                        (1u << (lch - EDMA_QDMA_CHANNEL_0));

            }

        } else {

            DMA_PRINTK ("EINVAL lch %d \n", lch);

            ret_val = EINVAL;

        }

        DMA_FN_OUT;

        return ret_val;

    }

    EXPORT_SYMBOL(davinci_start_dma);

    -------------------------------------------------------------------------------------
    Now as you can see my module doesn't enter into the code ...
    the condition..

      if (((davinci_dma_ch_hw_event_map[lch/32u]) &

                        (1u << (lch % 32u))) != 0)    

    is not getting satisfied.

    This is only depends on "lch"...(hope so !?)

    What should be the problem & plz suggest a solution !

    Thank you

  • I think I can do it manually...each time by calling "start_dma"...

    and I am still have the same question ,

    in dma.c,

    "davinci_dma_ch_hw_event_map " is 0xfdff0ffc

    Which means the 25th bit is "Zero"...Is this a problem ??

    How to set that bit ??

  •  Does anybody has the same problem??

  • Hurrey

    I have done IT using GPIO9 DMA channel 25...I am able to copy GPIo INDATA

    register to buffer using DMA...The problem was all the channels were not enabled in

    EDMA_DM355_CHANNEL_TO_EVENT_MAPPING0  variable in "asm/arch/edma.h" 93rd line .....Please change it if u want to usae gpio lines ;)

     

    But I have few doubts...

    1- Do I need to request and free DMA API on each transfer ??whats the exact flow

    calling APIs , I am using MV4 , LSP 1.3 .

    2- because of this I am getting triggering speed of 10KHz only..:( (

    measuring waveform on GPIO by keeping one

    GPIO pin toggling in between two start dma calls..)

    3- What is the exact speed to copy any register to memeory using ASYNC transfer

    mode and using EVENT trigerring ??

     

    tHANK YOU TI , thx e2e :)