mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2025-12-16 18:13:49 +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
|
||||
|
||||
#include "cpu.h"
|
||||
#include "macros/units.h"
|
||||
|
||||
#if defined(CPU_FAM_STM32F0)
|
||||
#include "periph/f0/periph_cpu.h"
|
||||
@ -620,6 +621,25 @@ typedef enum {
|
||||
/** @} */
|
||||
#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
|
||||
*/
|
||||
|
||||
@ -26,16 +26,21 @@
|
||||
* @}
|
||||
*/
|
||||
|
||||
#include "bitarithm.h"
|
||||
#include "cpu.h"
|
||||
#include "mutex.h"
|
||||
#include "assert.h"
|
||||
#include "periph/spi.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
|
||||
*/
|
||||
#define BR_SHIFT (3U)
|
||||
#define BR_MAX (7U)
|
||||
|
||||
#ifdef SPI_CR2_FRXTH
|
||||
/* configure SPI for 8-bit data width */
|
||||
@ -52,6 +57,16 @@
|
||||
*/
|
||||
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)
|
||||
{
|
||||
return spi_config[bus].dev;
|
||||
@ -64,6 +79,35 @@ static inline bool _use_dma(const spi_conf_t *conf)
|
||||
}
|
||||
#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)
|
||||
{
|
||||
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 */
|
||||
periph_clk_en(spi_config[bus].apbbus, spi_config[bus].rccmask);
|
||||
/* 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);
|
||||
/* Settings to add to CR2 in addition to SPI_CR2_SETTINGS */
|
||||
uint16_t cr2_extra_settings = 0;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user