I'm working on a project where I need to generate a pulse with a desired frequency, which can be adjusted through three different modes.
The modes are as follows:
- Frequency remains the same.
- Frequency is divided by 2.
- Frequency is multiplied by 2.
The mode is selected using a switch (configured for external interrupt callback), and the pulse is generated using Timer 4 (clock 48 MHz, prescaler 4800) in Output Compare mode with the "toggle on match" feature. The ARR (Auto-Reload Register) and CCR (Capture/Compare Register) values are set based on the output from a rotary encoder.
The pulse generation itself works as expected, but when switching between modes, the signal goes high for a fixed period of time (8 seconds) before returning to the expected pulse pattern.
Has anyone encountered a similar issue? What could be the possible reasons for this behavior, and how can I address it?
while (1)
{
Rotary_Enc_Chk();
if(rotChk == TRUE)
{
rotChk = FALSE;
sprintf(txBuffer, "Speed: %d\n\r", speed);
HAL_UART_Transmit(&huart1, (uint8_t*)txBuffer, strlen(txBuffer), 10);
TM1637_DisplayDecimal(speed, 0);
if(speed > 0)
{
uint16_t freq = (10000 / (2 * xFactor * speed )) - 1;
//uint16_t freq = speed;
TIM14->ARR = freq;
TIM14->CCR1 = freq;
HAL_TIM_OC_Start(&htim14, TIM_CHANNEL_1);
}
else {
sprintf(txBuffer, "Speed: %d\n\r", speed);
HAL_UART_Transmit(&huart1, (uint8_t*)txBuffer, strlen(txBuffer), 10);
}
}
if(modeChange == TRUE)
{
sprintf(txBuffer, "Mode: %d\n\r", speed);
HAL_UART_Transmit(&huart1, (uint8_t*)txBuffer, strlen(txBuffer), 10);
rotChk = TRUE;
modeChange = FALSE;
Mode_Check();
}
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
UNUSED(GPIO_Pin);
if((GPIO_Pin == _2X_SEL_Pin) || (GPIO_Pin == X_2_SEL_Pin))
{
modeChange = TRUE;
}
void Mode_Check()
{
if(HAL_GPIO_ReadPin(GPIOA, _2X_SEL_Pin) == GPIO_PIN_RESET)
{
currMode = FAST_2X;
xFactor = 2;
All_Led_Off();
Red_Led_On();
}
else if(HAL_GPIO_ReadPin(GPIOA, X_2_SEL_Pin) == GPIO_PIN_RESET)
{
currMode = SLOW_X_2;
xFactor = 0.5;
All_Led_Off();
Blue_Led_On();
}
else
{
currMode = MEDIUM_X;
xFactor = 1;
All_Led_Off();
Green_Led_On();
}
}
rotary encoder part void Rotary_Enc_Chk(void) { static uint32_t lastTick = 0; uint32_t currentTick = HAL_GetTick();
switch (encoderState) {
case WAIT_FOR_A_LOW:
if (HAL_GPIO_ReadPin(GPIOB, ROT_A_Pin) == GPIO_PIN_RESET) {
if (HAL_GPIO_ReadPin(GPIOB, ROT_B_Pin) == GPIO_PIN_RESET) {
encoderState = WAIT_FOR_B_LOW;
lastTick = currentTick;
} else {
encoderState = WAIT_FOR_B_HIGH;
lastTick = currentTick;
}
}
break;
case WAIT_FOR_B_LOW:
if (HAL_GPIO_ReadPin(GPIOB, ROT_B_Pin) == GPIO_PIN_SET) {
speed--;
encoderState = WAIT_FOR_A_HIGH;
rotChk = TRUE;
lastTick = currentTick;
} else if (currentTick - lastTick > 10) {
encoderState = WAIT_FOR_A_LOW;
}
break;
case WAIT_FOR_A_HIGH:
if (HAL_GPIO_ReadPin(GPIOB, ROT_A_Pin) == GPIO_PIN_SET) {
encoderState = WAIT_FOR_B_HIGH;
lastTick = currentTick;
} else if (currentTick - lastTick > 10) {
encoderState = WAIT_FOR_A_LOW;
}
break;
case WAIT_FOR_B_HIGH:
if (HAL_GPIO_ReadPin(GPIOB, ROT_B_Pin) == GPIO_PIN_RESET) {
speed++;
encoderState = WAIT_FOR_A_LOW;
lastTick = currentTick;
// Set rotChk flag
rotChk = TRUE;
} else if (currentTick - lastTick > 10) {
encoderState = WAIT_FOR_A_LOW;
}
break;
}
// Bound speed
if (speed < 0) speed = 0;
if (speed > 225) speed = 225;
}
void TM1637_DisplayDecimal(int v, int displaySeparator) { unsigned char digitArr[N_DISPLAYS]; for (int i = 0; i < N_DISPLAYS; ++i) { digitArr[i] = segmentMap[v % 10];
if (i == 2 && displaySeparator) //Code snippet for dot or display separator
{
digitArr[i] |= 1 << 7;
}
v /= 10;
}
if(digitArr[N_DISPLAYS - 1] == 0x3F) //Code Snippet for MSB zeros to be off
{
digitArr[N_DISPLAYS - 1] = 0x00;
if(digitArr[N_DISPLAYS - 2] == 0x3F)
{
digitArr[N_DISPLAYS - 2] = 0x00;
}
}
Rotary_Enc_Chk()
,TM1637_DisplayDecimal()
,All_Led_Off()
, and the red/green/blue on functions? Also can you try commenting out allsprintf()
, UART transmit, and LED on/off calls and see if that changes the behavior? \$\endgroup\$if (speed < 0) speed = 0;
anduint16_t freq = (10000 / (2 * xFactor * speed )) - 1;
is calling for troubles. Never divide by 0. \$\endgroup\$