mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2025-12-29 16:31:18 +01:00
cpu/cc2538+boards: adapted to SPI API changes
- adapted the SPI driver - adapted all boards using the CPU
This commit is contained in:
parent
b7109bd564
commit
ca5f1befb3
@ -58,7 +58,6 @@ static const timer_conf_t timer_config[] = {
|
||||
#define TIMER_IRQ_PRIO 1
|
||||
/** @} */
|
||||
|
||||
|
||||
/**
|
||||
* @name UART configuration
|
||||
* @{
|
||||
@ -112,22 +111,35 @@ static const i2c_conf_t i2c_config[I2C_NUMOF] = {
|
||||
};
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @brief Pre-calculated clock divider values based on a CLOCK_CORECLOCK (32MHz)
|
||||
*
|
||||
* Calculated with (CPSR * (SCR + 1)) = (CLOCK_CORECLOCK / bus_freq), where
|
||||
* CPSR and SCR cannot be larger than 255.
|
||||
*/
|
||||
static const spi_clk_conf_t spi_clk_config[] = {
|
||||
{ .cpsr = 10, .scr = 31 }, /* 100khz */
|
||||
{ .cpsr = 1, .scr = 79 }, /* 400khz */
|
||||
{ .cpsr = 1, .scr = 31 }, /* 1MHz */
|
||||
{ .cpsr = 1, .scr = 6 }, /* ~4.5MHz */
|
||||
{ .cpsr = 1, .scr = 2 } /* ~10.7MHz */
|
||||
};
|
||||
|
||||
/**
|
||||
* @name SPI configuration
|
||||
* @{
|
||||
*/
|
||||
#define SPI_NUMOF 1
|
||||
#define SPI_0_EN 1
|
||||
|
||||
static const periph_spi_conf_t spi_config[SPI_NUMOF] = {
|
||||
static const spi_conf_t spi_config[] = {
|
||||
{
|
||||
.dev = SSI0,
|
||||
.mosi_pin = GPIO_PA4,
|
||||
.miso_pin = GPIO_PA5,
|
||||
.sck_pin = GPIO_PA2,
|
||||
.cs_pin = GPIO_PD0,
|
||||
},
|
||||
.cs_pin = GPIO_PD0
|
||||
}
|
||||
};
|
||||
|
||||
#define SPI_NUMOF (sizeof(spi_config) / sizeof(spi_config[0]))
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
|
||||
@ -30,7 +30,7 @@
|
||||
* @name Clock system configuration
|
||||
* @{
|
||||
*/
|
||||
#define CLOCK_CORECLOCK (32000000U) /* desired core clock frequency, 32MHz */
|
||||
#define CLOCK_CORECLOCK (32000000U) /* desired core clock frequency, 32MHz */
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
@ -104,14 +104,25 @@ static const i2c_conf_t i2c_config[I2C_NUMOF] = {
|
||||
};
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @brief Pre-calculated clock divider values based on a CLOCK_CORECLOCK (32MHz)
|
||||
*
|
||||
* Calculated with (CPSR * (SCR + 1)) = (CLOCK_CORECLOCK / bus_freq), where
|
||||
* CPSR and SCR cannot be larger than 255.
|
||||
*/
|
||||
static const spi_clk_conf_t spi_clk_config[] = {
|
||||
{ .cpsr = 10, .scr = 31 }, /* 100khz */
|
||||
{ .cpsr = 1, .scr = 79 }, /* 400khz */
|
||||
{ .cpsr = 1, .scr = 31 }, /* 1MHz */
|
||||
{ .cpsr = 1, .scr = 6 }, /* ~4.5MHz */
|
||||
{ .cpsr = 1, .scr = 2 } /* ~10.7MHz */
|
||||
};
|
||||
|
||||
/**
|
||||
* @name SPI configuration
|
||||
* @{
|
||||
*/
|
||||
#define SPI_NUMOF 1
|
||||
#define SPI_0_EN 1
|
||||
|
||||
static const periph_spi_conf_t spi_config[SPI_NUMOF] = {
|
||||
static const spi_conf_t spi_config[] = {
|
||||
{
|
||||
.dev = SSI0,
|
||||
.mosi_pin = GPIO_PA5,
|
||||
@ -120,6 +131,8 @@ static const periph_spi_conf_t spi_config[SPI_NUMOF] = {
|
||||
.cs_pin = GPIO_PA3,
|
||||
},
|
||||
};
|
||||
|
||||
#define SPI_NUMOF (sizeof(spi_config) / sizeof(spi_config[0]))
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Freie Universität Berlin
|
||||
* Copyright (C) 2015 Zolertia SL
|
||||
* Copyright (C) 2014-2016 Freie Universität Berlin
|
||||
* 2015 Zolertia SL
|
||||
*
|
||||
* 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.
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
@ -15,7 +15,7 @@
|
||||
* @brief Peripheral MCU configuration for the Re-Mote board prototype A
|
||||
*
|
||||
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
|
||||
* Antonio Lignan <alinan@zolertia.com>
|
||||
* @author Antonio Lignan <alinan@zolertia.com>
|
||||
*/
|
||||
|
||||
#ifndef PERIPH_CONF_H
|
||||
@ -70,29 +70,42 @@ static const i2c_conf_t i2c_config[I2C_NUMOF] = {
|
||||
};
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @brief Pre-calculated clock divider values based on a CLOCK_CORECLOCK (32MHz)
|
||||
*
|
||||
* Calculated with (CPSR * (SCR + 1)) = (CLOCK_CORECLOCK / bus_freq), where
|
||||
* CPSR and SCR cannot be larger than 255.
|
||||
*/
|
||||
static const spi_clk_conf_t spi_clk_config[] = {
|
||||
{ .cpsr = 10, .scr = 31 }, /* 100khz */
|
||||
{ .cpsr = 1, .scr = 79 }, /* 400khz */
|
||||
{ .cpsr = 1, .scr = 31 }, /* 1MHz */
|
||||
{ .cpsr = 1, .scr = 6 }, /* ~4.5MHz */
|
||||
{ .cpsr = 1, .scr = 2 } /* ~10.7MHz */
|
||||
};
|
||||
|
||||
/**
|
||||
* @name SPI configuration
|
||||
* @{
|
||||
*/
|
||||
#define SPI_NUMOF 2
|
||||
#define SPI_0_EN 1
|
||||
#define SPI_1_EN 1
|
||||
|
||||
static const periph_spi_conf_t spi_config[SPI_NUMOF] = {
|
||||
static const spi_conf_t spi_config[] = {
|
||||
{
|
||||
.dev = SSI0,
|
||||
.mosi_pin = GPIO_PD0,
|
||||
.miso_pin = GPIO_PC4,
|
||||
.sck_pin = GPIO_PD1,
|
||||
.cs_pin = GPIO_PD3,
|
||||
.cs_pin = GPIO_PD3
|
||||
},
|
||||
{
|
||||
.dev = SSI1,
|
||||
.mosi_pin = GPIO_PC7,
|
||||
.miso_pin = GPIO_PA4,
|
||||
.sck_pin = GPIO_PB5,
|
||||
},
|
||||
.cs_pin = GPIO_UNDEF
|
||||
}
|
||||
};
|
||||
|
||||
#define SPI_NUMOF (sizeof(spi_config) / sizeof(spi_config[0]))
|
||||
/** @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Freie Universität Berlin
|
||||
* Copyright (C) 2015 Zolertia SL
|
||||
* Copyright (C) 2014-2016 Freie Universität Berlin
|
||||
* 2015 Zolertia SL
|
||||
*
|
||||
* 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.
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
@ -15,7 +15,7 @@
|
||||
* @brief Peripheral MCU configuration for the RE-Mote board revision A
|
||||
*
|
||||
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
|
||||
* Antonio Lignan <alinan@zolertia.com>
|
||||
* @author Antonio Lignan <alinan@zolertia.com>
|
||||
*/
|
||||
|
||||
#ifndef PERIPH_CONF_H
|
||||
@ -70,30 +70,42 @@ static const i2c_conf_t i2c_config[I2C_NUMOF] = {
|
||||
};
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @brief Pre-calculated clock divider values based on a CLOCK_CORECLOCK (32MHz)
|
||||
*
|
||||
* Calculated with (CPSR * (SCR + 1)) = (CLOCK_CORECLOCK / bus_freq), where
|
||||
* CPSR and SCR cannot be larger than 255.
|
||||
*/
|
||||
static const spi_clk_conf_t spi_clk_config[] = {
|
||||
{ .cpsr = 10, .scr = 31 }, /* 100khz */
|
||||
{ .cpsr = 1, .scr = 79 }, /* 400khz */
|
||||
{ .cpsr = 1, .scr = 31 }, /* 1MHz */
|
||||
{ .cpsr = 1, .scr = 6 }, /* ~4.5MHz */
|
||||
{ .cpsr = 1, .scr = 2 } /* ~10.7MHz */
|
||||
};
|
||||
|
||||
/**
|
||||
* @name SPI configuration
|
||||
* @{
|
||||
*/
|
||||
#define SPI_NUMOF 2
|
||||
#define SPI_0_EN 1
|
||||
#define SPI_1_EN 1
|
||||
|
||||
static const periph_spi_conf_t spi_config[SPI_NUMOF] = {
|
||||
static const spi_conf_t spi_config[] = {
|
||||
{
|
||||
.dev = SSI0,
|
||||
.mosi_pin = GPIO_PB1,
|
||||
.miso_pin = GPIO_PB3,
|
||||
.sck_pin = GPIO_PB2,
|
||||
.cs_pin = GPIO_PB5,
|
||||
.cs_pin = GPIO_PB5
|
||||
},
|
||||
{
|
||||
.dev = SSI1,
|
||||
.mosi_pin = GPIO_PC5,
|
||||
.miso_pin = GPIO_PC6,
|
||||
.sck_pin = GPIO_PC4,
|
||||
.cs_pin = GPIO_PA7,
|
||||
},
|
||||
.cs_pin = GPIO_PA7
|
||||
}
|
||||
};
|
||||
|
||||
#define SPI_NUMOF (sizeof(spi_config) / sizeof(spi_config[0]))
|
||||
/** @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@ -114,7 +114,7 @@
|
||||
* @name Onboard micro-sd slot pin definitions
|
||||
* @{
|
||||
*/
|
||||
#define SDCARD_SPI_PARAM_SPI SPI_1
|
||||
#define SDCARD_SPI_PARAM_SPI SPI_DEV(1)
|
||||
#define SDCARD_SPI_PARAM_CS GPIO_PIN(0,7)
|
||||
#define SDCARD_SPI_PARAM_CLK GPIO_PIN(2,4)
|
||||
#define SDCARD_SPI_PARAM_MOSI GPIO_PIN(2,5)
|
||||
|
||||
@ -70,30 +70,42 @@ static const i2c_conf_t i2c_config[I2C_NUMOF] = {
|
||||
};
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @brief Pre-calculated clock divider values based on a CLOCK_CORECLOCK (32MHz)
|
||||
*
|
||||
* Calculated with (CPSR * (SCR + 1)) = (CLOCK_CORECLOCK / bus_freq), where
|
||||
* CPSR and SCR cannot be larger than 255.
|
||||
*/
|
||||
static const spi_clk_conf_t spi_clk_config[] = {
|
||||
{ .cpsr = 10, .scr = 31 }, /* 100khz */
|
||||
{ .cpsr = 1, .scr = 79 }, /* 400khz */
|
||||
{ .cpsr = 1, .scr = 31 }, /* 1MHz */
|
||||
{ .cpsr = 1, .scr = 6 }, /* ~4.5MHz */
|
||||
{ .cpsr = 1, .scr = 2 } /* ~10.7MHz */
|
||||
};
|
||||
|
||||
/**
|
||||
* @name SPI configuration
|
||||
* @{
|
||||
*/
|
||||
#define SPI_NUMOF 2
|
||||
#define SPI_0_EN 1
|
||||
#define SPI_1_EN 1
|
||||
|
||||
static const periph_spi_conf_t spi_config[SPI_NUMOF] = {
|
||||
static const spi_conf_t spi_config[] = {
|
||||
{
|
||||
.dev = SSI0,
|
||||
.mosi_pin = GPIO_PB1,
|
||||
.miso_pin = GPIO_PB3,
|
||||
.sck_pin = GPIO_PB2,
|
||||
.cs_pin = GPIO_PB5,
|
||||
.cs_pin = GPIO_PB5
|
||||
},
|
||||
{
|
||||
.dev = SSI1,
|
||||
.mosi_pin = GPIO_PC5,
|
||||
.miso_pin = GPIO_PC6,
|
||||
.sck_pin = GPIO_PC4,
|
||||
.cs_pin = GPIO_PA7,
|
||||
},
|
||||
.cs_pin = GPIO_PA7
|
||||
}
|
||||
};
|
||||
|
||||
#define SPI_NUMOF (sizeof(spi_config) / sizeof(spi_config[0]))
|
||||
/** @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@ -77,6 +77,46 @@ typedef struct {
|
||||
#define SSI0 ( (cc2538_ssi_t*)0x40008000 ) /**< SSI0 Instance */
|
||||
#define SSI1 ( (cc2538_ssi_t*)0x40009000 ) /**< SSI1 Instance */
|
||||
|
||||
/**
|
||||
* @brief Define CR0 register bitfields
|
||||
* @{
|
||||
*/
|
||||
#define SSI_CR0_DSS(x) ((x - 1) << 0)
|
||||
#define SSI_CR0_SPO (1 << 6)
|
||||
#define SSI_CR0_SPH (1 << 7)
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @brief Define CR1 register bitfields
|
||||
* @{
|
||||
*/
|
||||
#define SSI_CR1_LBM (1 << 0)
|
||||
#define SSI_CR1_SSE (1 << 1)
|
||||
#define SSI_CR1_MS (1 << 2)
|
||||
#define SSI_CR1_SOD (1 << 3)
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @brief Define SR register bitfields
|
||||
* @{
|
||||
*/
|
||||
#define SSI_SR_TFE (1 << 0)
|
||||
#define SSI_SR_TNF (1 << 1)
|
||||
#define SSI_SR_RNE (1 << 2)
|
||||
#define SSI_SR_RFF (1 << 3)
|
||||
#define SSI_SR_BSY (1 << 4)
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @brief Define CC register bitfields
|
||||
* @{
|
||||
*/
|
||||
#define SSI_SS_PIOSC (1 << 0)
|
||||
#define SSI_SS_DSEN (1 << 2)
|
||||
#define SSI_SS_SYSDIV (0)
|
||||
#define SSI_SS_IODIV (SSI_SS_PIOSC)
|
||||
/** @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* end extern "C" */
|
||||
#endif
|
||||
|
||||
@ -50,10 +50,20 @@ typedef uint32_t gpio_t;
|
||||
*/
|
||||
#define GPIO_PIN(port, pin) (gpio_t)(((uint32_t)GPIO_A + (port << 12)) | pin)
|
||||
|
||||
/**
|
||||
* @brief I2C configuration options
|
||||
*/
|
||||
typedef struct {
|
||||
gpio_t scl_pin; /**< pin used for SCL */
|
||||
gpio_t sda_pin; /**< pin used for SDA */
|
||||
} i2c_conf_t;
|
||||
|
||||
/**
|
||||
* @brief declare needed generic SPI functions
|
||||
* @{
|
||||
*/
|
||||
#define PERIPH_SPI_NEEDS_INIT_CS
|
||||
#define PERIPH_SPI_NEEDS_TRANSFER_BYTE
|
||||
#define PERIPH_SPI_NEEDS_TRANSFER_REG
|
||||
#define PERIPH_SPI_NEEDS_TRANSFER_REGS
|
||||
/** @} */
|
||||
@ -74,12 +84,39 @@ typedef enum {
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @brief I2C configuration options
|
||||
* @brief Override SPI mode settings
|
||||
* @{
|
||||
*/
|
||||
#define HAVE_SPI_MODE_T
|
||||
typedef enum {
|
||||
SPI_MODE_0 = 0, /**< CPOL=0, CPHA=0 */
|
||||
SPI_MODE_1 = (SSI_CR0_SPH), /**< CPOL=0, CPHA=1 */
|
||||
SPI_MODE_2 = (SSI_CR0_SPO), /**< CPOL=1, CPHA=0 */
|
||||
SPI_MODE_3 = (SSI_CR0_SPO | SSI_CR0_SPH) /**< CPOL=1, CPHA=1 */
|
||||
} spi_mode_t;
|
||||
/** @ */
|
||||
|
||||
/**
|
||||
* @brief Override SPI clock settings
|
||||
* @{
|
||||
*/
|
||||
#define HAVE_SPI_CLK_T
|
||||
typedef enum {
|
||||
SPI_CLK_100KHZ = 0, /**< drive the SPI bus with 100KHz */
|
||||
SPI_CLK_400KHZ = 1, /**< drive the SPI bus with 400KHz */
|
||||
SPI_CLK_1MHZ = 2, /**< drive the SPI bus with 1MHz */
|
||||
SPI_CLK_5MHZ = 3, /**< drive the SPI bus with 5MHz */
|
||||
SPI_CLK_10MHZ = 4 /**< drive the SPI bus with 10MHz */
|
||||
} spi_clk_t;
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @brief Datafields for static SPI clock configuration values
|
||||
*/
|
||||
typedef struct {
|
||||
gpio_t scl_pin; /**< pin used for SCL */
|
||||
gpio_t sda_pin; /**< pin used for SDA */
|
||||
} i2c_conf_t;
|
||||
uint8_t cpsr; /**< CPSR clock divider */
|
||||
uint8_t scr; /**< SCR clock divider */
|
||||
} spi_clk_conf_t;
|
||||
|
||||
/**
|
||||
* @brief SPI configuration data structure
|
||||
@ -91,7 +128,7 @@ typedef struct {
|
||||
gpio_t miso_pin; /**< pin used for MISO */
|
||||
gpio_t sck_pin; /**< pin used for SCK */
|
||||
gpio_t cs_pin; /**< pin used for CS */
|
||||
} periph_spi_conf_t;
|
||||
} spi_conf_t;
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
|
||||
@ -1,327 +1,179 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Loci Controls Inc.
|
||||
* 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.
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @addtogroup driver_periph
|
||||
* @addtogroup cpu_cc2538
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief Low-level SPI driver implementation
|
||||
*
|
||||
* @author Ian Martin <ian@locicontrols.com>
|
||||
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
|
||||
*
|
||||
* @}
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "cc2538_ssi.h"
|
||||
|
||||
#include "cpu.h"
|
||||
#include "mutex.h"
|
||||
#include "assert.h"
|
||||
#include "periph/spi.h"
|
||||
#include "periph_conf.h"
|
||||
|
||||
/* guard file in case no SPI device is defined */
|
||||
#if SPI_NUMOF
|
||||
|
||||
/* clock sources for the SSI_CC register */
|
||||
#define CS_SYS_DIV 0
|
||||
#define CS_IO_DIV 1
|
||||
|
||||
#define SSI0_MASK (1 << 0)
|
||||
#define SSI1_MASK (1 << 1)
|
||||
|
||||
#ifndef SPI_DATA_BITS_NUMOF
|
||||
#define SPI_DATA_BITS_NUMOF 8
|
||||
#endif
|
||||
|
||||
#define spin_until(condition) while (!(condition)) thread_yield()
|
||||
|
||||
/**
|
||||
* @brief Array holding one pre-initialized mutex for each SPI device
|
||||
* @brief Array holding one pre-initialized mutex for each SPI device
|
||||
*/
|
||||
static mutex_t locks[SPI_NUMOF] = {MUTEX_INIT};
|
||||
static mutex_t locks[SPI_NUMOF];
|
||||
|
||||
int spi_init_master(spi_t dev, spi_conf_t conf, spi_speed_t speed)
|
||||
static inline cc2538_ssi_t *dev(spi_t bus)
|
||||
{
|
||||
cc2538_ssi_t* ssi = spi_config[dev].dev;
|
||||
|
||||
if ((unsigned int)dev >= SPI_NUMOF) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* power on the SPI device */
|
||||
spi_poweron(dev);
|
||||
|
||||
/* configure SCK, MISO and MOSI pin */
|
||||
spi_conf_pins(dev);
|
||||
|
||||
/* Disable the SSI and configure it for SPI master mode */
|
||||
ssi->CR1 = 0;
|
||||
|
||||
/* 3. Configure the SSI clock source */
|
||||
ssi->CC = CS_SYS_DIV;
|
||||
|
||||
/* 4. Configure the clock prescale divisor by writing the SSI_CPSR register.
|
||||
* frequency of the SSIClk is defined by: SSIClk = SysClk / (CPSDVSR x (1 + SCR))
|
||||
*/
|
||||
|
||||
const int32_t speed_lut[] = {
|
||||
[SPI_SPEED_100KHZ] = 100000 /* Hz */,
|
||||
[SPI_SPEED_400KHZ] = 400000 /* Hz */,
|
||||
[SPI_SPEED_1MHZ ] = 1000000 /* Hz */,
|
||||
[SPI_SPEED_5MHZ ] = 5000000 /* Hz */,
|
||||
[SPI_SPEED_10MHZ ] = 10000000 /* Hz */,
|
||||
};
|
||||
|
||||
int32_t SysClk = sys_clock_freq();
|
||||
int32_t f_desired = speed_lut[speed];
|
||||
int32_t f_actual;
|
||||
int32_t err;
|
||||
int32_t best_err = INT32_MAX;
|
||||
int32_t div1;
|
||||
int32_t div2;
|
||||
int32_t best_div1 = 2;
|
||||
int32_t best_div2 = 1;
|
||||
|
||||
/* System clock is first divided by CPSDVSR, then by SCR */
|
||||
for (div1 = 2; div1 <= 254; div1++) {
|
||||
div2 = SysClk;
|
||||
int32_t denom = div1 * f_desired;
|
||||
div2 += denom / 2;
|
||||
div2 /= denom;
|
||||
|
||||
if (div2 < 1) {
|
||||
div2 = 1;
|
||||
}
|
||||
else if (div2 > 256) {
|
||||
div2 = 256;
|
||||
}
|
||||
|
||||
f_actual = SysClk / (div1 * div2);
|
||||
err = f_actual - f_desired;
|
||||
if (err < 0) {
|
||||
err = -err;
|
||||
}
|
||||
if (err <= best_err) {
|
||||
best_div1 = div1;
|
||||
best_div2 = div2;
|
||||
best_err = err;
|
||||
}
|
||||
}
|
||||
|
||||
ssi->CPSR = best_div1; /* CPSDVSR */
|
||||
ssi->CR0bits.SCR = best_div2 - 1; /* Serial clock rate (SCR) */
|
||||
|
||||
switch (conf) {
|
||||
case SPI_CONF_FIRST_RISING:
|
||||
ssi->CR0bits.SPO = 0;
|
||||
ssi->CR0bits.SPH = 0;
|
||||
break;
|
||||
|
||||
case SPI_CONF_SECOND_RISING:
|
||||
ssi->CR0bits.SPO = 0;
|
||||
ssi->CR0bits.SPH = 1;
|
||||
break;
|
||||
|
||||
case SPI_CONF_FIRST_FALLING:
|
||||
ssi->CR0bits.SPO = 1;
|
||||
ssi->CR0bits.SPH = 0;
|
||||
break;
|
||||
|
||||
case SPI_CONF_SECOND_FALLING:
|
||||
ssi->CR0bits.SPO = 1;
|
||||
ssi->CR0bits.SPH = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
ssi->CR0bits.FRF = 0; /* SPI protocol mode */
|
||||
ssi->CR0bits.DSS = SPI_DATA_BITS_NUMOF - 1; /* The data size */
|
||||
|
||||
ssi->CR1bits.SSE = 1;
|
||||
|
||||
return 0;
|
||||
return spi_config[bus].dev;
|
||||
}
|
||||
|
||||
int spi_init_slave(spi_t dev, spi_conf_t conf, char(*cb)(char data))
|
||||
static inline void poweron(spi_t bus)
|
||||
{
|
||||
/* slave mode is not (yet) supported */
|
||||
return -1;
|
||||
SYS_CTRL_RCGCSSI |= (1 << bus);
|
||||
SYS_CTRL_SCGCSSI |= (1 << bus);
|
||||
SYS_CTRL_DCGCSSI |= (1 << bus);
|
||||
}
|
||||
|
||||
int spi_conf_pins(spi_t dev)
|
||||
static inline void poweroff(spi_t bus)
|
||||
{
|
||||
if ((unsigned int)dev >= SPI_NUMOF) {
|
||||
return -1;
|
||||
}
|
||||
SYS_CTRL_RCGCSSI &= ~(1 << bus);
|
||||
SYS_CTRL_SCGCSSI &= ~(1 << bus);
|
||||
SYS_CTRL_DCGCSSI &= ~(1 << bus);
|
||||
}
|
||||
|
||||
switch ((uintptr_t)spi_config[dev].dev) {
|
||||
void spi_init(spi_t bus)
|
||||
{
|
||||
assert(bus <= SPI_NUMOF);
|
||||
|
||||
/* temporarily power on the device */
|
||||
poweron(bus);
|
||||
/* configure device to be a master and disable SSI operation mode */
|
||||
dev(bus)->CR1 = 0;
|
||||
/* configure system clock as SSI clock source */
|
||||
dev(bus)->CC = SSI_SS_IODIV;
|
||||
/* and power off the bus again */
|
||||
poweroff(bus);
|
||||
|
||||
/* trigger SPI pin configuration */
|
||||
spi_init_pins(bus);
|
||||
}
|
||||
|
||||
void spi_init_pins(spi_t bus)
|
||||
{
|
||||
switch ((uintptr_t)spi_config[bus].dev) {
|
||||
case (uintptr_t)SSI0:
|
||||
IOC_PXX_SEL[spi_config[dev].mosi_pin] = SSI0_TXD;
|
||||
IOC_PXX_SEL[spi_config[dev].sck_pin ] = SSI0_CLKOUT;
|
||||
IOC_PXX_SEL[spi_config[dev].cs_pin ] = SSI0_FSSOUT;
|
||||
IOC_PXX_SEL[spi_config[bus].mosi_pin] = SSI0_TXD;
|
||||
IOC_PXX_SEL[spi_config[bus].sck_pin ] = SSI0_CLKOUT;
|
||||
IOC_PXX_SEL[spi_config[bus].cs_pin ] = SSI0_FSSOUT;
|
||||
|
||||
IOC_SSIRXD_SSI0 = spi_config[dev].miso_pin;
|
||||
IOC_SSIRXD_SSI0 = spi_config[bus].miso_pin;
|
||||
break;
|
||||
|
||||
case (uintptr_t)SSI1:
|
||||
IOC_PXX_SEL[spi_config[dev].mosi_pin] = SSI1_TXD;
|
||||
IOC_PXX_SEL[spi_config[dev].sck_pin ] = SSI1_CLKOUT;
|
||||
IOC_PXX_SEL[spi_config[dev].cs_pin ] = SSI1_FSSOUT;
|
||||
IOC_PXX_SEL[spi_config[bus].mosi_pin] = SSI1_TXD;
|
||||
IOC_PXX_SEL[spi_config[bus].sck_pin ] = SSI1_CLKOUT;
|
||||
IOC_PXX_SEL[spi_config[bus].cs_pin ] = SSI1_FSSOUT;
|
||||
|
||||
IOC_SSIRXD_SSI1 = spi_config[dev].miso_pin;
|
||||
IOC_SSIRXD_SSI1 = spi_config[bus].miso_pin;
|
||||
break;
|
||||
}
|
||||
|
||||
IOC_PXX_OVER[spi_config[dev].mosi_pin] = IOC_OVERRIDE_OE;
|
||||
IOC_PXX_OVER[spi_config[dev].sck_pin ] = IOC_OVERRIDE_OE;
|
||||
IOC_PXX_OVER[spi_config[dev].cs_pin ] = IOC_OVERRIDE_OE;
|
||||
IOC_PXX_OVER[spi_config[dev].miso_pin] = IOC_OVERRIDE_DIS;
|
||||
IOC_PXX_OVER[spi_config[bus].mosi_pin] = IOC_OVERRIDE_OE;
|
||||
IOC_PXX_OVER[spi_config[bus].miso_pin] = IOC_OVERRIDE_DIS;
|
||||
IOC_PXX_OVER[spi_config[bus].sck_pin ] = IOC_OVERRIDE_OE;
|
||||
IOC_PXX_OVER[spi_config[bus].cs_pin ] = IOC_OVERRIDE_OE;
|
||||
|
||||
gpio_hardware_control(spi_config[dev].mosi_pin);
|
||||
gpio_hardware_control(spi_config[dev].miso_pin);
|
||||
gpio_hardware_control(spi_config[dev].sck_pin);
|
||||
gpio_hardware_control(spi_config[dev].cs_pin);
|
||||
|
||||
return 0;
|
||||
gpio_hardware_control(spi_config[bus].mosi_pin);
|
||||
gpio_hardware_control(spi_config[bus].miso_pin);
|
||||
gpio_hardware_control(spi_config[bus].sck_pin);
|
||||
gpio_hardware_control(spi_config[bus].cs_pin);
|
||||
}
|
||||
|
||||
int spi_acquire(spi_t dev)
|
||||
int spi_acquire(spi_t bus, spi_cs_t cs, spi_mode_t mode, spi_clk_t clk)
|
||||
{
|
||||
if ((unsigned int)dev >= SPI_NUMOF) {
|
||||
return -1;
|
||||
}
|
||||
mutex_lock(&locks[dev]);
|
||||
return 0;
|
||||
/* lock the bus */
|
||||
mutex_lock(&locks[bus]);
|
||||
/* power on device */
|
||||
poweron(bus);
|
||||
/* configure SCR clock field, data-width and mode */
|
||||
dev(bus)->CR0 = 0;
|
||||
dev(bus)->CPSR = (spi_clk_config[clk].cpsr);
|
||||
dev(bus)->CR0 = ((spi_clk_config[clk].scr << 8) | mode | SSI_CR0_DSS(8));
|
||||
/* enable SSI device */
|
||||
dev(bus)->CR1 = SSI_CR1_SSE;
|
||||
|
||||
return SPI_OK;
|
||||
}
|
||||
|
||||
int spi_release(spi_t dev)
|
||||
void spi_release(spi_t bus)
|
||||
{
|
||||
if ((unsigned int)dev >= SPI_NUMOF) {
|
||||
return -1;
|
||||
}
|
||||
mutex_unlock(&locks[dev]);
|
||||
return 0;
|
||||
/* disable and power off device */
|
||||
dev(bus)->CR1 = 0;
|
||||
poweroff(bus);
|
||||
/* and release lock... */
|
||||
mutex_unlock(&locks[bus]);
|
||||
}
|
||||
|
||||
static char ssi_flush_input(cc2538_ssi_t *ssi)
|
||||
void spi_transfer_bytes(spi_t bus, spi_cs_t cs, bool cont,
|
||||
const void *out, void *in, size_t len)
|
||||
{
|
||||
char tmp = 0;
|
||||
uint8_t *out_buf = (uint8_t *)out;
|
||||
uint8_t *in_buf = (uint8_t *)in;
|
||||
|
||||
while (ssi->SRbits.RNE) {
|
||||
tmp = ssi->DR;
|
||||
assert(out_buf || in_buf);
|
||||
|
||||
if (cs != SPI_CS_UNDEF) {
|
||||
gpio_clear((gpio_t)cs);
|
||||
}
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
int spi_transfer_byte(spi_t dev, char out, char *in)
|
||||
{
|
||||
cc2538_ssi_t* ssi = spi_config[dev].dev;
|
||||
char tmp;
|
||||
|
||||
ssi_flush_input(ssi);
|
||||
|
||||
/* transmit byte */
|
||||
spin_until(ssi->SRbits.TNF);
|
||||
ssi->DR = out;
|
||||
|
||||
/* receive byte */
|
||||
spin_until(ssi->SRbits.RNE);
|
||||
tmp = ssi->DR;
|
||||
|
||||
if (in) {
|
||||
*in = tmp;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int spi_transfer_bytes(spi_t dev, char *out, char *in, unsigned int length)
|
||||
{
|
||||
cc2538_ssi_t* ssi = spi_config[dev].dev;
|
||||
unsigned int tx_n = 0, rx_n = 0;
|
||||
|
||||
if ((unsigned int)dev >= SPI_NUMOF) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ssi_flush_input(ssi);
|
||||
|
||||
/* transmit and receive bytes */
|
||||
while (tx_n < length) {
|
||||
spin_until(ssi->SRbits.TNF || ssi->SRbits.RNE);
|
||||
|
||||
if (ssi->SRbits.TNF) {
|
||||
ssi->DR = out[tx_n];
|
||||
tx_n++;
|
||||
if (!in_buf) {
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
while (!(dev(bus)->SR & SSI_SR_TNF)) {}
|
||||
dev(bus)->DR = out_buf[i];
|
||||
}
|
||||
else if (ssi->SRbits.RNE) {
|
||||
assert(rx_n < length);
|
||||
in[rx_n] = ssi->DR;
|
||||
rx_n++;
|
||||
/* flush RX FIFO */
|
||||
while (dev(bus)->SR & SSI_SR_RNE) {
|
||||
dev(bus)->DR;
|
||||
}
|
||||
}
|
||||
if (!out_buf) {
|
||||
size_t in_cnt = 0;
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
while (!(dev(bus)->SR & SSI_SR_TNF)) {}
|
||||
dev(bus)->DR = 0;
|
||||
if (dev(bus)->SR & SSI_SR_RNE) {
|
||||
in_buf[in_cnt++] = dev(bus)->DR;
|
||||
}
|
||||
}
|
||||
/* get remaining bytes */
|
||||
while (dev(bus)->SR & SSI_SR_RNE) {
|
||||
in_buf[in_cnt++] = dev(bus)->DR;
|
||||
}
|
||||
}
|
||||
else {
|
||||
size_t in_cnt = 0;
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
while (!(dev(bus)->SR & SSI_SR_TNF)) {}
|
||||
dev(bus)->DR = out_buf[i];
|
||||
if (dev(bus)->SR & SSI_SR_RNE) {
|
||||
in_buf[in_cnt++] = dev(bus)->DR;
|
||||
}
|
||||
}
|
||||
/* get remaining bytes */
|
||||
while (dev(bus)->SR & SSI_SR_RNE) {
|
||||
in_buf[in_cnt++] = dev(bus)->DR;
|
||||
}
|
||||
}
|
||||
|
||||
/* receive remaining bytes */
|
||||
while (rx_n < length) {
|
||||
spin_until(ssi->SRbits.RNE);
|
||||
assert(rx_n < length);
|
||||
in[rx_n] = ssi->DR;
|
||||
rx_n++;
|
||||
}
|
||||
|
||||
return rx_n;
|
||||
}
|
||||
|
||||
void spi_transmission_begin(spi_t dev, char reset_val)
|
||||
{
|
||||
/* slave mode is not (yet) supported */
|
||||
}
|
||||
|
||||
void spi_poweron(spi_t dev)
|
||||
{
|
||||
switch ((uintptr_t)spi_config[dev].dev) {
|
||||
case (uintptr_t)SSI0:
|
||||
/* enable SSI0 in all three power modes */
|
||||
SYS_CTRL_RCGCSSI |= SSI0_MASK;
|
||||
SYS_CTRL_SCGCSSI |= SSI0_MASK;
|
||||
SYS_CTRL_DCGCSSI |= SSI0_MASK;
|
||||
break;
|
||||
|
||||
case (uintptr_t)SSI1:
|
||||
/* enable SSI1 in all three power modes */
|
||||
SYS_CTRL_RCGCSSI |= SSI1_MASK;
|
||||
SYS_CTRL_SCGCSSI |= SSI1_MASK;
|
||||
SYS_CTRL_DCGCSSI |= SSI1_MASK;
|
||||
break;
|
||||
if ((!cont) && (cs != SPI_CS_UNDEF)) {
|
||||
gpio_set((gpio_t)cs);
|
||||
}
|
||||
}
|
||||
|
||||
void spi_poweroff(spi_t dev)
|
||||
{
|
||||
switch ((uintptr_t)spi_config[dev].dev) {
|
||||
case (uintptr_t)SSI0:
|
||||
/* disable SSI0 in all three power modes */
|
||||
SYS_CTRL_RCGCSSI &= ~SSI0_MASK;
|
||||
SYS_CTRL_SCGCSSI &= ~SSI0_MASK;
|
||||
SYS_CTRL_DCGCSSI &= ~SSI0_MASK;
|
||||
break;
|
||||
|
||||
case (uintptr_t)SSI1:
|
||||
/* disable SSI1 in all three power modes */
|
||||
SYS_CTRL_RCGCSSI &= ~SSI1_MASK;
|
||||
SYS_CTRL_SCGCSSI &= ~SSI1_MASK;
|
||||
SYS_CTRL_DCGCSSI &= ~SSI1_MASK;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* SPI_NUMOF */
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user