2025-02-23 01:00 PM - last edited on 2025-02-24 10:09 AM by Andrew Neil
Hello everyone, I have a problem with sending a variable of type string using the USART interrupt in order to control an SG90 servo with PWM. Initially, the idea was to use keyboard key presses to make the motor rotate either to the right or to the left. The microcontroller is not responding; I tried using my own application as well as RealTerm. I don't understand what could be causing the interrupt not to work. I thought the issue might be related to not handling the flag register, but unfortunately, I haven't been able to figure out the solution.
#include "stm32f303xe.h"
#include "stdint.h"
#include "stm32f3xx.h"
#include <stdio.h>
#include <string.h>
volatile int currentindex=0;
volatile int position = 150;
volatile char message[50];
void clock_config(void)
{
RCC->CR |= RCC_CR_HSION;
while (!(RCC->CR & RCC_CR_HSIRDY));
RCC->APB1ENR |= RCC_APB1ENR_PWREN;
RCC->CFGR |= RCC_CFGR_HPRE_DIV1;
RCC->CFGR|= RCC_CFGR_PPRE1_DIV2;
//PPL SOURCE MUX
// RCC->CFGR |= RCC_CFGR_PLLMUL9;
RCC->CFGR |= (0x7 << RCC_CFGR_PLLMUL_Pos);
RCC->CR |= RCC_CR_PLLON;
while (!(RCC->CR & RCC_CR_PLLRDY));
RCC->CFGR |= RCC_CFGR_SW_PLL;
while(!(RCC->CFGR & RCC_CFGR_SWS));
}
void config_UART(void)
{
RCC -> AHBENR |= RCC_AHBENR_GPIOAEN;
//PA2_TXAF7
GPIOA -> MODER &= ~(GPIO_MODER_MODER2_0);
GPIOA->MODER |= GPIO_MODER_MODER2_1;
GPIOA->AFR[0] &= ~((0xF << GPIO_AFRL_AFRL2_Pos));
GPIOA->AFR[0] |= (0x7 << GPIO_AFRL_AFRL2_Pos);
//PA3_RXAF7
GPIOA -> MODER &= ~(GPIO_MODER_MODER3_0);
GPIOA->MODER |= GPIO_MODER_MODER3_1;
GPIOA->AFR[0] &= ~((0xF << GPIO_AFRL_AFRL3_Pos));
GPIOA->AFR[0] |= (0x7 << GPIO_AFRL_AFRL3_Pos);
//GPIOA -> OTYPER |= GPIO_OTYPER_OT_3;
//GPIOA->PUPDR |= GPIO_PUPDR_PUPDR3_0;
RCC -> APB1ENR |= RCC_APB1ENR_USART2EN;
//RCC -> CFGR |= RCC_CFGR_PPRE1_2;
USART2->BRR = 36000000/115200;
USART2-> CR1 |= USART_CR1_UE | USART_CR1_TE | USART_CR1_RE;
USART2-> CR1 |= USART_CR1_IDLEIE | USART_CR1_RXNEIE;
NVIC_SetPriority(USART2_IRQn, 0);
NVIC_EnableIRQ(USART2_IRQn);
}
void USART2_IRQHandler(void)
{
if(USART2->ISR & USART_ISR_RXNE)
{
message[currentindex] = USART2-> RDR;
currentindex++;
}else if(USART2->ISR & USART_ISR_IDLE)
{
if(strcmp(message,"L") == 0)
{
if(position < 250)
{
position+=2;
TIM3->CCR1 = position;
}
}
else if(strcmp(message,"P") == 0)
{
if(position > 50)
{
position-=2;
TIM3->CCR1 = position;
}
}
memset(message,0,currentindex+1);
currentindex = 0;
USART2->ISR &= ~USART_ISR_IDLE;
}
}
void configureTIMER3(void);
void TIM3_start(void);
void interuptTIM3(void);
void pwmconfigration(void);
void configPWMPA6(void);
int main(void)
{
clock_config();
config_UART();
configureTIMER3();
TIM3_start();
pwmconfigration();
configPWMPA6();
interuptTIM3();
while(1)
{
}
}
void configureTIMER3(void)
{
//PA6:D12
RCC -> APB1ENR |= RCC_APB1ENR_TIM3EN;
TIM3->PSC = 71; //72mghz
TIM3->ARR = 1999; //PA6
}
void TIM3_start(void)
{
TIM3->CNT=0;
TIM3->CR1|= TIM_CR1_CEN;
}
void interuptTIM3(void)
{
TIM3 -> DIER |= TIM_DIER_UIE;
TIM3 -> DIER |= TIM_DIER_CC1IE;
NVIC_SetPriority(TIM3_IRQn, 1);
NVIC_EnableIRQ(TIM3_IRQn);
}
void TIM3_IRQHandler(void)
{
if(TIM3 -> SR & TIM_SR_UIF)
{
TIM3 -> SR &= ~(TIM_SR_UIF);
}
if(TIM3 -> SR & TIM_SR_CC1IF)
{
TIM3 -> SR &= ~(TIM_SR_CC1IF);
}
}
void pwmconfigration(void)
{
TIM3 -> CCMR1 |= TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1M_2;
TIM3 -> CCMR1 |= TIM_CCMR1_OC1PE;
TIM3 -> CCR1 = 450;
TIM3->CR1 |= TIM_CR1_ARPE;
TIM3 -> CCER |= TIM_CCER_CC1E;
}
void configPWMPA6(void)
{
GPIOA-> MODER |= GPIO_MODER_MODER6_1;
GPIOA->AFR[0] |= (0x2 << GPIO_AFRL_AFRL6_Pos);
}
2025-02-23 02:29 PM - edited 2025-02-23 02:33 PM
> I don't understand what could be causing the interrupt not to work.
Interrupt works, but it loops infinitely. In 'F3 UART, IDLE is not cleared by writing to it, but by writing 1 to the IDLECF in
the USART_ICR register, see description of IDLE bit of UART_ISR register in RM.
Probably not the primary issue, but do handle the UART error flags, especially overflow. Also, don't RMW flags registers.
JW
PS. Why did you set "string" in bold typeface in your post?
2025-02-23 02:32 PM
Unfortunately register level coding comes with responsibility to debug it yourself, and go over the register definitions to understand the reported conditions when it fails.
Is there a Noise or Framing type error blocking further reception? If the source of the interrupt is not cleared it will keep reentering.
Confirm the UART2 is outputting successfully by sending a diagnostic message as the code starts.
Also
TIM3->SR = ~(TIM_SR_UIF); // Just write the mask, don't do the RMW &=
2025-02-24 10:02 AM
@waclawek.jan According to your recommendations, I fixed the interrupt handling code, but unfortunately, I did not receive the desired letter from you.
void USART2_IRQHandler(void)
{
if(USART2->ISR & USART_ISR_RXNE)
{
message[currentindex] = USART2-> RDR;
currentindex++;
}else if(USART2->ISR & USART_ISR_IDLE)
{
if(strcmp(message,"L") == 0)
{
if(position < 250)
{
position+=2;
TIM3->CCR1 = position;
}
}
else if(strcmp(message,"P") == 0)
{
if(position > 50)
{
position-=2;
TIM3->CCR1 = position;
}
}
memset(message,0,currentindex+1);
currentindex = 0;
USART2->ICR |= USART_ICR_IDLECF;
}
if (USART2->ISR & (USART_ISR_ORE | USART_ISR_FE | USART_ISR_NE))
{
// Wyczyść flagi błędów przez zapisanie 1 do odpowiednich bitów w rejestrze USART_ICR
USART2->ICR |= (USART_ICR_ORECF | USART_ICR_FECF | USART_ICR_NCF);
}
}
2025-02-24 10:08 AM
@Tesla DeLorean At the beginning of the program execution, I successfully sent the letter. However, the USART is not receiving the letter I am sending for interrupt. The registers in SRFs debugger mode do not show any Noise or Framing type error blocking further reception.