"gpiolite" simple GPIO driver for MQX on MCF52259

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

"gpiolite" simple GPIO driver for MQX on MCF52259

Jump to solution
1,852 Views
trailman
Contributor V

Hi forum !

 

I have written a simple gpio driver for MCF52259 because the original gpio driver seemed a little bit complex to me.

I post it here in the even it could be useful to somebody.

 

It is much more simplier than the standard gpio driver, because it makes use of the specific features of the MCF52259 such as the atomic level setting of I/Os through SET or CLR registers (only a write required, no read+modify+write), and does not have to support several processors each having a different way to manage the GPIO.

 

Interupts are also supported on the port NQ pins (IRQ1,3,5,7)

 

It has been tested with MQX 3.4 (built with CodeWarrior 7.1.2 GUI) but is probably OK with newer versions.

 

It is supplied "AS IS" at your own risks. Do as you want with it.

 

WARNING : To use it, disable the standard GPIO driver in the BSP configuration to avoid side effects :
            #define BSPCFG_ENABLE_GPIODEV 0

WARNING : take care not to confuse the GPIOLITE_xxx macros from this driver with the GPIO_xxx ones from the standard driver (they are not compatible).

Here is a brief overview of its very simple API :

 

--- Install the driver ---
  _io_gpiolite_install("gpiolite:");

--- Open the driver device file ---
  FILE_PTR fd_gpiolite;
  fd_gpiolite = fopen("gpiolite:", NULL);

--- Set PORTUB pin 2 as input and read current level ---
  ioctl(fd_gpiolite, GPIOLITE_IOCTL_SET_INPUT, (pointer)(GPIOLITE_PORTUB | GPIOLITE_PIN2));
  level = ioctl(fd_gpiolite, GPIOLITE_IOCTL_READ, (pointer)(GPIOLITE_PORTUB | GPIOLITE_PIN2));

--- Set PORTUA pin 3 as output, then to level 1, then to level 0 ---
  ioctl(fd_gpiolite, GPIOLITE_IOCTL_SET_OUTPUT, (pointer)(GPIOLITE_PORTTA | GPIOLITE_PIN3));
  ioctl(fd_gpiolite, GPIOLITE_IOCTL_WRITE1, (pointer)(GPIOLITE_PORTTA | GPIOLITE_PIN3));
  ioctl(fd_gpiolite, GPIOLITE_IOCTL_WRITE0, (pointer)(GPIOLITE_PORTTA | GPIOLITE_PIN3));

Note : a GPIO can be changed at any time from input to output and back.

--- Enable interrupt on both edges for PORTNQ pin 1 (IRQ1) and install a handler ---

Note : once a pin has been configured for interrupt, it is exclusively used as input with the handler defined. GPIOLITE_IOCTL_READ and GPIOLITE_IOCTL_WRITE1/0 IOCTLs should not be used on this pin.

  static void gpio_it_handler(uint_8 pin, uint_8 level)
  {
    // the code here must be short and fast as it is run from interrupt context
    // pin is the pin number on which IRQ occured (in case several pins have the same handler)
    // level is the current level read on pin when this function was called
  }

  {
    GPIOLITE_DEV_SET_PNQ_IT_DATA pnq_it_data;
    pnq_it_data.pin = (GPIOLITE_PORTNQ | GPIOLITE_PIN1);
    pnq_it_data.itmode = PORTNQ_ITMODE_BOTH_EDGES;
    pnq_it_data.handler = gpio_it_handler;
    if (ioctl(fd_gpiolite, GPIOLITE_IOCTL_SET_PNQ_IT, &pnq_it_data)) {
        printf("ERROR: GPIOLITE_IOCTL_SET_PNQ_IT failed.\n");
    }
  }

 

0 Kudos
1 Solution
806 Views
trailman
Contributor V

Oooops, Sorry !

 

I forgot to mention this #define to be added to mqx/source/include/ioctl.h

For MQX 3.4, I used :

#define IO_TYPE_GPIOLITE           0x12
but this value must be changed if already used in your BSP

View solution in original post

0 Kudos
10 Replies
806 Views
DavidS
NXP Employee
NXP Employee

