Author Topic: Fast port configuration macro for Kinetis  (Read 8298 times)

Offline mark

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 3236
    • View Profile
    • uTasker
Fast port configuration macro for Kinetis
« on: August 13, 2011, 12:47:32 AM »
Hi All

One slight difficulty with the Kinetis is that its watchdog timer needs to be configured within a few clock cycles after a reset otherwise and attempt to write it will result in a reset. Therefore, just about the first thing to be done after a reset to to configure it (or disable it) before this short time runs out.

Since the instructions available to do this are limited, it is also compiler optimisation dependent how many instructions it takes to get to the debugger. It was found that the CW10.1 project code obviously takes a few more clock cycles to get to this point because it was found to be failing (at least in the latest version) due to this, although other compiler builds seem to be OK.

It had already been realised that configuring a port input to be used to decide whether to disable the watchdog or not was the code taking up most time before the watchdog could be written to. The reason being due to the fact that the port configuration macro is very general and uses a loop to configure multiple inpust with the same set of configuration characteristics in one go. This loop obviously uses up a few of these precious clock cycles up to this point.

To make this more efficient, and especially to ensure that the CW10.1 project can't fail, the port configuration macros have been specially extended with fast version, avoiding the loop and using a special register that supports the configuration of multiple ports charactertistics in one instruction.

As comparison, to configure port inputs, the following is used:

_CONFIG_PORT_INPUT(A, (PORTA_BIT19 | PORTA_BIT20), PORT_PS_UP_ENABLE);

This configures port A - bits 19 and 20 - as inputs with pull-up resistor.

The new, faster macro version is
_CONFIG_PORT_INPUT_FAST_HIGH(A, (PORTA_BIT19 | PORTA_BIT20), PORT_PS_UP_ENABLE);

Thsi does the same but, instead of using a loop to write the characteristics to each port bit's PCR register, it uses the port's GPCHR (Global Pin Control Register - High). This allows up to 16 port bits' characteristics to be set in one go (saving looping and writing to each individual one).

The only drawback with this is that it doesn't allow all possible 32 bits of a port to be configured at one time - either pins in the 0..15 range or pins in the 16..31 range. If the bits are no in the same half, two calls are required (to configure port A bits 7 and 19):

_CONFIG_PORT_INPUT_FAST_LOW(A, (PORTA_BIT7), PORT_PS_UP_ENABLE);
_CONFIG_PORT_INPUT_FAST_HIGH(A, (PORTA_BIT19), PORT_PS_UP_ENABLE);


In an equivalent manner, the configuration for outputs has been extended from
_CONFIG_PORT_OUTPUT(ref, pins, chars)
_CONFIG_DRIVE_PORT_OUTPUT_VALUE(ref, pins, value, chars)


with
_CONFIG_PORT_OUTPUT_FAST_LOW(ref, pins, chars)
_CONFIG_PORT_OUTPUT_FAST_HIGH(ref, pins, chars)
_CONFIG_DRIVE_PORT_OUTPUT_VALUE(ref, pins, chars)
_CONFIG_DRIVE_PORT_OUTPUT_VALUE(ref, pins, chars)


The use of the fast version is recommended for the configuration of the watchdog decision input (INIT_WATCHDOG_DISABLE()) in any case.
Present use of the standard macros are no problem in general cases. The fast versions can also be used instead of these, remembering to be careful that the fast versions cannot always handle all pins of a port in one go (some care thus needs to be taken when using the fast versions and also when maintaining project where the pins could move around on a single port since this could break project code if one is not very careful!).

Regards

Mark

P.S For CW10.1 users who encounter a problem that the debugger keeps hitting main, please make the following change in case the new project code is not yet available.

- Add the fast input configuration macros as follows to kinetis.h:

#define _CONFIG_PORT_INPUT_FAST_LOW(ref, pins, chars)  SIM_SCGC5 |= SIM_SCGC5_PORT##ref; PORT##ref##_GPCLR = (((pins) << 16) | chars); GPIO##ref##_PDDR &= ~(pins); _SIM_PORT_CHANGE
#define _CONFIG_PORT_INPUT_FAST_HIGH(ref, pins, chars) SIM_SCGC5 |= SIM_SCGC5_PORT##ref; PORT##ref##_GPCHR = (((pins) & 0xffff0000) | chars); GPIO##ref##_PDDR &= ~(pins); _SIM_PORT_CHANGE


- Change the INIT_WATCHDOG_DISABLE() to use the fast version, eg.
#define INIT_WATCHDOG_DISABLE() _CONFIG_PORT_INPUT_FAST_HIGH(A, SWITCH_1, PORT_PS_UP_ENABLE)