1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00

cpu/msp430: added SPI periph driver

This commit is contained in:
Hauke Petersen 2015-09-02 12:43:21 +02:00
parent 92cd6dfcba
commit 399e7c1c2e
4 changed files with 285 additions and 1 deletions

View File

@ -2,4 +2,4 @@ INCLUDES += -I$(RIOTCPU)/msp430fxyz/include/
include $(RIOTCPU)/msp430-common/Makefile.include
export USEMODULE += periph
export USEMODULE += periph periph_common

View File

@ -111,6 +111,20 @@ typedef struct {
REG8 BTXBUF; /**< B transmit buffer */
} msp_usci_t;
/**
* @brief USCI SPI specific registers
*/
typedef struct {
REG8 CTL0; /**< control 0 */
REG8 CTL1; /**< control 1 */
REG8 BR0; /**< baud rate 0 */
REG8 BR1; /**< baud rate 1 */
REG8 reserved; /**< reserved */
REG8 STAT; /**< status */
REG8 RXBUF; /**< receive buffer */
REG8 TXBUF; /**< transmit buffer */
} msp_usci_spi_t;
/**
* @brief Timer interrupt status registers
*/
@ -201,6 +215,7 @@ typedef struct {
* @{
*/
#define USART_TCTL_TXEPT (0x01)
#define USART_TCTL_STC (0x02)
#define USART_TCTL_TXWAKE (0x04)
#define USART_TCTL_URXSE (0x08)
#define USART_TCTL_SSEL_MASK (0x30)
@ -208,6 +223,7 @@ typedef struct {
#define USART_TCTL_SSEL_ACLK (0x10)
#define USART_TCTL_SSEL_SMCLK (0x20)
#define USART_TCTL_CKPL (0x40)
#define USART_TCTL_CKPH (0x80)
/** @} */
/**
@ -241,6 +257,22 @@ typedef struct {
#define USCI_ACTL0_PEN (0x80)
/** @} */
/**
* @brief USCI control register 0 bitmap SPI mode
* @{
*/
#define USCI_SPI_CTL0_UCSYNC (0x01)
#define USCI_SPI_CTL0_MODE_3 (0x06)
#define USCI_SPI_CTL0_MODE_0 (0x00)
#define USCI_SPI_CTL0_MODE_1 (0x02)
#define USCI_SPI_CTL0_MODE_2 (0x04)
#define USCI_SPI_CTL0_MST (0x08)
#define USCI_SPI_CTL0_7BIT (0x10)
#define USCI_SPI_CTL0_MSB (0x20)
#define USCI_SPI_CTL0_CKPL (0x40)
#define USCI_SPI_CTL0_CKPH (0x80)
/** @} */
/**
* @brief USCI control A register 1 bitmap
* @{
@ -257,6 +289,17 @@ typedef struct {
#define USCI_ACTL1_SSEL_SMCLK (0xc0)
/** @} */
/**
* @brief USCI control register 1 bitmap SPI mode
* @{
*/
#define USCI_SPI_CTL1_SWRST (0x01)
#define USCI_SPI_CTL1_SSEL_MASK (0xc0)
#define USCI_SPI_CTL1_SSEL_NA (0x00)
#define USCI_SPI_CTL1_SSEL_ACLK (0x40)
#define USCI_SPI_CTL1_SSEL_SMCLK (0xc0)
/** @} */
/**
* @brief USCI modulation A control register
* @{
@ -351,7 +394,11 @@ typedef struct {
#define TIMER_B_BASE ((uint16_t)0x0180)
#define WD_BASE ((uint16_t)0x0120)
#define USCI_0_BASE ((uint16_t)0x005d)
#define USCI_0_A_BASE ((uint16_t)0x0060)
#define USCI_0_B_BASE ((uint16_t)0x0068)
#define USCI_1_BASE ((uint16_t)0x00cd)
#define USCI_1_A_BASE ((uint16_t)0x00d0)
#define USCI_1_B_BASE ((uint16_t)0x00d8)
/** @} */
/**
@ -374,6 +421,10 @@ typedef struct {
#define WD ((msp_wd_t *)WD_BASE)
#define USCI_0 ((msp_usci_t *)USCI_0_BASE)
#define USCI_1 ((msp_usci_t *)USCI_1_BASE)
#define USCI_0_A_SPI ((msp_usci_spi_t *)USCI_0_A_BASE)
#define USCI_0_B_SPI ((msp_usci_spi_t *)USCI_0_B_BASE)
#define USCI_1_A ((msp_usci_t *)USCI_1_A_BASE)
#define USCI_1_B ((msp_usci_t *)USCI_1_B_BASE)
/** @} */
#ifdef __cplusplus

View File

@ -88,6 +88,14 @@ enum {
*/
void gpio_periph_mode(gpio_t pin, bool enable);
/**
* @brief declare needed generic SPI functions
* @{
*/
#define PERIPH_SPI_NEEDS_TRANSFER_BYTES
#define PERIPH_SPI_NEEDS_TRANSFER_REG
#define PERIPH_SPI_NEEDS_TRANSFER_REGS
/** @} */
#ifdef __cplusplus
}

225
cpu/msp430fxyz/periph/spi.c Normal file
View File

@ -0,0 +1,225 @@
/*
* 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_msp430fxyz
* @{
*
* @file
* @brief Low-level SPI driver implementation
*
* This SPI driver implementation does only support one single SPI device for
* now. This is sufficient, as most MSP430 CPU's only support two serial
* devices - one used as UART and one as SPI.
*
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
*
* @}
*/
#include "cpu.h"
#include "mutex.h"
#include "periph_cpu.h"
#include "periph_conf.h"
#include "periph/spi.h"
/**
* @brief Mutex for locking the SPI device
*/
static mutex_t spi_lock = MUTEX_INIT;
/* per default, we use the legacy MSP430 USART module for UART functionality */
#ifndef SPI_USE_USIC
int spi_init_master(spi_t dev, spi_conf_t conf, spi_speed_t speed)
{
if (dev != 0) {
return -2;
}
/* reset SPI device */
SPI_DEV->CTL = USART_CTL_SWRST;
/* configure pins */
spi_conf_pins(dev);
/* configure USART to SPI mode with SMCLK driving it */
SPI_DEV->CTL |= (USART_CTL_CHAR | USART_CTL_SYNC | USART_CTL_MM);
SPI_DEV->RCTL = 0;
SPI_DEV->TCTL = (USART_TCTL_SSEL_SMCLK | USART_TCTL_STC);
/* set polarity and phase */
switch (conf) {
case SPI_CONF_SECOND_RISING:
SPI_DEV->TCTL |= USART_TCTL_CKPH;
break;
case SPI_CONF_FIRST_FALLING:
SPI_DEV->TCTL |= SPI_CONF_FIRST_FALLING;
break;
case SPI_CONF_SECOND_FALLING:
SPI_DEV->TCTL |= (USART_TCTL_CKPH | SPI_CONF_FIRST_FALLING);
break;
default:
/* do nothing */
break;
}
/* configure clock - we use no modulation for now */
uint32_t br = CLOCK_CMCLK;
switch (speed) {
case SPI_SPEED_100KHZ:
br /= 100000;
case SPI_SPEED_400KHZ:
br /= 400000;
case SPI_SPEED_1MHZ:
br /= 1000000;
case SPI_SPEED_5MHZ:
br /= 5000000;
if (br < 2) { /* make sure the is not smaller then 2 */
br = 2;
}
break;
default:
/* other clock speeds are not supported */
return -1;
}
SPI_DEV->BR0 = (uint8_t)br;
SPI_DEV->BR1 = (uint8_t)(br >> 8);
SPI_DEV->MCTL = 0;
/* enable SPI mode */
SPI_ME |= SPI_ME_BIT;
/* release from software reset */
SPI_DEV->CTL &= ~(USART_CTL_SWRST);
return 0;
}
/* we use alternative SPI code in case the board used the USIC module for SPI
* instead of the (older) USART module */
#else /* SPI_USE_USIC */
int spi_init_master(spi_t dev, spi_conf_t conf, spi_speed_t speed)
{
if (dev != 0) {
return -2;
}
/* reset SPI device */
SPI_DEV->CTL1 |= USCI_SPI_CTL1_SWRST;
/* configure pins */
spi_conf_pins(dev);
/* configure USART to SPI mode with SMCLK driving it */
SPI_DEV->CTL0 |= (USCI_SPI_CTL0_UCSYNC | USCI_SPI_CTL0_MST
| USCI_SPI_CTL0_MODE_0 | USCI_SPI_CTL0_MSB);
SPI_DEV->CTL1 |= (USCI_SPI_CTL1_SSEL_SMCLK);
/* set polarity and phase */
switch (conf) {
case SPI_CONF_FIRST_RISING:
SPI_DEV->CTL0 |= (USCI_SPI_CTL0_CKPH & ~(USCI_SPI_CTL0_CKPL));
break;
case SPI_CONF_SECOND_RISING:
SPI_DEV->CTL0 |= (~(USCI_SPI_CTL0_CKPH) & ~(USCI_SPI_CTL0_CKPL));
break;
case SPI_CONF_FIRST_FALLING:
SPI_DEV->CTL0 |= (USCI_SPI_CTL0_CKPH & USCI_SPI_CTL0_CKPL);
break;
case SPI_CONF_SECOND_FALLING:
SPI_DEV->CTL0 |= (~(USCI_SPI_CTL0_CKPH) & USCI_SPI_CTL0_CKPL);
break;
default:
/* do nothing */
break;
}
/* configure clock - we use no modulation for now */
uint32_t br = CLOCK_CMCLK;
switch (speed) {
case SPI_SPEED_100KHZ:
br /= 100000;
case SPI_SPEED_400KHZ:
br /= 400000;
case SPI_SPEED_1MHZ:
br /= 1000000;
case SPI_SPEED_5MHZ:
br /= 5000000;
if (br < 2) { /* make sure the is not smaller then 2 */
br = 2;
}
break;
default:
/* other clock speeds are not supported */
return -1;
}
SPI_DEV->BR0 = (uint8_t)br;
SPI_DEV->BR1 = (uint8_t)(br >> 8);
/* release from software reset */
SPI_DEV->CTL1 &= ~(USCI_SPI_CTL1_SWRST);
return 0;
}
#endif /* UART_USE_USIC */
int spi_init_slave(spi_t dev, spi_conf_t conf, char (*cb)(char data))
{
/* not supported so far */
(void)dev;
(void)conf;
(void)cb;
return -1;
}
void spi_transmission_begin(spi_t dev, char reset_val)
{
/* not supported so far */
(void)dev;
(void)reset_val;
}
int spi_conf_pins(spi_t dev)
{
(void)dev;
gpio_periph_mode(SPI_PIN_MISO, true);
gpio_periph_mode(SPI_PIN_MOSI, true);
gpio_periph_mode(SPI_PIN_CLK, true);
return 0;
}
int spi_acquire(spi_t dev)
{
(void)dev;
mutex_lock(&spi_lock);
return 0;
}
int spi_release(spi_t dev)
{
(void)dev;
mutex_unlock(&spi_lock);
return 0;
}
int spi_transfer_byte(spi_t dev, char out, char *in)
{
(void)dev;
char tmp;
while (!(SPI_IF & SPI_IE_TX_BIT));
SPI_DEV->TXBUF = (uint8_t)out;
while (!(SPI_IF & SPI_IE_RX_BIT));
tmp = (char)SPI_DEV->RXBUF;
if (in) {
*in = tmp;
}
return 1;
}
void spi_poweron(spi_t dev)
{
/* not supported so far */
(void)dev;
}
void spi_poweroff(spi_t dev)
{
/* not supported so far */
(void)dev;
}