Skip to content

Commit b66a31c

Browse files
committed
stmhal: Allow SPI.init to specify prescaler directly; improve SPI docs.
1 parent 0082511 commit b66a31c

2 files changed

Lines changed: 44 additions & 22 deletions

File tree

docs/library/pyb.SPI.rst

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,12 +52,29 @@ Methods
5252

5353
Turn off the SPI bus.
5454

55-
.. method:: spi.init(mode, baudrate=328125, \*, polarity=1, phase=0, bits=8, firstbit=SPI.MSB, ti=False, crc=None)
55+
.. method:: spi.init(mode, baudrate=328125, \*, prescaler, polarity=1, phase=0, bits=8, firstbit=SPI.MSB, ti=False, crc=None)
5656

5757
Initialise the SPI bus with the given parameters:
5858

5959
- ``mode`` must be either ``SPI.MASTER`` or ``SPI.SLAVE``.
6060
- ``baudrate`` is the SCK clock rate (only sensible for a master).
61+
- ``prescaler`` is the prescaler to use to derive SCK from the APB bus frequency;
62+
use of ``prescaler`` overrides ``baudrate``.
63+
- ``polarity`` can be 0 or 1, and is the level the idle clock line sits at.
64+
- ``phase`` can be 0 or 1 to sample data on the first or second clock edge
65+
respectively.
66+
- ``firstbit`` can be ``SPI.MSB`` or ``SPI.LSB``.
67+
- ``crc`` can be None for no CRC, or a polynomial specifier.
68+
69+
Note that the SPI clock frequency will not always be the requested baudrate.
70+
The hardware only supports baudrates that are the APB bus frequency
71+
(see :meth:`pyb.freq`) divided by a prescaler, which can be 2, 4, 8, 16, 32,
72+
64, 128 or 256. SPI(1) is on AHB2, and SPI(2) is on AHB1. For precise
73+
control over the SPI clock frequency, specify ``prescaler`` instead of
74+
``baudrate``.
75+
76+
Printing the SPI object will show you the computed baudrate and the chosen
77+
prescaler.
6178

6279
.. method:: spi.recv(recv, \*, timeout=5000)
6380

stmhal/spi.c

