zmatt icon

sys_gpio.h for pru (on am335x)

zmatt | PRO | 09/03/21 09:00:27 PM UTC | 0 ⭐ | 1753 👁️ | Never ⏰ | []
C |

4.47 KB

|

None

|

0 👍

/

0 👎

#pragma once
#include <stdint.h>
#include <stdbool.h>
 
// CAUTION:  DO NOT MODIFY REGISTERS FROM PRU unless you can be
// absolutely certain that linux will not modify the register around the
// same time, otherwise you'll create a race condition that may randomly
// cause register writes to be lost.
//
// The only exceptions are CLEARDATAOUT and SETDATAOUT which are
// write-only registers that perform atomic operations on the DATAOUT
// register and are therefore safe for concurrent use by pru and linux.
// (This also applies to IRQSTATUS_SET/CLR but obviously you shouldn't
// mess with interrupt handling registers used by linux, with or without
// race condition.)
//
typedef struct {
/*000*/ uint32_t volatile REVISION;
 
/*004*/ uint32_t volatile rsvd004[(0x010-0x004)/4];
 
/*010*/ uint32_t volatile SYSCONFIG;
 
/*014*/ uint32_t volatile rsvd014[(0x020-0x014)/4];
 
/*020*/ uint32_t volatile EOI;
/*024*/ uint32_t volatile IRQSTATUS_RAW[2];
/*02c*/ uint32_t volatile IRQSTATUS[2];
/*034*/ uint32_t volatile IRQSTATUS_SET[2];
/*03c*/ uint32_t volatile IRQSTATUS_CLR[2];
/*044*/ uint32_t volatile IRQWAKEN[2];
 
/*04c*/ uint32_t volatile rsvd04c[(0x114-0x04c)/4];
 
/*114*/ uint32_t volatile SYSSTATUS;
 
/*118*/ uint32_t volatile rsvd118[(0x130-0x118)/4];
 
/*130*/ uint32_t volatile CTRL;
 
/*134*/ uint32_t volatile OE;
/*138*/ uint32_t volatile DATAIN;
/*13c*/ uint32_t volatile DATAOUT;
 
/*140*/ uint32_t volatile LEVELDETECT0;
/*144*/ uint32_t volatile LEVELDETECT1;
/*148*/ uint32_t volatile RISINGDETECT;
/*14c*/ uint32_t volatile FALLINGDETECT;
 
/*150*/ uint32_t volatile DEBOUNCENABLE;
/*154*/ uint32_t volatile DEBOUNCINGTIME;
 
/*158*/ uint32_t volatile rsvd158[(0x190-0x158)/4];
 
/*190*/ uint32_t volatile CLEARDATAOUT;
/*194*/ uint32_t volatile SETDATAOUT;
 
} sysGpio;
 
#define GPIO0 (*(sysGpio *)0x44e07000)
#define GPIO1 (*(sysGpio *)0x4804c000)
#define GPIO2 (*(sysGpio *)0x481ac000)
#define GPIO3 (*(sysGpio *)0x481ae000)
 
 
//------------------ Safe wrapper functions ---------------------------------------------------
//
// The first argument must always be one of: &GPIO0, &GPIO1, &GPIO2, &GPIO3.
//
// For efficiency you can act on multiple gpios of one controller at the same time, with the
// 32 gpios of one controller represented by the bits of an uint32_t.  Convenience wrappers
// that act on a single gpio are also provided further down.
//
// It is unsafe to change gpio direction from PRU so I'm not making a wrapper for that, set the
// gpio direction from linux instead.  Output values of gpios configured as input are ignored.
 
 
// read all gpios of one gpio controller.
static inline uint32_t gpio_read( sysGpio *dev )
{
    return dev->DATAIN;
}
 
// set output value to 0 for one or more gpios of one gpio controller.
static inline void gpio_set_low( sysGpio *dev, uint32_t mask )
{
    dev->CLEARDATAOUT = mask;
}
 
// set output value to 1 for one or more gpios of one gpio controller.
static inline void gpio_set_high( sysGpio *dev, uint32_t mask )
{
    dev->SETDATAOUT = mask;
}
 
// combines gpio_set_low() and gpio_set_high(), but optimized to use only a single bus write.
// this minimizes the delay between the two actions.
static inline void gpio_set_low_set_high( sysGpio *dev, uint32_t low_mask, uint32_t high_mask )
{
    *(uint64_t volatile *)&dev->CLEARDATAOUT = low_mask | (uint64_t)high_mask << 32;
}
 
// set output value for one or more gpios of one gpio controller, with value specified per gpio.
static inline void gpio_set( sysGpio *dev, uint32_t mask, uint32_t values )
{
    gpio_set_low_set_high( dev, mask & ~values, mask & values );
}
 
// set output value for one or more gpios of one gpio controller, using same value for all.
static inline void gpio_fill( sysGpio *dev, uint32_t mask, bool value )
{
    (&dev->CLEARDATAOUT)[ value ] = mask;
}
 
 
// Convenience wrappers for accessing a single gpio (0..31) of a gpio controller:
 
// read one gpio
static inline bool gpio_read_one( sysGpio *dev, uint8_t gpio )
{
    return ( gpio_read( dev ) >> gpio ) & 1;
}
 
// set output value of one gpio to 0
static inline void gpio_set_one_low( sysGpio *dev, uint8_t gpio )
{
    gpio_set_low( dev, 1u << gpio );
}
 
// set output value of one gpio to 1
static inline void gpio_set_one_high( sysGpio *dev, uint8_t gpio )
{
    gpio_set_high( dev, 1u << gpio );
}
 
// set output value of one gpio
static inline void gpio_set_one( sysGpio *dev, uint8_t gpio, bool value )
{
    gpio_fill( dev, 1u << gpio, value );
}

Comments