From 008251180d860f0bdf1b23c2772a2a7bfdc736fb Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 8 Dec 2014 21:32:55 +0000 Subject: [PATCH] stmhal: Enhance pyb.freq to configure bus (AHB, APB1, APB2) freqs. This is useful if you need precise control over the speed of peripherals (eg SPI clock). --- docs/library/pyb.rst | 30 ++++++++++++++++++-------- stmhal/modpyb.c | 50 ++++++++++++++++++++++++++++++++------------ 2 files changed, 58 insertions(+), 22 deletions(-) diff --git a/docs/library/pyb.rst b/docs/library/pyb.rst index 8bb08215b5..8af0090c14 100644 --- a/docs/library/pyb.rst +++ b/docs/library/pyb.rst @@ -93,26 +93,38 @@ Interrupt related functions Power related functions ----------------------- -.. function:: freq([sys_freq]) +.. function:: freq([sysclk[, hclk[, pclk1[, pclk2]]]]) If given no arguments, returns a tuple of clock frequencies: - (SYSCLK, HCLK, PCLK1, PCLK2). - - If given an argument, sets the system frequency to that value in Hz. - Eg freq(120000000) gives 120MHz. Note that not all values are - supported and the largest supported frequency not greater than - the given sys_freq will be selected. + (sysclk, hclk, pclk1, pclk2). + These correspond to: + - sysclk: frequency of the CPU + - hclk: frequency of the AHB bus, core memory and DMA + - pclk1: frequency of the APB1 bus + - pclk2: frequency of the APB2 bus - Supported frequencies are (in MHz): 8, 16, 24, 30, 32, 36, 40, 42, 48, + If given any arguments then the function sets the frequency of the CPU, + and the busses if additional arguments are given. Frequencies are given in + Hz. Eg freq(120000000) sets sysclk (the CPU frequency) to 120MHz. Note that + not all values are supported and the largest supported frequency not greater + than the given value will be selected. + + Supported sysclk frequencies are (in MHz): 8, 16, 24, 30, 32, 36, 40, 42, 48, 54, 56, 60, 64, 72, 84, 96, 108, 120, 144, 168. + The hclk, pclk1 and pclk2 frequencies are derived from the sysclk frequency + using a prescaler (divider). Supported prescalers for hclk are: 1, 2, 4, 8, + 16, 64, 128, 256, 512. Supported prescalers for pclk1 and pclk2 are: 1, 2, + 4, 8. A prescaler will be chosen to best match the requested frequency. + + A sysclk frequency of 8MHz uses the HSE (external crystal) directly and 16MHz uses the HSI (internal oscillator) directly. The higher frequencies use the HSE to drive the PLL (phase locked loop), and then use the output of the PLL. Note that if you change the frequency while the USB is enabled then the USB may become unreliable. It is best to change the frequency - in boot.py, before the USB peripheral is started. Also note that + in boot.py, before the USB peripheral is started. Also note that sysclk frequencies below 36MHz do not allow the USB to function correctly. .. function:: wfi() diff --git a/stmhal/modpyb.c b/stmhal/modpyb.c index 46ce0e0987..98fa62ac2c 100644 --- a/stmhal/modpyb.c +++ b/stmhal/modpyb.c @@ -173,15 +173,25 @@ STATIC mp_obj_t pyb_unique_id(void) { } STATIC MP_DEFINE_CONST_FUN_OBJ_0(pyb_unique_id_obj, pyb_unique_id); -/// \function freq([sys_freq]) -/// -/// If given no arguments, returns a tuple of clock frequencies: -/// (SYSCLK, HCLK, PCLK1, PCLK2). -/// -/// If given an argument, sets the system frequency to that value in Hz. -/// Eg freq(120000000) gives 120MHz. Note that not all values are -/// supported and the largest supported frequency not greater than -/// the given sys_freq will be selected. +// get or set the MCU frequencies +STATIC mp_uint_t pyb_freq_calc_ahb_div(mp_uint_t wanted_div) { + if (wanted_div <= 1) { return RCC_SYSCLK_DIV1; } + else if (wanted_div <= 2) { return RCC_SYSCLK_DIV2; } + else if (wanted_div <= 4) { return RCC_SYSCLK_DIV4; } + else if (wanted_div <= 8) { return RCC_SYSCLK_DIV8; } + else if (wanted_div <= 16) { return RCC_SYSCLK_DIV16; } + else if (wanted_div <= 64) { return RCC_SYSCLK_DIV64; } + else if (wanted_div <= 128) { return RCC_SYSCLK_DIV128; } + else if (wanted_div <= 256) { return RCC_SYSCLK_DIV256; } + else { return RCC_SYSCLK_DIV512; } +} +STATIC mp_uint_t pyb_freq_calc_apb_div(mp_uint_t wanted_div) { + if (wanted_div <= 1) { return RCC_HCLK_DIV1; } + else if (wanted_div <= 2) { return RCC_HCLK_DIV2; } + else if (wanted_div <= 4) { return RCC_HCLK_DIV4; } + else if (wanted_div <= 8) { return RCC_HCLK_DIV8; } + else { return RCC_SYSCLK_DIV16; } +} STATIC mp_obj_t pyb_freq(mp_uint_t n_args, const mp_obj_t *args) { if (n_args == 0) { // get @@ -273,9 +283,23 @@ STATIC mp_obj_t pyb_freq(mp_uint_t n_args, const mp_obj_t *args) { // directly set the system clock source as desired RCC_ClkInitStruct.SYSCLKSource = sysclk_source; } - RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; - RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4; - RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2; + wanted_sysclk *= 1000000; + if (n_args >= 2) { + // note: AHB freq required to be >= 14.2MHz for USB operation + RCC_ClkInitStruct.AHBCLKDivider = pyb_freq_calc_ahb_div(wanted_sysclk / mp_obj_get_int(args[1])); + } else { + RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; + } + if (n_args >= 3) { + RCC_ClkInitStruct.APB1CLKDivider = pyb_freq_calc_apb_div(wanted_sysclk / mp_obj_get_int(args[2])); + } else { + RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4; + } + if (n_args >= 4) { + RCC_ClkInitStruct.APB2CLKDivider = pyb_freq_calc_apb_div(wanted_sysclk / mp_obj_get_int(args[3])); + } else { + RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2; + } if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1) != HAL_OK) { goto fail; } @@ -314,7 +338,7 @@ STATIC mp_obj_t pyb_freq(mp_uint_t n_args, const mp_obj_t *args) { __fatal_error("can't change freq"); } } -STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_freq_obj, 0, 1, pyb_freq); +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_freq_obj, 0, 4, pyb_freq); /// \function sync() /// Sync all file systems.