mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2025-12-18 19:13:51 +01:00
stm32: Add support for arbitrary SPI clock rates
This commit is contained in:
parent
99365873fd
commit
b9d62e47d3
@ -22,6 +22,7 @@
|
|||||||
#define PERIPH_CPU_H
|
#define PERIPH_CPU_H
|
||||||
|
|
||||||
#include "cpu.h"
|
#include "cpu.h"
|
||||||
|
#include "macros/units.h"
|
||||||
|
|
||||||
#if defined(CPU_FAM_STM32F0)
|
#if defined(CPU_FAM_STM32F0)
|
||||||
#include "periph/f0/periph_cpu.h"
|
#include "periph/f0/periph_cpu.h"
|
||||||
@ -620,6 +621,25 @@ typedef enum {
|
|||||||
/** @} */
|
/** @} */
|
||||||
#endif /* ndef DOXYGEN */
|
#endif /* ndef DOXYGEN */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Override SPI clock speed values
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
#define HAVE_SPI_CLK_T
|
||||||
|
enum {
|
||||||
|
SPI_CLK_100KHZ = KHZ(100), /**< drive the SPI bus with 100KHz */
|
||||||
|
SPI_CLK_400KHZ = KHZ(400), /**< drive the SPI bus with 400KHz */
|
||||||
|
SPI_CLK_1MHZ = MHZ(1), /**< drive the SPI bus with 1MHz */
|
||||||
|
SPI_CLK_5MHZ = MHZ(5), /**< drive the SPI bus with 5MHz */
|
||||||
|
SPI_CLK_10MHZ = MHZ(10), /**< drive the SPI bus with 10MHz */
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief SPI clock type
|
||||||
|
*/
|
||||||
|
typedef uint32_t spi_clk_t;
|
||||||
|
/** @} */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Structure for UART configuration data
|
* @brief Structure for UART configuration data
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -26,16 +26,21 @@
|
|||||||
* @}
|
* @}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "bitarithm.h"
|
||||||
#include "cpu.h"
|
#include "cpu.h"
|
||||||
#include "mutex.h"
|
#include "mutex.h"
|
||||||
#include "assert.h"
|
#include "assert.h"
|
||||||
#include "periph/spi.h"
|
#include "periph/spi.h"
|
||||||
#include "pm_layered.h"
|
#include "pm_layered.h"
|
||||||
|
|
||||||
|
#define ENABLE_DEBUG (0)
|
||||||
|
#include "debug.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Number of bits to shift the BR value in the CR1 register
|
* @brief Number of bits to shift the BR value in the CR1 register
|
||||||
*/
|
*/
|
||||||
#define BR_SHIFT (3U)
|
#define BR_SHIFT (3U)
|
||||||
|
#define BR_MAX (7U)
|
||||||
|
|
||||||
#ifdef SPI_CR2_FRXTH
|
#ifdef SPI_CR2_FRXTH
|
||||||
/* configure SPI for 8-bit data width */
|
/* configure SPI for 8-bit data width */
|
||||||
@ -52,6 +57,16 @@
|
|||||||
*/
|
*/
|
||||||
static mutex_t locks[SPI_NUMOF];
|
static mutex_t locks[SPI_NUMOF];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Clock configuration cache
|
||||||
|
*/
|
||||||
|
static uint32_t clocks[SPI_NUMOF];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Clock divider cache
|
||||||
|
*/
|
||||||
|
static uint8_t dividers[SPI_NUMOF];
|
||||||
|
|
||||||
static inline SPI_TypeDef *dev(spi_t bus)
|
static inline SPI_TypeDef *dev(spi_t bus)
|
||||||
{
|
{
|
||||||
return spi_config[bus].dev;
|
return spi_config[bus].dev;
|
||||||
@ -64,6 +79,35 @@ static inline bool _use_dma(const spi_conf_t *conf)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Multiplier for clock divider calculations
|
||||||
|
*
|
||||||
|
* Makes the divider calculation fixed point
|
||||||
|
*/
|
||||||
|
#define SPI_APB_CLOCK_SHIFT (4U)
|
||||||
|
#define SPI_APB_CLOCK_MULT (1U << SPI_APB_CLOCK_SHIFT)
|
||||||
|
|
||||||
|
static uint8_t _get_clkdiv(const spi_conf_t *conf, uint32_t clock)
|
||||||
|
{
|
||||||
|
uint32_t bus_clock = periph_apb_clk(conf->apbbus);
|
||||||
|
/* Shift bus_clock with SPI_APB_CLOCK_SHIFT to create a fixed point int */
|
||||||
|
uint32_t div = (bus_clock << SPI_APB_CLOCK_SHIFT) / (2 * clock);
|
||||||
|
DEBUG("[spi] clock: divider: %"PRIu32"\n", div);
|
||||||
|
/* Test if the divider is 2 or smaller, keeping the fixed point in mind */
|
||||||
|
if (div <= SPI_APB_CLOCK_MULT) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/* determine MSB and compensate back for the fixed point int shift */
|
||||||
|
uint8_t rounded_div = bitarithm_msb(div) - SPI_APB_CLOCK_SHIFT;
|
||||||
|
/* Determine if rounded_div is not a power of 2 */
|
||||||
|
if ((div & (div - 1)) != 0) {
|
||||||
|
/* increment by 1 to ensure that the clock speed at most the
|
||||||
|
* requested clock speed */
|
||||||
|
rounded_div++;
|
||||||
|
}
|
||||||
|
return rounded_div > BR_MAX ? BR_MAX : rounded_div;
|
||||||
|
}
|
||||||
|
|
||||||
void spi_init(spi_t bus)
|
void spi_init(spi_t bus)
|
||||||
{
|
{
|
||||||
assert(bus < SPI_NUMOF);
|
assert(bus < SPI_NUMOF);
|
||||||
@ -162,7 +206,18 @@ int spi_acquire(spi_t bus, spi_cs_t cs, spi_mode_t mode, spi_clk_t clk)
|
|||||||
/* enable SPI device clock */
|
/* enable SPI device clock */
|
||||||
periph_clk_en(spi_config[bus].apbbus, spi_config[bus].rccmask);
|
periph_clk_en(spi_config[bus].apbbus, spi_config[bus].rccmask);
|
||||||
/* enable device */
|
/* enable device */
|
||||||
uint8_t br = spi_divtable[spi_config[bus].apbbus][clk];
|
if (clk != clocks[bus]) {
|
||||||
|
dividers[bus] = _get_clkdiv(&spi_config[bus], clk);
|
||||||
|
clocks[bus] = clk;
|
||||||
|
}
|
||||||
|
uint8_t br = dividers[bus];
|
||||||
|
|
||||||
|
DEBUG("[spi] acquire: requested clock: %"PRIu32", resulting clock: %"PRIu32
|
||||||
|
" BR divider: %u\n",
|
||||||
|
clk,
|
||||||
|
periph_apb_clk(spi_config[bus].apbbus)/(1 << (br + 1)),
|
||||||
|
br);
|
||||||
|
|
||||||
uint16_t cr1_settings = ((br << BR_SHIFT) | mode | SPI_CR1_MSTR);
|
uint16_t cr1_settings = ((br << BR_SHIFT) | mode | SPI_CR1_MSTR);
|
||||||
/* Settings to add to CR2 in addition to SPI_CR2_SETTINGS */
|
/* Settings to add to CR2 in addition to SPI_CR2_SETTINGS */
|
||||||
uint16_t cr2_extra_settings = 0;
|
uint16_t cr2_extra_settings = 0;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user