PIC32MZ: Implement support for IO port interrupts
This commit is contained in:
parent
7ae730c810
commit
625cd7b43a
@ -248,13 +248,56 @@ config PIC32MZ_CTMU
|
||||
|
||||
endmenu
|
||||
|
||||
config PIC32MZ_GPIOIRQ
|
||||
bool "GPIO Interrupt"
|
||||
menuconfig PIC32MZ_GPIOIRQ
|
||||
bool "GPIO Interrupt Support"
|
||||
default n
|
||||
depends on EXPERIMENTAL
|
||||
---help---
|
||||
Build in support for interrupts based on GPIO inputs from IOPorts
|
||||
|
||||
if PIC32MZ_GPIOIRQ
|
||||
|
||||
menuconfig PIC32MZ_GPIOIRQ_PORTA
|
||||
bool "I/O PORTA Interrupt Support"
|
||||
default n
|
||||
|
||||
menuconfig PIC32MZ_GPIOIRQ_PORTB
|
||||
bool "I/O PORTB Interrupt Support"
|
||||
default n
|
||||
|
||||
menuconfig PIC32MZ_GPIOIRQ_PORTC
|
||||
bool "I/O PORTC Interrupt Support"
|
||||
default n
|
||||
|
||||
menuconfig PIC32MZ_GPIOIRQ_PORTD
|
||||
bool "I/O PORTD Interrupt Support"
|
||||
default n
|
||||
|
||||
menuconfig PIC32MZ_GPIOIRQ_PORTE
|
||||
bool "I/O PORTE Interrupt Support"
|
||||
default n
|
||||
|
||||
menuconfig PIC32MZ_GPIOIRQ_PORTF
|
||||
bool "I/O PORTF Interrupt Support"
|
||||
default n
|
||||
|
||||
menuconfig PIC32MZ_GPIOIRQ_PORTG
|
||||
bool "I/O PORTG Interrupt Support"
|
||||
default n
|
||||
|
||||
menuconfig PIC32MZ_GPIOIRQ_PORTH
|
||||
bool "I/O PORTH Interrupt Support"
|
||||
default n
|
||||
|
||||
menuconfig PIC32MZ_GPIOIRQ_PORTJ
|
||||
bool "I/O PORTJ Interrupt Support"
|
||||
default n
|
||||
|
||||
menuconfig PIC32MZ_GPIOIRQ_PORTK
|
||||
bool "I/O PORTK Interrupt Support"
|
||||
default n
|
||||
|
||||
endif # PIC32MZ_GPIOIRQ
|
||||
|
||||
config PIC32MZ_T1_SOSC
|
||||
bool
|
||||
default n
|
||||
|
@ -51,16 +51,16 @@
|
||||
********************************************************************************************/
|
||||
/* IOPort Peripheral Offsets ****************************************************************/
|
||||
|
||||
#define PI32MZ_IOPORTA 0
|
||||
#define PI32MZ_IOPORTB 1
|
||||
#define PI32MZ_IOPORTC 2
|
||||
#define PI32MZ_IOPORTD 3
|
||||
#define PI32MZ_IOPORTE 4
|
||||
#define PI32MZ_IOPORTF 5
|
||||
#define PI32MZ_IOPORTG 6
|
||||
#define PI32MZ_IOPORTH 7
|
||||
#define PI32MZ_IOPORTJ 8
|
||||
#define PI32MZ_IOPORTK 9
|
||||
#define PIC32MZ_IOPORTA 0
|
||||
#define PIC32MZ_IOPORTB 1
|
||||
#define PIC32MZ_IOPORTC 2
|
||||
#define PIC32MZ_IOPORTD 3
|
||||
#define PIC32MZ_IOPORTE 4
|
||||
#define PIC32MZ_IOPORTF 5
|
||||
#define PIC32MZ_IOPORTG 6
|
||||
#define PIC32MZ_IOPORTH 7
|
||||
#define PIC32MZ_IOPORTJ 8
|
||||
#define PIC32MZ_IOPORTK 9
|
||||
|
||||
#define PIC32MZ_IOPORTn_OFFSET(n) ((n)<<8)
|
||||
# define PIC32MZ_IOPORTA_OFFSET 0x0000
|
||||
@ -789,30 +789,37 @@
|
||||
/* Analog select register */
|
||||
|
||||
#define IOPORT_ANSEL(n) (1 << (n)) /* Bits 0-15: Analog select */
|
||||
#define IOPORT_ANSEL_ALL 0x0000ffff
|
||||
|
||||
/* Tri-state register */
|
||||
|
||||
#define IOPORT_TRIS(n) (1 << (n)) /* Bits 0-15: 1: Input 0: Output */
|
||||
#define IOPORT_TRIS_ALL 0x0000ffff
|
||||
|
||||
/* Port register */
|
||||
|
||||
#define IOPORT_PORT(n) (1 << (n)) /* Bits 0-15: Pin value */
|
||||
#define IOPORT_PORT_ALL 0x0000ffff
|
||||
|
||||
/* Port data latch register */
|
||||
|
||||
#define IOPORT_LAT(n) (1 << (n)) /* Bits 0-15: Port latch value */
|
||||
#define IOPORT_LAT_ALL 0x0000ffff
|
||||
|
||||
/* Open drain control register */
|
||||
|
||||
#define IOPORT_ODC(n) (1 << (n)) /* Bits 0-15: 1: OD output enabled, 0: Disabled */
|
||||
#define IOPORT_ODC_ALL 0x0000ffff
|
||||
|
||||
/* Change Notice Pull-up register */
|
||||
|
||||
#define IOPORT_CNPU(n) (1 << (n)) /* Bits 0:15: 1=Pull-up enabled */
|
||||
#define IOPORT_CNPU_ALL 0x0000ffff
|
||||
|
||||
/* Change Notice Pull-down register */
|
||||
|
||||
#define IOPORT_CNPD(n) (1 << (n)) /* Bits 0:15: 1=Pull-down enabled */
|
||||
#define IOPORT_CNPD_ALL 0x0000ffff
|
||||
|
||||
/* Change Notice Control register */
|
||||
|
||||
@ -822,10 +829,12 @@
|
||||
/* Change Notice Interrupt Enable register */
|
||||
|
||||
#define IOPORT_CNEN(n) (1 << (n)) /* Bits 0-15: 1=Interrupt enabled */
|
||||
#define IOPORT_CNEN_ALL 0x0000ffff
|
||||
|
||||
/* Change Notice Control register */
|
||||
/* Change Notice Status register */
|
||||
|
||||
#define IOPORT_CNSTAT(n) (1 << (n) /* Bits 0-15: Change notice control pin n */
|
||||
#define IOPORT_CNSTAT(n) (1 << (n)) /* Bits 0-15: Change notice control pin n */
|
||||
#define IOPORT_CNSTAT_ALL 0x0000ffff
|
||||
|
||||
/********************************************************************************************
|
||||
* Public Types
|
||||
|
@ -48,6 +48,52 @@
|
||||
/************************************************************************************
|
||||
* Pre-processor Definitions
|
||||
************************************************************************************/
|
||||
/* GPIO IRQs ************************************************************************/
|
||||
|
||||
#ifndef PIC32MZ_GPIOIRQ
|
||||
# undef CONFIG_PIC32MZ_GPIOIRQ_PORTA
|
||||
# undef CONFIG_PIC32MZ_GPIOIRQ_PORTB
|
||||
# undef CONFIG_PIC32MZ_GPIOIRQ_PORTC
|
||||
# undef CONFIG_PIC32MZ_GPIOIRQ_PORTD
|
||||
# undef CONFIG_PIC32MZ_GPIOIRQ_PORTE
|
||||
# undef CONFIG_PIC32MZ_GPIOIRQ_PORTF
|
||||
# undef CONFIG_PIC32MZ_GPIOIRQ_PORTG
|
||||
# undef CONFIG_PIC32MZ_GPIOIRQ_PORTH
|
||||
# undef CONFIG_PIC32MZ_GPIOIRQ_PORTJ
|
||||
# undef CONFIG_PIC32MZ_GPIOIRQ_PORTK
|
||||
#endif
|
||||
|
||||
#if CHIP_NPORTS < 1
|
||||
# undef CONFIG_PIC32MZ_GPIOIRQ_PORTA
|
||||
#endif
|
||||
#if CHIP_NPORTS < 2
|
||||
# undef CONFIG_PIC32MZ_GPIOIRQ_PORTB
|
||||
#endif
|
||||
#if CHIP_NPORTS < 3
|
||||
# undef CONFIG_PIC32MZ_GPIOIRQ_PORTC
|
||||
#endif
|
||||
#if CHIP_NPORTS < 4
|
||||
# undef CONFIG_PIC32MZ_GPIOIRQ_PORTD
|
||||
#endif
|
||||
#if CHIP_NPORTS < 5
|
||||
# undef CONFIG_PIC32MZ_GPIOIRQ_PORTE
|
||||
#endif
|
||||
#if CHIP_NPORTS < 6
|
||||
# undef CONFIG_PIC32MZ_GPIOIRQ_PORTF
|
||||
#endif
|
||||
#if CHIP_NPORTS < 7
|
||||
# undef CONFIG_PIC32MZ_GPIOIRQ_PORTG
|
||||
#endif
|
||||
#if CHIP_NPORTS < 8
|
||||
# undef CONFIG_PIC32MZ_GPIOIRQ_PORTH
|
||||
#endif
|
||||
#if CHIP_NPORTS < 9
|
||||
# undef CONFIG_PIC32MZ_GPIOIRQ_PORTJ
|
||||
#endif
|
||||
#if CHIP_NPORTS < 10
|
||||
# undef CONFIG_PIC32MZ_GPIOIRQ_PORTK
|
||||
#endif
|
||||
|
||||
/* UARTs ****************************************************************************/
|
||||
/* Don't enable UARTs not supported by the chip. */
|
||||
|
||||
|
@ -61,12 +61,12 @@
|
||||
/****************************************************************************
|
||||
* Public Data
|
||||
****************************************************************************/
|
||||
/* This table can be used to map a port number to a IOPORT base address. For
|
||||
* example, an index of zero would correspond to IOPORTA, one with IOPORTB,
|
||||
* etc.
|
||||
*/
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
|
||||
static const uintptr_t g_gpiobase[CHIP_NPORTS] =
|
||||
const uintptr_t g_gpiobase[CHIP_NPORTS] =
|
||||
{
|
||||
PIC32MZ_IOPORTA_K1BASE
|
||||
#if CHIP_NPORTS > 1
|
||||
@ -106,37 +106,37 @@ static const uintptr_t g_gpiobase[CHIP_NPORTS] =
|
||||
* Name: Inline PIN set field extractors
|
||||
****************************************************************************/
|
||||
|
||||
static inline bool pic32mz_output(uint16_t pinset)
|
||||
static inline bool pic32mz_output(pinset_t pinset)
|
||||
{
|
||||
return ((pinset & GPIO_OUTPUT) != 0);
|
||||
}
|
||||
|
||||
static inline bool pic32mz_opendrain(uint16_t pinset)
|
||||
static inline bool pic32mz_opendrain(pinset_t pinset)
|
||||
{
|
||||
return ((pinset & GPIO_MODE_MASK) == GPIO_OPENDRAN);
|
||||
}
|
||||
|
||||
static inline bool pic32mz_outputhigh(uint16_t pinset)
|
||||
static inline bool pic32mz_outputhigh(pinset_t pinset)
|
||||
{
|
||||
return ((pinset & GPIO_VALUE_MASK) != 0);
|
||||
}
|
||||
|
||||
static inline bool pic32mz_value(uint16_t pinset)
|
||||
static inline bool pic32mz_value(pinset_t pinset)
|
||||
{
|
||||
return ((pinset & GPIO_VALUE_MASK) != GPIO_VALUE_ZERO);
|
||||
}
|
||||
|
||||
static inline unsigned int pic32mz_portno(uint16_t pinset)
|
||||
static inline unsigned int pic32mz_portno(pinset_t pinset)
|
||||
{
|
||||
return ((pinset & GPIO_PORT_MASK) >> GPIO_PORT_SHIFT);
|
||||
}
|
||||
|
||||
static inline unsigned int pic32mz_pinno(uint16_t pinset)
|
||||
static inline unsigned int pic32mz_pinno(pinset_t pinset)
|
||||
{
|
||||
return ((pinset & GPIO_PIN_MASK) >> GPIO_PIN_SHIFT);
|
||||
}
|
||||
|
||||
static inline unsigned int pic32mz_analog(uint16_t pinset)
|
||||
static inline unsigned int pic32mz_analog(pinset_t pinset)
|
||||
{
|
||||
return ((pinset & GPIO_ANALOG_MASK) != 0);
|
||||
}
|
||||
@ -157,7 +157,7 @@ static inline unsigned int pic32mz_analog(uint16_t pinset)
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int pic32mz_configgpio(uint16_t cfgset)
|
||||
int pic32mz_configgpio(pinset_t cfgset)
|
||||
{
|
||||
unsigned int port = pic32mz_portno(cfgset);
|
||||
unsigned int pin = pic32mz_pinno(cfgset);
|
||||
@ -242,7 +242,7 @@ int pic32mz_configgpio(uint16_t cfgset)
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void pic32mz_gpiowrite(uint16_t pinset, bool value)
|
||||
void pic32mz_gpiowrite(pinset_t pinset, bool value)
|
||||
{
|
||||
unsigned int port = pic32mz_portno(pinset);
|
||||
unsigned int pin = pic32mz_pinno(pinset);
|
||||
@ -277,7 +277,7 @@ void pic32mz_gpiowrite(uint16_t pinset, bool value)
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
bool pic32mz_gpioread(uint16_t pinset)
|
||||
bool pic32mz_gpioread(pinset_t pinset)
|
||||
{
|
||||
unsigned int port = pic32mz_portno(pinset);
|
||||
unsigned int pin = pic32mz_pinno(pinset);
|
||||
|
@ -42,6 +42,8 @@
|
||||
|
||||
#include <nuttx/config.h>
|
||||
#include <nuttx/compiler.h>
|
||||
#include <nuttx/irq.h>
|
||||
#include <arch/pic32mz/irq.h>
|
||||
|
||||
/************************************************************************************
|
||||
* Pre-processor Definitions
|
||||
@ -66,15 +68,9 @@
|
||||
# define GPIO_VALUE_ONE (1 << 12)
|
||||
# define GPIO_VALUE_ZERO (0)
|
||||
|
||||
#define GPIO_PULLUP (1 << 11) /* Bit 11: Change notification pull-up */
|
||||
|
||||
#define GPIO_INT_SHIFT (10) /* Bits 10-11: Interrupt mode */
|
||||
#define GPIO_INT_MASK (3 << GPIO_INT_SHIFT)
|
||||
# define GPIO_INT_NONE (0 << GPIO_INT_SHIFT) /* Bit 00: No interrupt */
|
||||
# define GPIO_INT (1 << GPIO_INT_SHIFT) /* Bit 01: Change notification enable */
|
||||
# define GPIO_PUINT (3 << GPIO_INT_SHIFT) /* Bit 11: Pulled-up interrupt input */
|
||||
|
||||
#define GPIO_PULLDOWN (1 << 9) /* Bit 11: Change notification pull-down */
|
||||
#define GPIO_INTERRUPT (1 << 11) /* Bit 11: Change notification enable */
|
||||
#define GPIO_PULLUP (1 << 10) /* Bit 10: Change notification pull-up */
|
||||
#define GPIO_PULLDOWN (1 << 9) /* Bit 9: Change notification pull-down */
|
||||
|
||||
#define GPIO_PORT_SHIFT (5) /* Bits 5-8: Port number */
|
||||
#define GPIO_PORT_MASK (15 << GPIO_PORT_SHIFT)
|
||||
@ -114,6 +110,8 @@
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
typedef uint16_t pinset_t;
|
||||
|
||||
/************************************************************************************
|
||||
* Public Data
|
||||
************************************************************************************/
|
||||
@ -127,6 +125,13 @@ extern "C"
|
||||
#define EXTERN extern
|
||||
#endif
|
||||
|
||||
/* This table can be used to map a port number to a IOPORT base address. For
|
||||
* example, an index of zero would correspond to IOPORTA, one with IOPORTB,
|
||||
* etc.
|
||||
*/
|
||||
|
||||
EXTERN const uintptr_t g_gpiobase[CHIP_NPORTS];
|
||||
|
||||
/************************************************************************************
|
||||
* Public Function Prototypes
|
||||
************************************************************************************/
|
||||
@ -143,7 +148,7 @@ extern "C"
|
||||
*
|
||||
************************************************************************************/
|
||||
|
||||
int pic32mz_configgpio(uint16_t cfgset);
|
||||
int pic32mz_configgpio(pinset_t cfgset);
|
||||
|
||||
/************************************************************************************
|
||||
* Name: pic32mz_gpiowrite
|
||||
@ -207,7 +212,7 @@ void pic32mz_gpioirqinitialize(void);
|
||||
************************************************************************************/
|
||||
|
||||
#ifdef CONFIG_PIC32MZ_GPIOIRQ
|
||||
xcpt_t pic32mz_gpioattach(uint32_t pinset, unsigned int cn, xcpt_t handler);
|
||||
xcpt_t pic32mz_gpioattach(uint32_t pinset, xcpt_t handler);
|
||||
#else
|
||||
# define pic32mz_gpioattach(p,f) (NULL)
|
||||
#endif
|
||||
@ -221,7 +226,7 @@ xcpt_t pic32mz_gpioattach(uint32_t pinset, unsigned int cn, xcpt_t handler);
|
||||
************************************************************************************/
|
||||
|
||||
#ifdef CONFIG_PIC32MZ_GPIOIRQ
|
||||
void pic32mz_gpioirqenable(unsigned int cn);
|
||||
void pic32mz_gpioirqenable(pinset_t pinset);
|
||||
#else
|
||||
# define pic32mz_gpioirqenable(irq)
|
||||
#endif
|
||||
@ -235,7 +240,7 @@ void pic32mz_gpioirqenable(unsigned int cn);
|
||||
************************************************************************************/
|
||||
|
||||
#ifdef CONFIG_PIC32MZ_GPIOIRQ
|
||||
void pic32mz_gpioirqdisable(unsigned int cn);
|
||||
void pic32mz_gpioirqdisable(pinset_t pinset);
|
||||
#else
|
||||
# define pic32mz_gpioirqdisable(irq)
|
||||
#endif
|
||||
|
@ -45,8 +45,10 @@
|
||||
#include <nuttx/irq.h>
|
||||
#include <nuttx/arch.h>
|
||||
#include <arch/board/board.h>
|
||||
#include <arch/pic32mz/irq.h>
|
||||
|
||||
#include "up_arch.h"
|
||||
#include "up_internal.h"
|
||||
#include "chip/pic32mz-ioport.h"
|
||||
#include "pic32mz-gpio.h"
|
||||
|
||||
@ -60,15 +62,101 @@
|
||||
* Private Types
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Private Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
static inline unsigned int pic32mz_ioport(pinset_t pinset);
|
||||
static inline unsigned int pic32mz_pin(pinset_t pinset);
|
||||
static inline bool pic32mz_input(pinset_t pinset);
|
||||
static inline bool pic32mz_interrupt(pinset_t pinset);
|
||||
static inline bool pic32mz_pullup(pinset_t pinset);
|
||||
static inline bool pic32mz_pulldown(pinset_t pinset);
|
||||
static int pic32mz_cninterrupt(int irq, FAR void *context);
|
||||
|
||||
/****************************************************************************
|
||||
* Public Data
|
||||
****************************************************************************/
|
||||
|
||||
struct ioport_level2_s
|
||||
{
|
||||
xcpt_t handler[16];
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
|
||||
static xcpt_t g_cnisrs[IOPORT_NUMCN];
|
||||
/* Arrays of second level interrupt handlers for each pin of each enabled
|
||||
* I/O port.
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_PIC32MZ_GPIOIRQ_PORTA
|
||||
static struct ioport_level2_s g_ioporta_cnisrs;
|
||||
#endif
|
||||
#ifdef CONFIG_PIC32MZ_GPIOIRQ_PORTB
|
||||
static struct ioport_level2_s g_ioportb_cnisrs;
|
||||
#endif
|
||||
#ifdef CONFIG_PIC32MZ_GPIOIRQ_PORTC
|
||||
static struct ioport_level2_s g_ioportc_cnisrs;
|
||||
#endif
|
||||
#ifdef CONFIG_PIC32MZ_GPIOIRQ_PORTD
|
||||
static struct ioport_level2_s g_ioportd_cnisrs;
|
||||
#endif
|
||||
#ifdef CONFIG_PIC32MZ_GPIOIRQ_PORTE
|
||||
static struct ioport_level2_s g_ioporte_cnisrs;
|
||||
#endif
|
||||
#ifdef CONFIG_PIC32MZ_GPIOIRQ_PORTF
|
||||
static struct ioport_level2_s g_ioportf_cnisrs;
|
||||
#endif
|
||||
#ifdef CONFIG_PIC32MZ_GPIOIRQ_PORTG
|
||||
static struct ioport_level2_s g_ioportg_cnisrs;
|
||||
#endif
|
||||
#ifdef CONFIG_PIC32MZ_GPIOIRQ_PORTH
|
||||
static struct ioport_level2_s g_ioporth_cnisrs;
|
||||
#endif
|
||||
#ifdef CONFIG_PIC32MZ_GPIOIRQ_PORTJ
|
||||
static struct ioport_level2_s g_ioportj_cnisrs;
|
||||
#endif
|
||||
#ifdef CONFIG_PIC32MZ_GPIOIRQ_PORTK
|
||||
static struct ioport_level2_s g_ioportk_cnisrs;
|
||||
#endif
|
||||
|
||||
/* Look-up of port to interrupt handler array */
|
||||
|
||||
static struct ioport_level2_s * const g_level2_handlers[CHIP_NPORTS] =
|
||||
{
|
||||
#ifdef CONFIG_PIC32MZ_GPIOIRQ_PORTA
|
||||
[PIC32MZ_IOPORTA] = &g_ioporta_cnisrs,
|
||||
#endif
|
||||
#ifdef CONFIG_PIC32MZ_GPIOIRQ_PORTB
|
||||
[PIC32MZ_IOPORTB] = &g_ioportb_cnisrs,
|
||||
#endif
|
||||
#ifdef CONFIG_PIC32MZ_GPIOIRQ_PORTC
|
||||
[PIC32MZ_IOPORTC] = &g_ioportc_cnisrs,
|
||||
#endif
|
||||
#ifdef CONFIG_PIC32MZ_GPIOIRQ_PORTD
|
||||
[PIC32MZ_IOPORTD] = &g_ioportd_cnisrs,
|
||||
#endif
|
||||
#ifdef CONFIG_PIC32MZ_GPIOIRQ_PORTE
|
||||
[PIC32MZ_IOPORTE] = &g_ioporte_cnisrs,
|
||||
#endif
|
||||
#ifdef CONFIG_PIC32MZ_GPIOIRQ_PORTF
|
||||
[PIC32MZ_IOPORTF] = &g_ioportf_cnisrs,
|
||||
#endif
|
||||
#ifdef CONFIG_PIC32MZ_GPIOIRQ_PORTG
|
||||
[PIC32MZ_IOPORTG] = &g_ioportg_cnisrs,
|
||||
#endif
|
||||
#ifdef CONFIG_PIC32MZ_GPIOIRQ_PORTH
|
||||
[PIC32MZ_IOPORTH] = &g_ioporth_cnisrs,
|
||||
#endif
|
||||
#ifdef CONFIG_PIC32MZ_GPIOIRQ_PORTJ
|
||||
[PIC32MZ_IOPORTJ] = &g_ioportj_cnisrs,
|
||||
#endif
|
||||
#ifdef CONFIG_PIC32MZ_GPIOIRQ_PORTK
|
||||
[PIC32MZ_IOPORTK] = &g_ioportk_cnisrs,
|
||||
#endif
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
@ -78,58 +166,123 @@ static xcpt_t g_cnisrs[IOPORT_NUMCN];
|
||||
* Name: Inline PIN set field extractors
|
||||
****************************************************************************/
|
||||
|
||||
static inline bool pic32mz_input(uint16_t pinset)
|
||||
static inline bool pic32mz_input(pinset_t pinset)
|
||||
{
|
||||
return ((pinset & GPIO_MODE_MASK) != GPIO_INPUT);
|
||||
}
|
||||
|
||||
static inline bool pic32mz_interrupt(uint16_t pinset)
|
||||
static inline bool pic32mz_interrupt(pinset_t pinset)
|
||||
{
|
||||
return ((pinset & GPIO_INTERRUPT) != 0);
|
||||
}
|
||||
|
||||
static inline bool pic32mz_pullup(uint16_t pinset)
|
||||
static inline bool pic32mz_pullup(pinset_t pinset)
|
||||
{
|
||||
return ((pinset & GPIO_INT_MASK) == GPIO_PUINT);
|
||||
return ((pinset & GPIO_PULLUP) != 0);
|
||||
}
|
||||
|
||||
static inline bool pic32mz_pulldown(pinset_t pinset)
|
||||
{
|
||||
return ((pinset & GPIO_PULLDOWN) != 0);
|
||||
}
|
||||
|
||||
static inline unsigned int pic32mz_ioport(pinset_t pinset)
|
||||
{
|
||||
return ((pinset & GPIO_PORT_MASK) >> GPIO_PORT_SHIFT);
|
||||
}
|
||||
|
||||
static inline unsigned int pic32mz_pin(pinset_t pinset)
|
||||
{
|
||||
return ((pinset & GPIO_PIN_MASK) >> GPIO_PIN_SHIFT);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: pic32mz_cninterrupt
|
||||
*
|
||||
* Description:
|
||||
* Change notification interrupt handler.
|
||||
* Common change notification interrupt handler.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int pic32mz_cninterrupt(int irq, FAR void *context)
|
||||
{
|
||||
struct ioport_level2_s *handlers;
|
||||
xcpt_t handler;
|
||||
uintptr_t base;
|
||||
uint32_t cnstat;
|
||||
uint32_t cnen;
|
||||
uint32_t pending;
|
||||
uint32_t regval;
|
||||
int ioport;
|
||||
int status;
|
||||
int ret = OK;
|
||||
int i;
|
||||
|
||||
/* Call all attached handlers */
|
||||
/* Get the IO port index from the IRQ number. This, of course,
|
||||
* assumes that the irq numbers are consecutive beginning with
|
||||
* IOPORTA.
|
||||
*/
|
||||
|
||||
for (i = 0; i < IOPORT_NUMCN; i++)
|
||||
ioport = irq - PIC32MZ_IRQ_PORTA;
|
||||
DEBUGASSERT(ioport >= 0 && ioport < CHIP_NPORTS);
|
||||
|
||||
/* If we got this interrupt, then there must also be an array
|
||||
* of second level handlers (and a base address) for the IOPORT.
|
||||
*/
|
||||
|
||||
handlers = g_level2_handlers[ioport];
|
||||
base = g_gpiobase[ioport];
|
||||
DEBUGASSERT(handlers && base);
|
||||
|
||||
if (handlers && base)
|
||||
{
|
||||
/* Is this one attached */
|
||||
/* Get the interrupt status associated with this interrupt */
|
||||
|
||||
if (g_cnisrs[i])
|
||||
cnstat = getreg32(base + PIC32MZ_IOPORT_CNSTAT_OFFSET);
|
||||
cnen = getreg32(base + PIC32MZ_IOPORT_CNSTAT_OFFSET);
|
||||
pending = cnstat & cnen;
|
||||
|
||||
/* Hmmm.. the data sheet implies that the status will pend
|
||||
* until the corresponding PORTx registers is read? Clear
|
||||
* pending status.
|
||||
*/
|
||||
|
||||
regval = getreg32(base + PIC32MZ_IOPORT_PORT_OFFSET);
|
||||
UNUSED(regval);
|
||||
|
||||
/* Call all attached handlers for each pending interrupt */
|
||||
|
||||
for (i = 0; i < 16; i++)
|
||||
{
|
||||
/* Call the attached handler */
|
||||
/* Is this interrupt pending */
|
||||
|
||||
status = g_cnisrs[i](irq, context);
|
||||
if ((pending & (1 << IOPORT_CNSTAT(i))) != 0)
|
||||
{
|
||||
/* Yes.. Has the user attached a handler? */
|
||||
|
||||
/* Keep track of the status of the last handler that failed */
|
||||
handler = handlers->handler[i];
|
||||
if (handler)
|
||||
{
|
||||
/* Yes.. call the attached handler */
|
||||
|
||||
status = handler(irq, context);
|
||||
|
||||
/* Keep track of the status of the last handler that
|
||||
* failed.
|
||||
*/
|
||||
|
||||
if (status < 0)
|
||||
{
|
||||
ret = status;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Clear the pending interrupt */
|
||||
|
||||
up_clrpend_irq(PIC32MZ_IRQ_CN);
|
||||
up_clrpend_irq(irq);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -149,30 +302,53 @@ static int pic32mz_cninterrupt(int irq, FAR void *context)
|
||||
|
||||
void pic32mz_gpioirqinitialize(void)
|
||||
{
|
||||
uintptr_t base;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
/* Attach the change notice interrupt handler */
|
||||
/* Perform initialization for each IO port that has interrupt support
|
||||
* enabled. We can tell this because there will be an array of second
|
||||
* level handlers for each enabled IO port.
|
||||
*/
|
||||
|
||||
ret = irqattach(PIC32MZ_IRQ_CN, pic32mz_cninterrupt);
|
||||
for (i = 0; i < CHIP_NPORTS; i++)
|
||||
{
|
||||
/* Get the base address of this IO port peripheral */
|
||||
|
||||
base = g_gpiobase[i];
|
||||
DEBUGASSERT(base);
|
||||
|
||||
/* Reset all registers and disable the CN module */
|
||||
|
||||
putreg32(IOPORT_CNEN_ALL, base + PIC32MZ_IOPORT_CNENCLR_OFFSET);
|
||||
putreg32(IOPORT_CNPU_ALL, base + PIC32MZ_IOPORT_CNPUCLR_OFFSET);
|
||||
putreg32(IOPORT_CNPD_ALL, base + PIC32MZ_IOPORT_CNPDCLR_OFFSET);
|
||||
putreg32(0, base + PIC32MZ_IOPORT_CNCON_OFFSET);
|
||||
|
||||
/* Is interrupt support selected for this IO port? */
|
||||
|
||||
if (g_level2_handlers[i] != NULL)
|
||||
{
|
||||
/* Yes.. Attach the common change notice interrupt handler
|
||||
* to the IO port interrupt. Notice that this assumes that
|
||||
* each IRQ number is consecutive beginning with IOPORTA.
|
||||
*/
|
||||
|
||||
ret = irq_attach(PIC32MZ_IRQ_PORTA + i, pic32mz_cninterrupt);
|
||||
DEBUGASSERT(ret == OK);
|
||||
UNUSED(ret);
|
||||
|
||||
/* Set the interrupt priority */
|
||||
/* Enable the CN module. NOTE that the CN module is active when
|
||||
* in sleep mode.
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_ARCH_IRQPRIO
|
||||
ret = up_prioritize_irq(PIC32MZ_IRQ_CN, CONFIG_PIC32MZ_CNPRIO);
|
||||
DEBUGASSERT(ret == OK);
|
||||
#endif
|
||||
putreg32(IOPORT_CNCON_ON, base + PIC32MZ_IOPORT_CNCON_OFFSET);
|
||||
|
||||
/* Reset all registers and enable the CN module */
|
||||
/* And enable the GPIO interrupt. Same assumption as above. */
|
||||
|
||||
putreg32(IOPORT_CN_ALL, PIC32MZ_IOPORT_CNENCLR);
|
||||
putreg32(IOPORT_CN_ALL, PIC32MZ_IOPORT_CNPUECLR);
|
||||
putreg32(IOPORT_CNCON_ON, PIC32MZ_IOPORT_CNCON);
|
||||
|
||||
/* And enable the GPIO interrupt */
|
||||
|
||||
ret = up_enable_irq(PIC32MZ_IRQSRC_CN);
|
||||
DEBUGASSERT(ret == OK);
|
||||
up_enable_irq(PIC32MZ_IRQ_PORTA + i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
@ -187,11 +363,11 @@ void pic32mz_gpioirqinitialize(void)
|
||||
*
|
||||
* When an interrupt occurs, it is due to a change on the GPIO input pin.
|
||||
* In that case, all attached handlers will be called. Each handler must
|
||||
* maintain state and determine if the unlying GPIO input value changed.
|
||||
* maintain state and determine if the underlying GPIO input value changed.
|
||||
*
|
||||
* Parameters:
|
||||
* - pinset: GPIO pin configuration
|
||||
* - cn: The change notification number associated with the pin.
|
||||
* - pin: The change notification number associated with the pin.
|
||||
* - handler: Interrupt handler (may be NULL to detach)
|
||||
*
|
||||
* Returns:
|
||||
@ -201,28 +377,52 @@ void pic32mz_gpioirqinitialize(void)
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
xcpt_t pic32mz_gpioattach(uint32_t pinset, unsigned int cn, xcpt_t handler)
|
||||
xcpt_t pic32mz_gpioattach(uint32_t pinset, xcpt_t handler)
|
||||
{
|
||||
struct ioport_level2_s *handlers;
|
||||
xcpt_t oldhandler = NULL;
|
||||
irqstate_t flags;
|
||||
uintptr_t base;
|
||||
int ioport;
|
||||
int pin;
|
||||
|
||||
DEBUGASSERT(cn < IOPORT_NUMCN);
|
||||
DEBUGASSERT(pin < IOPORT_NUMCN);
|
||||
|
||||
/* First verify that the pinset is configured as an interrupting input */
|
||||
|
||||
if (pic32mz_input(pinset) && pic32mz_interrupt(pinset))
|
||||
{
|
||||
/* Get the ioport index and pin number from the pinset */
|
||||
|
||||
ioport = pic32mz_ioport(pinset);
|
||||
pin = pic32mz_pin(pinset);
|
||||
DEBUGASSERT(ioport >= 0 && ioport < CHIP_NPORTS);
|
||||
|
||||
/* Get the register base address for this port */
|
||||
|
||||
base = g_gpiobase[ioport];
|
||||
DEBUGASSERT(base);
|
||||
|
||||
/* If this IO port has been properly configured for interrupts, then
|
||||
* there should be an array of second level interrupt handlers
|
||||
* allocated for it.
|
||||
*/
|
||||
|
||||
handlers = g_level2_handlers[ioport];
|
||||
DEBUGASSERT(handlers);
|
||||
if (handlers)
|
||||
{
|
||||
/* Get the previously attached handler as the return value */
|
||||
|
||||
flags = irqsave();
|
||||
oldhandler = g_cnisrs[cn];
|
||||
oldhandler = handlers->handler[pin];
|
||||
|
||||
/* Are we attaching or detaching? */
|
||||
|
||||
if (handler != NULL)
|
||||
{
|
||||
/* Attaching... Make sure that the GPIO is properly configured as
|
||||
* an input
|
||||
/* Attaching... Make sure that the GPIO is properly configured
|
||||
* as an input
|
||||
*/
|
||||
|
||||
pic32mz_configgpio(pinset);
|
||||
@ -231,28 +431,46 @@ xcpt_t pic32mz_gpioattach(uint32_t pinset, unsigned int cn, xcpt_t handler)
|
||||
|
||||
if (pic32mz_pullup(pinset))
|
||||
{
|
||||
putreg32(1 << cn, PIC32MZ_IOPORT_CNPUESET);
|
||||
putreg32(1 << pin, base + PIC32MZ_IOPORT_CNPUSET_OFFSET);
|
||||
}
|
||||
else
|
||||
{
|
||||
putreg32(1 << cn, PIC32MZ_IOPORT_CNPUECLR);
|
||||
putreg32(1 << pin, base + PIC32MZ_IOPORT_CNPUCLR_OFFSET);
|
||||
}
|
||||
|
||||
/* Pull-down requested? */
|
||||
|
||||
if (pic32mz_pulldown(pinset))
|
||||
{
|
||||
putreg32(1 << pin, base + PIC32MZ_IOPORT_CNPDSET_OFFSET);
|
||||
}
|
||||
else
|
||||
{
|
||||
putreg32(1 << pin, base + PIC32MZ_IOPORT_CNPDCLR_OFFSET);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Make sure that any further interrupts are disabled.
|
||||
* (disable the pull-up as well).
|
||||
/* Disable the pull-up/downs (just so things look better in
|
||||
* the debugger).
|
||||
*/
|
||||
|
||||
putreg32(1 << cn, PIC32MZ_IOPORT_CNENCLR);
|
||||
putreg32(1 << cn, PIC32MZ_IOPORT_CNPUECLR);
|
||||
putreg32(1 << pin, base + PIC32MZ_IOPORT_CNPUCLR_OFFSET);
|
||||
putreg32(1 << pin, base + PIC32MZ_IOPORT_CNPDCLR_OFFSET);
|
||||
}
|
||||
|
||||
/* Whether attaching or detaching, the next state of the interrupt
|
||||
* should be disabled.
|
||||
*/
|
||||
|
||||
putreg32(1 << pin, base + PIC32MZ_IOPORT_CNENCLR_OFFSET);
|
||||
|
||||
/* Set the new handler (perhaps NULLifying the current handler) */
|
||||
|
||||
g_cnisrs[cn] = handler;
|
||||
handlers->handler[pin] = handler;
|
||||
irqrestore(flags);
|
||||
}
|
||||
}
|
||||
|
||||
return oldhandler;
|
||||
}
|
||||
@ -265,10 +483,31 @@ xcpt_t pic32mz_gpioattach(uint32_t pinset, unsigned int cn, xcpt_t handler)
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void pic32mz_gpioirqenable(unsigned int cn)
|
||||
void pic32mz_gpioirqenable(pinset_t pinset)
|
||||
{
|
||||
DEBUGASSERT(cn < IOPORT_NUMCN);
|
||||
putreg32(1 << cn, PIC32MZ_IOPORT_CNENSET);
|
||||
uintptr_t base;
|
||||
int ioport;
|
||||
int pin;
|
||||
|
||||
/* Get the ioport index and pin number from the pinset */
|
||||
|
||||
ioport = pic32mz_ioport(pinset);
|
||||
pin = pic32mz_pin(pinset);
|
||||
DEBUGASSERT(ioport >= 0 && ioport < CHIP_NPORTS);
|
||||
|
||||
/* Get the register base address for this port */
|
||||
|
||||
base = g_gpiobase[ioport];
|
||||
DEBUGASSERT(base);
|
||||
if (base)
|
||||
{
|
||||
/* And enable the interrupt. NOTE that we don't actually check if
|
||||
* interrupts are configured for this IO port. If not, this operation
|
||||
* should do nothing.
|
||||
*/
|
||||
|
||||
putreg32(1 << pin, base + PIC32MZ_IOPORT_CNENSET_OFFSET);
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
@ -279,10 +518,31 @@ void pic32mz_gpioirqenable(unsigned int cn)
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void pic32mz_gpioirqdisable(unsigned int cn)
|
||||
void pic32mz_gpioirqdisable(pinset_t pinset)
|
||||
{
|
||||
DEBUGASSERT(cn < IOPORT_NUMCN);
|
||||
putreg32(1 << cn, PIC32MZ_IOPORT_CNENCLR);
|
||||
uintptr_t base;
|
||||
int ioport;
|
||||
int pin;
|
||||
|
||||
/* Get the ioport index and pin number from the pinset */
|
||||
|
||||
ioport = pic32mz_ioport(pinset);
|
||||
pin = pic32mz_pin(pinset);
|
||||
DEBUGASSERT(ioport >= 0 && ioport < CHIP_NPORTS);
|
||||
|
||||
/* Get the register base address for this port */
|
||||
|
||||
base = g_gpiobase[ioport];
|
||||
DEBUGASSERT(base);
|
||||
if (base)
|
||||
{
|
||||
/* And disable the interrupt. NOTE that we don't actually check if
|
||||
* interrupts are configured for this IO port. If not, this operation
|
||||
* should do nothing.
|
||||
*/
|
||||
|
||||
putreg32(1 << pin, base + PIC32MZ_IOPORT_CNENCLR_OFFSET);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* CONFIG_PIC32MZ_GPIOIRQ */
|
||||
|
Loading…
Reference in New Issue
Block a user