STM32 hangs when >100khz signal applied to input
Posted: Sun Feb 25, 2024 11:54 am
Hello, I am trying to make a frequency + duty cycle meter with a graphical display to be added in the future. I am using STM32F1038C8T6 with ArduinoSTM32 core from the github https://github.com/stm32duino.
Using the examples Frequency_Dutycycle_measurement.ino and PWM_FullConfiguration.ino in https://github.com/stm32duino/STM32Examples, I can measure the pwm generated on pin A8 with no issues. But when I change it to something higher than 100kHz, the serial monitor writes painfully slow (gives me 0 values) or just stops giving me output. When I disconnect PA10 from PA8 it comes back to life and shows the default 0 value because nothing is connected on input pin PA10. I also measured PA8 with voltmeter and it gives correct voltage according to the duty cycle I set. Can anyone help me figure out whats the problem or find a better solution? Sorry for bad english and bad code 
Code: Select all
#include <stm32f1xx_ll_adc.h>
volatile bool wave_rise=false;
unsigned long start=0, first=0, second=0;
volatile double d; volatile int s;
volatile uint32_t analogvoltage; //FOR A DIFFERENT FUNCTION NOT YET IMPLEMENTED
bool set=false,flag=false;
#define LL_ADC_RESOLUTION LL_ADC_RESOLUTION_12B
#define VINT 1200
#define anpin PA10 //analogInput pin
#define pin PA8 //PWM PIN
uint32_t channelRising, channelFalling;
volatile double FrequencyMeasured, DutycycleMeasured, LastPeriodCapture = 0, CurrentCapture, HighStateMeasured;
uint32_t input_freq = 0;
volatile uint32_t rolloverCompareCount = 0;
HardwareTimer *FRQ;
void TIMINPUT_Capture_Rising_IT_callback(void)
{
CurrentCapture = FRQ->getCaptureCompare(channelRising);
/* frequency computation */
if (CurrentCapture > LastPeriodCapture)
{
FrequencyMeasured = 1.0*input_freq / (CurrentCapture - LastPeriodCapture);
DutycycleMeasured = (HighStateMeasured * 100.0) / (CurrentCapture - LastPeriodCapture);
}
else if (CurrentCapture <= LastPeriodCapture)
{
/* 0x1000 is max overflow value */
FrequencyMeasured = 1.0*input_freq / (0x10000 + CurrentCapture - LastPeriodCapture);
DutycycleMeasured = (HighStateMeasured * 100.0) / (0x10000 + CurrentCapture - LastPeriodCapture);
}
LastPeriodCapture = CurrentCapture;
rolloverCompareCount = 0;
}
void Rollover_IT_callback(void)
{
rolloverCompareCount++;
if (rolloverCompareCount > 1)
{
FrequencyMeasured = 0;
DutycycleMeasured = 0;
}
}
void TIMINPUT_Capture_Falling_IT_callback(void)
{
/* prepare DutyCycle computation */
CurrentCapture = FRQ->getCaptureCompare(channelFalling);
if (CurrentCapture > LastPeriodCapture)
{
HighStateMeasured = CurrentCapture - LastPeriodCapture;
}
else if (CurrentCapture <= LastPeriodCapture)
{
/* 0x1000 is max overflow value */
HighStateMeasured = 0x10000 + CurrentCapture - LastPeriodCapture;
}
}
void Update_IT_callback(void)
{ // Update event correspond to Rising edge of PWM when configured in PWM1 mode
}
void Compare_IT_callback(void)
{ // Compare match event correspond to falling edge of PWM when configured in PWM1 mode
}
void setup() {
// TIM_TypeDef *PWM1 = (TIM_TypeDef *)pinmap_peripheral(digitalPinToPinName(pin1), PinMap_PWM);
// uint32_t p1 = STM_PIN_CHANNEL(pinmap_function(digitalPinToPinName(pin1), PinMap_PWM));
// HardwareTimer *PWMT1C1 = new HardwareTimer(PWM1);
TIM_TypeDef *FR = (TIM_TypeDef *)pinmap_peripheral(digitalPinToPinName(anpin), PinMap_PWM);
channelRising = STM_PIN_CHANNEL(pinmap_function(digitalPinToPinName(anpin), PinMap_PWM));
switch (channelRising) {
case 1:
channelFalling = 2;
break;
case 2:
channelFalling = 1;
break;
case 3:
channelFalling = 4;
break;
case 4:
channelFalling = 3;
break;
}
FRQ = new HardwareTimer(FR);
FRQ->setMode(channelRising, TIMER_INPUT_FREQ_DUTY_MEASUREMENT, anpin);
uint32_t PrescalerFactor = 1;
FRQ->setPrescaleFactor(PrescalerFactor);
FRQ->setOverflow(0x10000); // Max Period value to have the largest possible time to detect rising edge and avoid timer rollover
FRQ->attachInterrupt(channelRising, TIMINPUT_Capture_Rising_IT_callback);
FRQ->attachInterrupt(channelFalling, TIMINPUT_Capture_Falling_IT_callback);
FRQ->attachInterrupt(Rollover_IT_callback);
FRQ->resume();
input_freq = FRQ->getTimerClkFreq() / FRQ->getPrescaleFactor();
TIM_TypeDef *Instance = (TIM_TypeDef *)pinmap_peripheral(digitalPinToPinName(pin), PinMap_PWM);
uint32_t channel = STM_PIN_CHANNEL(pinmap_function(digitalPinToPinName(pin), PinMap_PWM));
HardwareTimer *MyTim = new HardwareTimer(Instance);
MyTim->setMode(channel, TIMER_OUTPUT_COMPARE_PWM1, pin);
MyTim->setOverflow(120000, HERTZ_FORMAT); //FREQUENCY IN MICROSEC
MyTim->setCaptureCompare(channel, 85, PERCENT_COMPARE_FORMAT); // DUTY CYCLE IN %
MyTim->attachInterrupt(Update_IT_callback);
MyTim->attachInterrupt(channel, Compare_IT_callback);
MyTim->resume();
}
void loop()
{
/* Print frequency and dutycycle measured on Serial monitor every seconds */
Serial.print("Frequency = ");
Serial.print(FrequencyMeasured/1.0,4);
Serial.print(" Dutycycle = " );
Serial.println(DutycycleMeasured/1.0,4);
delay(500);
}
