1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2025-12-24 22:13:52 +01:00

Merge pull request #5020 from haukepetersen/add_atmega_spi

cpu/atmega2560: added SPI driver
This commit is contained in:
Hauke Petersen 2016-03-10 13:03:12 +01:00
commit e97f843e66
6 changed files with 222 additions and 6 deletions

View File

@ -1,5 +1,6 @@
# Put defined MCU peripherals here (in alphabetical order)
FEATURES_PROVIDED += periph_gpio
FEATURES_PROVIDED += periph_spi
FEATURES_PROVIDED += periph_timer
FEATURES_PROVIDED += periph_uart

View File

@ -256,10 +256,21 @@ extern "C" {
/**
* @brief SPI configuration
*
* The atmega2560 has only one hardware SPI with fixed pin configuration, so all
* we can do here, is to enable or disable it...
*
* The fixed pins used, are:
* MOSI - PB2 (Arduino pin 51)
* MISO - PB3 (Arduino pin 50)
* SCK - PB1 (Arduino pin 52)
* SS - PB0 (Arduino pin 53) -> this pin is configured as output, but not used
*
* @{
*/
#define SPI_NUMOF (0U) /* TODO */
#define SPI_0_EN 0
#define SPI_1_EN 0
#define SPI_NUMOF 1 /* set to 0 to disable SPI */
#define SPI_0_EN 1 /* remove once SPI rework is done */
/** @} */
/**
* @brief I2C configuration

View File

@ -1,5 +1,6 @@
/*
* Copyright (C) 2015 HAW Hamburg
* 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
@ -14,14 +15,12 @@
* @brief CPU specific definitions for internal peripheral handling
*
* @author René Herthel <rene-herthel@outlook.de>
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
*/
#ifndef PERIPH_CPU_H_
#define PERIPH_CPU_H_
#include "periph/dev_enums.h"
#include <avr/io.h>
#ifdef __cplusplus
extern "C" {
#endif
@ -48,6 +47,54 @@ enum {
PORT_L = 10 /**< port L */
};
/**
* @brief SPI mode select macro
*
* The polarity is determined by bit 3 in the configuration register, the phase
* by bit 2.
*/
#define SPI_MODE_SEL(pol, pha) ((pol << 3) | (pha << 2))
/**
* @brief Override the SPI mode values
*
* As the mode is set in bit 3 and 2 of the configuration register, we put the
* correct configuration there
* @{
*/
#define HAVE_SPI_CONF_T
typedef enum {
SPI_CONF_FIRST_RISING = SPI_MODE_SEL(0, 0), /**< mode 0 */
SPI_CONF_SECOND_RISING = SPI_MODE_SEL(0, 1), /**< mode 1 */
SPI_CONF_FIRST_FALLING = SPI_MODE_SEL(1, 0), /**< mode 2 */
SPI_CONF_SECOND_FALLING = SPI_MODE_SEL(1, 1) /**< mode 3 */
} spi_conf_t;
/** @} */
/**
* @brief SPI speed selection macro
*
* We encode the speed in bits 2, 1, and 0, where bit0 and bit1 hold the SPCR
* prescaler bits, while bit2 holds the SPI2X bit.
*/
#define SPI_SPEED_SEL(s2x, pr1, pr0) ((s2x << 2) | (pr1 << 1) | pr0)
/**
* @brief Override SPI speed values
*
* We assume a master clock speed of 16MHz here.
* @{
*/
#define HAVE_SPI_SPEED_T
typedef enum {
SPI_SPEED_100KHZ = SPI_SPEED_SEL(0, 1, 1), /**< 16/128 -> 125KHz */
SPI_SPEED_400KHZ = SPI_SPEED_SEL(1, 1, 0), /**< 16/32 -> 500KHz */
SPI_SPEED_1MHZ = SPI_SPEED_SEL(0, 0, 1), /**< 16/16 -> 1MHz */
SPI_SPEED_5MHZ = SPI_SPEED_SEL(0, 0, 0), /**< 16/4 -> 4MHz */
SPI_SPEED_10MHZ = SPI_SPEED_SEL(1, 0, 0) /**< 16/2 -> 8MHz */
} spi_speed_t;
/** @} */
#ifdef __cplusplus
}
#endif

145
cpu/atmega2560/periph/spi.c Normal file
View File

@ -0,0 +1,145 @@
/*
* Copyright (C) 2015 Daniel Amkaer Sorensen
* 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
* directory for more details.
*/
/**
* @ingroup cpu_atmega2560
* @{
*
* @file
* @brief Low-level SPI driver implementation
*
* @author Daniel Amkaer Sorensen <daniel.amkaer@gmail.com>
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
*
* @}
*/
#include "cpu.h"
#include "mutex.h"
#include "periph/spi.h"
/* guard this file in case no SPI device is defined */
#if SPI_NUMOF
/**
* @brief Extract BR0, BR1 and SPI2X bits from speed value
* @{
*/
#define SPEED_MASK (0x3)
#define S2X_SHIFT (2)
/** @} */
static mutex_t lock = MUTEX_INIT;
int spi_init_master(spi_t dev, spi_conf_t conf, spi_speed_t speed)
{
/* make sure device is valid (there is only one...) */
if (dev != 0) {
return -1;
}
/* the pin configuration for this CPU is fixed:
* - PB3: MISO (configure as input - done automatically)
* - PB2: MOSI (configure as output)
* - PB1: SCK (configure as output)
* - PB0: SS (configure as output, but unused)
*
* The SS pin must be configured as output for the SPI device to work as
* master correctly, though we do not use it for now (as we handle the chip
* select externally for now)
*/
DDRB |= ((1 << DDB2) | (1 << DDB1) | (1 << DDB0));
/* make sure the SPI is not powered off */
PRR0 &= ~(1 << PRSPI);
/* configure as master, with given mode and clock */
SPSR = (speed >> S2X_SHIFT);
SPCR = ((1 << SPE) | (1 << MSTR) | conf | (speed & SPEED_MASK));
/* clear interrupt flag */
(void)SPSR;
(void)SPDR;
return 0;
}
int spi_acquire(spi_t dev)
{
mutex_lock(&lock);
return 0;
}
int spi_release(spi_t dev)
{
mutex_unlock(&lock);
return 0;
}
int spi_init_slave(spi_t dev, spi_conf_t conf, char (*cb)(char data))
{
(void) dev;
(void) conf;
(void) cb;
/* not implemented */
return -1;
}
void spi_transmission_begin(spi_t dev, char reset_val)
{
(void)dev;
(void)reset_val;
/* not implemented */
}
int spi_transfer_byte(spi_t dev, char out, char *in)
{
return spi_transfer_bytes(dev, &out, in, 1);
}
int spi_transfer_bytes(spi_t dev, char *out, char *in, unsigned int length)
{
for (unsigned int i = 0; i < length; i++) {
char tmp = (out) ? out[i] : 0;
SPDR = tmp;
while (!(SPSR & (1 << SPIF))) {}
tmp = SPDR;
if (in) {
in[i] = tmp;
}
}
return (int)length;
}
int spi_transfer_reg(spi_t dev, uint8_t reg, char out, char *in)
{
spi_transfer_bytes(dev, (char *)&reg, NULL, 1);
return spi_transfer_bytes(dev, &out, in, 1);
}
int spi_transfer_regs(spi_t dev, uint8_t reg, char *out, char *in, unsigned int length)
{
spi_transfer_bytes(dev, (char *)&reg, NULL, 1);
return spi_transfer_bytes(dev, out, in, length);
}
void spi_poweron(spi_t dev)
{
SPCR |= (1 << SPE);
}
void spi_poweroff(spi_t dev)
{
SPCR &= ~(1 << SPE);
}
#endif /* SPI_NUMOF */

View File

@ -27,6 +27,7 @@
#include <stdint.h>
#include "periph_cpu.h"
#include "periph_conf.h"
#ifdef __cplusplus
@ -57,7 +58,9 @@ typedef enum {
/**
* @brief The SPI mode is defined by the four possible combinations of clock polarity and
* clock phase.
* @{
*/
#ifndef HAVE_SPI_CONF_T
typedef enum {
/**
* The first data bit is sampled by the receiver on the first SCK edge. The
@ -84,13 +87,18 @@ typedef enum {
*/
SPI_CONF_SECOND_FALLING = 3
} spi_conf_t;
#endif
/** @} */
/**
* @brief Define a set of pre-defined SPI clock speeds.
*
* The actual speed of the bus can vary to some extend, as the combination of CPU clock and
* available prescale values on certain platforms may not make the exact values possible.
*
* @{
*/
#ifndef HAVE_SPI_SPEED_T
typedef enum {
SPI_SPEED_100KHZ = 0, /**< drive the SPI bus with 100KHz */
SPI_SPEED_400KHZ, /**< drive the SPI bus with 400KHz */
@ -98,6 +106,8 @@ typedef enum {
SPI_SPEED_5MHZ, /**< drive the SPI bus with 5MHz */
SPI_SPEED_10MHZ /**< drive the SPI bus with 10MHz */
} spi_speed_t;
#endif
/** @} */
/**
* @brief Initialize the given SPI device to work in master mode

View File

@ -1,6 +1,8 @@
APPLICATION = driver_adt7310
include ../Makefile.tests_common
BOARD_INSUFFICIENT_MEMORY := arduino-mega2560
FEATURES_REQUIRED = periph_spi periph_gpio
USEMODULE += adt7310