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
|
||||
-----------------------
|
||||
|
||||
.. 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()
|
||||
|
@ -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.
|
||||
|
Loading…
Reference in New Issue
Block a user