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:
parent
46c3ab2004
commit
008251180d
@ -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()
|
||||||
|
@ -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.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user