summaryrefslogblamecommitdiffstats
path: root/c/src/lib/libbsp/arm/atsam/libraries/libchip/source/pio_it.c
blob: 71762889929d93a0413505c232f8b4da3ae78350 (plain) (tree)






































                                                                                  


                                






















                                                                                


                                                




















                                                                                
                                                 

                        
                 
 


                                





                                                                    
 



                                                             











                                                                                
                                     
 
                                    





                                                              
                                     
 
                                    





                                                              
                                     
 
                                    






                                                              
                                     
 
                                    





                                                              
                                     
 
                                    

 
                                             
 
                             
 
                                            





                                                            









                                                 




                                                            









                                                 




                                                            









                                                 




                                                            









                                                 




                                                            









                                                 

 


                                                                        







                                                                            

                                                                              


                                 
                                    


                                             
                        
 




                                                        





                                                 




                                                                                    





















                                                                                                   
/* ---------------------------------------------------------------------------- */
/*                  Atmel Microcontroller Software Support                      */
/*                       SAM Software Package License                           */
/* ---------------------------------------------------------------------------- */
/* Copyright (c) 2015, Atmel Corporation                                        */
/*                                                                              */
/* All rights reserved.                                                         */
/*                                                                              */
/* Redistribution and use in source and binary forms, with or without           */
/* modification, are permitted provided that the following condition is met:    */
/*                                                                              */
/* - Redistributions of source code must retain the above copyright notice,     */
/* this list of conditions and the disclaimer below.                            */
/*                                                                              */
/* Atmel's name may not be used to endorse or promote products derived from     */
/* this software without specific prior written permission.                     */
/*                                                                              */
/* DISCLAIMER:  THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR   */
/* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE   */
/* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,      */
/* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT */
/* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,  */
/* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF    */
/* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING         */
/* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, */
/* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.                           */
/* ---------------------------------------------------------------------------- */

/*
 * \file
 */

/*----------------------------------------------------------------------------
 *        Headers
 *----------------------------------------------------------------------------*/

#include "chip.h"

#include <rtems/irq-extension.h>
#include <rtems/sysinit.h>
#include <bsp/fatal.h>

/*----------------------------------------------------------------------------
 *        Local definitions
 *----------------------------------------------------------------------------*/

/* Maximum number of interrupt sources that can be defined. This
 * constant can be increased, but the current value is the smallest possible
 * that will be compatible with all existing projects. */
#define MAX_INTERRUPT_SOURCES       7

/*----------------------------------------------------------------------------
 *        Local types
 *----------------------------------------------------------------------------*/

/**
 * Describes a PIO interrupt source, including the PIO instance triggering the
 * interrupt and the associated interrupt handler.
 */
typedef struct _InterruptSource {
	/* Pointer to the source pin instance. */
	const Pin *pPin;

	/* Interrupt handler. */
	void (*handler)(const Pin *, void *arg);

	void *arg;
} InterruptSource;

/*----------------------------------------------------------------------------
 *        Local variables
 *----------------------------------------------------------------------------*/

/* List of interrupt sources. */
static InterruptSource _aIntSources[MAX_INTERRUPT_SOURCES];

/* Number of currently defined interrupt sources. */
static uint32_t _dwNumSources = 0;

/*----------------------------------------------------------------------------
 *        Local Functions
 *----------------------------------------------------------------------------*/

/**
 * \brief Handles all interrupts on the given PIO controller.
 * \param id  PIO controller ID.
 * \param pPio  PIO controller base address.
 */
static void PIO_Interrupt(Pio *pPio, uint32_t id)
{
	uint32_t status;
	size_t i;

	status = pPio->PIO_ISR;
	status &= pPio->PIO_IMR;

	for (i = 0; status != 0 && i < MAX_INTERRUPT_SOURCES; ++i) {
		const InterruptSource *is = &_aIntSources[i];
		const Pin *pin = is->pPin;;

		if (pin->id == id) {
			uint32_t mask = pin->mask;

			if ((status & mask) != 0) {
				status &= ~mask;
				(*is->handler)(pin, is->arg);
			}
		}
	}
}

/*----------------------------------------------------------------------------
 *        Global Functions
 *----------------------------------------------------------------------------*/

/**
 * \brief Parallel IO Controller A interrupt handler
 * \Redefined PIOA interrupt handler for NVIC interrupt table.
 */
static void PIOA_Interrupt(void *arg)
{
	PIO_Interrupt(arg, ID_PIOA);
}

/**
 * \brief Parallel IO Controller B interrupt handler
 * \Redefined PIOB interrupt handler for NVIC interrupt table.
 */
static void PIOB_Interrupt(void *arg)
{
	PIO_Interrupt(arg, ID_PIOB);
}

/**
 * \brief Parallel IO Controller C interrupt handler
 * \Redefined PIOC interrupt handler for NVIC interrupt table.
 */
static void PIOC_Interrupt(void *arg)
{
	PIO_Interrupt(arg, ID_PIOC);
}


/**
 * \brief Parallel IO Controller D interrupt handler
 * \Redefined PIOD interrupt handler for NVIC interrupt table.
 */
static void PIOD_Interrupt(void *arg)
{
	PIO_Interrupt(arg, ID_PIOD);
}

/**
 * \brief Parallel IO Controller E interrupt handler
 * \Redefined PIOE interrupt handler for NVIC interrupt table.
 */
static void PIOE_Interrupt(void *arg)
{
	PIO_Interrupt(arg, ID_PIOE);
}

