diff --git a/docs/library/pyb.SPI.rst b/docs/library/pyb.SPI.rst index 5c732fccba..70d6454015 100644 --- a/docs/library/pyb.SPI.rst +++ b/docs/library/pyb.SPI.rst @@ -52,12 +52,29 @@ Methods Turn off the SPI bus. -.. method:: spi.init(mode, baudrate=328125, \*, polarity=1, phase=0, bits=8, firstbit=SPI.MSB, ti=False, crc=None) +.. method:: spi.init(mode, baudrate=328125, \*, prescaler, polarity=1, phase=0, bits=8, firstbit=SPI.MSB, ti=False, crc=None) Initialise the SPI bus with the given parameters: - ``mode`` must be either ``SPI.MASTER`` or ``SPI.SLAVE``. - ``baudrate`` is the SCK clock rate (only sensible for a master). + - ``prescaler`` is the prescaler to use to derive SCK from the APB bus frequency; + use of ``prescaler`` overrides ``baudrate``. + - ``polarity`` can be 0 or 1, and is the level the idle clock line sits at. + - ``phase`` can be 0 or 1 to sample data on the first or second clock edge + respectively. + - ``firstbit`` can be ``SPI.MSB`` or ``SPI.LSB``. + - ``crc`` can be None for no CRC, or a polynomial specifier. + + Note that the SPI clock frequency will not always be the requested baudrate. + The hardware only supports baudrates that are the APB bus frequency + (see :meth:`pyb.freq`) divided by a prescaler, which can be 2, 4, 8, 16, 32, + 64, 128 or 256. SPI(1) is on AHB2, and SPI(2) is on AHB1. For precise + control over the SPI clock frequency, specify ``prescaler`` instead of + ``baudrate``. + + Printing the SPI object will show you the computed baudrate and the chosen + prescaler. .. method:: spi.recv(recv, \*, timeout=5000) diff --git a/stmhal/spi.c b/stmhal/spi.c index 78d70d1657..9e2aeffe06 100644 --- a/stmhal/spi.c +++ b/stmhal/spi.c @@ -346,8 +346,9 @@ STATIC void pyb_spi_print(void (*print)(void *env, const char *fmt, ...), void * // SPI2 and SPI3 are on APB1 spi_clock = HAL_RCC_GetPCLK1Freq(); } - uint baudrate = spi_clock >> ((self->spi->Init.BaudRatePrescaler >> 3) + 1); - print(env, "SPI(%u, SPI.MASTER, baudrate=%u", spi_num, baudrate); + uint log_prescaler = (self->spi->Init.BaudRatePrescaler >> 3) + 1; + uint baudrate = spi_clock >> log_prescaler; + print(env, "SPI(%u, SPI.MASTER, baudrate=%u, prescaler=%u", spi_num, baudrate, 1 << log_prescaler); } else { print(env, "SPI(%u, SPI.SLAVE", spi_num); } @@ -369,6 +370,7 @@ STATIC mp_obj_t pyb_spi_init_helper(const pyb_spi_obj_t *self, mp_uint_t n_args, static const mp_arg_t allowed_args[] = { { MP_QSTR_mode, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} }, { MP_QSTR_baudrate, MP_ARG_INT, {.u_int = 328125} }, + { MP_QSTR_prescaler, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0xffffffff} }, { MP_QSTR_polarity, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1} }, { MP_QSTR_phase, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, { 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, SPI_InitTypeDef *init = &self->spi->Init; init->Mode = args[0].u_int; - // compute the baudrate prescaler from the requested baudrate - // select a prescaler that yields at most the requested baudrate - uint spi_clock; - if (self->spi->Instance == SPI1) { - // SPI1 is on APB2 - spi_clock = HAL_RCC_GetPCLK2Freq(); - } else { - // SPI2 and SPI3 are on APB1 - spi_clock = HAL_RCC_GetPCLK1Freq(); + // configure the prescaler + mp_uint_t br_prescale = args[2].u_int; + if (br_prescale == 0xffffffff) { + // prescaler not given, so select one that yields at most the requested baudrate + mp_uint_t spi_clock; + if (self->spi->Instance == SPI1) { + // SPI1 is on APB2 + spi_clock = HAL_RCC_GetPCLK2Freq(); + } else { + // SPI2 and SPI3 are on APB1 + spi_clock = HAL_RCC_GetPCLK1Freq(); + } + br_prescale = spi_clock / args[1].u_int; } - uint br_prescale = spi_clock / args[1].u_int; if (br_prescale <= 2) { init->BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2; } else if (br_prescale <= 4) { init->BaudRatePrescaler = SPI_BAUDRATEPRESCALER_4; } 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, else if (br_prescale <= 128) { init->BaudRatePrescaler = SPI_BAUDRATEPRESCALER_128; } else { init->BaudRatePrescaler = SPI_BAUDRATEPRESCALER_256; } - init->CLKPolarity = args[2].u_int == 0 ? SPI_POLARITY_LOW : SPI_POLARITY_HIGH; - init->CLKPhase = args[3].u_int == 0 ? SPI_PHASE_1EDGE : SPI_PHASE_2EDGE; - init->Direction = args[4].u_int; - init->DataSize = (args[5].u_int == 16) ? SPI_DATASIZE_16BIT : SPI_DATASIZE_8BIT; - init->NSS = args[6].u_int; - init->FirstBit = args[7].u_int; - init->TIMode = args[8].u_bool ? SPI_TIMODE_ENABLED : SPI_TIMODE_DISABLED; - if (args[9].u_obj == mp_const_none) { + init->CLKPolarity = args[3].u_int == 0 ? SPI_POLARITY_LOW : SPI_POLARITY_HIGH; + init->CLKPhase = args[4].u_int == 0 ? SPI_PHASE_1EDGE : SPI_PHASE_2EDGE; + init->Direction = args[5].u_int; + init->DataSize = (args[6].u_int == 16) ? SPI_DATASIZE_16BIT : SPI_DATASIZE_8BIT; + init->NSS = args[7].u_int; + init->FirstBit = args[8].u_int; + init->TIMode = args[9].u_bool ? SPI_TIMODE_ENABLED : SPI_TIMODE_DISABLED; + if (args[10].u_obj == mp_const_none) { init->CRCCalculation = SPI_CRCCALCULATION_DISABLED; init->CRCPolynomial = 0; } else { init->CRCCalculation = SPI_CRCCALCULATION_ENABLED; - init->CRCPolynomial = mp_obj_get_int(args[9].u_obj); + init->CRCPolynomial = mp_obj_get_int(args[10].u_obj); } // init the SPI bus