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.

OMAP3 DSP Control GPIO

I've been evaluating the OMAP3 using the beagle board and one of the things I would like to do is have the DSP directly control GPIO.  

Here is what I have so far:

I can build a working rootfs and kernel (Linux) for the ARM and I can build the DSP/GPP examples and run them successfully on the the Beagle board.  

What I need:

1.) Either a good example or description of how to have the DSP directly control a GPIO

2.) How to have the DSP directly control the SPI bus, although I suspect if I have the GPIO example I can figure out the SPI example.

 

Shane 

  • Is this question still open?  It seems like it should be moved to either the OMAP or Linux forums instead of the BIOS forum.

     

  • The page numbers in this post were from spruf98e.pdf.  The current revision is now 'i' so they are likely off a tiny bit.  I believe the procedure should look very close to the following:

    Let's say we want to do something with gpio_139, which is bit 11 of bank 5.

    gpio_139 = GPIO5[11]

    #define BIT11 (1<<11)

     

    There are several pieces to getting the GPIO interrupt:

    1)       The pinmuxing/padconf must be set appropriately in the system control module (Ch 7) such that the actual pin is routed to the GPIO peripheral.

    a.       CONTROL_PADCONF_X registers, page 761, gpio_139 is part of CONTROL_PADCONF_MMC2_DAT6[31:16].

    b.      Page 752 has CONTROL_PADCONF_X register description.

    c.       Set MUXMODE = 4 for gpio

    d.      Set INPUTENABLE = 1 or else the pad will be output only!

    2)       The GPIO peripheral itself (Ch 24) needs to be configured to generate an interrupt to the DSP.

    a.       Chapter 24.5.3.2 Description

    b.      GPIO5.GPIO_OE |= BIT11;

    c.       At this point if we have everything correct you should be able to see the pin state reflected in the GPIO5.GPIO_DATAIN[11] bit.  I recommend making sure this is correct before proceeding further as we certainly won’t get interrupts of the signal is not being properly received.

    d.      GPIO5.GPIO_RISINGEDGEDETECT |= BIT11;

    e.       GPIO5.GPIO_SETIRQENABLE2 = BIT11; /* just a write, not a read-modify-write */

    3)       The DSP (Ch 14) needs to have the interrupt configured appropriately.  This would be same procedure as the Timer.

    a.       The event needs to be unmasked in the WUGEN.

    b.      The DSP’s interrupt controller needs to be configured to map the GPIO interrupt to one of the 12 maskable interrupts of the DSP.

    c.       The ISR needs to be “plugged”.

    d.      The corresponding IER bit needs to be enabled.

  • Brad,

    Thanks for the info but I still have a question: Do I need to do anything with the DSP linker files or will the DSP just be able to access the GPIO memory space?  I searched for your referenced app note (spruf98e.pdf) but everything that came up was a broken link: (http://focus.ti.com/lit/ug/spruf98e/spruf98e.pdf)

    Regards,

    Shane

  • Shane Volpe said:
    Do I need to do anything with the DSP linker files or will the DSP just be able to access the GPIO memory space?

    I assume you are using BIOS in which case the linker command file is generated for you.  There is an MMU that sits at the boundary of the IVA subsystem.  It gets configured by the ARM while the ARM is loading the DSP.  In order for the DSP to have access to a memory location the ARM must program an entry into the DSP's MMU.  Those entries ultimately originate from a memTab inside the DSP's tcf/tci file.  As I recall there is already an entry for the L4 interconnect address space which is where the GPIO registers would reside.

    Shane Volpe said:
    I searched for your referenced app note (spruf98e.pdf) but everything that came up was a broken link: (http://focus.ti.com/lit/ug/spruf98e/spruf98e.pdf)

    It's not an app note but the TRM that I'm referencing.

  • I had no problems getting code written to toggle an IO via the DSP given the information above but I'm still having problems getting an IO to control the DSP IRQ.  I'm currently using the beagleboard and trying to get the user button on GPIO4 to trigger an interrupt in the DSP.  I have disabled all Linux control of the user button.  I have included a small example below that details how I'm trying to get the IRQ working in the DSP. 

    The following example stays in a while loop and *should* print out the message "User button was pressed!" when the user button IRQ triggers the DSP IRQ. Currently when the user button is pressed the GPIO1_IRQSTATUS2 0x10 bit gets set but the DSP IRQ dose not seem to call the userBInt() function.   I must still not have something configured correctly on the DSP side in either the DSP IRQ registers or the WUGEN registers.

    #include <stdio.h>

    #include <stdlib.h>

    #include <string.h>


    #define GPIO004_PADCONF                 (*((volatile unsigned short *)(0x48002a0c)))

    #define GPIO1_OE                        (*((volatile unsigned int   *)(0x48310034)))

    #define IRQENABLE2_GPIO1                (*((volatile unsigned int   *)(0x4831002c))) 

    #define IRQSTATUS2_GPIO1                (*((volatile unsigned int   *)(0x48310028)))    

    #define IRQRISINGEDGE_GPIO1             (*((volatile unsigned int   *)(0x48310048)))

    #define INTMUX1_DSP                     (*((volatile unsigned int   *)(0x01800108)))

    #define GPIO1_WUGEN_MASKCLEAR           (*((volatile unsigned int   *)(0x01c21070)))

    #define GPIO_WUGEN_CLEARINT             (*((volatile unsigned int   *)(0x01c21100)))

    #define WUGEN_MASK                      (*((volatile unsigned int   *)(0x01c21060)))

    #define TPCC_IESR                       (*((volatile unsigned int   *)(0x01c01060)))


    static int userBInt();

    static int userBInt()

    {

        printf("User button was pressed! \n");

        GPIO_WUGEN_CLEARINT = 0x10000000;   //Clear IRQ  

        IRQSTATUS2_GPIO1 = 0x10;            //Clear IRQ status

        return 0;

    }

    int main()

    {

      char option;

      GPIO004_PADCONF = 4;                  //Set GPIO004 to an IO.

      GPIO1_OE |= 0x10;                     //Configure GPIO004 as input 

      HWI_disable();

      IRQSTATUS2_GPIO1 = 0x10;              //Clear any existing IRQ statuses for GPIO004


      GPIO_WUGEN_CLEARINT = 0xFFFFFFFF;     //Clear all ints?? Not sure about this.

      IRQENABLE2_GPIO1 |= 0x10;             //Enable GPIO004 IRQ to DSP

      IRQRISINGEDGE_GPIO1 |= 0x10;          //Configure GPIO004 for rising edge IRQ detection



      INTMUX1_DSP = 73;                     //MAP GPIO1 (EVT73) to DSP IRQ4 (Page 1754:SPRUF98T)

      GPIO1_WUGEN_MASKCLEAR = 0x10000000;   //Clear IRQ73 (EVT73) MASK in WUGEN

      TPCC_IESR = 0x10000000;               //Enable IRQ73 IRQ.

      HWI_dispatchPlug(4,userBInt(),NULL,NULL); //Register userRBInt() function to DSP IRQ4.


      HWI_enable();


     do {

        printf("Do you want to exit? (y/n)?\n");

        fflush(stdout);

        option = getchar();

        while (getchar() != '\n');

      } while((option == 'n') || (option == 'N'));

      printf("Done!\n");

      return 0;

    }

     

  • Shane Volpe said:

      GPIO004_PADCONF = 4;                  //Set GPIO004 to an IO.

    You forgot to set the INPUTENABLE bit.

  • Brad Griffis said:
    You forgot to set the INPUTENABLE bit.
    I dont think I did forget as the following line sets GPIO004 as an input.
     GPIO1_OE |= 0x10;                     //Configure GPIO004 as input 
     
    Also Figure 25-5 (SRUGN4M) depicts that the output of the IRQSTATUS2 anded with the IRQENABLE2 gets directly routed into the IVA2.2 module.  As mentioned above I have confirmed that the IRQSTATUS2 is correctly triggering during the user button IRQ event and that the IRQENABLE2 is set so I think,  based on figure 25-5,  the issue must be in the settings for the IVA2.2 module since everything is working correctly up to the module. 
  • Ok I got it working.  I will clean up my example and post it here.  Thanks for all the help!

  • Are you going to post the example? It would be much appreciated. Was the problem not clearing the interrupt status?

    Thanks,

    Jon Pry

  • Jon,

    Thanks for reminding me, I got busy and forgot to post it.  I still have not cleaned up the code, however, I also do not want to forget to post it again so I will post it as-is and re-post if I ever do clean it up.  

    I just compiled the code below, loaded it on to the beagle board (Linux-2.6.39) and verified it still works.  This code uses c6run to print out a message to the console every time the user1 button is pressed.  The code uses an interrupt generated by user1 button to detect when the button is pressed.  I hope is example is useful to someone and please feel free to contact me if you have any questions.

     

    #include <stdio.h>

    #include <stdlib.h>

    #include <string.h>

    #include <c6x.h>

     

    #define GPIO004_PADCONF                 (*((volatile unsigned short *)(0x48002a0c)))

    #define GPIO1_OE                        (*((volatile unsigned int   *)(0x48310034)))

    #define IRQENABLE2_GPIO1                (*((volatile unsigned int   *)(0x4831002c)))

    #define IRQSTATUS2_GPIO1                (*((volatile unsigned int   *)(0x48310028)))

    #define IRQRISINGEDGE_GPIO1             (*((volatile unsigned int   *)(0x48310048)))

    #define GPIO1_CTRL                      (*((volatile unsigned int   *)(0x48310030)))

    #define GPIO1_DEBOUNCE_TIME             (*((volatile unsigned int   *)(0x48310054))) //(Debounce[0-255] time +1) * 31uS

    #define GPIO1_DEBOUNCE_ENABLE           (*((volatile unsigned int   *)(0x48310054)))

     

    //C6RUN Uses the following ints: IER:0x4033

    void userRBInt();

    volatile int irq;

     

    void userRBInt()

    {

     

        IER &= ~(0x40);                     //Enable DSP IRQ 4

        IRQSTATUS2_GPIO1 = 0x10;            //Clear IRQ status

        ICR = 0x040;                        //Clear DSP IRQ4

        irq = 1;

        IER |= 0x40;                        //Enable DSP IRQ 4

    }

     

     

    int main()

    {

      char option;

      HWI_disable();

      GPIO004_PADCONF = 4;                  //Set GPIO004 to an IO.

      GPIO1_OE |= 0x10;                     //Configure GPIO004 as input

      GPIO1_CTRL = 0x0;                     //Enable IRQs for GPIO1 with out being gated

      IRQSTATUS2_GPIO1 = 0x10;              //Clear any existing IRQ statuses for GPIO004

      IRQENABLE2_GPIO1 |= 0x10;             //Enable GPIO004 IRQ to DSP

      IRQRISINGEDGE_GPIO1 |= 0x10;          //Configure GPIO004 for rising edge IRQ detection

      GPIO1_DEBOUNCE_TIME = 0xFF;           //Set debounce time to max (8ms)

      GPIO1_DEBOUNCE_ENABLE |= 0x10;        //Enable debounce time for GPIO004

     

     

      HWI_eventMap(6, 73);

      HWI_enableWugen(73);                  //Enable INT GPIO1 in WuGEN

     

      HWI_dispatchPlug(6,(void*)userRBInt,NULL,NULL); //Register userRBInt() function to DSP IRQ4.

     

      HWI_enable();

      IER |= 0x0040;                        //Enable DSP IRQ 4

     

        irq = 0;

        option = 0;

            printf ("waiting for 5 button presses...\n");

            fflush(stdout);

     

        while(1){

            while (irq == 0)

            {

            }

            if (irq)
            {
                    printf ("button press number %d occurred!\n", ++option);
                    irq = 0;
            }
            if (option > 4)
                    break;
            fflush(stdout);
        }
      printf("Done!\n");
      HWI_disable();
      IRQENABLE2_GPIO1 &= ~(0x10);          //Disable GPIO004 IRQ to DSP
      IER &= ~(0x40);                       //Enable DSP IRQ 4
      return 0;
    }

  • Thanks for the code.  This is the only place I've seen a simple example of reading the GPIO from the DSP.

    Unfortunately I've been unable to make it work.  I've documented my experiences so far here.

    The summary is, I get the following error when compiling:

    /opt/toolchains/c6run_binary/bin/c6runapp-cc readPushbuttonViaDSP.c -o readPushbuttonViaDSP "readPushbuttonViaDSP.c", line 35: warning #225-D: function declared implicitly "readPushbuttonViaDSP.c", line 46: warning #225-D: function declared implicitly "readPushbuttonViaDSP.c", line 47: warning #225-D: function declared implicitly "readPushbuttonViaDSP.c", line 50: warning #225-D: function declared implicitly "readPushbuttonViaDSP.c", line 52: warning #225-D: function declared implicitly undefined first referenced symbol in file --------- ---------------- _HWI_enableWugen ./readPushbuttonViaDSP.temp.o error #10234-D: unresolved symbols remain error #10010: errors encountered during linking; "readPushbuttonViaDSP.dsp_image.out" not built make: *** [readPushbuttonViaDSP] Error 1

    If I comment out the line with HWI_enableWugen, the code compiles (on the Beagle xM), but when run never sees the push button. 

    I'm running v 1.1.0.0 of c6runapp and v2.6.32 of the kernel.

    Could you point me to where the various functions in the code are documented? It's been several years since I've taught a class using the 'C6000 and I'm rusty with it.

    Thanks...

    --Mark
  • Mark A. Yoder said:
    If I comment out the line with HWI_enableWugen, the code compiles (on the Beagle xM), but when run never sees the push button.

    HWI_enableWugen is a BIOS API. The BIOS documentation is bundled with the software, i.e. there's a "docs" directory.  The various "Wugen" APIs are all specific to OMAP2 and OMAP3 so you're likely getting an error if the linker step is grabbing the 64x+ library rather than the OMAP3 library.  I haven't looked closely at the c6run build flow, but I assume somewhere you need to tell c6run that you're on OMAP3 so that it can tell BIOS you're on OMAP3 and eventually the correct library gets linked in.

    If this isn't enough info to figure it out you may need to separately post to get more info specific to c6run, i.e. I know a lot more about the GPIO than I do about c6run!