mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2025-01-17 05:12:57 +01:00
cpu/sam0+boards: adapted to new SPI API
- adapted the SPI driver - merged SPI driver for samr21 and saml21 - adapted all boards using the CPU
This commit is contained in:
parent
10b0013315
commit
ea07a6817c
@ -183,23 +183,21 @@ static const pwm_conf_t pwm_config[] = {
|
||||
* @name SPI configuration
|
||||
* @{
|
||||
*/
|
||||
#define SPI_NUMOF (1)
|
||||
#define SPI_0_EN 1
|
||||
|
||||
/* SPI0 */
|
||||
#define SPI_0_DEV SERCOM4->SPI
|
||||
#define SPI_IRQ_0 SERCOM4_IRQn
|
||||
#define SPI_0_GCLK_ID SERCOM4_GCLK_ID_CORE
|
||||
/* SPI 0 pin configuration */
|
||||
#define SPI_0_SCLK GPIO_PIN(PB, 11)
|
||||
#define SPI_0_SCLK_MUX GPIO_MUX_D
|
||||
#define SPI_0_MISO GPIO_PIN(PA, 12)
|
||||
#define SPI_0_MISO_MUX GPIO_MUX_D
|
||||
#define SPI_0_MISO_PAD SPI_PAD_MISO_0
|
||||
#define SPI_0_MOSI GPIO_PIN(PB, 10)
|
||||
#define SPI_0_MOSI_MUX GPIO_MUX_D
|
||||
#define SPI_0_MOSI_PAD SPI_PAD_MOSI_2_SCK_3
|
||||
static const spi_conf_t spi_config[] = {
|
||||
{
|
||||
.dev = &SERCOM4->SPI,
|
||||
.miso_pin = GPIO_PIN(PA, 12),
|
||||
.mosi_pin = GPIO_PIN(PB, 10),
|
||||
.clk_pin = GPIO_PIN(PB, 11),
|
||||
.miso_mux = GPIO_MUX_D,
|
||||
.mosi_mux = GPIO_MUX_D,
|
||||
.clk_mux = GPIO_MUX_D,
|
||||
.miso_pad = SPI_PAD_MISO_0,
|
||||
.mosi_pad = SPI_PAD_MOSI_2_SCK_3
|
||||
}
|
||||
};
|
||||
|
||||
#define SPI_NUMOF (sizeof(spi_config) / sizeof(spi_config[0]))
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Kaspar Schleiser <kaspar@schleiser.de>
|
||||
* 2015 FreshTemp, LLC.
|
||||
* 2014 Freie Universität Berlin
|
||||
* 2014-2016 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
|
||||
@ -16,12 +16,15 @@
|
||||
* @brief Peripheral MCU configuration for the Atmel SAM L21 Xplained Pro board
|
||||
*
|
||||
* @author Thomas Eichinger <thomas.eichinger@fu-berlin.de>
|
||||
* @autor Kaspar Schleiser <kaspar@schleiser.de>
|
||||
* @author Kaspar Schleiser <kaspar@schleiser.de>
|
||||
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
|
||||
*/
|
||||
|
||||
#ifndef PERIPH_CONF_H
|
||||
#define PERIPH_CONF_H
|
||||
|
||||
#include "periph_cpu.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
@ -29,7 +32,7 @@ extern "C" {
|
||||
/**
|
||||
* @brief GCLK reference speed
|
||||
*/
|
||||
#define GCLK_REF (16000000U)
|
||||
#define CLOCK_CORECLOCK (16000000U)
|
||||
|
||||
/**
|
||||
* @name Timer peripheral configuration
|
||||
@ -71,8 +74,22 @@ extern "C" {
|
||||
* @name SPI configuration
|
||||
* @{
|
||||
*/
|
||||
#define SPI_NUMOF (1)
|
||||
#define SPI_0_EN 1
|
||||
static const spi_conf_t spi_config[] = {
|
||||
{
|
||||
.dev = &(SERCOM0->SPI),
|
||||
.miso_pin = GPIO_PIN(PA, 4),
|
||||
.mosi_pin = GPIO_PIN(PA, 6),
|
||||
.clk_pin = GPIO_PIN(PA, 7),
|
||||
.miso_mux = GPIO_MUX_D,
|
||||
.mosi_mux = GPIO_MUX_D,
|
||||
.clk_mux = GPIO_MUX_D,
|
||||
.miso_pad = SPI_PAD_MISO_0,
|
||||
.mosi_pad = SPI_PAD_MOSI_2_SCK_3
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
#define SPI_NUMOF (sizeof(spi_config) / sizeof(spi_config[0]))
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
|
@ -43,8 +43,8 @@ extern "C" {
|
||||
*
|
||||
* {spi bus, spi speed, cs pin, int pin, reset pin, sleep pin}
|
||||
*/
|
||||
#define AT86RF2XX_PARAMS_BOARD {.spi = SPI_0, \
|
||||
.spi_speed = SPI_SPEED_5MHZ, \
|
||||
#define AT86RF2XX_PARAMS_BOARD {.spi = SPI_DEV(0), \
|
||||
.spi_clk = SPI_CLK_5MHZ, \
|
||||
.cs_pin = GPIO_PIN(PB, 31), \
|
||||
.int_pin = GPIO_PIN(PB, 0), \
|
||||
.sleep_pin = GPIO_PIN(PA, 20), \
|
||||
|
@ -168,37 +168,32 @@ static const pwm_conf_t pwm_config[] = {
|
||||
* @name SPI configuration
|
||||
* @{
|
||||
*/
|
||||
#define SPI_NUMOF (2)
|
||||
#define SPI_0_EN 1
|
||||
#define SPI_1_EN 1
|
||||
static const spi_conf_t spi_config[] = {
|
||||
{
|
||||
.dev = &SERCOM4->SPI,
|
||||
.miso_pin = GPIO_PIN(PC, 19),
|
||||
.mosi_pin = GPIO_PIN(PB, 30),
|
||||
.clk_pin = GPIO_PIN(PC, 18),
|
||||
.miso_mux = GPIO_MUX_F,
|
||||
.mosi_mux = GPIO_MUX_F,
|
||||
.clk_mux = GPIO_MUX_F,
|
||||
.miso_pad = SPI_PAD_MISO_0,
|
||||
.mosi_pad = SPI_PAD_MOSI_2_SCK_3
|
||||
},
|
||||
{
|
||||
.dev = &SERCOM5->SPI,
|
||||
.miso_pin = GPIO_PIN(PB, 2),
|
||||
.mosi_pin = GPIO_PIN(PB, 22),
|
||||
.clk_pin = GPIO_PIN(PB, 23),
|
||||
.miso_mux = GPIO_MUX_D,
|
||||
.mosi_mux = GPIO_MUX_D,
|
||||
.clk_mux = GPIO_MUX_D,
|
||||
.miso_pad = SPI_PAD_MISO_0,
|
||||
.mosi_pad = SPI_PAD_MOSI_2_SCK_3
|
||||
}
|
||||
};
|
||||
|
||||
/* SPI0 */
|
||||
#define SPI_0_DEV SERCOM4->SPI
|
||||
#define SPI_IRQ_0 SERCOM4_IRQn
|
||||
#define SPI_0_GCLK_ID SERCOM4_GCLK_ID_CORE
|
||||
/* SPI 0 pin configuration */
|
||||
#define SPI_0_SCLK GPIO_PIN(PC, 18)
|
||||
#define SPI_0_SCLK_MUX GPIO_MUX_F
|
||||
#define SPI_0_MISO GPIO_PIN(PC, 19)
|
||||
#define SPI_0_MISO_MUX GPIO_MUX_F
|
||||
#define SPI_0_MISO_PAD SPI_PAD_MISO_0
|
||||
#define SPI_0_MOSI GPIO_PIN(PB, 30)
|
||||
#define SPI_0_MOSI_MUX GPIO_MUX_F
|
||||
#define SPI_0_MOSI_PAD SPI_PAD_MOSI_2_SCK_3
|
||||
|
||||
/* SPI1 */
|
||||
#define SPI_1_DEV SERCOM5->SPI
|
||||
#define SPI_IRQ_1 SERCOM5_IRQn
|
||||
#define SPI_1_GCLK_ID SERCOM5_GCLK_ID_CORE
|
||||
/* SPI 1 pin configuration */
|
||||
#define SPI_1_SCLK GPIO_PIN(PB, 23)
|
||||
#define SPI_1_SCLK_MUX GPIO_MUX_D
|
||||
#define SPI_1_MISO GPIO_PIN(PB, 02)
|
||||
#define SPI_1_MISO_MUX GPIO_MUX_D
|
||||
#define SPI_1_MISO_PAD SPI_PAD_MISO_0
|
||||
#define SPI_1_MOSI GPIO_PIN(PB, 22)
|
||||
#define SPI_1_MOSI_MUX GPIO_MUX_D
|
||||
#define SPI_1_MOSI_PAD SPI_PAD_MOSI_2_SCK_3
|
||||
#define SPI_NUMOF (sizeof(spi_config) / sizeof(spi_config[0]))
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
|
@ -133,7 +133,7 @@ static const uart_conf_t uart_config[] = {
|
||||
.mux = GPIO_MUX_C,
|
||||
.rx_pad = UART_PAD_RX_1,
|
||||
.tx_pad = UART_PAD_TX_2,
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
/* interrupt function name mapping */
|
||||
@ -184,27 +184,21 @@ static const pwm_conf_t pwm_config[] = {
|
||||
* @name SPI configuration
|
||||
* @{
|
||||
*/
|
||||
#define SPI_NUMOF (1)
|
||||
#define SPI_0_EN 1
|
||||
#define SPI_1_EN 0
|
||||
|
||||
/* SPI0 */
|
||||
#define SPI_0_DEV SERCOM3->SPI
|
||||
#define SPI_IRQ_0 SERCOM3_IRQn
|
||||
#define SPI_0_GCLK_ID SERCOM3_GCLK_ID_CORE
|
||||
/* SPI 0 pin configuration */
|
||||
#define SPI_0_SCLK GPIO_PIN(PA, 21)
|
||||
#define SPI_0_SCLK_MUX GPIO_MUX_D
|
||||
#define SPI_0_MISO GPIO_PIN(PA, 22)
|
||||
#define SPI_0_MISO_MUX GPIO_MUX_C
|
||||
#define SPI_0_MISO_PAD SPI_PAD_MISO_0
|
||||
#define SPI_0_MOSI GPIO_PIN(PA, 20)
|
||||
#define SPI_0_MOSI_MUX GPIO_MUX_D
|
||||
#define SPI_0_MOSI_PAD SPI_PAD_MOSI_2_SCK_3
|
||||
|
||||
// How/where do we define SS?
|
||||
#define SPI_0_SS GPIO_PIN(PA, 23)
|
||||
static const spi_conf_t spi_config[] = {
|
||||
{
|
||||
.dev = &SERCOM3->SPI,
|
||||
.miso_pin = GPIO_PIN(PA, 22),
|
||||
.mosi_pin = GPIO_PIN(PA, 20),
|
||||
.clk_pin = GPIO_PIN(PA, 21),
|
||||
.miso_mux = GPIO_MUX_C,
|
||||
.mosi_mux = GPIO_MUX_D,
|
||||
.clk_mux = GPIO_MUX_D,
|
||||
.miso_pad = SPI_PAD_MISO_0,
|
||||
.mosi_pad = SPI_PAD_MOSI_2_SCK_3,
|
||||
},
|
||||
};
|
||||
|
||||
#define SPI_NUMOF (sizeof(spi_config) / sizeof(spi_config[0]))
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
|
@ -34,7 +34,8 @@ extern "C" {
|
||||
* @brief Use shared SPI functions
|
||||
* @{
|
||||
*/
|
||||
#define PERIPH_SPI_NEEDS_TRANSFER_BYTES
|
||||
#define PERIPH_SPI_NEEDS_INIT_CS
|
||||
#define PERIPH_SPI_NEEDS_TRANSFER_BYTE
|
||||
#define PERIPH_SPI_NEEDS_TRANSFER_REG
|
||||
#define PERIPH_SPI_NEEDS_TRANSFER_REGS
|
||||
/** @} */
|
||||
@ -127,15 +128,46 @@ typedef enum {
|
||||
} spi_mosipad_t;
|
||||
|
||||
/**
|
||||
* @brief Possible selections for SERCOM SPI clock mode (inspired by Arduino)
|
||||
* @brief Override SPI modes
|
||||
* @{
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
SERCOM_SPI_MODE_0 = 0, // CPOL : 0 | CPHA : 0
|
||||
SERCOM_SPI_MODE_1 = 1, // CPOL : 0 | CPHA : 1
|
||||
SERCOM_SPI_MODE_2 = 2, // CPOL : 1 | CPHA : 0
|
||||
SERCOM_SPI_MODE_3 = 3, // CPOL : 1 | CPHA : 1
|
||||
} sercom_spi_clockmode_t;
|
||||
#define HAVE_SPI_MODE_T
|
||||
typedef enum {
|
||||
SPI_MODE_0 = 0x0, /**< CPOL=0, CPHA=0 */
|
||||
SPI_MODE_1 = 0x1, /**< CPOL=0, CPHA=1 */
|
||||
SPI_MODE_2 = 0x2, /**< CPOL=1, CPHA=0 */
|
||||
SPI_MODE_3 = 0x3 /**< CPOL=1, CPHA=1 */
|
||||
} spi_mode_t;
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @brief Override SPI clock speed values
|
||||
* @{
|
||||
*/
|
||||
#define HAVE_SPI_CLK_T
|
||||
typedef enum {
|
||||
SPI_CLK_100KHZ = 100000U, /**< drive the SPI bus with 100KHz */
|
||||
SPI_CLK_400KHZ = 400000U, /**< drive the SPI bus with 400KHz */
|
||||
SPI_CLK_1MHZ = 1000000U, /**< drive the SPI bus with 1MHz */
|
||||
SPI_CLK_5MHZ = 5000000U, /**< drive the SPI bus with 5MHz */
|
||||
SPI_CLK_10MHZ = 10000000U /**< drive the SPI bus with 10MHz */
|
||||
} spi_clk_t;
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @brief SPI device configuration
|
||||
*/
|
||||
typedef struct {
|
||||
SercomSpi *dev; /**< pointer to the used SPI device */
|
||||
gpio_t miso_pin; /**< used MISO pin */
|
||||
gpio_t mosi_pin; /**< used MOSI pin */
|
||||
gpio_t clk_pin; /**< used CLK pin */
|
||||
gpio_mux_t miso_mux; /**< alternate function for MISO pin (mux) */
|
||||
gpio_mux_t mosi_mux; /**< alternate function for MOSI pin (mux) */
|
||||
gpio_mux_t clk_mux; /**< alternate function for CLK pin (mux) */
|
||||
spi_misopad_t miso_pad; /**< pad to use for MISO line */
|
||||
spi_mosipad_t mosi_pad; /**< pad to use for MOSI and CLK line */
|
||||
} spi_conf_t;
|
||||
|
||||
/**
|
||||
* @brief Set up alternate function (PMUX setting) for a PORT pin
|
||||
@ -145,6 +177,18 @@ typedef enum
|
||||
*/
|
||||
void gpio_init_mux(gpio_t pin, gpio_mux_t mux);
|
||||
|
||||
/**
|
||||
* @brief Return the numeric id of a SERCOM device derived from its address
|
||||
*
|
||||
* @param[in] sercom SERCOM device
|
||||
*
|
||||
* @return numeric id of the given SERCOM device
|
||||
*/
|
||||
static inline int sercom_id(void *sercom)
|
||||
{
|
||||
return ((((uint32_t)sercom) >> 10) & 0x7) - 2;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
179
cpu/sam0_common/periph/spi.c
Normal file
179
cpu/sam0_common/periph/spi.c
Normal file
@ -0,0 +1,179 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2016 Freie Universität Berlin
|
||||
* 2015 Kaspar Schleiser <kaspar@schleiser.de>
|
||||
* 2015 FreshTemp, LLC.
|
||||
*
|
||||
* 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_samd21
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief Low-level SPI driver implementation
|
||||
*
|
||||
* @author Thomas Eichinger <thomas.eichinger@fu-berlin.de>
|
||||
* @author Troels Hoffmeyer <troels.d.hoffmeyer@gmail.com>
|
||||
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
|
||||
* @author Joakim Nohlgård <joakim.nohlgard@eistec.se>
|
||||
* @author Kaspar Schleiser <kaspar@schleiser.de>
|
||||
*
|
||||
* @}
|
||||
*/
|
||||
|
||||
#include "cpu.h"
|
||||
#include "mutex.h"
|
||||
#include "assert.h"
|
||||
#include "periph/spi.h"
|
||||
|
||||
#define ENABLE_DEBUG (0)
|
||||
#include "debug.h"
|
||||
|
||||
/**
|
||||
* @brief Array holding one pre-initialized mutex for each SPI device
|
||||
*/
|
||||
static mutex_t locks[SPI_NUMOF];
|
||||
|
||||
/**
|
||||
* @brief Shortcut for accessing the used SPI SERCOM device
|
||||
*/
|
||||
static inline SercomSpi *dev(spi_t bus)
|
||||
{
|
||||
return spi_config[bus].dev;
|
||||
}
|
||||
|
||||
static inline void poweron(spi_t bus)
|
||||
{
|
||||
#if defined(CPU_FAM_SAMD21)
|
||||
PM->APBCMASK.reg |= (PM_APBCMASK_SERCOM0 << sercom_id(dev(bus)));
|
||||
#elif defined(CPU_FAM_SAML21)
|
||||
MCLK->APBCMASK.reg |= (MCLK_APBCMASK_SERCOM0 << sercom_id(dev(bus)));
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void poweroff(spi_t bus)
|
||||
{
|
||||
#if defined(CPU_FAM_SAMD21)
|
||||
PM->APBCMASK.reg &= ~(PM_APBCMASK_SERCOM0 << sercom_id(dev(bus)));
|
||||
#elif defined(CPU_FAM_SAML21)
|
||||
MCLK->APBCMASK.reg &= ~(MCLK_APBCMASK_SERCOM0 << sercom_id(dev(bus)));
|
||||
#endif
|
||||
}
|
||||
|
||||
void spi_init(spi_t bus)
|
||||
{
|
||||
/* make sure given bus is good */
|
||||
assert(bus < SPI_NUMOF);
|
||||
|
||||
/* initialize the device lock */
|
||||
mutex_init(&locks[bus]);
|
||||
|
||||
/* configure pins and their muxes */
|
||||
spi_init_pins(bus);
|
||||
|
||||
/* wake up device */
|
||||
poweron(bus);
|
||||
|
||||
/* reset all device configuration */
|
||||
dev(bus)->CTRLA.reg |= SERCOM_SPI_CTRLA_SWRST;
|
||||
while ((dev(bus)->CTRLA.reg & SERCOM_SPI_CTRLA_SWRST) ||
|
||||
(dev(bus)->SYNCBUSY.reg & SERCOM_SPI_SYNCBUSY_SWRST));
|
||||
|
||||
/* configure base clock: using GLK GEN 0 */
|
||||
#if defined(CPU_FAM_SAMD21)
|
||||
GCLK->CLKCTRL.reg = (GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 |
|
||||
(SERCOM0_GCLK_ID_CORE + sercom_id(dev(bus))));
|
||||
while (GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY) {}
|
||||
#elif defined(CPU_FAM_SAML21)
|
||||
GCLK->PCHCTRL[SERCOM0_GCLK_ID_CORE + sercom_id(dev(bus))].reg =
|
||||
(GCLK_PCHCTRL_CHEN | GCLK_PCHCTRL_GEN_GCLK0);
|
||||
#endif
|
||||
|
||||
/* enable receiver and configure character size to 8-bit
|
||||
* no synchronization needed, as SERCOM device is not enabled */
|
||||
dev(bus)->CTRLB.reg = (SERCOM_SPI_CTRLB_CHSIZE(0) | SERCOM_SPI_CTRLB_RXEN);
|
||||
|
||||
/* put device back to sleep */
|
||||
poweroff(bus);
|
||||
}
|
||||
|
||||
void spi_init_pins(spi_t bus)
|
||||
{
|
||||
gpio_init(spi_config[bus].miso_pin, GPIO_IN);
|
||||
gpio_init(spi_config[bus].mosi_pin, GPIO_OUT);
|
||||
gpio_init(spi_config[bus].clk_pin, GPIO_OUT);
|
||||
gpio_init_mux(spi_config[bus].miso_pin, spi_config[bus].miso_mux);
|
||||
gpio_init_mux(spi_config[bus].mosi_pin, spi_config[bus].mosi_mux);
|
||||
gpio_init_mux(spi_config[bus].clk_pin, spi_config[bus].clk_mux);
|
||||
}
|
||||
|
||||
int spi_acquire(spi_t bus, spi_cs_t cs, spi_mode_t mode, spi_clk_t clk)
|
||||
{
|
||||
/* get exclusive access to the device */
|
||||
mutex_lock(&locks[bus]);
|
||||
/* power on the device */
|
||||
poweron(bus);
|
||||
|
||||
/* configure bus clock, in synchronous mode its calculated from
|
||||
* BAUD.reg = (f_ref / (2 * f_bus) - 1)
|
||||
* with f_ref := CLOCK_CORECLOCK as defined by the board */
|
||||
dev(bus)->BAUD.reg = (uint8_t)(((uint32_t)CLOCK_CORECLOCK) / (2 * clk) - 1);
|
||||
|
||||
/* configure device to be master and set mode and pads,
|
||||
*
|
||||
* NOTE: we could configure the pads already during spi_init, but for
|
||||
* efficiency reason we do that here, so we can do all in one single write
|
||||
* to the CTRLA register */
|
||||
dev(bus)->CTRLA.reg = (SERCOM_SPI_CTRLA_MODE(0x3) | /* 0x3 -> master */
|
||||
SERCOM_SPI_CTRLA_DOPO(spi_config[bus].mosi_pad) |
|
||||
SERCOM_SPI_CTRLA_DIPO(spi_config[bus].miso_pad) |
|
||||
(mode << SERCOM_SPI_CTRLA_CPOL_Pos));
|
||||
/* also no synchronization needed here, as CTRLA is write-synchronized */
|
||||
|
||||
/* finally enable the device */
|
||||
dev(bus)->CTRLA.reg |= SERCOM_SPI_CTRLA_ENABLE;
|
||||
while (dev(bus)->SYNCBUSY.reg & SERCOM_SPI_SYNCBUSY_ENABLE) {}
|
||||
|
||||
return SPI_OK;
|
||||
}
|
||||
|
||||
void spi_release(spi_t bus)
|
||||
{
|
||||
/* disable device and put it back to sleep */
|
||||
dev(bus)->CTRLA.reg &= ~(SERCOM_SPI_CTRLA_ENABLE);
|
||||
while (dev(bus)->SYNCBUSY.reg & SERCOM_SPI_SYNCBUSY_ENABLE) {}
|
||||
poweroff(bus);
|
||||
/* release access to the device */
|
||||
mutex_unlock(&locks[bus]);
|
||||
}
|
||||
|
||||
void spi_transfer_bytes(spi_t bus, spi_cs_t cs, bool cont,
|
||||
const void *out, void *in, size_t len)
|
||||
{
|
||||
uint8_t *out_buf = (uint8_t *)out;
|
||||
uint8_t *in_buf = (uint8_t *)in;
|
||||
|
||||
assert(out || in);
|
||||
|
||||
if (cs != SPI_CS_UNDEF) {
|
||||
gpio_clear((gpio_t)cs);
|
||||
}
|
||||
|
||||
for (int i = 0; i < (int)len; i++) {
|
||||
uint8_t tmp = (out_buf) ? out_buf[i] : 0;
|
||||
while (!(dev(bus)->INTFLAG.reg & SERCOM_SPI_INTFLAG_DRE)) {}
|
||||
dev(bus)->DATA.reg = tmp;
|
||||
while (!(dev(bus)->INTFLAG.reg & SERCOM_SPI_INTFLAG_RXC)) {}
|
||||
tmp = (uint8_t)dev(bus)->DATA.reg;
|
||||
if (in_buf) {
|
||||
in_buf[i] = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
if ((!cont) && (cs != SPI_CS_UNDEF)) {
|
||||
gpio_set((gpio_t)cs);
|
||||
}
|
||||
}
|
@ -107,4 +107,6 @@ void cpu_init(void)
|
||||
cortexm_init();
|
||||
/* Initialise clock sources and generic clocks */
|
||||
clk_init();
|
||||
/* trigger static peripheral initialization */
|
||||
periph_init();
|
||||
}
|
||||
|
@ -19,6 +19,8 @@
|
||||
#ifndef CPU_PERIPH_H
|
||||
#define CPU_PERIPH_H
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
#include "periph_cpu_common.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
@ -44,6 +46,13 @@ enum {
|
||||
*/
|
||||
#define GPIO_MODE(pr, ie, pe) (pr | (ie << 1) | (pe << 2))
|
||||
|
||||
/**
|
||||
* @brief Override SPI hardware chip select macro
|
||||
*
|
||||
* As of now, we do not support HW CS, so we always set it to a fixed value
|
||||
*/
|
||||
#define SPI_HWCS(x) (UINT_MAX - 1)
|
||||
|
||||
#ifndef DOXYGEN
|
||||
/**
|
||||
* @brief Override GPIO modes
|
||||
|
@ -1,327 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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_samd21
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief Low-level SPI driver implementation
|
||||
*
|
||||
* @author Thomas Eichinger <thomas.eichinger@fu-berlin.de>
|
||||
* @author Troels Hoffmeyer <troels.d.hoffmeyer@gmail.com>
|
||||
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
|
||||
* @author Joakim Nohlgård <joakim.nohlgard@eistec.se>
|
||||
*
|
||||
* @}
|
||||
*/
|
||||
|
||||
#include "cpu.h"
|
||||
#include "mutex.h"
|
||||
#include "periph/gpio.h"
|
||||
#include "periph/spi.h"
|
||||
#include "periph_conf.h"
|
||||
#include "board.h"
|
||||
#define ENABLE_DEBUG (0)
|
||||
#include "debug.h"
|
||||
|
||||
#if SPI_0_EN || SPI_1_EN
|
||||
|
||||
/**
|
||||
* @brief Internal helper function to do the actual work for spi_poweroff
|
||||
*/
|
||||
static void _spi_poweroff(SercomSpi* spi_dev);
|
||||
|
||||
/**
|
||||
* @brief Internal helper function to do the actual work for spi_poweron
|
||||
*/
|
||||
static void _spi_poweron(SercomSpi* spi_dev);
|
||||
|
||||
/**
|
||||
* @brief Array holding one pre-initialized mutex for each SPI device
|
||||
*/
|
||||
static mutex_t locks[] = {
|
||||
#if SPI_0_EN
|
||||
[SPI_0] = MUTEX_INIT,
|
||||
#endif
|
||||
#if SPI_1_EN
|
||||
[SPI_1] = MUTEX_INIT,
|
||||
#endif
|
||||
#if SPI_2_EN
|
||||
[SPI_2] = MUTEX_INIT
|
||||
#endif
|
||||
};
|
||||
|
||||
int spi_init_master(spi_t dev, spi_conf_t conf, spi_speed_t speed)
|
||||
{
|
||||
SercomSpi* spi_dev = 0;
|
||||
uint8_t sercom_gclk_id = 0;
|
||||
gpio_t pin_sclk = 0;
|
||||
gpio_t pin_miso = 0;
|
||||
gpio_t pin_mosi = 0;
|
||||
gpio_mux_t mux_sclk = 0;
|
||||
gpio_mux_t mux_miso = 0;
|
||||
gpio_mux_t mux_mosi = 0;
|
||||
spi_mosipad_t mosi_pad = 0;
|
||||
spi_misopad_t miso_pad = 0;
|
||||
uint32_t cpha = 0;
|
||||
uint32_t cpol = 0;
|
||||
uint32_t f_baud = 0;
|
||||
switch (speed)
|
||||
{
|
||||
case SPI_SPEED_100KHZ:
|
||||
f_baud = 100000;
|
||||
break;
|
||||
case SPI_SPEED_400KHZ:
|
||||
f_baud = 400000;
|
||||
break;
|
||||
case SPI_SPEED_1MHZ:
|
||||
f_baud = 1000000;
|
||||
break;
|
||||
case SPI_SPEED_5MHZ:
|
||||
#if CLOCK_CORECLOCK >= 5000000
|
||||
f_baud = 5000000;
|
||||
break;
|
||||
#else
|
||||
return -1;
|
||||
#endif
|
||||
case SPI_SPEED_10MHZ:
|
||||
#if CLOCK_CORECLOCK >= 10000000
|
||||
f_baud = 10000000;
|
||||
break;
|
||||
#else
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
switch (conf)
|
||||
{
|
||||
case SPI_CONF_FIRST_RISING: /**< first data bit is transacted on the first rising SCK edge */
|
||||
cpha = 0;
|
||||
cpol = 0;
|
||||
break;
|
||||
case SPI_CONF_SECOND_RISING: /**< first data bit is transacted on the second rising SCK edge */
|
||||
cpha = SERCOM_SPI_CTRLA_CPHA;
|
||||
cpol = 0;
|
||||
break;
|
||||
case SPI_CONF_FIRST_FALLING: /**< first data bit is transacted on the first falling SCK edge */
|
||||
cpha = 0;
|
||||
cpol = SERCOM_SPI_CTRLA_CPOL;
|
||||
break;
|
||||
case SPI_CONF_SECOND_FALLING: /**< first data bit is transacted on the second falling SCK edge */
|
||||
cpha = SERCOM_SPI_CTRLA_CPHA;
|
||||
cpol = SERCOM_SPI_CTRLA_CPOL;
|
||||
break;
|
||||
}
|
||||
switch (dev)
|
||||
{
|
||||
#if SPI_0_EN
|
||||
case SPI_0:
|
||||
spi_dev = &SPI_0_DEV;
|
||||
sercom_gclk_id = SPI_0_GCLK_ID;
|
||||
pin_sclk = SPI_0_SCLK;
|
||||
mux_sclk = SPI_0_SCLK_MUX;
|
||||
pin_miso = SPI_0_MISO;
|
||||
mux_miso = SPI_0_MISO_MUX;
|
||||
pin_mosi = SPI_0_MOSI;
|
||||
mux_mosi = SPI_0_MOSI_MUX;
|
||||
mosi_pad = SPI_0_MOSI_PAD;
|
||||
miso_pad = SPI_0_MISO_PAD;
|
||||
break;
|
||||
#endif
|
||||
#if SPI_1_EN
|
||||
case SPI_1:
|
||||
spi_dev = &SPI_1_DEV;
|
||||
sercom_gclk_id = SPI_1_GCLK_ID;
|
||||
pin_sclk = SPI_1_SCLK;
|
||||
mux_sclk = SPI_1_SCLK_MUX;
|
||||
pin_miso = SPI_1_MISO;
|
||||
mux_miso = SPI_1_MISO_MUX;
|
||||
pin_mosi = SPI_1_MOSI;
|
||||
mux_mosi = SPI_1_MOSI_MUX;
|
||||
mosi_pad = SPI_1_MOSI_PAD;
|
||||
miso_pad = SPI_1_MISO_PAD;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Use the same sequence as ArduinoCore
|
||||
* - setup pins
|
||||
* - disable SPI
|
||||
* - init SPI (reset, init clock NVIC, CTRLA, CTRLB)
|
||||
* - init cpha/cpol, BAUD.reg
|
||||
* - enable SPI
|
||||
*/
|
||||
gpio_init(pin_miso, GPIO_IN_PD);
|
||||
gpio_init_mux(pin_sclk, mux_sclk);
|
||||
gpio_init_mux(pin_miso, mux_miso);
|
||||
gpio_init_mux(pin_mosi, mux_mosi);
|
||||
|
||||
/* Disable spi to write confs */
|
||||
_spi_poweroff(spi_dev);
|
||||
|
||||
/* reset */
|
||||
// Setting the Software Reset bit to 1
|
||||
spi_dev->CTRLA.bit.SWRST = 1;
|
||||
|
||||
// Wait both bits Software Reset from CTRLA and SYNCBUSY are equal to 0
|
||||
while (spi_dev->CTRLA.bit.SWRST || spi_dev->SYNCBUSY.bit.SWRST) {}
|
||||
|
||||
/* Turn on power manager for sercom */
|
||||
PM->APBCMASK.reg |= (PM_APBCMASK_SERCOM0 << (sercom_gclk_id - GCLK_CLKCTRL_ID_SERCOM0_CORE_Val));
|
||||
|
||||
/* Setup clock */
|
||||
/* SPI using CLK GEN 0 */
|
||||
GCLK->CLKCTRL.reg = (GCLK_CLKCTRL_CLKEN |
|
||||
GCLK_CLKCTRL_GEN_GCLK0 |
|
||||
GCLK_CLKCTRL_ID(sercom_gclk_id));
|
||||
while (GCLK->STATUS.bit.SYNCBUSY) {}
|
||||
|
||||
/* ???? init NVIC. Maybe not needed in master mode. */
|
||||
|
||||
/* Master mode */
|
||||
spi_dev->CTRLA.reg |= SERCOM_SPI_CTRLA_MODE_SPI_MASTER;
|
||||
while (spi_dev->SYNCBUSY.reg) {}// ???? not needed
|
||||
|
||||
spi_dev->BAUD.bit.BAUD = (uint8_t) (((uint32_t)CLOCK_CORECLOCK) / (2 * f_baud) - 1); /* Synchronous mode*/
|
||||
|
||||
spi_dev->CTRLA.reg |= SERCOM_SPI_CTRLA_DOPO(mosi_pad)
|
||||
| SERCOM_SPI_CTRLA_DIPO(miso_pad)
|
||||
| cpha
|
||||
| cpol;
|
||||
while (spi_dev->SYNCBUSY.reg) {} // ???? not needed
|
||||
|
||||
/* datasize 0 => 8 bits */
|
||||
spi_dev->CTRLB.reg = (SERCOM_SPI_CTRLB_CHSIZE(0) | SERCOM_SPI_CTRLB_RXEN);
|
||||
while (spi_dev->SYNCBUSY.reg) {} // ???? Only wait for clear of spi_dev->SYNCBUSY.bit.CTRLB
|
||||
|
||||
/* enable */
|
||||
_spi_poweron(spi_dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int spi_init_slave(spi_t dev, spi_conf_t conf, char (*cb)(char))
|
||||
{
|
||||
(void)dev;
|
||||
(void)conf;
|
||||
(void)cb;
|
||||
/* TODO */
|
||||
assert(false);
|
||||
return -1;
|
||||
}
|
||||
|
||||
void spi_transmission_begin(spi_t dev, char reset_val)
|
||||
{
|
||||
(void)dev;
|
||||
(void)reset_val;
|
||||
/* TODO */
|
||||
assert(false);
|
||||
}
|
||||
|
||||
int spi_acquire(spi_t dev)
|
||||
{
|
||||
if ((unsigned int)dev >= SPI_NUMOF) {
|
||||
return -1;
|
||||
}
|
||||
mutex_lock(&locks[dev]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int spi_release(spi_t dev)
|
||||
{
|
||||
if ((unsigned int)dev >= SPI_NUMOF) {
|
||||
return -1;
|
||||
}
|
||||
mutex_unlock(&locks[dev]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int spi_transfer_byte(spi_t dev, char out, char *in)
|
||||
{
|
||||
SercomSpi* spi_dev = 0;
|
||||
char tmp;
|
||||
|
||||
switch(dev)
|
||||
{
|
||||
#if SPI_0_EN
|
||||
case SPI_0:
|
||||
spi_dev = &(SPI_0_DEV);
|
||||
break;
|
||||
#endif
|
||||
#if SPI_1_EN
|
||||
case SPI_1:
|
||||
spi_dev = &(SPI_1_DEV);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
||||
while (!spi_dev->INTFLAG.bit.DRE) {} /* while data register is not empty*/
|
||||
spi_dev->DATA.bit.DATA = out;
|
||||
|
||||
while (!spi_dev->INTFLAG.bit.DRE || !spi_dev->INTFLAG.bit.RXC) {} /* while receive is not complete*/
|
||||
tmp = (char)spi_dev->DATA.bit.DATA;
|
||||
|
||||
if (in != NULL)
|
||||
{
|
||||
in[0] = tmp;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void _spi_poweron(SercomSpi* spi_dev)
|
||||
{
|
||||
if (spi_dev == NULL) {
|
||||
return;
|
||||
}
|
||||
spi_dev->CTRLA.reg |= SERCOM_SPI_CTRLA_ENABLE;
|
||||
while (spi_dev->SYNCBUSY.bit.ENABLE) {}
|
||||
}
|
||||
|
||||
void spi_poweron(spi_t dev)
|
||||
{
|
||||
switch(dev) {
|
||||
#if SPI_0_EN
|
||||
case SPI_0:
|
||||
_spi_poweron(&SPI_0_DEV);
|
||||
break;
|
||||
#endif
|
||||
#if SPI_1_EN
|
||||
case SPI_1:
|
||||
_spi_poweron(&SPI_1_DEV);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
static void _spi_poweroff(SercomSpi* spi_dev)
|
||||
{
|
||||
if (spi_dev == NULL) {
|
||||
return;
|
||||
}
|
||||
spi_dev->CTRLA.bit.ENABLE = 0; /* Disable spi */
|
||||
while (spi_dev->SYNCBUSY.bit.ENABLE) {}
|
||||
}
|
||||
|
||||
void spi_poweroff(spi_t dev)
|
||||
{
|
||||
switch(dev) {
|
||||
#if SPI_0_EN
|
||||
case SPI_0:
|
||||
_spi_poweroff(&SPI_0_DEV);
|
||||
break;
|
||||
#endif
|
||||
#if SPI_1_EN
|
||||
case SPI_1:
|
||||
_spi_poweroff(&SPI_1_DEV);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* SPI_0_EN || SPI_1_EN */
|
@ -57,7 +57,7 @@ int uart_init(uart_t uart, uint32_t baudrate, uart_rx_cb_t rx_cb, void *arg)
|
||||
uart_ctx[uart].arg = arg;
|
||||
/* configure interrupts and enable RX interrupt */
|
||||
_uart(uart)->INTENSET.reg = SERCOM_USART_INTENSET_RXC;
|
||||
NVIC_EnableIRQ(SERCOM0_IRQn + _sercom_id(_uart(uart)));
|
||||
NVIC_EnableIRQ(SERCOM0_IRQn + sercom_id(_uart(uart)));
|
||||
return UART_OK;
|
||||
}
|
||||
|
||||
@ -112,18 +112,18 @@ void uart_write(uart_t uart, const uint8_t *data, size_t len)
|
||||
|
||||
void uart_poweron(uart_t uart)
|
||||
{
|
||||
PM->APBCMASK.reg |= (PM_APBCMASK_SERCOM0 << _sercom_id(_uart(uart)));
|
||||
PM->APBCMASK.reg |= (PM_APBCMASK_SERCOM0 << sercom_id(_uart(uart)));
|
||||
GCLK->CLKCTRL.reg = (GCLK_CLKCTRL_CLKEN |
|
||||
GCLK_CLKCTRL_GEN_GCLK0 |
|
||||
(SERCOM0_GCLK_ID_CORE + _sercom_id(_uart(uart))) <<
|
||||
(SERCOM0_GCLK_ID_CORE + sercom_id(_uart(uart))) <<
|
||||
GCLK_CLKCTRL_ID_Pos);
|
||||
while (GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY) {}
|
||||
}
|
||||
|
||||
void uart_poweroff(uart_t uart)
|
||||
{
|
||||
PM->APBCMASK.reg &= ~(PM_APBCMASK_SERCOM0 << _sercom_id(_uart(uart)));
|
||||
GCLK->CLKCTRL.reg = ((SERCOM0_GCLK_ID_CORE + _sercom_id(_uart(uart))) <<
|
||||
PM->APBCMASK.reg &= ~(PM_APBCMASK_SERCOM0 << sercom_id(_uart(uart)));
|
||||
GCLK->CLKCTRL.reg = ((SERCOM0_GCLK_ID_CORE + sercom_id(_uart(uart))) <<
|
||||
GCLK_CLKCTRL_ID_Pos);
|
||||
while (GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY) {}
|
||||
}
|
||||
|
@ -1,234 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Freie Universität Berlin
|
||||
* 2015 Kaspar Schleiser <kaspar@schleiser.de>
|
||||
* FreshTemp, LLC.
|
||||
*
|
||||
* 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_samd21
|
||||
* @{
|
||||
*
|
||||
* @file spi.c
|
||||
* @brief Low-level SPI driver implementation
|
||||
*
|
||||
* @author Thomas Eichinger <thomas.eichinger@fu-berlin.de>
|
||||
* @author Troels Hoffmeyer <troels.d.hoffmeyer@gmail.com>
|
||||
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
|
||||
* @author Joakim Nohlgård <joakim.nohlgard@eistec.se>
|
||||
* @author Kaspar Schleiser <kaspar@schleiser.de>
|
||||
*
|
||||
* @}
|
||||
*/
|
||||
|
||||
#include "cpu.h"
|
||||
#include "mutex.h"
|
||||
#include "periph/gpio.h"
|
||||
#include "periph/spi.h"
|
||||
|
||||
#define ENABLE_DEBUG (0)
|
||||
#include "debug.h"
|
||||
|
||||
#if SPI_0_EN || SPI_1_EN
|
||||
|
||||
/**
|
||||
* @brief Array holding one pre-initialized mutex for each SPI device
|
||||
*/
|
||||
static mutex_t locks[] = {
|
||||
#if SPI_0_EN
|
||||
[SPI_0] = MUTEX_INIT,
|
||||
#endif
|
||||
#if SPI_1_EN
|
||||
[SPI_1] = MUTEX_INIT,
|
||||
#endif
|
||||
#if SPI_2_EN
|
||||
[SPI_2] = MUTEX_INIT
|
||||
#endif
|
||||
};
|
||||
|
||||
typedef struct spi_saml21_pin {
|
||||
uint32_t pin;
|
||||
uint32_t pmux;
|
||||
} spi_saml21_pin_t;
|
||||
|
||||
typedef struct spi_saml21 {
|
||||
SercomSpi* dev;
|
||||
uint32_t mclk;
|
||||
uint32_t gclk_id;
|
||||
|
||||
spi_saml21_pin_t sclk;
|
||||
spi_saml21_pin_t miso;
|
||||
spi_saml21_pin_t mosi;
|
||||
|
||||
int dipo;
|
||||
int dopo;
|
||||
} spi_saml21_t;
|
||||
|
||||
static const spi_saml21_t spi[] = {
|
||||
#if SPI_0_EN
|
||||
/* SPI device */ /* MCLK flag */ /* GLCK id */ /* SCLK */ /* MISO */ /* MOSI */ /* dipo+dopo */
|
||||
{ &(SERCOM0->SPI), MCLK_APBCMASK_SERCOM0, SERCOM0_GCLK_ID_CORE, { GPIO_PIN(PA,7), 3 }, { GPIO_PIN(PA,4), 3 }, { GPIO_PIN(PA,6), 3 }, 0, 1 }
|
||||
#endif
|
||||
};
|
||||
|
||||
int spi_init_master(spi_t dev, spi_conf_t conf, spi_speed_t speed)
|
||||
{
|
||||
SercomSpi* spi_dev = spi[dev].dev;
|
||||
|
||||
uint8_t dopo = 0;
|
||||
uint8_t dipo = 0;
|
||||
uint8_t cpha = 0;
|
||||
uint8_t cpol = 0;
|
||||
uint32_t f_baud = 0;
|
||||
|
||||
switch(speed)
|
||||
{
|
||||
case SPI_SPEED_100KHZ:
|
||||
f_baud = 100000;
|
||||
break;
|
||||
case SPI_SPEED_400KHZ:
|
||||
f_baud = 400000;
|
||||
break;
|
||||
case SPI_SPEED_1MHZ:
|
||||
f_baud = 1000000;
|
||||
break;
|
||||
case SPI_SPEED_5MHZ:
|
||||
return -1;
|
||||
case SPI_SPEED_10MHZ:
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch(conf)
|
||||
{
|
||||
case SPI_CONF_FIRST_RISING: /**< first data bit is transacted on the first rising SCK edge */
|
||||
cpha = 0;
|
||||
cpol = 0;
|
||||
break;
|
||||
case SPI_CONF_SECOND_RISING:/**< first data bit is transacted on the second rising SCK edge */
|
||||
cpha = 1;
|
||||
cpol = 0;
|
||||
break;
|
||||
case SPI_CONF_FIRST_FALLING:/**< first data bit is transacted on the first falling SCK edge */
|
||||
cpha = 0;
|
||||
cpol = 1;
|
||||
break;
|
||||
case SPI_CONF_SECOND_FALLING:/**< first data bit is transacted on the second falling SCK edge */
|
||||
cpha = 1;
|
||||
cpol = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Enable sercom4 in power manager */
|
||||
MCLK->APBCMASK.reg |= spi[dev].mclk;
|
||||
|
||||
/* Setup clock */
|
||||
GCLK->PCHCTRL[ spi[dev].gclk_id ].reg =
|
||||
GCLK_PCHCTRL_CHEN |
|
||||
GCLK_PCHCTRL_GEN_GCLK0;
|
||||
|
||||
while (!(GCLK->PCHCTRL[spi[dev].gclk_id].reg & GCLK_PCHCTRL_CHEN)) {}
|
||||
|
||||
/* SCLK+MOSI = output */
|
||||
gpio_init(spi[dev].sclk.pin, GPIO_OUT);
|
||||
gpio_init(spi[dev].mosi.pin, GPIO_OUT);
|
||||
/* MISO = input */
|
||||
gpio_init(spi[dev].miso.pin, GPIO_IN);
|
||||
|
||||
/*
|
||||
* Set alternate funcion (PMUX) for our ports.
|
||||
*/
|
||||
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].mosi.pin, spi[dev].mosi.pmux);
|
||||
|
||||
/* pin pad mapping */
|
||||
dipo = spi[dev].dipo;
|
||||
dopo = spi[dev].dopo;
|
||||
|
||||
/* Disable spi to write config */
|
||||
spi_dev->CTRLA.bit.ENABLE = 0;
|
||||
while (spi_dev->SYNCBUSY.reg) {}
|
||||
|
||||
/* setup baud */
|
||||
spi_dev->BAUD.bit.BAUD = (uint8_t) (((uint32_t) GCLK_REF) / (2 * f_baud) - 1); /* Syncronous mode*/
|
||||
|
||||
spi_dev->CTRLA.reg |= SERCOM_SPI_CTRLA_MODE(0x3) /* 0x2 = slave 0x3 = master */
|
||||
| (SERCOM_SPI_CTRLA_DOPO(dopo))
|
||||
| (SERCOM_SPI_CTRLA_DIPO(dipo))
|
||||
| (cpha << SERCOM_SPI_CTRLA_CPHA_Pos)
|
||||
| (cpol << SERCOM_SPI_CTRLA_CPOL_Pos);
|
||||
|
||||
while (spi_dev->SYNCBUSY.reg) {}
|
||||
spi_dev->CTRLB.reg = (SERCOM_SPI_CTRLB_CHSIZE(0) | SERCOM_SPI_CTRLB_RXEN);
|
||||
while(spi_dev->SYNCBUSY.reg) {}
|
||||
spi_poweron(dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int spi_init_slave(spi_t dev, spi_conf_t conf, char (*cb)(char))
|
||||
{
|
||||
/* TODO */
|
||||
return -1;
|
||||
}
|
||||
|
||||
void spi_transmission_begin(spi_t dev, char reset_val)
|
||||
{
|
||||
/* TODO*/
|
||||
}
|
||||
|
||||
int spi_acquire(spi_t dev)
|
||||
{
|
||||
if ((unsigned int)dev >= SPI_NUMOF) {
|
||||
return -1;
|
||||
}
|
||||
mutex_lock(&locks[dev]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int spi_release(spi_t dev)
|
||||
{
|
||||
if ((unsigned int)dev >= SPI_NUMOF) {
|
||||
return -1;
|
||||
}
|
||||
mutex_unlock(&locks[dev]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int spi_transfer_byte(spi_t dev, char out, char *in)
|
||||
{
|
||||
SercomSpi* spi_dev = spi[dev].dev;
|
||||
|
||||
while (!spi_dev->INTFLAG.bit.DRE) {} /* while data register is not empty */
|
||||
spi_dev->DATA.bit.DATA = out;
|
||||
|
||||
if (in)
|
||||
{
|
||||
while (!spi_dev->INTFLAG.bit.RXC) {} /* while receive is not complete */
|
||||
*in = spi_dev->DATA.bit.DATA;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* clear input byte even if we're not interested */
|
||||
spi_dev->DATA.bit.DATA;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void spi_poweron(spi_t dev)
|
||||
{
|
||||
SercomSpi* spi_dev = spi[dev].dev;
|
||||
spi_dev->CTRLA.reg |= SERCOM_SPI_CTRLA_ENABLE;
|
||||
while(spi_dev->SYNCBUSY.bit.ENABLE) {}
|
||||
}
|
||||
|
||||
void spi_poweroff(spi_t dev)
|
||||
{
|
||||
SercomSpi* spi_dev = spi[dev].dev;
|
||||
spi_dev->CTRLA.bit.ENABLE = 0;
|
||||
while(spi_dev->SYNCBUSY.bit.ENABLE) {}
|
||||
}
|
||||
|
||||
#endif /* SPI_0_EN || SPI_1_EN */
|
Loading…
Reference in New Issue
Block a user