#include "stm32f4xx.h"
#include "math.h"
#include "LCD2x16.c"
#define pi 3.141592653589
#define B00 0x0001
#define B01 0x0002
#define B02 0x0004
#define B03 0x0008
#define B04 0x0010
#define B05 0x0020
int Ref[64], x[64], Ptr; // declare circular buffers
float Kp = 1.0, Ki = 0.0, Kd = 0.0; // declare & init params
int Error[64]; // declare error vector
int Reg[64]; // declare past output vector
float Prop, Dif, Int = 0; // declare (& init) vars
float Ts = 0.0001; // defined by constant 8400 in TIM2->arr;
void ADC_setup(void) {
RCC->APB2ENR |= 0x00000100; // clock for ADC1
RCC->APB2ENR |= 0x00000200; // clock for ADC2
ADC->CCR = 0x00000006; // Regular simultaneous mode only
ADC1->CR2 = 0x00000001; // ADC1 ON
ADC1->SQR3 = 0x00000002; // use PA02 as input
ADC2->CR2 = 0x00000001; // ADC1 ON
ADC2->SQR3 = 0x00000003; // use PA03 as input
GPIOA->MODER |= 0x000000f0; // PA02, PA03 are analog inputs
ADC1->CR2 |= 0x06000000; // use TIM2, TRG0 as SC source
ADC1->CR2 |= 0x10000000; // Enable external SC, rising edge
ADC1->CR1 |= 0x00000020; // Enable ADC Interrupt for EOC
}
void DAC_setup(void) {
RCC->APB1ENR |= 0x20000000; // Enable clock for DAC
DAC->CR |= 0x00010001; // DAC control reg, both channels ON
GPIOA->MODER |= 0x00000f00; // PA04, PA05 are analog outputs
}
void GPIO_setup(void) {
RCC->AHB1ENR |= 0x00000001; // Enable clock for GPIOA
RCC->AHB1ENR |= 0x00000010; // Enable clock for GPIOE
GPIOE->MODER |= 0x00010000; // output pin PE08: time mark
GPIOE->MODER |= 0x00040000; // output pin PE09: toggle
GPIOA->MODER |= 0x00001000; // output pin PA06: LED D390
}
void Timer2_setup(void) {
RCC->APB1ENR |= 0x0001; // Enable clock for Timer 2
TIM2->ARR = 8400; // Auto Reload value: 8400 == 100us
TIM2->CR2 |= 0x0020; // select TRGO to be update event (UE)
TIM2->CR1 |= 0x0001; // Enable Counting
}
int main () {
GPIO_setup(); // GPIO set-up
DAC_setup(); // DAC set-up
ADC_setup(); // ADC set-up
Timer2_setup(); // Timer 2 set-up
NVIC_EnableIRQ(ADC_IRQn); // Enable IRQ for ADC in NVIC
LCD_init();
LCD_string("Kp:", 0x00);
LCD_string("Kd:", 0x09);
LCD_string("Ki:", 0x49);
// set gains & waste time - indefinite loop
while (1) {
if ((GPIOE->IDR & 0x003f) == (B00 + B05)) Kp++; // manually set Kp
if ((GPIOE->IDR & 0x003f) == (B00 + B04)) Kp--;
if (Kp<0) Kp = 0; if (Kp > 1000) Kp = 1000;
if ((GPIOE->IDR & 0x003f) == (B01 + B05)) Kd += 0.001; // manually set Kd
if ((GPIOE->IDR & 0x003f) == (B01 + B04)) Kd -= 0.001;
if (Kd < 0) Kd = 0; if (Kd > 1) Kd = 1;
if ((GPIOE->IDR & 0x003f) == (B02 + B05)) Ki += 0.0001; // manually set Ki
if ((GPIOE->IDR & 0x003f) == (B02 + B04)) Ki -= 0.0001;
if (Ki < 0) Ki = 0; if (Ki > 1) Ki = 1;
LCD_sInt3DG((int)Kp,0x03,1); // write Kp
LCD_sInt3DG((int)(Kd*1000),0x0c,1); // write Kd
LCD_sInt3DG((int)(Ki*10000),0x4c,1); // write Ki
for (int i = 0; i < 2000000; i++) {}; // waste time
};
}
// IRQ function
void ADC_IRQHandler(void) // this takes approx 6us of CPU time!
{
GPIOE->ODR |= 0x0100; // PE08 up
Ref[Ptr] = ADC1->DR; // pass ADC -> circular buffer x1
x[Ptr] = ADC2->DR; // pass ADC -> circular buffer x2
// PID calculation start
Error[Ptr] = Ref[Ptr] - x[Ptr]; // calculate error
Prop = Kp * (float)Error[Ptr]; // proportional part
Dif = Kd * (float)(Error[Ptr] - Error[(Ptr-1) & 63]) / Ts; // differential part
Int += Ki * (float)Error[Ptr]; // integral part
Reg[Ptr] = (int)(Prop + Dif + Int); // summ all three
// PID calculation stop
if (Reg[Ptr] > 4095) DAC->DHR12R1 = 4095; // limit output due to the DAC
else if (Reg[Ptr] < 0) DAC->DHR12R1 = 0;
else DAC->DHR12R1 = (int)Reg[Ptr]; // regulator output -> DAC
DAC->DHR12R2 = Error[Ptr] + 2048; // Error -> DAC
Ptr = (Ptr + 1) & 63; // increment pointer to circular buffer
GPIOE->ODR &= ~0x0100; // PE08 down
}