I am trying to control the position of a servo motor using an STM32F103C8T6 MCU (blue pill). The problem I am facing is that the servo does not move to different positions when given different values (in a infinite loop.)
I am using bare-metal programming so that I can understand the basic at hardware level.
Here is my code:
// ------------ THIS Code WORKS ------------------------------------------
#include "stm32f10x.h" // Device header
void delayMs(void);
void systick_init(void);
void delayMillis(int);
void writeMicroseconds(int);
int main(void){
RCC->APB1ENR |= RCC_APB1ENR_TIM4EN; //enable clock for TIM4
RCC->APB2ENR |= RCC_APB2ENR_IOPBEN | RCC_APB2ENR_AFIOEN; //enable clock for PORTB and enable AFIO
//cofigure PB6 as pwm output CNF6 = 10 (alternate fnc output push pull) MODE6 = 11 (output 50MHz)
GPIOB->CRL = 0x4B444444;//(1<<25)|(1<<24)|(1<<27)|(0<<26);
//configure pwm as active high and enable the signal
TIM4->CCER |= 1;
TIM4->CR1 |= (1<<7);//Auto reload preload enable ARPE
//timer config for pwm mode
//CH1 > OC1M = 110 & ocipe = 1
TIM4->CCMR1 |= (1<<6)|(1<<5)|(1<<3);
//Timer config for PSC and ARR
// clk = 72000000 : need 50Hz => 50 = 72000000/x/20000; => x = 72
TIM4->PSC = 72 - 1;
TIM4->ARR = 20000;
//enable all registers by UG bit
TIM4->EGR |= 1;
TIM4->CR1 |= 1; //enable timer CEN = 1;
writeMicroseconds(1500); // SERVO gets set to 90° perfectly
}
void writeMicroseconds(int32_t pwm){
TIM4->CCR1 = pwm;
}
//systick timer config
void systick_init(void){
SysTick->CTRL = 0;
SysTick->LOAD = 0x00ffffff;
SysTick->VAL = 0;
SysTick->CTRL = 5;
}
//single millisecond control config
void delayMs(void){
SysTick->LOAD = 72000-1;
SysTick->VAL = 0;
while((SysTick->CTRL & 0x00010000) == 0);
}
//given millisecond delay fnc
void delayMillis(int t){
for(;t>0;t--){
delayMs();
}
}
// ------------ THIS Code DOES NOT ------------------------------------------
#include "stm32f10x.h" // Device header
void delayMs(void);
void systick_init(void);
void delayMillis(int);
void writeMicroseconds(int);
int main(void){
RCC->APB1ENR |= RCC_APB1ENR_TIM4EN; //enable clock for TIM4
RCC->APB2ENR |= RCC_APB2ENR_IOPBEN | RCC_APB2ENR_AFIOEN; //enable clock for PORTB and enable AFIO
//cofigure PB6 as pwm output CNF6 = 10 (alternate fnc output push pull) MODE6 = 11 (output 50MHz)
GPIOB->CRL = 0x4B444444;//(1<<25)|(1<<24)|(1<<27)|(0<<26);
//configure pwm as active high and enable the signal
TIM4->CCER |= 1;
TIM4->CR1 |= (1<<7);//Auto reload preload enable ARPE
//timer config for pwm mode
//CH1 > OC1M = 110 & ocipe = 1
TIM4->CCMR1 |= (1<<6)|(1<<5)|(1<<3);
//Timer config for PSC and ARR
// clk = 72000000 : need 50Hz => 50 = 72000000/x/20000; => x = 72
TIM4->PSC = 72 - 1;
TIM4->ARR = 20000;
//enable all registers by UG bit
TIM4->EGR |= 1;
TIM4->CR1 |= 1; //enable timer CEN = 1;
while(1){ // In this loop the servo gets fixed at one position and then doesn't move at all! even though I Change CCR1 value.
writeMicroseconds(1500);
delayMillis(500);
writeMicroseconds(1050);
delayMillis(500);
writeMicroseconds(1500);
delayMillis(500);
writeMicroseconds(2000);
delayMillis(500);
writeMicroseconds(1500);
delayMillis(500);
writeMicroseconds(1050);
delayMillis(500);
}
}
void writeMicroseconds(int32_t pwm){
TIM4->CCR1 = pwm;
}
//systick timer config
void systick_init(void){
SysTick->CTRL = 0;
SysTick->LOAD = 0x00ffffff;
SysTick->VAL = 0;
SysTick->CTRL = 5;
}
//single millisecond control config
void delayMs(void){
SysTick->LOAD = 72000-1;
SysTick->VAL = 0;
while((SysTick->CTRL & 0x00010000) == 0);
}
//given millisecond delay fnc
void delayMillis(int t){
for(;t>0;t--){
delayMs();
}
}
I did this using the reference manual available in Keil MDK also here - Chapter 15. In the manual under PWM mode, an approach is given which I followed.
This is what is happening:
The servo gets fixed at a certain PWM (probably the fist value given to CCR1
initially). Even though I change the value of CCR1 register in the while loop, the servo stays fixed.
I tried with individual PWM widths and it works fine. But I want to change the PWM width in a loop - whatever value I pass to writeMicroseconds()
, the servo should get to that position; that's not happening in my code.
There is no particular reference to do this. I did it only on the basis of the manual and now I don't understand what I did wrong.
TIM4->CCR1 = 1500
is out of the while loop, the servo holds the position and its true position because I have calibrated it at that position. The only problem is that I am unable to change values of PWM width in the while loop(cant see my servo moving to those positions). As I want the servo to keep repeating the position sequence. \$\endgroup\$ – Sajil Dec 15 '20 at 6:38