current_control.c 5.73 KB
Newer Older
Pontus Giselsson's avatar
Pontus Giselsson committed
1
2
/*
***************************************************************
Pontus Giselsson's avatar
Pontus Giselsson committed
3
4
5
6

 Current regulation - Pontus Giselsson, Per-Ola Larsson 18/02/09
           for LTH - reglerteknik

Pontus Giselsson's avatar
Pontus Giselsson committed
7
8
***************************************************************
*/
9
10
11
12
13
14
15
16
#include <avr/twi.h>
#include <avr/io.h>
#include <avr/signal.h>
#include <avr/interrupt.h>
#include <inttypes.h>


// control variables
Pontus Giselsson's avatar
Pontus Giselsson committed
17
18
19
20
21
22
23
24
25
26
27
28
29
volatile int16_t ref=0;        // reference value (from velocity controller)
volatile int16_t y;            // measurement, 9 frac bits
volatile uint16_t low, high;   // when reading AD-conversion
volatile int16_t e = 0;        // control error, 9 frac bits
volatile int16_t v = 0;        // temporary ctrl signal, 9 frac bits
volatile int16_t vSat = 0;     // saturated temporary ctrl signal, 9 frac bits
volatile int16_t I = 0;        // integral part of ctrl, 13 frac bits
volatile int16_t u = 0;        // ctrl signal = pwm high time (8 bits)
volatile int16_t K = 111;      // 7 frac bits
volatile int16_t Ke = 38;      // 7 frac bits, K*h/Ti
volatile int8_t intCond = 0;   // flag for conditional integration

#define V_MAX 508              //max/min for saturation
30
31
#define V_MIN -508

32
33
34
// twi variable
volatile int16_t status;

35
// logging variables
36
/*
37
38
39
40
41
42
43
44
#define log_len 100
volatile int16_t ctrl_log[log_len];
volatile int16_t error_log[log_len];
volatile int32_t I_log[log_len];
volatile int16_t skipSamples = 1000;
volatile int16_t countSamples = 0;
volatile int16_t jj=0;
volatile int8_t stop = 0;
45
46
47
48
49
50
51
52
53
54
55
56
*/

/* Routine used to transmit bytes on the serial port */
/*
static void putchar(unsigned char ch)
{
	while ((inp(UCSRA) & 0x20) == 0) {};
	outp(ch, UDR);
	while ((inp(UCSRA) & 0x20) == 0) {};
}
*/

57
/* Send logged data over Serial connection */
58
/*
59
60
61
static inline void sendData() {
  int16_t ii = 0;
  while (ii < log_len) {
62

63
64
    putchar((unsigned char) ((ctrl_log[ii]&0xff00)>>8));
    putchar((unsigned char) (ctrl_log[ii]&0x00ff));
65

66
67
68
69
70
71
72
73
74
75
76
77
    putchar((unsigned char) ((error_log[ii]&0xff00)>>8));
    putchar((unsigned char) (error_log[ii]&0x00ff));

    putchar((unsigned char) ((I_log[ii]&0xff000000)>>24));
    putchar((unsigned char) ((I_log[ii]&0x00ff0000)>>16));

    putchar((unsigned char) ((I_log[ii]&0x0000ff00)>>8));
    putchar((unsigned char) (I_log[ii]&0x000000ff));

    ii++;
  }
}
78
*/
79
80
81



