From 5f08864d1fa8146bc909f3b79daa0bf026e94c6b Mon Sep 17 00:00:00 2001 From: Mike La Spina Date: Tue, 23 Nov 2021 14:05:50 -0600 Subject: [PATCH] =?UTF-8?q?=F0=9F=90=9B=20Fix=20STM32=20set=5Fpwm=5Fduty?= =?UTF-8?q?=20(#23125)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/HAL/STM32/MarlinSPI.cpp | 11 +-- Marlin/src/HAL/STM32/fast_pwm.cpp | 74 +++++++++++++++------ Marlin/src/HAL/STM32/tft/tft_spi.cpp | 12 ++-- Marlin/src/HAL/STM32F1/HAL.h | 6 +- Marlin/src/HAL/STM32F1/fast_pwm.cpp | 50 +++++++------- Marlin/src/lcd/extui/mks_ui/wifi_module.cpp | 2 +- Marlin/src/pins/stm32f1/pins_LONGER3D_LK.h | 1 - 7 files changed, 96 insertions(+), 60 deletions(-) diff --git a/Marlin/src/HAL/STM32/MarlinSPI.cpp b/Marlin/src/HAL/STM32/MarlinSPI.cpp index 7078d210dc..f7c603d77e 100644 --- a/Marlin/src/HAL/STM32/MarlinSPI.cpp +++ b/Marlin/src/HAL/STM32/MarlinSPI.cpp @@ -114,16 +114,19 @@ byte MarlinSPI::transfer(uint8_t _data) { return rxData; } +__STATIC_INLINE void LL_SPI_EnableDMAReq_RX(SPI_TypeDef *SPIx) { SET_BIT(SPIx->CR2, SPI_CR2_RXDMAEN); } +__STATIC_INLINE void LL_SPI_EnableDMAReq_TX(SPI_TypeDef *SPIx) { SET_BIT(SPIx->CR2, SPI_CR2_TXDMAEN); } + uint8_t MarlinSPI::dmaTransfer(const void *transmitBuf, void *receiveBuf, uint16_t length) { const uint8_t ff = 0xFF; - //if ((hspi->Instance->CR1 & SPI_CR1_SPE) != SPI_CR1_SPE) //only enable if disabled + //if (!LL_SPI_IsEnabled(_spi.handle)) // only enable if disabled __HAL_SPI_ENABLE(&_spi.handle); if (receiveBuf) { setupDma(_spi.handle, _dmaRx, DMA_PERIPH_TO_MEMORY, true); HAL_DMA_Start(&_dmaRx, (uint32_t)&(_spi.handle.Instance->DR), (uint32_t)receiveBuf, length); - SET_BIT(_spi.handle.Instance->CR2, SPI_CR2_RXDMAEN); /* Enable Rx DMA Request */ + LL_SPI_EnableDMAReq_RX(_spi.handle.Instance); // Enable Rx DMA Request } // check for 2 lines transfer @@ -136,7 +139,7 @@ uint8_t MarlinSPI::dmaTransfer(const void *transmitBuf, void *receiveBuf, uint16 if (transmitBuf) { setupDma(_spi.handle, _dmaTx, DMA_MEMORY_TO_PERIPH, mincTransmit); HAL_DMA_Start(&_dmaTx, (uint32_t)transmitBuf, (uint32_t)&(_spi.handle.Instance->DR), length); - SET_BIT(_spi.handle.Instance->CR2, SPI_CR2_TXDMAEN); /* Enable Tx DMA Request */ + LL_SPI_EnableDMAReq_TX(_spi.handle.Instance); // Enable Tx DMA Request } if (transmitBuf) { @@ -160,7 +163,7 @@ uint8_t MarlinSPI::dmaSend(const void * transmitBuf, uint16_t length, bool minc) setupDma(_spi.handle, _dmaTx, DMA_MEMORY_TO_PERIPH, minc); HAL_DMA_Start(&_dmaTx, (uint32_t)transmitBuf, (uint32_t)&(_spi.handle.Instance->DR), length); __HAL_SPI_ENABLE(&_spi.handle); - SET_BIT(_spi.handle.Instance->CR2, SPI_CR2_TXDMAEN); /* Enable Tx DMA Request */ + LL_SPI_EnableDMAReq_TX(_spi.handle.Instance); // Enable Tx DMA Request HAL_DMA_PollForTransfer(&_dmaTx, HAL_DMA_FULL_TRANSFER, HAL_MAX_DELAY); HAL_DMA_Abort(&_dmaTx); // DeInit objects diff --git a/Marlin/src/HAL/STM32/fast_pwm.cpp b/Marlin/src/HAL/STM32/fast_pwm.cpp index 4d450374d3..4986e138a1 100644 --- a/Marlin/src/HAL/STM32/fast_pwm.cpp +++ b/Marlin/src/HAL/STM32/fast_pwm.cpp @@ -27,37 +27,67 @@ #include "../../inc/MarlinConfig.h" #include "timers.h" -void set_pwm_duty(const pin_t pin, const uint16_t v, const uint16_t v_size/*=255*/, const bool invert/*=false*/) { - if (!PWM_PIN(pin)) return; // Don't proceed if no hardware timer +// Array to support sticky frequency sets per timer +static uint16_t timer_freq[TIMER_NUM]; +void set_pwm_duty(const pin_t pin, const uint16_t v, const uint16_t v_size/*=255*/, const bool invert/*=false*/) { + if (!PWM_PIN(pin)) return; // Don't proceed if no hardware timer + bool needs_freq; PinName pin_name = digitalPinToPinName(pin); TIM_TypeDef *Instance = (TIM_TypeDef *)pinmap_peripheral(pin_name, PinMap_PWM); + HardwareTimer *HT; + TimerModes_t previousMode; - uint16_t adj_val = Instance->ARR * v / v_size; - if (invert) adj_val = Instance->ARR - adj_val; - switch (get_pwm_channel(pin_name)) { - case TIM_CHANNEL_1: LL_TIM_OC_SetCompareCH1(Instance, adj_val); break; - case TIM_CHANNEL_2: LL_TIM_OC_SetCompareCH2(Instance, adj_val); break; - case TIM_CHANNEL_3: LL_TIM_OC_SetCompareCH3(Instance, adj_val); break; - case TIM_CHANNEL_4: LL_TIM_OC_SetCompareCH4(Instance, adj_val); break; + uint16_t value = v; + if (invert) value = v_size - value; + + uint32_t index = get_timer_index(Instance); + + if (HardwareTimer_Handle[index] == nullptr) { + HardwareTimer_Handle[index]->__this = new HardwareTimer((TIM_TypeDef *)pinmap_peripheral(pin_name, PinMap_PWM)); + needs_freq = true; // The instance must be new set the default frequency of PWM_FREQUENCY } + + HT = (HardwareTimer *)(HardwareTimer_Handle[index]->__this); + uint32_t channel = STM_PIN_CHANNEL(pinmap_function(pin_name, PinMap_PWM)); + previousMode = HT->getMode(channel); + + if (previousMode != TIMER_OUTPUT_COMPARE_PWM1) + HT->setMode(channel, TIMER_OUTPUT_COMPARE_PWM1, pin); + + if (needs_freq) { + if (timer_freq[index] == 0 ) { // If the timer is unconfigured and no freq is set then default PWM_FREQUENCY. + timer_freq[index] = PWM_FREQUENCY; + set_pwm_frequency(pin_name, timer_freq[index]); // Set the frequency and save the value to the assigned index no. + } + } + // Note the resolution is sticky here, the input can be upto 16 bits and that would require RESOLUTION_16B_COMPARE_FORMAT (16) + // If such a need were to manifest then we would need to calc the resolution based on the v_size parameter and add code for it. + HT->setCaptureCompare(channel, value, RESOLUTION_8B_COMPARE_FORMAT); // Sets the duty, the calc is done in the library :) + pinmap_pinout(pin_name, PinMap_PWM); // Make sure the pin output state is set. + if (previousMode != TIMER_OUTPUT_COMPARE_PWM1) HT->resume(); } -#if NEEDS_HARDWARE_PWM +void set_pwm_frequency(const pin_t pin, int f_desired) { + if (!PWM_PIN(pin)) return; // Don't proceed if no hardware timer + HardwareTimer *HT; + PinName pin_name = digitalPinToPinName(pin); + TIM_TypeDef *Instance = (TIM_TypeDef *)pinmap_peripheral(pin_name, PinMap_PWM); // Get HAL timer instance - void set_pwm_frequency(const pin_t pin, int f_desired) { - if (!PWM_PIN(pin)) return; // Don't proceed if no hardware timer + uint32_t index = get_timer_index(Instance); - PinName pin_name = digitalPinToPinName(pin); - TIM_TypeDef *Instance = (TIM_TypeDef *)pinmap_peripheral(pin_name, PinMap_PWM); // Get HAL timer instance + // Protect used timers + if (index == TEMP_TIMER_NUM || index == STEP_TIMER_NUM + #if PULSE_TIMER_NUM != STEP_TIMER_NUM + || index == PULSE_TIMER_NUM + #endif + ) return; - LOOP_S_L_N(i, 0, NUM_HARDWARE_TIMERS) // Protect used timers - if (timer_instance[i] && timer_instance[i]->getHandle()->Instance == Instance) - return; - - pwm_start(pin_name, f_desired, 0, RESOLUTION_8B_COMPARE_FORMAT); - } - -#endif + if (HardwareTimer_Handle[index] == nullptr) // If frequency is set before duty we need to create a handle here. + HardwareTimer_Handle[index]->__this = new HardwareTimer((TIM_TypeDef *)pinmap_peripheral(pin_name, PinMap_PWM)); + HT = (HardwareTimer *)(HardwareTimer_Handle[index]->__this); + timer_freq[index] = f_desired; // Save the last frequency so duty will not set the default for this timer number. + HT->setOverflow(f_desired, HERTZ_FORMAT); +} #endif // HAL_STM32 diff --git a/Marlin/src/HAL/STM32/tft/tft_spi.cpp b/Marlin/src/HAL/STM32/tft/tft_spi.cpp index 790513e7ed..4ad35cee8b 100644 --- a/Marlin/src/HAL/STM32/tft/tft_spi.cpp +++ b/Marlin/src/HAL/STM32/tft/tft_spi.cpp @@ -161,11 +161,11 @@ uint32_t TFT_SPI::ReadID(uint16_t Reg) { for (i = 0; i < 4; i++) { #if TFT_MISO_PIN != TFT_MOSI_PIN //if (hspi->Init.Direction == SPI_DIRECTION_2LINES) { - while ((SPIx.Instance->SR & SPI_FLAG_TXE) != SPI_FLAG_TXE) {} + while (!__HAL_SPI_GET_FLAG(&SPIx, SPI_FLAG_TXE)) {} SPIx.Instance->DR = 0; //} #endif - while ((SPIx.Instance->SR & SPI_FLAG_RXNE) != SPI_FLAG_RXNE) {} + while (!__HAL_SPI_GET_FLAG(&SPIx, SPI_FLAG_RXNE)) {} Data = (Data << 8) | SPIx.Instance->DR; } @@ -195,8 +195,8 @@ bool TFT_SPI::isBusy() { void TFT_SPI::Abort() { // Wait for any running spi - while ((SPIx.Instance->SR & SPI_FLAG_TXE) != SPI_FLAG_TXE) {} - while ((SPIx.Instance->SR & SPI_FLAG_BSY) == SPI_FLAG_BSY) {} + while (!__HAL_SPI_GET_FLAG(&SPIx, SPI_FLAG_TXE)) {} + while ( __HAL_SPI_GET_FLAG(&SPIx, SPI_FLAG_BSY)) {} // First, abort any running dma HAL_DMA_Abort(&DMAtx); // DeInit objects @@ -214,8 +214,8 @@ void TFT_SPI::Transmit(uint16_t Data) { SPIx.Instance->DR = Data; - while ((SPIx.Instance->SR & SPI_FLAG_TXE) != SPI_FLAG_TXE) {} - while ((SPIx.Instance->SR & SPI_FLAG_BSY) == SPI_FLAG_BSY) {} + while (!__HAL_SPI_GET_FLAG(&SPIx, SPI_FLAG_TXE)) {} + while ( __HAL_SPI_GET_FLAG(&SPIx, SPI_FLAG_BSY)) {} if (TFT_MISO_PIN != TFT_MOSI_PIN) __HAL_SPI_CLEAR_OVRFLAG(&SPIx); // Clear overrun flag in 2 Lines communication mode because received is not read diff --git a/Marlin/src/HAL/STM32F1/HAL.h b/Marlin/src/HAL/STM32F1/HAL.h index 3bdfb9703c..026e83bc0d 100644 --- a/Marlin/src/HAL/STM32F1/HAL.h +++ b/Marlin/src/HAL/STM32F1/HAL.h @@ -264,7 +264,10 @@ void analogWrite(pin_t pin, int pwm_val8); // PWM only! mul by 257 in maple!? #define PLATFORM_M997_SUPPORT void flashFirmware(const int16_t); -#define HAL_CAN_SET_PWM_FREQ // This HAL supports PWM Frequency adjustment +#ifndef PWM_FREQUENCY + #define PWM_FREQUENCY 1000 // Default PWM Frequency +#endif +#define HAL_CAN_SET_PWM_FREQ // This HAL supports PWM Frequency adjustment /** * set_pwm_frequency @@ -278,5 +281,6 @@ void set_pwm_frequency(const pin_t pin, int f_desired); * Set the PWM duty cycle of the provided pin to the provided value * Optionally allows inverting the duty cycle [default = false] * Optionally allows changing the maximum size of the provided value to enable finer PWM duty control [default = 255] + * The timer must be pre-configured with set_pwm_frequency() if the default frequency is not desired. */ void set_pwm_duty(const pin_t pin, const uint16_t v, const uint16_t v_size=255, const bool invert=false); diff --git a/Marlin/src/HAL/STM32F1/fast_pwm.cpp b/Marlin/src/HAL/STM32F1/fast_pwm.cpp index 5171c11545..b510a4c8a0 100644 --- a/Marlin/src/HAL/STM32F1/fast_pwm.cpp +++ b/Marlin/src/HAL/STM32F1/fast_pwm.cpp @@ -30,40 +30,40 @@ void set_pwm_duty(const pin_t pin, const uint16_t v, const uint16_t v_size/*=255*/, const bool invert/*=false*/) { if (!PWM_PIN(pin)) return; timer_dev *timer = PIN_MAP[pin].timer_device; + if (!(timer->regs.bas->SR & TIMER_CR1_CEN)) // Ensure the timer is enabled + set_pwm_frequency(pin, PWM_FREQUENCY); uint16_t max_val = timer->regs.bas->ARR * v / v_size; if (invert) max_val = v_size - max_val; pwmWrite(pin, max_val); + } -#if NEEDS_HARDWARE_PWM +void set_pwm_frequency(const pin_t pin, int f_desired) { + if (!PWM_PIN(pin)) return; // Don't proceed if no hardware timer - void set_pwm_frequency(const pin_t pin, int f_desired) { - if (!PWM_PIN(pin)) return; // Don't proceed if no hardware timer + timer_dev *timer = PIN_MAP[pin].timer_device; + uint8_t channel = PIN_MAP[pin].timer_channel; - timer_dev *timer = PIN_MAP[pin].timer_device; - uint8_t channel = PIN_MAP[pin].timer_channel; + // Protect used timers + if (timer == get_timer_dev(TEMP_TIMER_NUM)) return; + if (timer == get_timer_dev(STEP_TIMER_NUM)) return; + #if PULSE_TIMER_NUM != STEP_TIMER_NUM + if (timer == get_timer_dev(PULSE_TIMER_NUM)) return; + #endif - // Protect used timers - if (timer == get_timer_dev(TEMP_TIMER_NUM)) return; - if (timer == get_timer_dev(STEP_TIMER_NUM)) return; - #if PULSE_TIMER_NUM != STEP_TIMER_NUM - if (timer == get_timer_dev(PULSE_TIMER_NUM)) return; - #endif + if (!(timer->regs.bas->SR & TIMER_CR1_CEN)) // Ensure the timer is enabled + timer_init(timer); - if (!(timer->regs.bas->SR & TIMER_CR1_CEN)) // Ensure the timer is enabled - timer_init(timer); - - timer_set_mode(timer, channel, TIMER_PWM); - uint16_t preload = 255; // Lock 255 PWM resolution for high frequencies - int32_t prescaler = (HAL_TIMER_RATE) / (preload + 1) / f_desired - 1; - if (prescaler > 65535) { // For low frequencies increase prescaler - prescaler = 65535; - preload = (HAL_TIMER_RATE) / (prescaler + 1) / f_desired - 1; - } - if (prescaler < 0) return; // Too high frequency - timer_set_reload(timer, preload); - timer_set_prescaler(timer, prescaler); + timer_set_mode(timer, channel, TIMER_PWM); + uint16_t preload = 255; // Lock 255 PWM resolution for high frequencies + int32_t prescaler = (HAL_TIMER_RATE) / (preload + 1) / f_desired - 1; + if (prescaler > 65535) { // For low frequencies increase prescaler + prescaler = 65535; + preload = (HAL_TIMER_RATE) / (prescaler + 1) / f_desired - 1; } + if (prescaler < 0) return; // Too high frequency + timer_set_reload(timer, preload); + timer_set_prescaler(timer, prescaler); +} -#endif // NEEDS_HARDWARE_PWM #endif // __STM32F1__ diff --git a/Marlin/src/lcd/extui/mks_ui/wifi_module.cpp b/Marlin/src/lcd/extui/mks_ui/wifi_module.cpp index f56d68366c..cc8458ce43 100644 --- a/Marlin/src/lcd/extui/mks_ui/wifi_module.cpp +++ b/Marlin/src/lcd/extui/mks_ui/wifi_module.cpp @@ -345,7 +345,7 @@ static bool longName2DosName(const char *longName, char *dosName) { hdma->DmaBaseAddress->IFCR = (DMA_ISR_GIF1 << hdma->ChannelIndex); SET_BIT(hdma->ErrorCode, HAL_DMA_ERROR_TE); // Update error code - hdma->State= HAL_DMA_STATE_READY; // Change the DMA state + hdma->State = HAL_DMA_STATE_READY; // Change the DMA state __HAL_UNLOCK(hdma); // Process Unlocked return HAL_ERROR; } diff --git a/Marlin/src/pins/stm32f1/pins_LONGER3D_LK.h b/Marlin/src/pins/stm32f1/pins_LONGER3D_LK.h index 3a8019a27e..c6f1e014e0 100644 --- a/Marlin/src/pins/stm32f1/pins_LONGER3D_LK.h +++ b/Marlin/src/pins/stm32f1/pins_LONGER3D_LK.h @@ -96,7 +96,6 @@ #else #define FAST_PWM_FAN // STM32 Variant allow TIMER2 Hardware PWM #define FAST_PWM_FAN_FREQUENCY 31400 // This frequency allow a good range, fan starts at 3%, half noise at 50% - #define NEEDS_HARDWARE_PWM 1 #define FAN_MIN_PWM 5 #define FAN_MAX_PWM 255 #endif