Over a million developers have joined DZone.

Optimized BitIO_LDD Programming with Processor Expert

· Performance Zone

See Gartner’s latest research on the application performance monitoring landscape and how APM suites are becoming more and more critical to the business, brought to you in partnership with AppDynamics.

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 the "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 enforce 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 that 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 that 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

The 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.

:idea: It would be very cool if Processor Expert could have the 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 :-)




The Performance Zone is brought to you in partnership with AppDynamics.  See Gartner’s latest research on the application performance monitoring landscape and how APM suites are becoming more and more critical to the business.

Topics:

Published at DZone with permission of Erich Styger, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

The best of DZone straight to your inbox.

SEE AN EXAMPLE
Please provide a valid email address.

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.
Subscribe

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}