82
/* Timer 2 compare match interupt, 28.8 kHz, syncronized with pwm-period */
83
SIGNAL(SIG_OUTPUT_COMPARE2) {
84

85
86
87
  // Start AD conversion
  ADCSRA |= BV(ADSC);
  
88
  // Read previous AD-conversion result
89
90
  low = inp(ADCL);
  high = inp(ADCH);
91
92
93
94
  y = ((int16_t)((high<<8) | low)) - 512; // y 9 frac bits

  // control error
  e = ref-y; // e 9 frac bits
95
  
96
  // temporary ctrl-signal
97
98
99
100
101
102
103
104
105
106
107
108
109
110
  v = (((K*e+64)>>7)+((I+8)>>4));

  // variable that decides if I-part should be updated
  intCond = 1;

  // saturation and update integral part of ctrl with antiwindup
  if (v > V_MAX) {
    vSat = V_MAX;
    if (e > 0)
      intCond = 0;
  } else if (v < V_MIN) {
    vSat = V_MIN;
    if (e < 0)
      intCond = 0; 
111
  } else {
112
    vSat = v;
113
  }
114
115
116
117

  if (intCond)
    I = I + (((Ke*e)+(1<<2))>>3);

118
  // ctrl signal, 7 bits + direction
119
  u = ((vSat+2)>>2); //7 frac bits to pwm 
120

121
122
  // set pwm switching time
  if (u < 0) {
123
    PORTC |= 0x80;  // set direction of motion
124
    OCR1BL = ((unsigned char) (-u)); // set length of pwm-high
125
  } else {
126
127
    PORTC &= 0x7f; // set direction of motion
    OCR1BL = ((unsigned char) (u)); // set length of pwm-high
128
129
  }

130
  
131
  // TWI-communication, recieve reference from velocity controller
132
133
  if ((BV(TWINT)&inp(TWCR))) {
    status = (inp(TWSR)&0xf8);
134
    // status 0x80 means data recieved
135
    if (status == 0x80) {
136
      ref = (int16_t)((int8_t)inp(TWDR)); // read 8 bit reference
Pontus Giselsson's avatar
Pontus Giselsson committed
137
      ref = (ref<<2);  // shift up 2 steps for 10 bits reference in loop
138
139
140
141
142
143
    } 
    else {
    }
    outp(BV(TWINT)|BV(TWEN)|BV(TWEA),TWCR);
  }

144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
  // For logging purposes
  /*
  countSamples++;
  if (countSamples == skipSamples) {
    ctrl_log[jj] = u;
    I_log[jj] = I;
    error_log[jj] = e;
    jj++;
    countSamples = 0;
    
    // Stop after a while
    if ((jj == (log_len-1)) & !stop) {
	outp(0x7f,OCR1BL);
	stop = 1;
	sendData();
    }
  }
  */
162
  
163
164
165
166
167
}


int main()
{
168
  // clear interrupts (might not be needed)
169
170
171
  cli();
  
  //Port directions
172
173
174
  outp(0x08,PORTC); // pull up on overtemperature signals
  outp(0xa0,DDRC);  // output on direction and brake
  outp(0x10,DDRD);  // output on pwm-signal
175
176
  outp(0x40,DDRB);  // temp pwm output

177
  /* Timer section */
Pontus Giselsson's avatar
Pontus Giselsson committed
178
  // Timer 1, fast PWM no prescaling (non-inverting mode (start high, switch to low))
179
  outp(BV(COM1B1)|BV(WGM11)|BV(WGM10),TCCR1A);
180
181
  outp(BV(CS10)|BV(WGM13)|BV(WGM12),TCCR1B);
  
182
  // Reset Timer1 and set TOP-value to 128 (means 7-bit pwm-signal-> 115.2 kHz)
183
184
185
186
187
188
189
  outp(0x00,OCR1AH);
  outp(0x7f,OCR1AL);
  outp(0x00,TCNT1H);
  outp(0x00,TCNT1L);
  outp(0x00,OCR1BH);
  outp(0x7f,OCR1BL); // to not start motor-rotation before control

190

191
  
192
  /* Timer 2, 4 times pwm-period, for control sampling, prescaler 8, 28.8 kHz */
193
194
195
196
  outp(BV(WGM21)|BV(CS21),TCCR2);
  outp(0x3f,OCR2);
  /* Reset timer 2 */
  outp(0,TCNT2);
197
198
199
200

  // Enable timer2 compare match interrupts
  outp(BV(OCIE2),TIMSK);

201
202
  //Serial communication
  outp(0x00, UCSRA);	// USART:
203
  outp(0x18, UCSRB);	// USART: RxEnable|TxEnable
204
205
206
207
  outp(0x86, UCSRC);	// USART: 8bit, no parity
  outp(0x00, UBRRH);	// USART: 115200 @ 14.7456MHz
  outp(7,UBRRL);	// USART: 115200 @ 14.7456MHz
  
208
  /* AREF (AREF is 5V) pin external capacitor, MUX0 for current measurement */
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
  outp(BV(REFS0)|BV(MUX0),ADMUX); 	
  
  // Enable ADC, start first conversion, prescaler 32, not free running mode
  outp(BV(ADEN)|BV(ADSC)|BV(ADPS2)|BV(ADPS0),ADCSRA);


  // Initialize TWI
  outp(0x02,TWBR);  // set SCL-frequency CPU-freq/(16+2*2)
  outp(0x02,TWAR);  // slave address
  outp(BV(TWEA)|BV(TWEN),TWCR); // enable TWI, enable ACK

  //Enable interrupts
  sei();

  // loop
  while (1) {}
}