Optimized BitIO_LDD Programming with Processor Expert

In my tutorial “Bits and Pins with Kinetis” I showed how to use the BitIO_LDD approach for Bit I/O access. I do not like this LDD (logical device driver) approach for several reasons:

  1. It requires an extra ‘device handle’ passed to the functions, even if such a device handle is not needed or desired.
  2. The code efficiency/size is negatively impacted by this.

Luckily, there is a way to hack around this 🙂

DeviceDataPtr for BitIO_LDD

If using the BitIO_LDD approch as in “Bits and Pins with Kinetis”, then every call to the BitIO routines need to have ‘device’ pointer parameter which is created with the Init() method. With the component property ‘Auto Initialization’ set to ‘yes’, it will call that Init() method for me automatically as part of the PE_low_level_init() inside main():

Auto Initialization for BitIO_LDD

Auto Initialization for BitIO_LDD

This automatically created device handle needs to be passed to very BitIO_LDD function:

GREEN_ClrVal(GREEN_DeviceData);

As you can imagine, passing such a parameter comes with some cost (code size and execution cycles. And this is even more disappointing if I look at the source code of the function called:

/*
** ===================================================================
**     Method      :  GREEN_ClrVal (component BitIO_LDD)
*/
/*!
**     @brief
**         Clears (set to zero) the output value. It is equivalent to
**         the [PutVal(FALSE)]. This method is available only if the
**         direction = _[output]_ or _[input/output]_.
**     @param
**         DeviceDataPtr   - Pointer to device data
**                           structure returned by <Init> method.
*/
/* ===================================================================*/
void GREEN_ClrVal(LDD_TDeviceData *DeviceDataPtr)
{
  (void)DeviceDataPtr;                 /* Parameter is not used, suppress unused argument warning */

  GPIO_PDD_ClearPortDataOutputMask(GREEN_MODULE_BASE_ADDRESS, GREEN_PORT_MASK);
}

We pass a parameter which is not used at all 😦

Hacking around the Device Parameter

If that parameter is not used, why enforcing it at all in the API? That parameter would make sense if I want to have concurrent access to the peripheral (e.g. if I have an RTOS and multiple tasks who want to use a Bit I/O). But in my case I do not use an RTOS, and Processor Expert should know this. I would expect Processor Expert to take advantage of this knowledge, but at least up to MCU10.5 it does not. The good news is: I can hack around it 😉

The idea is to define macros like the ones below which do *not* need that device handle parameter:

#define RED_Clr()     GPIO_PDD_ClearPortDataOutputMask(RED_MODULE_BASE_ADDRESS, RED_PORT_MASK)
#define RED_Set()     GPIO_PDD_SetPortDataOutputMask(RED_MODULE_BASE_ADDRESS, RED_PORT_MASK)
#define GREEN_Clr()   GPIO_PDD_ClearPortDataOutputMask(GREEN_MODULE_BASE_ADDRESS, GREEN_PORT_MASK)
#define GREEN_Set()   GPIO_PDD_SetPortDataOutputMask(GREEN_MODULE_BASE_ADDRESS, GREEN_PORT_MASK)
#define BLUE_Clr()    GPIO_PDD_ClearPortDataOutputMask(BLUE_MODULE_BASE_ADDRESS, BLUE_PORT_MASK)
#define BLUE_Set()    GPIO_PDD_SetPortDataOutputMask(BLUE_MODULE_BASE_ADDRESS, BLUE_PORT_MASK)
#define SW1_Get()     (GPIO_PDD_GetPortDataInput(SW1_MODULE_BASE_ADDRESS) & SW1_PORT_MASK)
define SW1_Get()      (GPIO_PDD_GetPortDataInput(SW2_MODULE_BASE_ADDRESS) & SW2_PORT_MASK)

The macros are what is implemented inside the methods (which are using the NULL parameter, but do not use it.

With this, I can change my original implementation from

GREEN_ClrVal(GREEN_DeviceData); /* turn on green LED */
WAIT1_Waitms(1000);
GREEN_SetVal(GREEN_DeviceData); /* turn off green LED */
for(;;) {
  if (SW1_GetVal(SW1_DeviceData)==0) { /* button low level => pressed */
    RED_ClrVal(RED_DeviceData); /* LED cathode is connected to microcontroller pin: low level turns it on */
    BLUE_SetVal(BLUE_DeviceData); /* turn off blue led */
  } else {
   RED_SetVal(RED_DeviceData); /* turn off red led */
   BLUE_ClrVal(BLUE_DeviceData); /* turn on blue led */
  }
  if (SW2_GetVal(SW2_DeviceData)==0) { /* switch low level => pressed */
   BLUE_ClrVal(BLUE_DeviceData); /* turn on blue led */
  } else {
    BLUE_SetVal(BLUE_DeviceData); /* turn off blue led */
  }
}

to this:

GREEN_Clr(); /* turn on green LED */
WAIT1_Waitms(1000);
GREEN_Set(); /* turn off green LED */
for(;;) {
  if (SW1_Get()==0) { /* button low level => pressed */
    RED_Clr(); /* LED cathode is connected to microcontroller pin: low level turns it on */
    BLUE_Set(); /* turn off blue led */
  } else {
    RED_Set(); /* turn off red led */
    BLUE_Clr(); /* turn on blue led */
  }
  if (SW2_Get()==0) { /* switch low level => pressed */
    BLUE_Clr(); /* turn on blue led */
  } else {
    BLUE_Set(); /* turn off blue led */
  }
}

The positive impact: instead of 1544 bytes, the optimized version needs 1416 bytes of code for the application, about 10% less 🙂

Summary

Processor Expert BitIO_LDD component requires a device handle passed to very function in its API, but this parameter is not used at all inside the functions if there is no RTOS used. Even with using an RTOS, and not needing concurrent access to the Bits, the parameter is not necessary and only increases code size and code latency.But macros could be used to bypass this for better code efficiency without losing the advantage of using Processor Expert. It is just that these additional macros are hacking around something which Processor Expert should do out of the box.

💡 It would be very cool if Processor Expert would have a property ‘do not use device handle pointer’ or something similar. At least Processor Expert knows that it is not using the parameter, so I would expect it would create the API/macros as I did above for better code efficiency.

Happy Optimizing 🙂

12 thoughts on “Optimized BitIO_LDD Programming with Processor Expert

      • Why do you think the compiler would not optimize it out due to WHERE is was located? The compiler would compile the function and see that the parameter wasn’t being used and should optimize it out.

        It absolutely will if even -O1 is set.
        https://godbolt.org/g/YTAMxP

        Like

        • Hi Richard,
          if the function is defined in an another compilation unit, then the compiler won’t know that the paramter of the function is not used. In your example on https://godbolt.org/g/YTAMxP the compiler can optimized it, because the implementation of the function mine() is known at the time of the comilation of the function main(). If you have this:

          int mine(int thisdata);
          int main(void) {
          mine(6);
          return 1;
          }

          then even if -O1 it is

          main:
          stmfd sp!, {r4, lr}
          mov r0, #6
          bl mine(int)
          mov r0, #1
          ldmfd sp!, {r4, lr}
          bx lr

          I hope this helps?
          Erich

          Like

  1. Well, I don’t like device handle either. Do you know if there are someone in freescale we could ask this things about processor expert?

    Thanks Very Much

    Like

  2. Hi Erich,

    Would the following save more space? I started puttering with microcontrollers about 15 years ago and this is how I had to do it back then. (I am still just puttering. 😉 It is also the way I figured out how to use the KL25Z IOs before you wrote your tutorial on MCUONECLIPSE.

    PORTC_PCR3|=0X03; // Set PTC3 (SW1) for input and pull-up
    PORTC_PCR12|=0X03; // Set PTC12 (SW3) for input and pull-up

    if((GPIOC_PDIR & 0x08)==0){ // if SW1 goes low
    GPIOD_PDOR &= 0xdf; // Set PTD5 Low – GRN LED on
    }
    else{
    GPIOD_PDOR |= 0x20; // Set PTD5 High – GRN LED off
    }

    if((GPIOC_PDIR & 0x1000)==0){ // if SW3 goes low
    GPIOE_PDOR &= 0xdfffffff; // Set PTE29 Low – RED LED on
    }
    else{
    GPIOE_PDOR |= 0x20000000; // Set PTE29 High – RED LED off
    }

    Like

      • Erich

        Can you please briefly describe how is created GREEN_DeviceData handler?

        In my case I am using
        Direction_A of type BitIO_LDD

        how create handler?

        Thanks in advance

        Kamil

        Like

        • That device handle is the result of the Init() method of the BitIO_LDD. That device handle get automatically created as well if you set the ‘Initialization > Auto Initialization’ property of the component to ‘yes’. You will find the declaration of the handle variable in the header file of the LDD component.

          Like

What do you think?

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.