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.

TM4C1294NCPDT: Calculate PERIPH parameter from GPIO_BASE

Part Number: TM4C1294NCPDT


I know it is possible, but I haven't found the documentation referring to it.

How can we determine the Peripheral uint32 value of a GPIO port, given the port base?

Briefly, I'd like to make a small GPIO config function, which can be simplified for this example to the following code:

void SystemUtilitiesGPIOSetAsOutput(BASE, PIN)
{
    // First, determine PERIPH from BASE/PIN information (not done here)
    if (!(SysCtlPeripheralReady(PERIPH)))
    {
	    SysCtlPeripheralDisable(PERIPH);
	    SysCtlPeripheralReset(PERIPH);
	    SysCtlPeripheralEnable(PERIPH);
	    while(!SysCtlPeripheralReady(PERIPH));
    }
    GPIOPinTypeGPIOOutput(BASE, PIN);
}

Just for clarity, what I refer to PERIPH here are the likes of SYSCTL_PERIPH_GPIOA.

It just seems ugly to force the application to pass the peripheral parameter, as it can certainly be "created" by the fact that we know it is a GPIO port, and we know the port address (of course, by looking up proper Tivaware included files)

I posted something similar in the past, on the thread below. While Veikko Immonen came up with an interesting suggestion, it is still not exactly what I was looking for - not would it apply to GPIO's, only to alternative peripheral mux settings.

https://e2e.ti.com/support/microcontrollers/tiva_arm/f/908/t/580747

Regards

