mirror of
https://github.com/openmv/openmv.git
synced 2025-11-04 14:49:50 +08:00
267 lines
10 KiB
C
267 lines
10 KiB
C
/*
|
|
* SPDX-License-Identifier: MIT
|
|
*
|
|
* Copyright (C) 2013-2024 OpenMV, LLC.
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
* in the Software without restriction, including without limitation the rights
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
* furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in
|
|
* all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
* THE SOFTWARE.
|
|
*
|
|
* CPU frequency scaling module.
|
|
*/
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <math.h>
|
|
#include "py/obj.h"
|
|
#include "py/runtime.h"
|
|
|
|
#include "py_cpufreq.h"
|
|
#include "py_helper.h"
|
|
#include "omv_boardconfig.h"
|
|
#include STM32_HAL_H
|
|
|
|
#if defined(STM32F7) || defined(STM32H7)
|
|
|
|
#if defined(STM32H7)
|
|
#define N_FREQUENCIES (4)
|
|
static const uint32_t CPUFREQ_FREQS_REV_V[N_FREQUENCIES] = {60, 120, 240, 480};
|
|
static const uint32_t CPUFREQ_FREQS_REV_XY[N_FREQUENCIES] = {50, 100, 200, 400};
|
|
#elif defined(STM32F7)
|
|
#define N_FREQUENCIES (5)
|
|
static const uint32_t cpufreq_pllq[N_FREQUENCIES] = {5, 6, 7, 8, 9};
|
|
static const uint32_t cpufreq_freqs[N_FREQUENCIES] = {120, 144, 168, 192, 216};
|
|
static const uint32_t cpufreq_latency[N_FREQUENCIES] = {
|
|
// Flash latency (see table 11)
|
|
FLASH_LATENCY_3, FLASH_LATENCY_4, FLASH_LATENCY_5, FLASH_LATENCY_7, FLASH_LATENCY_7
|
|
};
|
|
#endif
|
|
|
|
#if defined(STM32H7)
|
|
static const uint32_t *cpufreq_get_frequencies() {
|
|
#if (OMV_MAX_CPU_FREQ == 400)
|
|
(void) CPUFREQ_FREQS_REV_V;
|
|
// If the maximum frequency is set to 400 use rev x/y frequencies.
|
|
return CPUFREQ_FREQS_REV_XY;
|
|
#else
|
|
// Otherwise, determine the frequencies dynamically using the revid.
|
|
if (HAL_GetREVID() >= 0x2003) {
|
|
return CPUFREQ_FREQS_REV_V;
|
|
} else {
|
|
return CPUFREQ_FREQS_REV_XY;
|
|
}
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
static uint32_t cpufreq_get_cpuclk() {
|
|
uint32_t cpuclk = HAL_RCC_GetSysClockFreq();
|
|
|
|
#if defined(STM32H7)
|
|
uint32_t flatency;
|
|
RCC_ClkInitTypeDef RCC_ClkInitStruct;
|
|
|
|
HAL_RCC_GetClockConfig(&RCC_ClkInitStruct, &flatency);
|
|
switch (RCC_ClkInitStruct.SYSCLKDivider) {
|
|
case RCC_SYSCLK_DIV1:
|
|
break;
|
|
case RCC_SYSCLK_DIV2:
|
|
cpuclk /= 2;
|
|
break;
|
|
case RCC_SYSCLK_DIV4:
|
|
cpuclk /= 4;
|
|
break;
|
|
case RCC_SYSCLK_DIV8:
|
|
cpuclk /= 8;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
#endif
|
|
return cpuclk;
|
|
}
|
|
|
|
mp_obj_t py_cpufreq_get_current_frequencies() {
|
|
mp_obj_t tuple[4] = {
|
|
mp_obj_new_int(cpufreq_get_cpuclk() / (1000000)),
|
|
mp_obj_new_int(HAL_RCC_GetHCLKFreq() / (1000000)),
|
|
mp_obj_new_int(HAL_RCC_GetPCLK1Freq() / (1000000)),
|
|
mp_obj_new_int(HAL_RCC_GetPCLK2Freq() / (1000000)),
|
|
};
|
|
return mp_obj_new_tuple(4, tuple);
|
|
}
|
|
|
|
mp_obj_t py_cpufreq_get_supported_frequencies() {
|
|
#if defined(STM32H7)
|
|
const uint32_t *cpufreq_freqs = cpufreq_get_frequencies();
|
|
#endif
|
|
mp_obj_t freq_list = mp_obj_new_list(0, NULL);
|
|
for (int i = 0; i < N_FREQUENCIES; i++) {
|
|
mp_obj_list_append(freq_list, mp_obj_new_int(cpufreq_freqs[i]));
|
|
}
|
|
return freq_list;
|
|
}
|
|
|
|
mp_obj_t py_cpufreq_set_frequency(mp_obj_t cpufreq_obj) {
|
|
RCC_ClkInitTypeDef RCC_ClkInitStruct;
|
|
#if defined(STM32F7)
|
|
RCC_OscInitTypeDef RCC_OscInitStruct;
|
|
#endif
|
|
|
|
// Check if frequency is supported
|
|
int cpufreq_idx = -1;
|
|
uint32_t cpufreq = mp_obj_get_int(cpufreq_obj);
|
|
#if defined(STM32H7)
|
|
const uint32_t *cpufreq_freqs = cpufreq_get_frequencies();
|
|
#endif
|
|
for (int i = 0; i < N_FREQUENCIES; i++) {
|
|
if (cpufreq == cpufreq_freqs[i]) {
|
|
cpufreq_idx = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Frequency is Not supported.
|
|
if (cpufreq_idx == -1) {
|
|
mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("Unsupported frequency!"));
|
|
}
|
|
|
|
// Return if frequency hasn't changed.
|
|
if (cpufreq == (cpufreq_get_cpuclk() / (1000000))) {
|
|
return mp_const_true;
|
|
}
|
|
|
|
#if defined(STM32H7)
|
|
uint32_t flatency = FLASH_LATENCY_2;
|
|
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
|
|
RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK |
|
|
RCC_CLOCKTYPE_D1PCLK1 | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2 | RCC_CLOCKTYPE_D3PCLK1);
|
|
|
|
switch (cpufreq) {
|
|
case 50:
|
|
case 60:
|
|
RCC_ClkInitStruct.SYSCLKDivider = RCC_SYSCLK_DIV8; // D1CPRE
|
|
RCC_ClkInitStruct.AHBCLKDivider = RCC_HCLK_DIV1; // HPRE
|
|
RCC_ClkInitStruct.APB1CLKDivider = RCC_APB1_DIV1; // D2PPRE1
|
|
RCC_ClkInitStruct.APB2CLKDivider = RCC_APB2_DIV1; // D2PPRE2
|
|
RCC_ClkInitStruct.APB3CLKDivider = RCC_APB3_DIV1; // D1PPRE
|
|
RCC_ClkInitStruct.APB4CLKDivider = RCC_APB4_DIV1; // D3PPRE
|
|
break;
|
|
|
|
case 100:
|
|
case 120:
|
|
RCC_ClkInitStruct.SYSCLKDivider = RCC_SYSCLK_DIV4; // D1CPRE
|
|
RCC_ClkInitStruct.AHBCLKDivider = RCC_HCLK_DIV1; // HPRE
|
|
RCC_ClkInitStruct.APB1CLKDivider = RCC_APB1_DIV1; // D2PPRE1
|
|
RCC_ClkInitStruct.APB2CLKDivider = RCC_APB2_DIV1; // D2PPRE2
|
|
RCC_ClkInitStruct.APB3CLKDivider = RCC_APB3_DIV1; // D1PPRE
|
|
RCC_ClkInitStruct.APB4CLKDivider = RCC_APB4_DIV1; // D3PPRE
|
|
break;
|
|
|
|
case 200:
|
|
case 240:
|
|
RCC_ClkInitStruct.SYSCLKDivider = RCC_SYSCLK_DIV2; // D1CPRE
|
|
RCC_ClkInitStruct.AHBCLKDivider = RCC_HCLK_DIV1; // HPRE
|
|
RCC_ClkInitStruct.APB1CLKDivider = RCC_APB1_DIV2; // D2PPRE1
|
|
RCC_ClkInitStruct.APB2CLKDivider = RCC_APB2_DIV2; // D2PPRE2
|
|
RCC_ClkInitStruct.APB3CLKDivider = RCC_APB3_DIV2; // D1PPRE
|
|
RCC_ClkInitStruct.APB4CLKDivider = RCC_APB4_DIV2; // D3PPRE
|
|
break;
|
|
|
|
case 400:
|
|
case 480:
|
|
RCC_ClkInitStruct.SYSCLKDivider = RCC_SYSCLK_DIV1; // D1CPRE
|
|
RCC_ClkInitStruct.AHBCLKDivider = RCC_HCLK_DIV2; // HPRE
|
|
RCC_ClkInitStruct.APB1CLKDivider = RCC_APB1_DIV2; // D2PPRE1
|
|
RCC_ClkInitStruct.APB2CLKDivider = RCC_APB2_DIV2; // D2PPRE2
|
|
RCC_ClkInitStruct.APB3CLKDivider = RCC_APB3_DIV2; // D1PPRE
|
|
RCC_ClkInitStruct.APB4CLKDivider = RCC_APB4_DIV2; // D3PPRE
|
|
break;
|
|
|
|
default:
|
|
mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("Unsupported frequency!"));
|
|
break;
|
|
}
|
|
|
|
#elif defined(STM32F7)
|
|
// Select HSE as system clock source
|
|
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSE;
|
|
RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_SYSCLK |
|
|
RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2);
|
|
// Configure the HCLK, PCLK1 and PCLK2 clocks dividers
|
|
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
|
|
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
|
|
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
|
|
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_7) != HAL_OK) {
|
|
// Initialization Error
|
|
mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("RCC CLK Initialization Error!!"));
|
|
}
|
|
|
|
// Enable HSE Oscillator and activate PLL with HSE as source
|
|
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
|
|
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
|
|
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
|
|
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
|
|
RCC_OscInitStruct.PLL.PLLM = 12; // depends on HSE
|
|
RCC_OscInitStruct.PLL.PLLN = cpufreq_freqs[cpufreq_idx] * 2;
|
|
RCC_OscInitStruct.PLL.PLLP = 2;
|
|
RCC_OscInitStruct.PLL.PLLQ = cpufreq_pllq[cpufreq_idx];
|
|
|
|
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {
|
|
// Initialization Error
|
|
mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("RCC OSC Initialization Error!!"));
|
|
}
|
|
|
|
// Select PLL as system clock source
|
|
uint32_t flatency = cpufreq_latency[cpufreq_idx];
|
|
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK;
|
|
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
|
|
#endif
|
|
|
|
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, flatency) != HAL_OK) {
|
|
// Initialization Error
|
|
mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("RCC CLK Initialization Error!!"));
|
|
}
|
|
return mp_const_true;
|
|
}
|
|
|
|
static MP_DEFINE_CONST_FUN_OBJ_1(py_cpufreq_set_frequency_obj, py_cpufreq_set_frequency);
|
|
static MP_DEFINE_CONST_FUN_OBJ_0(py_cpufreq_get_current_frequencies_obj, py_cpufreq_get_current_frequencies);
|
|
static MP_DEFINE_CONST_FUN_OBJ_0(py_cpufreq_get_supported_frequencies_obj, py_cpufreq_get_supported_frequencies);
|
|
#endif // defined(STM32F7) || defined(STM32H7)
|
|
|
|
static const mp_map_elem_t globals_dict_table[] = {
|
|
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_cpufreq) },
|
|
#if defined(STM32F7) || defined(STM32H7)
|
|
{ MP_OBJ_NEW_QSTR(MP_QSTR_set_frequency), (mp_obj_t) &py_cpufreq_set_frequency_obj },
|
|
{ MP_OBJ_NEW_QSTR(MP_QSTR_get_current_frequencies), (mp_obj_t) &py_cpufreq_get_current_frequencies_obj },
|
|
{ MP_OBJ_NEW_QSTR(MP_QSTR_get_supported_frequencies), (mp_obj_t) &py_cpufreq_get_supported_frequencies_obj },
|
|
#else
|
|
{ MP_OBJ_NEW_QSTR(MP_QSTR_set_frequency), (mp_obj_t) &py_func_unavailable_obj },
|
|
{ MP_OBJ_NEW_QSTR(MP_QSTR_get_current_frequencies), (mp_obj_t) &py_func_unavailable_obj },
|
|
{ MP_OBJ_NEW_QSTR(MP_QSTR_get_supported_frequencies), (mp_obj_t) &py_func_unavailable_obj },
|
|
#endif
|
|
{ NULL, NULL },
|
|
};
|
|
static MP_DEFINE_CONST_DICT(globals_dict, globals_dict_table);
|
|
|
|
const mp_obj_module_t cpufreq_module = {
|
|
.base = { &mp_type_module },
|
|
.globals = (mp_obj_t) &globals_dict,
|
|
};
|
|
|
|
MP_REGISTER_MODULE(MP_QSTR_cpufreq, cpufreq_module);
|