|
28 | 28 |
|
29 | 29 | #include <assert.h> |
30 | 30 |
|
31 | | -#include "bitarithm.h" |
32 | 31 | #include "mutex.h" |
33 | 32 | #include "periph/gpio.h" |
34 | 33 | #include "periph/spi.h" |
@@ -80,33 +79,24 @@ static inline bool _use_dma(const spi_conf_t *conf) |
80 | 79 | } |
81 | 80 | #endif |
82 | 81 |
|
83 | | -/** |
84 | | - * @brief Multiplier for clock divider calculations |
85 | | - * |
86 | | - * Makes the divider calculation fixed point |
87 | | - */ |
88 | | -#define SPI_APB_CLOCK_SHIFT (4U) |
89 | | -#define SPI_APB_CLOCK_MULT (1U << SPI_APB_CLOCK_SHIFT) |
90 | | - |
91 | 82 | static uint8_t _get_clkdiv(const spi_conf_t *conf, uint32_t clock) |
92 | 83 | { |
93 | 84 | uint32_t bus_clock = periph_apb_clk(conf->apbbus); |
94 | | - /* Shift bus_clock with SPI_APB_CLOCK_SHIFT to create a fixed point int */ |
95 | | - uint32_t div = (bus_clock << SPI_APB_CLOCK_SHIFT) / (2 * clock); |
96 | | - DEBUG("[spi] clock: divider: %"PRIu32"\n", div); |
97 | | - /* Test if the divider is 2 or smaller, keeping the fixed point in mind */ |
98 | | - if (div <= SPI_APB_CLOCK_MULT) { |
99 | | - return 0; |
100 | | - } |
101 | | - /* determine MSB and compensate back for the fixed point int shift */ |
102 | | - uint8_t rounded_div = bitarithm_msb(div) - SPI_APB_CLOCK_SHIFT; |
103 | | - /* Determine if rounded_div is not a power of 2 */ |
104 | | - if ((div & (div - 1)) != 0) { |
105 | | - /* increment by 1 to ensure that the clock speed at most the |
106 | | - * requested clock speed */ |
107 | | - rounded_div++; |
108 | | - } |
109 | | - return rounded_div > BR_MAX ? BR_MAX : rounded_div; |
| 85 | + |
| 86 | + uint8_t div = 0; |
| 87 | + uint32_t divided_clock = bus_clock >> 1; |
| 88 | + const uint8_t div_max = SPI_CR1_BR_Msk >> SPI_CR1_BR_Pos; |
| 89 | + for (; (divided_clock > clock) && (div < div_max); div++) { |
| 90 | + divided_clock >>= 1; |
| 91 | + } |
| 92 | + |
| 93 | + /* If the callers asks for an SPI frequency of at most x, bad things will |
| 94 | + * happen if this cannot be met. So let's have a blown assertion |
| 95 | + * rather than runtime failures that require a logic analyzer to |
| 96 | + * debug. */ |
| 97 | + assert(divided_clock <= clock); |
| 98 | + |
| 99 | + return div; |
110 | 100 | } |
111 | 101 |
|
112 | 102 | void spi_init(spi_t bus) |
@@ -239,11 +229,11 @@ void spi_acquire(spi_t bus, spi_cs_t cs, spi_mode_t mode, spi_clk_t clk) |
239 | 229 | } |
240 | 230 | uint8_t br = dividers[bus]; |
241 | 231 |
|
242 | | - DEBUG("[spi] acquire: requested clock: %"PRIu32", resulting clock: %"PRIu32 |
243 | | - " BR divider: %u\n", |
| 232 | + DEBUG("[spi] acquire: requested clock: %" PRIu32 |
| 233 | + " Hz, resulting clock: %" PRIu32 " Hz, BR divider: %u\n", |
244 | 234 | clk, |
245 | | - periph_apb_clk(spi_config[bus].apbbus)/(1 << (br + 1)), |
246 | | - br); |
| 235 | + periph_apb_clk(spi_config[bus].apbbus) >> (br + 1), |
| 236 | + (unsigned)br); |
247 | 237 |
|
248 | 238 | uint16_t cr1 = ((br << BR_SHIFT) | mode | SPI_CR1_MSTR | SPI_CR1_SPE); |
249 | 239 | /* Settings to add to CR2 in addition to SPI_CR2_SETTINGS */ |
|
0 commit comments