🐛 Fix STM32 set_pwm_duty (#23125)

This commit is contained in:
Mike La Spina
2021-11-23 14:05:50 -06:00
committed by Scott Lahteine
parent 184fc36a08
commit 5f08864d1f
7 changed files with 96 additions and 60 deletions

View File

@ -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

View File

@ -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

View File

@ -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