static void PIO_SysInitializeInterrupts(void)
{
	rtems_status_code sc;

	TRACE_DEBUG("PIO_Initialize()\n\r");

	/* Configure PIO interrupt sources */
	TRACE_DEBUG("PIO_Initialize: Configuring PIOA\n\r");
	PMC_EnablePeripheral(ID_PIOA);
	PIOA->PIO_ISR;
	PIOA->PIO_IDR = 0xFFFFFFFF;
	sc = rtems_interrupt_handler_install(
		PIOA_IRQn,
		"PIO A",
		RTEMS_INTERRUPT_UNIQUE,
		PIOA_Interrupt,
		PIOA
	);
	if (sc != RTEMS_SUCCESSFUL) {
		bsp_fatal(ATSAM_FATAL_PIO_IRQ_A);
	}

	TRACE_DEBUG("PIO_Initialize: Configuring PIOB\n\r");
	PMC_EnablePeripheral(ID_PIOB);
	PIOB->PIO_ISR;
	PIOB->PIO_IDR = 0xFFFFFFFF;
	sc = rtems_interrupt_handler_install(
		PIOB_IRQn,
		"PIO B",
		RTEMS_INTERRUPT_UNIQUE,
		PIOB_Interrupt,
		PIOB
	);
	if (sc != RTEMS_SUCCESSFUL) {
		bsp_fatal(ATSAM_FATAL_PIO_IRQ_B);
	}

	TRACE_DEBUG("PIO_Initialize: Configuring PIOC\n\r");
	PMC_EnablePeripheral(ID_PIOC);
	PIOC->PIO_ISR;
	PIOC->PIO_IDR = 0xFFFFFFFF;
	sc = rtems_interrupt_handler_install(
		PIOC_IRQn,
		"PIO C",
		RTEMS_INTERRUPT_UNIQUE,
		PIOC_Interrupt,
		PIOC
	);
	if (sc != RTEMS_SUCCESSFUL) {
		bsp_fatal(ATSAM_FATAL_PIO_IRQ_C);
	}

	TRACE_DEBUG("PIO_Initialize: Configuring PIOD\n\r");
	PMC_EnablePeripheral(ID_PIOD);
	PIOD->PIO_ISR;
	PIOD->PIO_IDR = 0xFFFFFFFF;
	sc = rtems_interrupt_handler_install(
		PIOD_IRQn,
		"PIO D",
		RTEMS_INTERRUPT_UNIQUE,
		PIOD_Interrupt,
		PIOD
	);
	if (sc != RTEMS_SUCCESSFUL) {
		bsp_fatal(ATSAM_FATAL_PIO_IRQ_D);
	}

	TRACE_DEBUG("PIO_Initialize: Configuring PIOE\n\r");
	PMC_EnablePeripheral(ID_PIOE);
	PIOE->PIO_ISR;
	PIOE->PIO_IDR = 0xFFFFFFFF;
	sc = rtems_interrupt_handler_install(
		PIOE_IRQn,
		"PIO E",
		RTEMS_INTERRUPT_UNIQUE,
		PIOE_Interrupt,
		PIOE
	);
	if (sc != RTEMS_SUCCESSFUL) {
		bsp_fatal(ATSAM_FATAL_PIO_IRQ_E);
	}
}

RTEMS_SYSINIT_ITEM(PIO_SysInitializeInterrupts, RTEMS_SYSINIT_BSP_START,
    RTEMS_SYSINIT_ORDER_LAST);

/**
 * Configures a PIO or a group of PIO to generate an interrupt on status
 * change. The provided interrupt handler will be called with the triggering
 * pin as its parameter (enabling different pin instances to share the same
 * handler).
 * \param pPin  Pointer to a Pin instance.
 * \param handler  Interrupt handler function pointer.
 */
void PIO_ConfigureIt(const Pin *pPin, void (*handler)(const Pin *, void *arg),
    void *arg)
{
	Pio *pio;
	InterruptSource *pSource;
	rtems_interrupt_level level;

	TRACE_DEBUG("PIO_ConfigureIt()\n\r");

	pio = pPin->pio;

	rtems_interrupt_disable(level);

	if (_dwNumSources == MAX_INTERRUPT_SOURCES) {
		bsp_fatal(ATSAM_FATAL_PIO_CONFIGURE_IT);
	}

	pSource = &(_aIntSources[_dwNumSources]);
	pSource->pPin = pPin;
	pSource->handler = handler;
	_dwNumSources++;

	rtems_interrupt_enable(level);

	/* Define new source */
	TRACE_DEBUG("PIO_ConfigureIt: Defining new source #%d.\n\r", _dwNumSources);

	/* PIO3 with additional interrupt support
	 * Configure additional interrupt mode registers */
	if (pPin->attribute & PIO_IT_AIME) {
		// enable additional interrupt mode
		pio->PIO_AIMER  = pPin->mask;

		// if bit field of selected pin is 1, set as Rising Edge/High level detection event
		if (pPin->attribute & PIO_IT_RE_OR_HL)
			pio->PIO_REHLSR    = pPin->mask;
		else
			pio->PIO_FELLSR     = pPin->mask;

		/* if bit field of selected pin is 1, set as edge detection source */
		if (pPin->attribute & PIO_IT_EDGE)
			pio->PIO_ESR     = pPin->mask;
		else
			pio->PIO_LSR     = pPin->mask;
	} else {
		/* disable additional interrupt mode */
		pio->PIO_AIMDR       = pPin->mask;
	}
}