Thank you Tailman for sharing.  It really is nice of you.

Regards,

David

0 Kudos
806 Views
CarlFST60L
Senior Contributor II

Thanks for sharing! I do have a very large project that uses the standard GPIO driver that I will port over at some point. I will see if I can get a before and after code size when I get around to it.

0 Kudos
806 Views
trailman
Contributor V

Hi CarlFST60L,

 

When comparing "gpiolite" to the standard "gpio" driver, the code size is not the only thing to consider.

With "gpiolite" :

- each GPIO can be switched between input and output at any time

- no memory allocation is made ("gpio" calls _mem_alloc_system_zero() / _mem_free() for IOCTLs)

- no _int_disable() / _int_enable() when reading or writing a GPIO level

- only one read or write is made in a register to read or write a GPIO level

So probably "gpiolite" is faster and more suitable for applications with critical timings.

 

0 Kudos
806 Views
oscar
Contributor I

Hi,

 

I'm trying to install your nice driver but I had an error when I compiled the BSP project.

 - undefined identifier 'IO_TYPE_GPIOLITE'.

 

I can't find this definition in your provided source. Can you help me about this issue?

 

Thanks in advance.

 

0 Kudos
806 Views
oscar
Contributor I

I defined IO_TYPE_GPIOLITE in ioctl.h.

Problem fixed.

0 Kudos
807 Views
trailman
Contributor V

Oooops, Sorry !

 

I forgot to mention this #define to be added to mqx/source/include/ioctl.h

For MQX 3.4, I used :

#define IO_TYPE_GPIOLITE           0x12
but this value must be changed if already used in your BSP

0 Kudos
806 Views
MikeMarynowski
Contributor III

Hi,

 

Thanks for contributing your GPIO driver code. It looks like it works well for individual pins, but I don't take it there is any way to read/write an entire port at a time (i.e. using GPIO as an 8 bit parallel bus)?

 

0 Kudos
806 Views
trailman
Contributor V

Hi Mike,

 

You're right, I forgot to mention that each ioctl only applies to a pin, and only one (seems to be the same for the new official "lwgpio" driver).

 

This is because the application for which I wrote this driver did not require more, and also to keep the code as small as possible (to prevent "gpiolite" from becoming as complex as the standard  "gpio" driver) :

- at initialization time, I run several ioctl to configure the pins, but it's only at initialization time without real-time requirement, so it's not a problem

- at runtime I only have to manage a single pin at a time, each from a different thread for a very different purpose

 

As you said, it would be interesting to have a port based interface, but in this case the driver has to deal with the problem of which pin of the port to configure as GPIO or not.

 

Probably a solution would be :

- to keep current individual GPIOLITE_IOCTL_SET_INPUT, GPIOLITE_IOCTL_SET_OUTPUT to set the required pins in GPIO mode and their direction

- add new ioctl to read or write a full port : GPIOLITE_IOCTL_PORT_READ,  GPIOLITE_IOCTL_PORT_WRITE0, GPIOLITE_IOCTL_PORT_WRITE1

 

Please also note that to build on MQX 3.7, the

    #if MQX_CPU == 5225
must be changed to

    #if PSP_MQX_CPU_IS_MCF5225X
in the driver's .h files

0 Kudos
806 Views
trailman
Contributor V

Another solution to manage several pins at a time would be to redefine GPIOLITE_PIN<n> macros to define them as a pin mask rather that as the pin number.

Then to modify io_gpiolite_mcf5225.c accordingly.

For examle   #define GPIOLITE_PIN4    (4)  would become  #define GPIOLITE_PIN4    (1 << 4)

 

0 Kudos
806 Views
PetrL
NXP Employee
NXP Employee

Hi,

 

we have introduced small and fast gpio driver in MQX 3.7.0 - it's call LWGPIO and it can be found here:

<MQX INSTAL DIR>\mqx\source\io\lwgpio\lwgpio.h .

 

The MQX 3.7 contain initial implementation, supporting only for MCF52259 and Kinetis devices. In the MQX 3.8 this driver will be improved and ported to all supported platforms. I hope you will like it.

 

PetrL

 

 

0 Kudos