cpu/saml21: remodeld GPIO driver implementation
This commit is contained in:
parent
3a2d89f88d
commit
aeecb09883
89
cpu/saml21/include/periph_cpu.h
Normal file
89
cpu/saml21/include/periph_cpu.h
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015 Freie Universität Berlin
|
||||||
|
*
|
||||||
|
* This file is subject to the terms and conditions of the GNU Lesser
|
||||||
|
* General Public License v2.1. See the file LICENSE in the top level
|
||||||
|
* directory for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ingroup cpu_saml21
|
||||||
|
* @{
|
||||||
|
*
|
||||||
|
* @file
|
||||||
|
* @brief CPU specific definitions for internal peripheral handling
|
||||||
|
*
|
||||||
|
* @author Hauke Petersen <hauke.peterse@fu-berlin.de>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef PERIPH_CPU_H_
|
||||||
|
#define PERIPH_CPU_H_
|
||||||
|
|
||||||
|
#include "cpu.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Define mandatory GPIO types for NRF51822 CPUs
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
#define HAVE_GPIO_T
|
||||||
|
typedef uint32_t gpio_t;
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Mandatory function for defining a GPIO pins
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
#define GPIO(x, y) (((gpio_t)(&PORT->Group[x])) | y)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Available ports on the SAML21 for convenient access
|
||||||
|
*/
|
||||||
|
enum {
|
||||||
|
PA = 0, /**< port A */
|
||||||
|
PB = 1, /**< port B */
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Override active flank configuration values
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
#define HAVE_GPIO_FLANK_T
|
||||||
|
typedef enum {
|
||||||
|
GPIO_FALLING = 2, /**< emit interrupt on falling flank */
|
||||||
|
GPIO_RISING = 1, /**< emit interrupt on rising flank */
|
||||||
|
GPIO_BOTH = 3 /**< emit interrupt on both flanks */
|
||||||
|
} gpio_flank_t;
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Available MUX values for configuring a pin's alternate function
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
GPIO_MUX_A = 0x0, /**< select peripheral function A */
|
||||||
|
GPIO_MUX_B = 0x1, /**< select peripheral function B */
|
||||||
|
GPIO_MUX_C = 0x2, /**< select peripheral function C */
|
||||||
|
GPIO_MUX_D = 0x3, /**< select peripheral function D */
|
||||||
|
GPIO_MUX_E = 0x4, /**< select peripheral function E */
|
||||||
|
GPIO_MUX_F = 0x5, /**< select peripheral function F */
|
||||||
|
GPIO_MUX_G = 0x6, /**< select peripheral function G */
|
||||||
|
GPIO_MUX_H = 0x7, /**< select peripheral function H */
|
||||||
|
} gpio_mux_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set up alternate function (PMUX setting) for a PORT pin
|
||||||
|
*
|
||||||
|
* @param[in] dev Pin to set the multiplexing for
|
||||||
|
* @param[in] mux Mux value
|
||||||
|
*/
|
||||||
|
void gpio_init_mux(gpio_t dev, gpio_mux_t mux);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* PERIPH_CPU_H_ */
|
||||||
|
/** @} */
|
||||||
@ -27,52 +27,6 @@ extern "C" {
|
|||||||
#include "cpu_conf.h"
|
#include "cpu_conf.h"
|
||||||
#include "panic.h"
|
#include "panic.h"
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief gpio dev to gpio id mapping table (used internally by implementation)
|
|
||||||
*/
|
|
||||||
extern const uint8_t gpio_table[];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief return PORT ptr for GPIO pin
|
|
||||||
*
|
|
||||||
* @param[in] dev GPIO dev to get PORT for
|
|
||||||
*
|
|
||||||
* @returns pointer to PORT instance
|
|
||||||
*/
|
|
||||||
static inline PortGroup* _port(gpio_t dev)
|
|
||||||
{
|
|
||||||
/* Config validity check. See saml21 periph_conf.h.
|
|
||||||
* This gets optimized out if the configuration is correct.
|
|
||||||
* I put it here so it crashes the board on first GPIO use. */
|
|
||||||
if (GPIO_NUMOF != GPIO_UNUSED) {
|
|
||||||
core_panic(0, "unmatched GPIO_NUMOF and GPIO_UNUSED. Fix periph_conf.\n");
|
|
||||||
}
|
|
||||||
return &PORT->Group[gpio_table[dev]/32];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief return pin nr for gpio dev
|
|
||||||
*
|
|
||||||
* E.g., PA02 -> 2, PC19 -> 19
|
|
||||||
*
|
|
||||||
* @param[in] dev GPIO dev to get pin nr from
|
|
||||||
* @returns pin nr of GPIO dev
|
|
||||||
*/
|
|
||||||
static inline uint32_t _pin(gpio_t dev)
|
|
||||||
{
|
|
||||||
return gpio_table[dev] % 32;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Set up alternate function (PMUX setting) for a PORT pin
|
|
||||||
*
|
|
||||||
* @param[in] dev The Port ID to work on (port*32 + pin)
|
|
||||||
* @param[in] mux required PMUX setting (Mapping A = 0, B=1, ...)
|
|
||||||
*
|
|
||||||
* @returns 0 on success, <0 on error
|
|
||||||
*/
|
|
||||||
int gpio_init_mux(gpio_t dev, uint32_t mux);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2014 Freie Universität Berlin
|
* Copyright (C) 2014-2015 Freie Universität Berlin
|
||||||
* 2015 Kaspar Schleiser <kaspar@schleiser.de>
|
* 2015 Kaspar Schleiser <kaspar@schleiser.de>
|
||||||
* 2015 FreshTemp, LLC.
|
* 2015 FreshTemp, LLC.
|
||||||
*
|
*
|
||||||
@ -18,6 +18,7 @@
|
|||||||
* @author Troels Hoffmeyer <troels.d.hoffmeyer@gmail.com>
|
* @author Troels Hoffmeyer <troels.d.hoffmeyer@gmail.com>
|
||||||
* @author Thomas Eichinger <thomas.eichinger@fu-berlin.de>
|
* @author Thomas Eichinger <thomas.eichinger@fu-berlin.de>
|
||||||
* @author Kaspar Schleiser <kaspar@schleiser.de>
|
* @author Kaspar Schleiser <kaspar@schleiser.de>
|
||||||
|
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
|
||||||
*
|
*
|
||||||
* @}
|
* @}
|
||||||
*/
|
*/
|
||||||
@ -32,366 +33,196 @@
|
|||||||
#include "thread.h"
|
#include "thread.h"
|
||||||
#include "panic.h"
|
#include "panic.h"
|
||||||
|
|
||||||
#define ENABLE_DEBUG (1)
|
#define ENABLE_DEBUG (0)
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
|
|
||||||
/* guard file in case no GPIO devices are defined */
|
/**
|
||||||
#if GPIO_NUMOF
|
* @brief Number of external interrupt lines
|
||||||
|
*/
|
||||||
|
#define NUMOF_IRQS (16U)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Mapping of pins to EXTI lines, -1 means not EXTI possible
|
||||||
|
*/
|
||||||
|
static const int8_t exti_config[2][32] = {
|
||||||
|
{ 0, 1, 2, 3, 4, 5, 6, 7, -1, 9, 10, 11, 12, 13, 14, 15,
|
||||||
|
0, 1, 2, 3, 4, 5, 6, 7, 12, 13, -1, 15, -1, -1, 10, 11},
|
||||||
|
{-1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
|
||||||
|
0, 1, -1, -1, -1, -1, 6, 7, -1, -1, -1, -1, -1, -1, 14, 15},
|
||||||
|
};
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
gpio_cb_t cb; /**< callback called from GPIO interrupt */
|
gpio_cb_t cb; /**< callback called from GPIO interrupt */
|
||||||
void *arg; /**< argument passed to the callback */
|
void *arg; /**< argument passed to the callback */
|
||||||
} gpio_state_t;
|
} gpio_state_t;
|
||||||
|
|
||||||
/**
|
static gpio_state_t gpio_config[NUMOF_IRQS];
|
||||||
* Shitloads of macros just to make sure we don't have to allocate
|
|
||||||
* more than the actually enabled amount of exti states.
|
|
||||||
* The result is an array with the amount of enabled EXIT lines times gpio_state_t,
|
|
||||||
* and an array mapping any EXTI nr to either a unique slot or -1.
|
|
||||||
*
|
|
||||||
* Example: only GPIO_EXTI3_EN and GPIO_EXTI7_EN are set.
|
|
||||||
* GPIO_EXTI_TOTAL will be "2"
|
|
||||||
* gpio_config will be 2*sizeof(gpio_state_t)
|
|
||||||
* gpio_exti_map will have the following content:
|
|
||||||
*
|
|
||||||
* { -1, -1, -1, 0, -1, -1, -1, 1, -1 , ...}
|
|
||||||
*
|
|
||||||
* This maps EXTI3 to gpio_config[0], EXTI7 to gpio_config[1].
|
|
||||||
*
|
|
||||||
* */
|
|
||||||
#define GPIO_EXTI0_POS 0
|
|
||||||
#define GPIO_EXTI1_POS GPIO_EXTI0_EN
|
|
||||||
#define GPIO_EXTI2_POS (GPIO_EXTI1_POS + GPIO_EXTI1_EN)
|
|
||||||
#define GPIO_EXTI3_POS (GPIO_EXTI2_POS + GPIO_EXTI2_EN)
|
|
||||||
#define GPIO_EXTI4_POS (GPIO_EXTI3_POS + GPIO_EXTI3_EN)
|
|
||||||
#define GPIO_EXTI5_POS (GPIO_EXTI4_POS + GPIO_EXTI4_EN)
|
|
||||||
#define GPIO_EXTI6_POS (GPIO_EXTI5_POS + GPIO_EXTI5_EN)
|
|
||||||
#define GPIO_EXTI7_POS (GPIO_EXTI6_POS + GPIO_EXTI6_EN)
|
|
||||||
#define GPIO_EXTI8_POS (GPIO_EXTI7_POS + GPIO_EXTI7_EN)
|
|
||||||
#define GPIO_EXTI9_POS (GPIO_EXTI8_POS + GPIO_EXTI8_EN)
|
|
||||||
#define GPIO_EXTI10_POS (GPIO_EXTI9_POS + GPIO_EXTI9_EN)
|
|
||||||
#define GPIO_EXTI11_POS (GPIO_EXTI10_POS + GPIO_EXTI10_EN)
|
|
||||||
#define GPIO_EXTI12_POS (GPIO_EXTI11_POS + GPIO_EXTI11_EN)
|
|
||||||
#define GPIO_EXTI13_POS (GPIO_EXTI12_POS + GPIO_EXTI12_EN)
|
|
||||||
#define GPIO_EXTI14_POS (GPIO_EXTI13_POS + GPIO_EXTI13_EN)
|
|
||||||
#define GPIO_EXTI15_POS (GPIO_EXTI14_POS + GPIO_EXTI14_EN)
|
|
||||||
|
|
||||||
const static int8_t gpio_exti_map[] = {
|
|
||||||
GPIO_EXTI0_EN ? GPIO_EXTI0_POS : -1,
|
|
||||||
GPIO_EXTI1_EN ? GPIO_EXTI1_POS : -1,
|
|
||||||
GPIO_EXTI2_EN ? GPIO_EXTI2_POS : -1,
|
|
||||||
GPIO_EXTI3_EN ? GPIO_EXTI3_POS : -1,
|
|
||||||
GPIO_EXTI4_EN ? GPIO_EXTI4_POS : -1,
|
|
||||||
GPIO_EXTI5_EN ? GPIO_EXTI5_POS : -1,
|
|
||||||
GPIO_EXTI6_EN ? GPIO_EXTI6_POS : -1,
|
|
||||||
GPIO_EXTI7_EN ? GPIO_EXTI7_POS : -1,
|
|
||||||
GPIO_EXTI8_EN ? GPIO_EXTI8_POS : -1,
|
|
||||||
GPIO_EXTI9_EN ? GPIO_EXTI9_POS : -1,
|
|
||||||
GPIO_EXTI10_EN ? GPIO_EXTI10_POS : -1,
|
|
||||||
GPIO_EXTI11_EN ? GPIO_EXTI11_POS : -1,
|
|
||||||
GPIO_EXTI12_EN ? GPIO_EXTI12_POS : -1,
|
|
||||||
GPIO_EXTI13_EN ? GPIO_EXTI13_POS : -1,
|
|
||||||
GPIO_EXTI14_EN ? GPIO_EXTI14_POS : -1,
|
|
||||||
GPIO_EXTI15_EN ? GPIO_EXTI15_POS : -1,
|
|
||||||
};
|
|
||||||
|
|
||||||
#define GPIO_EXTI_TOTAL (\
|
static inline PortGroup *_port(gpio_t pin)
|
||||||
GPIO_EXTI0_EN + \
|
|
||||||
GPIO_EXTI1_EN + \
|
|
||||||
GPIO_EXTI2_EN + \
|
|
||||||
GPIO_EXTI3_EN + \
|
|
||||||
GPIO_EXTI4_EN + \
|
|
||||||
GPIO_EXTI5_EN + \
|
|
||||||
GPIO_EXTI6_EN + \
|
|
||||||
GPIO_EXTI7_EN + \
|
|
||||||
GPIO_EXTI8_EN + \
|
|
||||||
GPIO_EXTI9_EN + \
|
|
||||||
GPIO_EXTI10_EN + \
|
|
||||||
GPIO_EXTI11_EN + \
|
|
||||||
GPIO_EXTI12_EN + \
|
|
||||||
GPIO_EXTI13_EN + \
|
|
||||||
GPIO_EXTI14_EN + \
|
|
||||||
GPIO_EXTI15_EN)
|
|
||||||
|
|
||||||
static gpio_state_t gpio_config[GPIO_EXTI_TOTAL];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Convenience enum
|
|
||||||
*/
|
|
||||||
enum {
|
|
||||||
PA,
|
|
||||||
PB,
|
|
||||||
PC,
|
|
||||||
PD,
|
|
||||||
PE,
|
|
||||||
PF
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Map from 0..GPIO_NUMOF-1 to actual GPIO pins
|
|
||||||
*
|
|
||||||
* This map/macro combo is used to map natural integers
|
|
||||||
* starting by 0 upto GPIO_NUMOF-1 to the actual GPIO pin.
|
|
||||||
*
|
|
||||||
* GPIO pins are mapped into an implicit flat number space, e.g.,
|
|
||||||
* Port C Pin 14 is mapped to (2*32 + 14)
|
|
||||||
*
|
|
||||||
* Pxn is supposed to be part of an enum set in "periph_conf.h".
|
|
||||||
*
|
|
||||||
* Example:
|
|
||||||
*
|
|
||||||
* enum {
|
|
||||||
* PA2,
|
|
||||||
* PB10,
|
|
||||||
* GPIO_UNUSED,
|
|
||||||
* PB5,
|
|
||||||
* PA3,
|
|
||||||
* };
|
|
||||||
*
|
|
||||||
* All pins > GPIO_UNUSED are mapped to the same spot so
|
|
||||||
* they don't waste memory.
|
|
||||||
*/
|
|
||||||
#define DEFINE_GPIO_PIN(port, pin) [(port ## pin) > GPIO_UNUSED ? GPIO_UNUSED : (port ## pin)] = (port*32 + pin)
|
|
||||||
const uint8_t gpio_table[] = {
|
|
||||||
DEFINE_GPIO_PIN(PA, 2),
|
|
||||||
DEFINE_GPIO_PIN(PA, 4),
|
|
||||||
DEFINE_GPIO_PIN(PA, 5),
|
|
||||||
DEFINE_GPIO_PIN(PA, 6),
|
|
||||||
DEFINE_GPIO_PIN(PA, 7),
|
|
||||||
DEFINE_GPIO_PIN(PA, 3),
|
|
||||||
DEFINE_GPIO_PIN(PA, 12),
|
|
||||||
DEFINE_GPIO_PIN(PA, 13),
|
|
||||||
DEFINE_GPIO_PIN(PB, 4),
|
|
||||||
DEFINE_GPIO_PIN(PB, 5),
|
|
||||||
DEFINE_GPIO_PIN(PB, 6),
|
|
||||||
DEFINE_GPIO_PIN(PB, 7),
|
|
||||||
DEFINE_GPIO_PIN(PB, 9),
|
|
||||||
DEFINE_GPIO_PIN(PB, 10),
|
|
||||||
};
|
|
||||||
|
|
||||||
int gpio_init_mux(gpio_t dev, uint32_t mux)
|
|
||||||
{
|
{
|
||||||
if (dev >= GPIO_NUMOF) {
|
return (PortGroup *)(pin & ~(0x1f));
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
PortGroup* port = _port(dev);
|
|
||||||
uint32_t pin = _pin(dev);
|
|
||||||
|
|
||||||
/* WRCONFIG supports only half of the pin-space, selected by HWSEL
|
|
||||||
* (half-word selection).
|
|
||||||
* So here we either just use the lower half, or shift it by a
|
|
||||||
* half-word and set the half-word select (HWSEL) flag.
|
|
||||||
* */
|
|
||||||
uint32_t hwmode = (pin < 16) ? (1 << pin) : (((1 << pin) >> 16) | PORT_WRCONFIG_HWSEL);
|
|
||||||
|
|
||||||
port->WRCONFIG.reg = PORT_WRCONFIG_WRPINCFG
|
|
||||||
| PORT_WRCONFIG_WRPMUX
|
|
||||||
| PORT_WRCONFIG_PMUX(mux)
|
|
||||||
| PORT_WRCONFIG_PMUXEN
|
|
||||||
/*| (mux ? PORT_WRCONFIG_PMUXEN : 0)*/
|
|
||||||
| hwmode;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
int gpio_init_out(gpio_t dev, gpio_pp_t pushpull)
|
|
||||||
|
static inline int _pin_pos(gpio_t pin)
|
||||||
{
|
{
|
||||||
if (dev >= GPIO_NUMOF) {
|
return (pin & 0x1f);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int _pin_mask(gpio_t pin)
|
||||||
|
{
|
||||||
|
return (1 << _pin_pos(pin));
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _exti(gpio_t pin)
|
||||||
|
{
|
||||||
|
int port_num = ((pin >> 7) & 0x03);
|
||||||
|
|
||||||
|
if (port_num > 1) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
return exti_config[port_num][_pin_pos(pin)];
|
||||||
|
}
|
||||||
|
|
||||||
PortGroup* port = _port(dev);
|
void gpio_init_mux(gpio_t pin, gpio_mux_t mux)
|
||||||
uint32_t pin = _pin(dev);
|
{
|
||||||
|
PortGroup* port = _port(pin);
|
||||||
|
int pin_pos = _pin_pos(pin);
|
||||||
|
|
||||||
/* configure as output */
|
port->PINCFG[pin_pos].reg |= PORT_PINCFG_PMUXEN;
|
||||||
port->DIRSET.reg = 1 << pin;
|
port->PMUX[pin_pos >> 1].reg &= ~(0xf << (4 * (pin_pos & 0x1)));
|
||||||
|
port->PMUX[pin_pos >> 1].reg |= (mux << (4 * (pin_pos & 0x1)));
|
||||||
|
}
|
||||||
|
|
||||||
/* configure the pin's pull resistor state */
|
int gpio_init(gpio_t pin, gpio_dir_t dir, gpio_pp_t pushpull)
|
||||||
|
{
|
||||||
|
PortGroup* port = _port(pin);
|
||||||
|
int pin_pos = _pin_pos(pin);
|
||||||
|
int pin_mask = _pin_mask(pin);
|
||||||
|
|
||||||
|
/* configure the pin's pull resistor and reset all other configuration */
|
||||||
switch (pushpull) {
|
switch (pushpull) {
|
||||||
case GPIO_PULLDOWN:
|
case GPIO_PULLDOWN:
|
||||||
return -1;
|
port->OUTCLR.reg = pin_mask;
|
||||||
|
port->PINCFG[pin_pos].reg = PORT_PINCFG_PULLEN;
|
||||||
|
break;
|
||||||
case GPIO_PULLUP:
|
case GPIO_PULLUP:
|
||||||
port->PINCFG[pin].bit.PULLEN = true;
|
port->OUTSET.reg = pin_mask;
|
||||||
|
port->PINCFG[pin_pos].reg = PORT_PINCFG_PULLEN;
|
||||||
break;
|
break;
|
||||||
case GPIO_NOPULL:
|
case GPIO_NOPULL:
|
||||||
port->PINCFG[pin].bit.PULLEN = false;
|
port->PINCFG[pin_pos].reg = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
/* set pin_pos direction */
|
||||||
|
if (dir == GPIO_DIR_OUT) {
|
||||||
|
if (pushpull == GPIO_PULLDOWN) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
port->DIRSET.reg = pin_mask; /* configure as output */
|
||||||
|
port->OUTCLR.reg = pin_mask; /* set pin LOW on init */
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
port->DIRCLR.reg = pin_mask; /* configure as input */
|
||||||
|
port->PINCFG[pin_pos].reg |= PORT_PINCFG_INEN;
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int gpio_init_in(gpio_t dev, gpio_pp_t pushpull)
|
int gpio_init_int(gpio_t pin, gpio_pp_t pullup, gpio_flank_t flank,
|
||||||
|
gpio_cb_t cb, void *arg)
|
||||||
{
|
{
|
||||||
if (dev >= GPIO_NUMOF) {
|
int exti = _exti(pin);
|
||||||
|
|
||||||
|
/* make sure EIC channel is valid */
|
||||||
|
if (exti == -1) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
PortGroup* port = _port(dev);
|
|
||||||
uint32_t pin = _pin(dev);
|
|
||||||
|
|
||||||
/* configure as input */
|
|
||||||
port->DIRCLR.reg = 1 << pin;
|
|
||||||
/* buffer input value */
|
|
||||||
port->PINCFG[pin].bit.INEN = true;
|
|
||||||
|
|
||||||
/* configure the pin's pull resistor state */
|
|
||||||
switch (pushpull) {
|
|
||||||
case GPIO_PULLDOWN:
|
|
||||||
port->OUTCLR.reg = 1 << pin;
|
|
||||||
port->PINCFG[pin].bit.PULLEN = true;
|
|
||||||
break;
|
|
||||||
case GPIO_PULLUP:
|
|
||||||
port->OUTSET.reg = 1 << pin;
|
|
||||||
port->PINCFG[pin].bit.PULLEN = true;
|
|
||||||
break;
|
|
||||||
case GPIO_NOPULL:
|
|
||||||
port->PINCFG[pin].bit.PULLEN = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int gpio_init_int(gpio_t dev, gpio_pp_t pullup, gpio_flank_t flank, gpio_cb_t cb, void *arg)
|
|
||||||
{
|
|
||||||
if (dev >= GPIO_NUMOF) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t pin = _pin(dev);
|
|
||||||
uint32_t extint = pin % 16;
|
|
||||||
|
|
||||||
int exti_pos = gpio_exti_map[extint];
|
|
||||||
if (exti_pos == -1) {
|
|
||||||
/* EXTI line not enabled. */
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int res = 0;
|
|
||||||
|
|
||||||
/* set pin mux */
|
|
||||||
gpio_init_mux(dev, 0);
|
|
||||||
|
|
||||||
/* configure pin as input */
|
|
||||||
res = gpio_init_in(dev, pullup);
|
|
||||||
if (res < 0) {
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Turn on APB clock */
|
|
||||||
MCLK->APBAMASK.reg |= MCLK_APBAMASK_EIC;
|
|
||||||
|
|
||||||
/* setup GCLK for EIC */
|
|
||||||
GCLK->PCHCTRL[EIC_GCLK_ID].reg = GCLK_PCHCTRL_CHEN | GCLK_PCHCTRL_GEN_GCLK0;
|
|
||||||
|
|
||||||
/* Setup interrupt */
|
|
||||||
NVIC_SetPriority(EIC_IRQn, 10);
|
|
||||||
NVIC_EnableIRQ(EIC_IRQn);
|
|
||||||
|
|
||||||
/* save callback */
|
/* save callback */
|
||||||
gpio_config[exti_pos].cb = cb;
|
gpio_config[exti].cb = cb;
|
||||||
gpio_config[exti_pos].arg = arg;
|
gpio_config[exti].arg = arg;
|
||||||
|
/* configure ping as input and set MUX to peripheral function A */
|
||||||
/* must disable EIC before configuring. */
|
gpio_init(pin, GPIO_DIR_IN, pullup);
|
||||||
EIC->CTRLA.bit.ENABLE = false;
|
gpio_init_mux(pin, GPIO_MUX_A);
|
||||||
|
/* enable clocks for the EIC module */
|
||||||
|
MCLK->APBAMASK.reg |= MCLK_APBAMASK_EIC;
|
||||||
|
GCLK->PCHCTRL[EIC_GCLK_ID].reg = GCLK_PCHCTRL_CHEN | GCLK_PCHCTRL_GEN_GCLK0;
|
||||||
|
/* configure the active flank */
|
||||||
|
EIC->CONFIG[exti >> 3].reg &= ~(0xf << ((exti & 0x7) * 4));
|
||||||
|
EIC->CONFIG[exti >> 3].reg |= (flank << ((exti & 0x7) * 4));
|
||||||
|
/* enable the global EIC interrupt */
|
||||||
|
NVIC_EnableIRQ(EIC_IRQn);
|
||||||
/*Enable pin interrupt */
|
/*Enable pin interrupt */
|
||||||
EIC->INTFLAG.reg |= (1 << extint);
|
EIC->INTFLAG.reg = (1 << exti);
|
||||||
EIC->INTENSET.reg = 1 << extint;
|
EIC->INTENSET.reg = (1 << exti);
|
||||||
|
/* enable the EIC module*/
|
||||||
/*Set config */
|
EIC->CTRLA.reg = EIC_CTRLA_ENABLE;
|
||||||
uint8_t config_pos = (4 * (extint % 8));
|
while (EIC->SYNCBUSY.reg & EIC_SYNCBUSY_ENABLE);
|
||||||
uint8_t config_reg = extint / 8;
|
|
||||||
/*Set flank detection */
|
|
||||||
switch (flank) {
|
|
||||||
case GPIO_FALLING:
|
|
||||||
EIC->CONFIG[config_reg].reg
|
|
||||||
|= (EIC_CONFIG_SENSE0_FALL_Val << config_pos);
|
|
||||||
break;
|
|
||||||
case GPIO_RISING:
|
|
||||||
EIC->CONFIG[config_reg].reg
|
|
||||||
|= (EIC_CONFIG_SENSE0_RISE_Val << config_pos);
|
|
||||||
break;
|
|
||||||
case GPIO_BOTH:
|
|
||||||
EIC->CONFIG[config_reg].reg
|
|
||||||
|= (EIC_CONFIG_SENSE0_BOTH_Val << config_pos);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*Enable external interrupts*/
|
|
||||||
EIC->CTRLA.bit.ENABLE = true;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void gpio_irq_enable(gpio_t dev)
|
void gpio_irq_enable(gpio_t pin)
|
||||||
{
|
{
|
||||||
uint32_t extint = _pin(dev) % 16;
|
int exti = _exti(pin);
|
||||||
EIC->INTENSET.reg = 1 << extint;
|
if (exti == -1) {
|
||||||
}
|
return;
|
||||||
|
|
||||||
void gpio_irq_disable(gpio_t dev)
|
|
||||||
{
|
|
||||||
uint32_t extint = _pin(dev) % 16;
|
|
||||||
EIC->INTENCLR.reg = 1 << extint;
|
|
||||||
}
|
|
||||||
|
|
||||||
int gpio_read(gpio_t dev)
|
|
||||||
{
|
|
||||||
PortGroup* port = _port(dev);
|
|
||||||
uint32_t pin = _pin(dev);
|
|
||||||
int res = -1;
|
|
||||||
|
|
||||||
res = port->IN.reg & (1 << pin);
|
|
||||||
|
|
||||||
/* make sure we are not returning a negative value if bit 31 is set */
|
|
||||||
if (res < -1) {
|
|
||||||
res = 1;
|
|
||||||
}
|
}
|
||||||
|
EIC->INTENSET.reg = (1 << exti);
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void gpio_set(gpio_t dev)
|
void gpio_irq_disable(gpio_t pin)
|
||||||
{
|
{
|
||||||
PortGroup* port = _port(dev);
|
int exti = _exti(pin);
|
||||||
uint32_t pin = _pin(dev);
|
if (exti == -1) {
|
||||||
|
return;
|
||||||
port->OUTSET.reg = 1 << pin;
|
}
|
||||||
|
EIC->INTENCLR.reg = (1 << exti);
|
||||||
}
|
}
|
||||||
|
|
||||||
void gpio_clear(gpio_t dev)
|
int gpio_read(gpio_t pin)
|
||||||
{
|
{
|
||||||
PortGroup* port = _port(dev);
|
PortGroup *port = _port(pin);
|
||||||
uint32_t pin = _pin(dev);
|
int mask = _pin_mask(pin);
|
||||||
port->OUTCLR.reg = 1 << pin;
|
|
||||||
|
if (port->DIR.reg & mask) {
|
||||||
|
return (port->OUT.reg & mask) ? 1 : 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return (port->IN.reg & mask) ? 1 : 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void gpio_toggle(gpio_t dev)
|
void gpio_set(gpio_t pin)
|
||||||
{
|
{
|
||||||
PortGroup* port = _port(dev);
|
_port(pin)->OUTSET.reg = _pin_mask(pin);
|
||||||
uint32_t pin = _pin(dev);
|
|
||||||
port->OUTTGL.reg = 1 << pin;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void gpio_write(gpio_t dev, int value)
|
void gpio_clear(gpio_t pin)
|
||||||
|
{
|
||||||
|
_port(pin)->OUTCLR.reg = _pin_mask(pin);
|
||||||
|
}
|
||||||
|
|
||||||
|
void gpio_toggle(gpio_t pin)
|
||||||
|
{
|
||||||
|
_port(pin)->OUTTGL.reg = _pin_mask(pin);
|
||||||
|
}
|
||||||
|
|
||||||
|
void gpio_write(gpio_t pin, int value)
|
||||||
{
|
{
|
||||||
if (value) {
|
if (value) {
|
||||||
gpio_set(dev);
|
_port(pin)->OUTSET.reg = _pin_mask(pin);
|
||||||
} else {
|
} else {
|
||||||
gpio_clear(dev);
|
_port(pin)->OUTCLR.reg = _pin_mask(pin);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void isr_eic(void)
|
void isr_eic(void)
|
||||||
{
|
{
|
||||||
uint16_t status = EIC->INTFLAG.reg;
|
for (int i = 0; i < NUMOF_IRQS; i++) {
|
||||||
for (int i = 0; i < 16; i++) {
|
if (EIC->INTFLAG.reg & (1 << i)) {
|
||||||
if (status & (0x1<<i)) {
|
EIC->INTFLAG.reg = (1 << i);
|
||||||
int gpio_exti = gpio_exti_map[i];
|
gpio_config[i].cb(gpio_config[i].arg);
|
||||||
gpio_config[gpio_exti].cb(gpio_config[gpio_exti].arg);
|
|
||||||
EIC->INTFLAG.reg = 0x1 << i;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -399,5 +230,3 @@ void isr_eic(void)
|
|||||||
thread_yield();
|
thread_yield();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* GPIO_NUMOF */
|
|
||||||
|
|||||||
@ -72,7 +72,7 @@ typedef struct spi_saml21 {
|
|||||||
static const spi_saml21_t spi[] = {
|
static const spi_saml21_t spi[] = {
|
||||||
#if SPI_0_EN
|
#if SPI_0_EN
|
||||||
/* SPI device */ /* MCLK flag */ /* GLCK id */ /* SCLK */ /* MISO */ /* MOSI */ /* dipo+dopo */
|
/* SPI device */ /* MCLK flag */ /* GLCK id */ /* SCLK */ /* MISO */ /* MOSI */ /* dipo+dopo */
|
||||||
{ &(SERCOM0->SPI), MCLK_APBCMASK_SERCOM0, SERCOM0_GCLK_ID_CORE, { PA7, 3 }, { PA4, 3 }, { PA6, 3 }, 0, 1 }
|
{ &(SERCOM0->SPI), MCLK_APBCMASK_SERCOM0, SERCOM0_GCLK_ID_CORE, { GPIO(PA,7), 3 }, { GPIO(PA,4), 3 }, { GPIO(PA,6), 3 }, 0, 1 }
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -133,21 +133,19 @@ int spi_init_master(spi_t dev, spi_conf_t conf, spi_speed_t speed)
|
|||||||
|
|
||||||
while (!(GCLK->PCHCTRL[spi[dev].gclk_id].reg & GCLK_PCHCTRL_CHEN));
|
while (!(GCLK->PCHCTRL[spi[dev].gclk_id].reg & GCLK_PCHCTRL_CHEN));
|
||||||
|
|
||||||
|
/* SCLK+MOSI = output */
|
||||||
|
gpio_init(spi[dev].sclk.pin, GPIO_DIR_OUT, GPIO_NOPULL);
|
||||||
|
gpio_init(spi[dev].mosi.pin, GPIO_DIR_OUT, GPIO_NOPULL);
|
||||||
|
/* MISO = input */
|
||||||
|
gpio_init(spi[dev].miso.pin, GPIO_DIR_IN, GPIO_PULLUP);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Set alternate funcion (PMUX) for our ports.
|
* Set alternate funcion (PMUX) for our ports.
|
||||||
* This has to be done before gpio_init_[in|out].
|
|
||||||
*/
|
*/
|
||||||
gpio_init_mux(spi[dev].sclk.pin, spi[dev].sclk.pmux);
|
gpio_init_mux(spi[dev].sclk.pin, spi[dev].sclk.pmux);
|
||||||
gpio_init_mux(spi[dev].miso.pin, spi[dev].miso.pmux);
|
gpio_init_mux(spi[dev].miso.pin, spi[dev].miso.pmux);
|
||||||
gpio_init_mux(spi[dev].mosi.pin, spi[dev].mosi.pmux);
|
gpio_init_mux(spi[dev].mosi.pin, spi[dev].mosi.pmux);
|
||||||
|
|
||||||
/* SCLK+MOSI = output */
|
|
||||||
gpio_init_out(spi[dev].sclk.pin, GPIO_NOPULL);
|
|
||||||
gpio_init_out(spi[dev].mosi.pin, GPIO_NOPULL);
|
|
||||||
|
|
||||||
/* MISO = input */
|
|
||||||
gpio_init_in(spi[dev].miso.pin, GPIO_PULLUP);
|
|
||||||
|
|
||||||
/* pin pad mapping */
|
/* pin pad mapping */
|
||||||
dipo = spi[dev].dipo;
|
dipo = spi[dev].dipo;
|
||||||
dopo = spi[dev].dopo;
|
dopo = spi[dev].dopo;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user