🐛 Fix STM32 set_pwm_duty (#23125)
This commit is contained in:
parent
184fc36a08
commit
5f08864d1f
|
@ -114,16 +114,19 @@ byte MarlinSPI::transfer(uint8_t _data) {
|
||||||
return rxData;
|
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) {
|
uint8_t MarlinSPI::dmaTransfer(const void *transmitBuf, void *receiveBuf, uint16_t length) {
|
||||||
const uint8_t ff = 0xFF;
|
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);
|
__HAL_SPI_ENABLE(&_spi.handle);
|
||||||
|
|
||||||
if (receiveBuf) {
|
if (receiveBuf) {
|
||||||
setupDma(_spi.handle, _dmaRx, DMA_PERIPH_TO_MEMORY, true);
|
setupDma(_spi.handle, _dmaRx, DMA_PERIPH_TO_MEMORY, true);
|
||||||
HAL_DMA_Start(&_dmaRx, (uint32_t)&(_spi.handle.Instance->DR), (uint32_t)receiveBuf, length);
|
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
|
// check for 2 lines transfer
|
||||||
|
@ -136,7 +139,7 @@ uint8_t MarlinSPI::dmaTransfer(const void *transmitBuf, void *receiveBuf, uint16
|
||||||
if (transmitBuf) {
|
if (transmitBuf) {
|
||||||
setupDma(_spi.handle, _dmaTx, DMA_MEMORY_TO_PERIPH, mincTransmit);
|
setupDma(_spi.handle, _dmaTx, DMA_MEMORY_TO_PERIPH, mincTransmit);
|
||||||
HAL_DMA_Start(&_dmaTx, (uint32_t)transmitBuf, (uint32_t)&(_spi.handle.Instance->DR), length);
|
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) {
|
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);
|
setupDma(_spi.handle, _dmaTx, DMA_MEMORY_TO_PERIPH, minc);
|
||||||
HAL_DMA_Start(&_dmaTx, (uint32_t)transmitBuf, (uint32_t)&(_spi.handle.Instance->DR), length);
|
HAL_DMA_Start(&_dmaTx, (uint32_t)transmitBuf, (uint32_t)&(_spi.handle.Instance->DR), length);
|
||||||
__HAL_SPI_ENABLE(&_spi.handle);
|
__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_PollForTransfer(&_dmaTx, HAL_DMA_FULL_TRANSFER, HAL_MAX_DELAY);
|
||||||
HAL_DMA_Abort(&_dmaTx);
|
HAL_DMA_Abort(&_dmaTx);
|
||||||
// DeInit objects
|
// DeInit objects
|
||||||
|
|
|
@ -27,37 +27,67 @@
|
||||||
#include "../../inc/MarlinConfig.h"
|
#include "../../inc/MarlinConfig.h"
|
||||||
#include "timers.h"
|
#include "timers.h"
|
||||||
|
|
||||||
|
// 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*/) {
|
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
|
if (!PWM_PIN(pin)) return; // Don't proceed if no hardware timer
|
||||||
|
bool needs_freq;
|
||||||
PinName pin_name = digitalPinToPinName(pin);
|
PinName pin_name = digitalPinToPinName(pin);
|
||||||
TIM_TypeDef *Instance = (TIM_TypeDef *)pinmap_peripheral(pin_name, PinMap_PWM);
|
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;
|
uint16_t value = v;
|
||||||
if (invert) adj_val = Instance->ARR - adj_val;
|
if (invert) value = v_size - value;
|
||||||
switch (get_pwm_channel(pin_name)) {
|
|
||||||
case TIM_CHANNEL_1: LL_TIM_OC_SetCompareCH1(Instance, adj_val); break;
|
uint32_t index = get_timer_index(Instance);
|
||||||
case TIM_CHANNEL_2: LL_TIM_OC_SetCompareCH2(Instance, adj_val); break;
|
|
||||||
case TIM_CHANNEL_3: LL_TIM_OC_SetCompareCH3(Instance, adj_val); break;
|
if (HardwareTimer_Handle[index] == nullptr) {
|
||||||
case TIM_CHANNEL_4: LL_TIM_OC_SetCompareCH4(Instance, adj_val); break;
|
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
|
||||||
}
|
}
|
||||||
|
|
||||||
#if NEEDS_HARDWARE_PWM
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
void set_pwm_frequency(const pin_t pin, int f_desired) {
|
void set_pwm_frequency(const pin_t pin, int f_desired) {
|
||||||
if (!PWM_PIN(pin)) return; // Don't proceed if no hardware timer
|
if (!PWM_PIN(pin)) return; // Don't proceed if no hardware timer
|
||||||
|
HardwareTimer *HT;
|
||||||
PinName pin_name = digitalPinToPinName(pin);
|
PinName pin_name = digitalPinToPinName(pin);
|
||||||
TIM_TypeDef *Instance = (TIM_TypeDef *)pinmap_peripheral(pin_name, PinMap_PWM); // Get HAL timer instance
|
TIM_TypeDef *Instance = (TIM_TypeDef *)pinmap_peripheral(pin_name, PinMap_PWM); // Get HAL timer instance
|
||||||
|
|
||||||
LOOP_S_L_N(i, 0, NUM_HARDWARE_TIMERS) // Protect used timers
|
uint32_t index = get_timer_index(Instance);
|
||||||
if (timer_instance[i] && timer_instance[i]->getHandle()->Instance == Instance)
|
|
||||||
return;
|
|
||||||
|
|
||||||
pwm_start(pin_name, f_desired, 0, RESOLUTION_8B_COMPARE_FORMAT);
|
// 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;
|
||||||
|
|
||||||
|
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
|
|
||||||
|
|
||||||
#endif // HAL_STM32
|
#endif // HAL_STM32
|
||||||
|
|
|
@ -161,11 +161,11 @@ uint32_t TFT_SPI::ReadID(uint16_t Reg) {
|
||||||
for (i = 0; i < 4; i++) {
|
for (i = 0; i < 4; i++) {
|
||||||
#if TFT_MISO_PIN != TFT_MOSI_PIN
|
#if TFT_MISO_PIN != TFT_MOSI_PIN
|
||||||
//if (hspi->Init.Direction == SPI_DIRECTION_2LINES) {
|
//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;
|
SPIx.Instance->DR = 0;
|
||||||
//}
|
//}
|
||||||
#endif
|
#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;
|
Data = (Data << 8) | SPIx.Instance->DR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -195,8 +195,8 @@ bool TFT_SPI::isBusy() {
|
||||||
|
|
||||||
void TFT_SPI::Abort() {
|
void TFT_SPI::Abort() {
|
||||||
// Wait for any running spi
|
// Wait for any running spi
|
||||||
while ((SPIx.Instance->SR & SPI_FLAG_TXE) != SPI_FLAG_TXE) {}
|
while (!__HAL_SPI_GET_FLAG(&SPIx, SPI_FLAG_TXE)) {}
|
||||||
while ((SPIx.Instance->SR & SPI_FLAG_BSY) == SPI_FLAG_BSY) {}
|
while ( __HAL_SPI_GET_FLAG(&SPIx, SPI_FLAG_BSY)) {}
|
||||||
// First, abort any running dma
|
// First, abort any running dma
|
||||||
HAL_DMA_Abort(&DMAtx);
|
HAL_DMA_Abort(&DMAtx);
|
||||||
// DeInit objects
|
// DeInit objects
|
||||||
|
@ -214,8 +214,8 @@ void TFT_SPI::Transmit(uint16_t Data) {
|
||||||
|
|
||||||
SPIx.Instance->DR = Data;
|
SPIx.Instance->DR = Data;
|
||||||
|
|
||||||
while ((SPIx.Instance->SR & SPI_FLAG_TXE) != SPI_FLAG_TXE) {}
|
while (!__HAL_SPI_GET_FLAG(&SPIx, SPI_FLAG_TXE)) {}
|
||||||
while ((SPIx.Instance->SR & SPI_FLAG_BSY) == SPI_FLAG_BSY) {}
|
while ( __HAL_SPI_GET_FLAG(&SPIx, SPI_FLAG_BSY)) {}
|
||||||
|
|
||||||
if (TFT_MISO_PIN != TFT_MOSI_PIN)
|
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
|
__HAL_SPI_CLEAR_OVRFLAG(&SPIx); // Clear overrun flag in 2 Lines communication mode because received is not read
|
||||||
|
|
|
@ -264,6 +264,9 @@ void analogWrite(pin_t pin, int pwm_val8); // PWM only! mul by 257 in maple!?
|
||||||
#define PLATFORM_M997_SUPPORT
|
#define PLATFORM_M997_SUPPORT
|
||||||
void flashFirmware(const int16_t);
|
void flashFirmware(const int16_t);
|
||||||
|
|
||||||
|
#ifndef PWM_FREQUENCY
|
||||||
|
#define PWM_FREQUENCY 1000 // Default PWM Frequency
|
||||||
|
#endif
|
||||||
#define HAL_CAN_SET_PWM_FREQ // This HAL supports PWM Frequency adjustment
|
#define HAL_CAN_SET_PWM_FREQ // This HAL supports PWM Frequency adjustment
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -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
|
* Set the PWM duty cycle of the provided pin to the provided value
|
||||||
* Optionally allows inverting the duty cycle [default = false]
|
* 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]
|
* 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);
|
void set_pwm_duty(const pin_t pin, const uint16_t v, const uint16_t v_size=255, const bool invert=false);
|
||||||
|
|
|
@ -30,12 +30,13 @@
|
||||||
void set_pwm_duty(const pin_t pin, const uint16_t v, const uint16_t v_size/*=255*/, const bool invert/*=false*/) {
|
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;
|
if (!PWM_PIN(pin)) return;
|
||||||
timer_dev *timer = PIN_MAP[pin].timer_device;
|
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;
|
uint16_t max_val = timer->regs.bas->ARR * v / v_size;
|
||||||
if (invert) max_val = v_size - max_val;
|
if (invert) max_val = v_size - max_val;
|
||||||
pwmWrite(pin, max_val);
|
pwmWrite(pin, max_val);
|
||||||
}
|
|
||||||
|
|
||||||
#if NEEDS_HARDWARE_PWM
|
}
|
||||||
|
|
||||||
void set_pwm_frequency(const pin_t pin, int f_desired) {
|
void set_pwm_frequency(const pin_t pin, int f_desired) {
|
||||||
if (!PWM_PIN(pin)) return; // Don't proceed if no hardware timer
|
if (!PWM_PIN(pin)) return; // Don't proceed if no hardware timer
|
||||||
|
@ -65,5 +66,4 @@ void set_pwm_duty(const pin_t pin, const uint16_t v, const uint16_t v_size/*=255
|
||||||
timer_set_prescaler(timer, prescaler);
|
timer_set_prescaler(timer, prescaler);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // NEEDS_HARDWARE_PWM
|
|
||||||
#endif // __STM32F1__
|
#endif // __STM32F1__
|
||||||
|
|
|
@ -96,7 +96,6 @@
|
||||||
#else
|
#else
|
||||||
#define FAST_PWM_FAN // STM32 Variant allow TIMER2 Hardware PWM
|
#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 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_MIN_PWM 5
|
||||||
#define FAN_MAX_PWM 255
|
#define FAN_MAX_PWM 255
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in a new issue