Lines changed: 26 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -346,8 +346,9 @@ STATIC void pyb_spi_print(void (*print)(void *env, const char *fmt, ...), void *
346346
// SPI2 and SPI3 are on APB1
347347
spi_clock = HAL_RCC_GetPCLK1Freq();
348348
}
349-
uint baudrate = spi_clock >> ((self->spi->Init.BaudRatePrescaler >> 3) + 1);
350-
print(env, "SPI(%u, SPI.MASTER, baudrate=%u", spi_num, baudrate);
349+
uint log_prescaler = (self->spi->Init.BaudRatePrescaler >> 3) + 1;
350+
uint baudrate = spi_clock >> log_prescaler;
351+
print(env, "SPI(%u, SPI.MASTER, baudrate=%u, prescaler=%u", spi_num, baudrate, 1 << log_prescaler);
351352
} else {
352353
print(env, "SPI(%u, SPI.SLAVE", spi_num);
353354
}
@@ -369,6 +370,7 @@ STATIC mp_obj_t pyb_spi_init_helper(const pyb_spi_obj_t *self, mp_uint_t n_args,
369370
static const mp_arg_t allowed_args[] = {
370371
{ MP_QSTR_mode, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} },
371372
{ MP_QSTR_baudrate, MP_ARG_INT, {.u_int = 328125} },
373+
{ MP_QSTR_prescaler, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0xffffffff} },
372374
{ MP_QSTR_polarity, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1} },
373375
{ MP_QSTR_phase, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
374376
{ MP_QSTR_dir, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = SPI_DIRECTION_2LINES} },
@@ -387,17 +389,20 @@ STATIC mp_obj_t pyb_spi_init_helper(const pyb_spi_obj_t *self, mp_uint_t n_args,
387389
SPI_InitTypeDef *init = &self->spi->Init;
388390
init->Mode = args[0].u_int;
389391

390-
// compute the baudrate prescaler from the requested baudrate
391-
// select a prescaler that yields at most the requested baudrate
392-
uint spi_clock;
393-
if (self->spi->Instance == SPI1) {
394-
// SPI1 is on APB2
395-
spi_clock = HAL_RCC_GetPCLK2Freq();
396-
} else {
397-
// SPI2 and SPI3 are on APB1
398-
spi_clock = HAL_RCC_GetPCLK1Freq();
392+
// configure the prescaler
393+
mp_uint_t br_prescale = args[2].u_int;
394+
if (br_prescale == 0xffffffff) {
395+
// prescaler not given, so select one that yields at most the requested baudrate
396+
mp_uint_t spi_clock;
397+
if (self->spi->Instance == SPI1) {
398+
// SPI1 is on APB2
399+
spi_clock = HAL_RCC_GetPCLK2Freq();
400+
} else {
401+
// SPI2 and SPI3 are on APB1
402+
spi_clock = HAL_RCC_GetPCLK1Freq();
403+
}
404+
br_prescale = spi_clock / args[1].u_int;
399405
}
400-
uint br_prescale = spi_clock / args[1].u_int;
401406
if (br_prescale <= 2) { init->BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2; }
402407
else if (br_prescale <= 4) { init->BaudRatePrescaler = SPI_BAUDRATEPRESCALER_4; }
403408
else if (br_prescale <= 8) { init->BaudRatePrescaler = SPI_BAUDRATEPRESCALER_8; }
@@ -407,19 +412,19 @@ STATIC mp_obj_t pyb_spi_init_helper(const pyb_spi_obj_t *self, mp_uint_t n_args,
407412
else if (br_prescale <= 128) { init->BaudRatePrescaler = SPI_BAUDRATEPRESCALER_128; }
408413
else { init->BaudRatePrescaler = SPI_BAUDRATEPRESCALER_256; }
409414

410-
init->CLKPolarity = args[2].u_int == 0 ? SPI_POLARITY_LOW : SPI_POLARITY_HIGH;
411-
init->CLKPhase = args[3].u_int == 0 ? SPI_PHASE_1EDGE : SPI_PHASE_2EDGE;
412-
init->Direction = args[4].u_int;
413-
init->DataSize = (args[5].u_int == 16) ? SPI_DATASIZE_16BIT : SPI_DATASIZE_8BIT;
414-
init->NSS = args[6].u_int;
415-
init->FirstBit = args[7].u_int;
416-
init->TIMode = args[8].u_bool ? SPI_TIMODE_ENABLED : SPI_TIMODE_DISABLED;
417-
if (args[9].u_obj == mp_const_none) {
415+
init->CLKPolarity = args[3].u_int == 0 ? SPI_POLARITY_LOW : SPI_POLARITY_HIGH;
416+
init->CLKPhase = args[4].u_int == 0 ? SPI_PHASE_1EDGE : SPI_PHASE_2EDGE;
417+
init->Direction = args[5].u_int;
418+
init->DataSize = (args[6].u_int == 16) ? SPI_DATASIZE_16BIT : SPI_DATASIZE_8BIT;
419+
init->NSS = args[7].u_int;
420+
init->FirstBit = args[8].u_int;
421+
init->TIMode = args[9].u_bool ? SPI_TIMODE_ENABLED : SPI_TIMODE_DISABLED;
422+
if (args[10].u_obj == mp_const_none) {
418423
init->CRCCalculation = SPI_CRCCALCULATION_DISABLED;
419424
init->CRCPolynomial = 0;
420425
} else {
421426
init->CRCCalculation = SPI_CRCCALCULATION_ENABLED;
422-
init->CRCPolynomial = mp_obj_get_int(args[9].u_obj);
427+
init->CRCPolynomial = mp_obj_get_int(args[10].u_obj);
423428
}
424429

425430
// init the SPI bus

0 commit comments

Comments
 (0)