Bruno

  • Bruno Saraiva said:
    posted something similar in the past, on the thread below.

    Might that be "WAY BELOW?"    (i.e. invisible to this reporter and "higher viewing" crack staff...)

  • A few ms ago, my editing of the original post crossed paths to your replying. I too had noted that the "below" was off-limits to my screen...
  • Glad to have noted (and advised/assisted.)

    We "take issue" w/your use (w/in subject line) of the word "calculate." Indeed - for highly similar Function Blocks (such as GPIO) there may well exist a predictable, stepped, linear relationship. (and such meets your desire to "calculate")

    That said/admitted - when moving AWAY from (any) one Function Block - the "ability to calculate" is impaired - and a "Look-Up Table" seems far more suitable...
  • While I've ordered a Brownie, I'll be happy with Petit Gateau as well.

    If such a lookup table exists somewhere in the TivaWare files, that will do. The closest I know of is pin_map.h, but that doesn't do it.
  • We'd be "shocked" it it (look-up table) exists - the choice of "calculate" (still) appears limited to one peripheral at a time - and fails when another is to be similarly processed.

    (food order (clearly uncalculated) - somehow - escapes our source recognition...)

  • If I understand you correctly Bruno you are attempting to create a function to set GPIO pin characteristics and enable it, independent of the the port (IE not knowing the port in advance).

    I can understand why you would want to do this and why it appears to be a good idea but I would raise a caution (actually several). First is that effort/reward ratio. While quite rightly you are not concerned with the extra time this will take during execution but you are taking time to optimize initialization code and parameters that are only used once in an application. You run the risk, in my view a large risk, of spending far more effort than will be paid back in documentation or reduced effort.

    Any effort like this relies on payback over multiple projects and probably micros. You run the, probably minor, risk of the register relationship changing between micros. The TIVAWare library would be updated to handle that nicely but you'd need to

    • notice it
    • update your library accordingly.

    That said, if you are stuck on doing this, I'd suggest something a lot simpler than you are proposing. Just use a a switch statement. Key in on the base address and select the peripheral address based on that. Don't overdo the effort, you're not saving enough to justify it.

    All in all, it may be a lot more productive to just develop an initialization pattern (including documentation).

    One other point. I would consider this

    Bruno Saraiva said:
    while(!SysCtlPeripheralReady(PERIPH));

    bad code. It should instead be

    while(!SysCtlPeripheralReady(PERIPH)){
         }

    Loops should always use brackets of their code body. No exceptions. To do otherwise is to invite *ahem* interesting bugs. You may do that already but I thought it worth emphasizing.

    Robert

    drawing credit: xkcd

  • Greetings Robert,

    Those (neat) drawings call to mind "Rube Goldberg" (almost) do they not?      (we'd need a few more "transition points" - possibly "bug catcher" illustration, too)

    Love your point, "Don't overdo the effort, you're not saving enough to justify it."     While B's Subject Line includes "Calculate" - such exercise (justification of time/effort) - if any - appears NOT to have been made.  (thus the "Return on ROI" cannot be gleaned...)

    Drawings, "forcefully, clearly & convincingly" make the point (which you/I often present) AGAINST, "Premature Optimization."      (so often yields the "unanticipated" (yet predictable) consequence of "deflection from the central task...")

  • cb1_mobile said:
    Those (neat) drawings call to mind "Rube Goldberg" (almost) do they not?

    You can credit xkcd for that one. A little line drawing can be quite eloquent sometimes.

    Robert

  • Robert Adsett72 said:
    A little line drawing can be quite eloquent sometimes.

    So true - and likely proves, "More Diplomatic" than (other) modes of suggested, "approach/contrast/comment."      (especially true for those w/ "limited artistic skills" - asked NOT to, "Sing, Dance or Draw" @ multiple (past) celebrations!)

  • Hi Robert,

    We are not really stuck on this or anything - it would just be for code clarity. While the original example was simplified for this discussion, in the end, we'd like to be able to call:

    SystemUtilitiesGPIOSetAsOutput(BASE, PIN, PADCONFIG, PADSTRENGTH, INITIALVALUE);

    Well, if we add one more parameter to it, that won't hurt anyone.

    SystemUtilitiesGPIOSetAsOutput(PERIPH, BASE, PIN, PADCONFIG, PADSTRENGTH, INITIALVALUE);

    As for the lookup table idea: as simple as such table would be, I'm not sure that I can do that if the SystemUtilities library is pre-compiled. It is easy to figure that if BASE parameter is GPIO_PORTA_BASE, the associated peripheral is SYSCTL_PERIPH_GPIOA, but that's only a macro, and the actual value might be different for different target p/n's. I guess the pre-compiled table would fail... 

    There are many "easy ways" out of repeating those lines on the example 30 times per project, one for each output pin. As for the peripheral itself, it doesn't hurt to simply enable ALL GPIO ports before configuring pins, end of story... Still, it would be nice to have a clean and reliable GPIOSetAsOutput solution that could take care of system peripheral initialization as well.

    (Oh, and about the brackets, I did strip them out when pasting the code here, just to make it look nicer - but yet, I have to confess I did not know that the good practice is to respect them as mandatory - for the code does appear to work just fine on this particular environment.)

    I like and fully agree to the drawing you attached. One of my colleagues here is obnoxious about automating everything! In the end, he will spend a week to automate a method to turn the office light on in the morning, while the cleaning lady simply open the door and flips the switch on the wall before she starts working...

    And changing one's mind is though, ain't it?

    Cheers and good week to all patient and inspired friends who keep adding to the enlightenment of this group!!!!

    Bruno

  • Bruno Saraiva said:
    We are not really stuck on this or anything - it would just be for code clarity

    Yep, understood that to be the case.

    Bruno Saraiva said:
    but that's only a macro, and the actual value might be different for different target p/n's. I guess the pre-compiled table would fail... 

    So might the offset. I don't expect either case is true currently but....

    That's why I was suggesting a better solution was a initialization pattern (or rather set of them) rather than a function. Unless you are doing a large number of wildly different projects within the same family I don't see the payoff. Developing, testing and maintaining will take longer than using a pattern.

    However, in terms of general development there is yet another option.  Use C's macro facility. That eases any worries about different micros having different offsets and address for the ports.

    Bruno Saraiva said:
    (Oh, and about the brackets, I did strip them out when pasting the code here, just to make it look nicer - but yet, I have to confess I did not know that the good practice is to respect them as mandatory - for the code does appear to work just fine on this particular environment.)

    Good.

    As for why it's bad take a quick look at the following code chunks

    /* Snippet A */
    while(1) /* Stop here*/
    blowup();
    
    /*Snippet B */
    while(1); /* Keep pulsing forever */
        Pulse();

    How long did it take you to find the bugs? How easily do you think they would slip by you when reading code (imagine a intermittent bug that happened because of an occasional flag difference. Now think of how much easier it is to spot if missing brackets is automatically considered a bug (I've got PC-Lint set to enforce this which means I don't even need to rely on the Mark I eyeball.

    Robert

  • Robert Adsett72 said:
    How long did it take you to find the bugs?

    Of course, having been pre-warned, it took me less than 137.5ns to find both bugs. But I fully understand and appreciate the explanation!

    As for the original goal, I decided to abandon the wish of including peripheral initialization inside the pin config function - period! For sanity, simply initialize the whole bunch of ports altogether and let it be.

    The current syntax will probably live long:

    SystemUtilitiesGPIOSetAsOutput(LED_STAT1_BASE, LED_STAT1_PIN, GPIO_STRENGTH_8MA, GPIO_PIN_TYPE_STD, 0);

    That takes care of special/locked pins on the background. And it fits "one single line" instead of 3 or 4, which is just a personal preference... 

    Bruno