🐛 Fix STM32 set_pwm_duty (#23125)
This commit is contained in:
		
				
					committed by
					
						 Scott Lahteine
						Scott Lahteine
					
				
			
			
				
	
			
			
			
						parent
						
							184fc36a08
						
					
				
				
					commit
					5f08864d1f
				
			| @@ -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 | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
| @@ -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); | ||||
|   | ||||
| @@ -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__ | ||||
|   | ||||
| @@ -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; | ||||
|         } | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
		Reference in New Issue
	
	Block a user