furi_hal_pwm.c 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. #include <furi_hal_pwm.h>
  2. #include <core/check.h>
  3. #include <furi_hal_resources.h>
  4. #include <stdint.h>
  5. #include <stm32wbxx_ll_tim.h>
  6. #include <stm32wbxx_ll_lptim.h>
  7. #include <stm32wbxx_ll_rcc.h>
  8. #include <furi.h>
  9. const uint32_t lptim_psc_table[] = {
  10. LL_LPTIM_PRESCALER_DIV1,
  11. LL_LPTIM_PRESCALER_DIV2,
  12. LL_LPTIM_PRESCALER_DIV4,
  13. LL_LPTIM_PRESCALER_DIV8,
  14. LL_LPTIM_PRESCALER_DIV16,
  15. LL_LPTIM_PRESCALER_DIV32,
  16. LL_LPTIM_PRESCALER_DIV64,
  17. LL_LPTIM_PRESCALER_DIV128,
  18. };
  19. void furi_hal_pwm_start(FuriHalPwmOutputId channel, uint32_t freq, uint8_t duty) {
  20. if(channel == FuriHalPwmOutputIdTim1PA7) {
  21. furi_hal_gpio_init_ex(
  22. &gpio_ext_pa7,
  23. GpioModeAltFunctionPushPull,
  24. GpioPullNo,
  25. GpioSpeedVeryHigh,
  26. GpioAltFn1TIM1);
  27. FURI_CRITICAL_ENTER();
  28. LL_TIM_DeInit(TIM1);
  29. FURI_CRITICAL_EXIT();
  30. LL_TIM_SetCounterMode(TIM1, LL_TIM_COUNTERMODE_UP);
  31. LL_TIM_SetRepetitionCounter(TIM1, 0);
  32. LL_TIM_SetClockDivision(TIM1, LL_TIM_CLOCKDIVISION_DIV1);
  33. LL_TIM_SetClockSource(TIM1, LL_TIM_CLOCKSOURCE_INTERNAL);
  34. LL_TIM_EnableARRPreload(TIM1);
  35. LL_TIM_OC_EnablePreload(TIM1, LL_TIM_CHANNEL_CH1);
  36. LL_TIM_OC_SetMode(TIM1, LL_TIM_CHANNEL_CH1, LL_TIM_OCMODE_PWM1);
  37. LL_TIM_OC_SetPolarity(TIM1, LL_TIM_CHANNEL_CH1N, LL_TIM_OCPOLARITY_HIGH);
  38. LL_TIM_OC_DisableFast(TIM1, LL_TIM_CHANNEL_CH1);
  39. LL_TIM_CC_EnableChannel(TIM1, LL_TIM_CHANNEL_CH1N);
  40. LL_TIM_EnableAllOutputs(TIM1);
  41. furi_hal_pwm_set_params(channel, freq, duty);
  42. LL_TIM_EnableCounter(TIM1);
  43. } else if(channel == FuriHalPwmOutputIdLptim2PA4) {
  44. furi_hal_gpio_init_ex(
  45. &gpio_ext_pa4,
  46. GpioModeAltFunctionPushPull,
  47. GpioPullNo,
  48. GpioSpeedVeryHigh,
  49. GpioAltFn14LPTIM2);
  50. FURI_CRITICAL_ENTER();
  51. LL_LPTIM_DeInit(LPTIM2);
  52. FURI_CRITICAL_EXIT();
  53. LL_LPTIM_SetUpdateMode(LPTIM2, LL_LPTIM_UPDATE_MODE_ENDOFPERIOD);
  54. LL_RCC_SetLPTIMClockSource(LL_RCC_LPTIM2_CLKSOURCE_PCLK1);
  55. LL_LPTIM_SetClockSource(LPTIM2, LL_LPTIM_CLK_SOURCE_INTERNAL);
  56. LL_LPTIM_ConfigOutput(
  57. LPTIM2, LL_LPTIM_OUTPUT_WAVEFORM_PWM, LL_LPTIM_OUTPUT_POLARITY_INVERSE);
  58. LL_LPTIM_SetCounterMode(LPTIM2, LL_LPTIM_COUNTER_MODE_INTERNAL);
  59. LL_LPTIM_Enable(LPTIM2);
  60. furi_hal_pwm_set_params(channel, freq, duty);
  61. LL_LPTIM_StartCounter(LPTIM2, LL_LPTIM_OPERATING_MODE_CONTINUOUS);
  62. }
  63. }
  64. void furi_hal_pwm_stop(FuriHalPwmOutputId channel) {
  65. if(channel == FuriHalPwmOutputIdTim1PA7) {
  66. furi_hal_gpio_init_simple(&gpio_ext_pa7, GpioModeAnalog);
  67. FURI_CRITICAL_ENTER();
  68. LL_TIM_DeInit(TIM1);
  69. FURI_CRITICAL_EXIT();
  70. } else if(channel == FuriHalPwmOutputIdLptim2PA4) {
  71. furi_hal_gpio_init_simple(&gpio_ext_pa4, GpioModeAnalog);
  72. FURI_CRITICAL_ENTER();
  73. LL_LPTIM_DeInit(LPTIM2);
  74. FURI_CRITICAL_EXIT();
  75. }
  76. }
  77. void furi_hal_pwm_set_params(FuriHalPwmOutputId channel, uint32_t freq, uint8_t duty) {
  78. furi_assert(freq > 0);
  79. uint32_t freq_div = 64000000LU / freq;
  80. if(channel == FuriHalPwmOutputIdTim1PA7) {
  81. uint32_t prescaler = freq_div / 0x10000LU;
  82. uint32_t period = freq_div / (prescaler + 1);
  83. uint32_t compare = period * duty / 100;
  84. LL_TIM_SetPrescaler(TIM1, prescaler);
  85. LL_TIM_SetAutoReload(TIM1, period - 1);
  86. LL_TIM_OC_SetCompareCH1(TIM1, compare);
  87. } else if(channel == FuriHalPwmOutputIdLptim2PA4) {
  88. uint32_t prescaler = 0;
  89. uint32_t period = 0;
  90. bool clock_lse = false;
  91. do {
  92. period = freq_div / (1UL << prescaler);
  93. if(period <= 0xFFFF) {
  94. break;
  95. }
  96. prescaler++;
  97. if(prescaler > 7) {
  98. prescaler = 0;
  99. clock_lse = true;
  100. period = 32768LU / freq;
  101. break;
  102. }
  103. } while(1);
  104. uint32_t compare = period * duty / 100;
  105. LL_LPTIM_SetPrescaler(LPTIM2, lptim_psc_table[prescaler]);
  106. LL_LPTIM_SetAutoReload(LPTIM2, period);
  107. LL_LPTIM_SetCompare(LPTIM2, compare);
  108. if(clock_lse) {
  109. LL_RCC_SetLPTIMClockSource(LL_RCC_LPTIM2_CLKSOURCE_LSE);
  110. } else {
  111. LL_RCC_SetLPTIMClockSource(LL_RCC_LPTIM2_CLKSOURCE_PCLK1);
  112. }
  113. }
  114. }