[FL-2797] Signal Generator app (#1793)
* Signal Generator app * MCO pin initialization in app * furi_hal_pwm documentation Co-authored-by: あく <alleteam@gmail.com>
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
entry,status,name,type,params
|
||||
Version,+,1.12,,
|
||||
Version,+,1.13,,
|
||||
Header,+,applications/services/bt/bt_service/bt.h,,
|
||||
Header,+,applications/services/cli/cli.h,,
|
||||
Header,+,applications/services/cli/cli_vcp.h,,
|
||||
@@ -42,6 +42,7 @@ Header,+,firmware/targets/f7/furi_hal/furi_hal_i2c_types.h,,
|
||||
Header,+,firmware/targets/f7/furi_hal/furi_hal_idle_timer.h,,
|
||||
Header,+,firmware/targets/f7/furi_hal/furi_hal_interrupt.h,,
|
||||
Header,+,firmware/targets/f7/furi_hal/furi_hal_os.h,,
|
||||
Header,+,firmware/targets/f7/furi_hal/furi_hal_pwm.h,,
|
||||
Header,+,firmware/targets/f7/furi_hal/furi_hal_resources.h,,
|
||||
Header,+,firmware/targets/f7/furi_hal/furi_hal_spi_config.h,,
|
||||
Header,+,firmware/targets/f7/furi_hal/furi_hal_spi_types.h,,
|
||||
@@ -954,6 +955,8 @@ Function,+,furi_hal_cdc_set_callbacks,void,"uint8_t, CdcCallbacks*, void*"
|
||||
Function,+,furi_hal_clock_deinit_early,void,
|
||||
Function,-,furi_hal_clock_init,void,
|
||||
Function,-,furi_hal_clock_init_early,void,
|
||||
Function,+,furi_hal_clock_mco_disable,void,
|
||||
Function,+,furi_hal_clock_mco_enable,void,"FuriHalClockMcoSourceId, FuriHalClockMcoDivisorId"
|
||||
Function,-,furi_hal_clock_resume_tick,void,
|
||||
Function,-,furi_hal_clock_suspend_tick,void,
|
||||
Function,-,furi_hal_clock_switch_to_hsi,void,
|
||||
@@ -1150,6 +1153,9 @@ Function,+,furi_hal_power_sleep,void,
|
||||
Function,+,furi_hal_power_sleep_available,_Bool,
|
||||
Function,+,furi_hal_power_suppress_charge_enter,void,
|
||||
Function,+,furi_hal_power_suppress_charge_exit,void,
|
||||
Function,+,furi_hal_pwm_set_params,void,"FuriHalPwmOutputId, uint32_t, uint8_t"
|
||||
Function,+,furi_hal_pwm_start,void,"FuriHalPwmOutputId, uint32_t, uint8_t"
|
||||
Function,+,furi_hal_pwm_stop,void,FuriHalPwmOutputId
|
||||
Function,+,furi_hal_random_fill_buf,void,"uint8_t*, uint32_t"
|
||||
Function,+,furi_hal_random_get,uint32_t,
|
||||
Function,+,furi_hal_region_get,const FuriHalRegion*,
|
||||
@@ -2665,6 +2671,8 @@ Variable,+,I_SDQuestion_35x43,const Icon,
|
||||
Variable,+,I_SDcardFail_11x8,const Icon,
|
||||
Variable,+,I_SDcardMounted_11x8,const Icon,
|
||||
Variable,+,I_Scanning_123x52,const Icon,
|
||||
Variable,+,I_SmallArrowDown_4x7,const Icon,
|
||||
Variable,+,I_SmallArrowUp_4x7,const Icon,
|
||||
Variable,+,I_Smile_18x18,const Icon,
|
||||
Variable,+,I_Space_65x18,const Icon,
|
||||
Variable,+,I_Tap_reader_36x38,const Icon,
|
||||
|
|
@@ -1,4 +1,5 @@
|
||||
#include <furi_hal_clock.h>
|
||||
#include <furi_hal_resources.h>
|
||||
#include <furi.h>
|
||||
|
||||
#include <stm32wbxx_ll_pwr.h>
|
||||
@@ -236,3 +237,63 @@ void furi_hal_clock_suspend_tick() {
|
||||
void furi_hal_clock_resume_tick() {
|
||||
SET_BIT(SysTick->CTRL, SysTick_CTRL_ENABLE_Msk);
|
||||
}
|
||||
|
||||
void furi_hal_clock_mco_enable(FuriHalClockMcoSourceId source, FuriHalClockMcoDivisorId div) {
|
||||
if(source == FuriHalClockMcoLse) {
|
||||
LL_RCC_ConfigMCO(LL_RCC_MCO1SOURCE_LSE, div);
|
||||
} else if(source == FuriHalClockMcoSysclk) {
|
||||
LL_RCC_ConfigMCO(LL_RCC_MCO1SOURCE_SYSCLK, div);
|
||||
} else {
|
||||
LL_RCC_MSI_Enable();
|
||||
while(LL_RCC_MSI_IsReady() != 1)
|
||||
;
|
||||
switch(source) {
|
||||
case FuriHalClockMcoMsi100k:
|
||||
LL_RCC_MSI_SetRange(LL_RCC_MSIRANGE_0);
|
||||
break;
|
||||
case FuriHalClockMcoMsi200k:
|
||||
LL_RCC_MSI_SetRange(LL_RCC_MSIRANGE_1);
|
||||
break;
|
||||
case FuriHalClockMcoMsi400k:
|
||||
LL_RCC_MSI_SetRange(LL_RCC_MSIRANGE_2);
|
||||
break;
|
||||
case FuriHalClockMcoMsi800k:
|
||||
LL_RCC_MSI_SetRange(LL_RCC_MSIRANGE_3);
|
||||
break;
|
||||
case FuriHalClockMcoMsi1m:
|
||||
LL_RCC_MSI_SetRange(LL_RCC_MSIRANGE_4);
|
||||
break;
|
||||
case FuriHalClockMcoMsi2m:
|
||||
LL_RCC_MSI_SetRange(LL_RCC_MSIRANGE_5);
|
||||
break;
|
||||
case FuriHalClockMcoMsi4m:
|
||||
LL_RCC_MSI_SetRange(LL_RCC_MSIRANGE_6);
|
||||
break;
|
||||
case FuriHalClockMcoMsi8m:
|
||||
LL_RCC_MSI_SetRange(LL_RCC_MSIRANGE_7);
|
||||
break;
|
||||
case FuriHalClockMcoMsi16m:
|
||||
LL_RCC_MSI_SetRange(LL_RCC_MSIRANGE_8);
|
||||
break;
|
||||
case FuriHalClockMcoMsi24m:
|
||||
LL_RCC_MSI_SetRange(LL_RCC_MSIRANGE_9);
|
||||
break;
|
||||
case FuriHalClockMcoMsi32m:
|
||||
LL_RCC_MSI_SetRange(LL_RCC_MSIRANGE_10);
|
||||
break;
|
||||
case FuriHalClockMcoMsi48m:
|
||||
LL_RCC_MSI_SetRange(LL_RCC_MSIRANGE_11);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
LL_RCC_ConfigMCO(LL_RCC_MCO1SOURCE_MSI, div);
|
||||
}
|
||||
}
|
||||
|
||||
void furi_hal_clock_mco_disable() {
|
||||
LL_RCC_ConfigMCO(LL_RCC_MCO1SOURCE_NOCLOCK, FuriHalClockMcoDiv1);
|
||||
LL_RCC_MSI_Disable();
|
||||
while(LL_RCC_MSI_IsReady() != 0)
|
||||
;
|
||||
}
|
@@ -4,6 +4,33 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stm32wbxx_ll_rcc.h>
|
||||
|
||||
typedef enum {
|
||||
FuriHalClockMcoLse,
|
||||
FuriHalClockMcoSysclk,
|
||||
FuriHalClockMcoMsi100k,
|
||||
FuriHalClockMcoMsi200k,
|
||||
FuriHalClockMcoMsi400k,
|
||||
FuriHalClockMcoMsi800k,
|
||||
FuriHalClockMcoMsi1m,
|
||||
FuriHalClockMcoMsi2m,
|
||||
FuriHalClockMcoMsi4m,
|
||||
FuriHalClockMcoMsi8m,
|
||||
FuriHalClockMcoMsi16m,
|
||||
FuriHalClockMcoMsi24m,
|
||||
FuriHalClockMcoMsi32m,
|
||||
FuriHalClockMcoMsi48m,
|
||||
} FuriHalClockMcoSourceId;
|
||||
|
||||
typedef enum {
|
||||
FuriHalClockMcoDiv1 = LL_RCC_MCO1_DIV_1,
|
||||
FuriHalClockMcoDiv2 = LL_RCC_MCO1_DIV_2,
|
||||
FuriHalClockMcoDiv4 = LL_RCC_MCO1_DIV_4,
|
||||
FuriHalClockMcoDiv8 = LL_RCC_MCO1_DIV_8,
|
||||
FuriHalClockMcoDiv16 = LL_RCC_MCO1_DIV_16,
|
||||
} FuriHalClockMcoDivisorId;
|
||||
|
||||
/** Early initialization */
|
||||
void furi_hal_clock_init_early();
|
||||
|
||||
@@ -25,6 +52,16 @@ void furi_hal_clock_suspend_tick();
|
||||
/** Continue SysTick counter operation */
|
||||
void furi_hal_clock_resume_tick();
|
||||
|
||||
/** Enable clock output on MCO pin
|
||||
*
|
||||
* @param source MCO clock source
|
||||
* @param div MCO clock division
|
||||
*/
|
||||
void furi_hal_clock_mco_enable(FuriHalClockMcoSourceId source, FuriHalClockMcoDivisorId div);
|
||||
|
||||
/** Disable clock output on MCO pin */
|
||||
void furi_hal_clock_mco_disable();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
138
firmware/targets/f7/furi_hal/furi_hal_pwm.c
Normal file
138
firmware/targets/f7/furi_hal/furi_hal_pwm.c
Normal file
@@ -0,0 +1,138 @@
|
||||
#include "furi_hal_pwm.h"
|
||||
#include <core/check.h>
|
||||
#include <furi_hal_resources.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stm32wbxx_ll_tim.h>
|
||||
#include <stm32wbxx_ll_lptim.h>
|
||||
#include <stm32wbxx_ll_rcc.h>
|
||||
|
||||
#include <furi.h>
|
||||
|
||||
const uint32_t lptim_psc_table[] = {
|
||||
LL_LPTIM_PRESCALER_DIV1,
|
||||
LL_LPTIM_PRESCALER_DIV2,
|
||||
LL_LPTIM_PRESCALER_DIV4,
|
||||
LL_LPTIM_PRESCALER_DIV8,
|
||||
LL_LPTIM_PRESCALER_DIV16,
|
||||
LL_LPTIM_PRESCALER_DIV32,
|
||||
LL_LPTIM_PRESCALER_DIV64,
|
||||
LL_LPTIM_PRESCALER_DIV128,
|
||||
};
|
||||
|
||||
void furi_hal_pwm_start(FuriHalPwmOutputId channel, uint32_t freq, uint8_t duty) {
|
||||
if(channel == FuriHalPwmOutputIdTim1PA7) {
|
||||
furi_hal_gpio_init_ex(
|
||||
&gpio_ext_pa7,
|
||||
GpioModeAltFunctionPushPull,
|
||||
GpioPullNo,
|
||||
GpioSpeedVeryHigh,
|
||||
GpioAltFn1TIM1);
|
||||
|
||||
FURI_CRITICAL_ENTER();
|
||||
LL_TIM_DeInit(TIM1);
|
||||
FURI_CRITICAL_EXIT();
|
||||
|
||||
LL_TIM_SetCounterMode(TIM1, LL_TIM_COUNTERMODE_UP);
|
||||
LL_TIM_SetRepetitionCounter(TIM1, 0);
|
||||
LL_TIM_SetClockDivision(TIM1, LL_TIM_CLOCKDIVISION_DIV1);
|
||||
LL_TIM_SetClockSource(TIM1, LL_TIM_CLOCKSOURCE_INTERNAL);
|
||||
LL_TIM_EnableARRPreload(TIM1);
|
||||
|
||||
LL_TIM_OC_EnablePreload(TIM1, LL_TIM_CHANNEL_CH1);
|
||||
LL_TIM_OC_SetMode(TIM1, LL_TIM_CHANNEL_CH1, LL_TIM_OCMODE_PWM1);
|
||||
LL_TIM_OC_SetPolarity(TIM1, LL_TIM_CHANNEL_CH1N, LL_TIM_OCPOLARITY_HIGH);
|
||||
LL_TIM_OC_DisableFast(TIM1, LL_TIM_CHANNEL_CH1);
|
||||
LL_TIM_CC_EnableChannel(TIM1, LL_TIM_CHANNEL_CH1N);
|
||||
|
||||
LL_TIM_EnableAllOutputs(TIM1);
|
||||
|
||||
furi_hal_pwm_set_params(channel, freq, duty);
|
||||
|
||||
LL_TIM_EnableCounter(TIM1);
|
||||
} else if(channel == FuriHalPwmOutputIdLptim2PA4) {
|
||||
furi_hal_gpio_init_ex(
|
||||
&gpio_ext_pa4,
|
||||
GpioModeAltFunctionPushPull,
|
||||
GpioPullNo,
|
||||
GpioSpeedVeryHigh,
|
||||
GpioAltFn14LPTIM2);
|
||||
|
||||
FURI_CRITICAL_ENTER();
|
||||
LL_LPTIM_DeInit(LPTIM2);
|
||||
FURI_CRITICAL_EXIT();
|
||||
|
||||
LL_LPTIM_SetUpdateMode(LPTIM2, LL_LPTIM_UPDATE_MODE_ENDOFPERIOD);
|
||||
LL_RCC_SetLPTIMClockSource(LL_RCC_LPTIM2_CLKSOURCE_PCLK1);
|
||||
LL_LPTIM_SetClockSource(LPTIM2, LL_LPTIM_CLK_SOURCE_INTERNAL);
|
||||
LL_LPTIM_ConfigOutput(
|
||||
LPTIM2, LL_LPTIM_OUTPUT_WAVEFORM_PWM, LL_LPTIM_OUTPUT_POLARITY_INVERSE);
|
||||
LL_LPTIM_SetCounterMode(LPTIM2, LL_LPTIM_COUNTER_MODE_INTERNAL);
|
||||
|
||||
LL_LPTIM_Enable(LPTIM2);
|
||||
|
||||
furi_hal_pwm_set_params(channel, freq, duty);
|
||||
|
||||
LL_LPTIM_StartCounter(LPTIM2, LL_LPTIM_OPERATING_MODE_CONTINUOUS);
|
||||
}
|
||||
}
|
||||
|
||||
void furi_hal_pwm_stop(FuriHalPwmOutputId channel) {
|
||||
if(channel == FuriHalPwmOutputIdTim1PA7) {
|
||||
furi_hal_gpio_init_simple(&gpio_ext_pa7, GpioModeAnalog);
|
||||
FURI_CRITICAL_ENTER();
|
||||
LL_TIM_DeInit(TIM1);
|
||||
FURI_CRITICAL_EXIT();
|
||||
} else if(channel == FuriHalPwmOutputIdLptim2PA4) {
|
||||
furi_hal_gpio_init_simple(&gpio_ext_pa4, GpioModeAnalog);
|
||||
FURI_CRITICAL_ENTER();
|
||||
LL_LPTIM_DeInit(LPTIM2);
|
||||
FURI_CRITICAL_EXIT();
|
||||
}
|
||||
}
|
||||
|
||||
void furi_hal_pwm_set_params(FuriHalPwmOutputId channel, uint32_t freq, uint8_t duty) {
|
||||
furi_assert(freq > 0);
|
||||
uint32_t freq_div = 64000000LU / freq;
|
||||
|
||||
if(channel == FuriHalPwmOutputIdTim1PA7) {
|
||||
uint32_t prescaler = freq_div / 0x10000LU;
|
||||
uint32_t period = freq_div / (prescaler + 1);
|
||||
uint32_t compare = period * duty / 100;
|
||||
|
||||
LL_TIM_SetPrescaler(TIM1, prescaler);
|
||||
LL_TIM_SetAutoReload(TIM1, period - 1);
|
||||
LL_TIM_OC_SetCompareCH1(TIM1, compare);
|
||||
} else if(channel == FuriHalPwmOutputIdLptim2PA4) {
|
||||
uint32_t prescaler = 0;
|
||||
uint32_t period = 0;
|
||||
|
||||
bool clock_lse = false;
|
||||
|
||||
do {
|
||||
period = freq_div / (1 << prescaler);
|
||||
if(period <= 0xFFFF) {
|
||||
break;
|
||||
}
|
||||
prescaler++;
|
||||
if(prescaler > 7) {
|
||||
prescaler = 0;
|
||||
clock_lse = true;
|
||||
period = 32768LU / freq;
|
||||
break;
|
||||
}
|
||||
} while(1);
|
||||
|
||||
uint32_t compare = period * duty / 100;
|
||||
|
||||
LL_LPTIM_SetPrescaler(LPTIM2, lptim_psc_table[prescaler]);
|
||||
LL_LPTIM_SetAutoReload(LPTIM2, period);
|
||||
LL_LPTIM_SetCompare(LPTIM2, compare);
|
||||
|
||||
if(clock_lse) {
|
||||
LL_RCC_SetLPTIMClockSource(LL_RCC_LPTIM2_CLKSOURCE_LSE);
|
||||
} else {
|
||||
LL_RCC_SetLPTIMClockSource(LL_RCC_LPTIM2_CLKSOURCE_PCLK1);
|
||||
}
|
||||
}
|
||||
}
|
42
firmware/targets/f7/furi_hal/furi_hal_pwm.h
Normal file
42
firmware/targets/f7/furi_hal/furi_hal_pwm.h
Normal file
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* @file furi_hal_pwm.h
|
||||
* PWM contol HAL
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef enum {
|
||||
FuriHalPwmOutputIdTim1PA7,
|
||||
FuriHalPwmOutputIdLptim2PA4,
|
||||
} FuriHalPwmOutputId;
|
||||
|
||||
/** Enable PWM channel and set parameters
|
||||
*
|
||||
* @param[in] channel PWM channel (FuriHalPwmOutputId)
|
||||
* @param[in] freq Frequency in Hz
|
||||
* @param[in] duty Duty cycle value in %
|
||||
*/
|
||||
void furi_hal_pwm_start(FuriHalPwmOutputId channel, uint32_t freq, uint8_t duty);
|
||||
|
||||
/** Disable PWM channel
|
||||
*
|
||||
* @param[in] channel PWM channel (FuriHalPwmOutputId)
|
||||
*/
|
||||
void furi_hal_pwm_stop(FuriHalPwmOutputId channel);
|
||||
|
||||
/** Set PWM channel parameters
|
||||
*
|
||||
* @param[in] channel PWM channel (FuriHalPwmOutputId)
|
||||
* @param[in] freq Frequency in Hz
|
||||
* @param[in] duty Duty cycle value in %
|
||||
*/
|
||||
void furi_hal_pwm_set_params(FuriHalPwmOutputId channel, uint32_t freq, uint8_t duty);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
Reference in New Issue
Block a user