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).
This commit is contained in:
Damien George 2014-12-08 21:32:55 +00:00
parent 46c3ab2004
commit 008251180d
2 changed files with 58 additions and 22 deletions

View File

@ -93,26 +93,38 @@ Interrupt related functions
Power 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: If given no arguments, returns a tuple of clock frequencies:
(SYSCLK, HCLK, PCLK1, PCLK2). (sysclk, hclk, pclk1, pclk2).
These correspond to:
If given an argument, sets the system frequency to that value in Hz. - sysclk: frequency of the CPU
Eg freq(120000000) gives 120MHz. Note that not all values are - hclk: frequency of the AHB bus, core memory and DMA
supported and the largest supported frequency not greater than - pclk1: frequency of the APB1 bus
the given sys_freq will be selected. - 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. 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 8MHz uses the HSE (external crystal) directly and 16MHz uses the HSI
(internal oscillator) directly. The higher frequencies use the HSE to (internal oscillator) directly. The higher frequencies use the HSE to
drive the PLL (phase locked loop), and then use the output of the PLL. 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 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 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. frequencies below 36MHz do not allow the USB to function correctly.
.. function:: wfi() .. function:: wfi()

View File

@ -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); STATIC MP_DEFINE_CONST_FUN_OBJ_0(pyb_unique_id_obj, pyb_unique_id);
/// \function freq([sys_freq]) // get or set the MCU frequencies
/// STATIC mp_uint_t pyb_freq_calc_ahb_div(mp_uint_t wanted_div) {
/// If given no arguments, returns a tuple of clock frequencies: if (wanted_div <= 1) { return RCC_SYSCLK_DIV1; }
/// (SYSCLK, HCLK, PCLK1, PCLK2). else if (wanted_div <= 2) { return RCC_SYSCLK_DIV2; }
/// else if (wanted_div <= 4) { return RCC_SYSCLK_DIV4; }
/// If given an argument, sets the system frequency to that value in Hz. else if (wanted_div <= 8) { return RCC_SYSCLK_DIV8; }
/// Eg freq(120000000) gives 120MHz. Note that not all values are else if (wanted_div <= 16) { return RCC_SYSCLK_DIV16; }
/// supported and the largest supported frequency not greater than else if (wanted_div <= 64) { return RCC_SYSCLK_DIV64; }
/// the given sys_freq will be selected. 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) { STATIC mp_obj_t pyb_freq(mp_uint_t n_args, const mp_obj_t *args) {
if (n_args == 0) { if (n_args == 0) {
// get // 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 // directly set the system clock source as desired
RCC_ClkInitStruct.SYSCLKSource = sysclk_source; RCC_ClkInitStruct.SYSCLKSource = sysclk_source;
} }
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; wanted_sysclk *= 1000000;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4; if (n_args >= 2) {
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2; // 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) { if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1) != HAL_OK) {
goto fail; 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"); __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() /// \function sync()
/// Sync all file systems. /// Sync all file systems.