0.6.0 this is the first version for the new hardware
[digitaldcpower] / analog.c
1 /* vim: set sw=8 ts=8 si : */
2 /*********************************************
3 * Author: Guido Socher, Copyright: GPL 
4 *
5 * Digital analog conversion of channel ADC0 and ADC1 in
6 * free running mode. 
7 **********************************************/
8 #include <avr/interrupt.h>
9 #include <avr/io.h>
10 #include <inttypes.h>
11 #include <stdlib.h>
12 #include "dac.h"
13 #include "hardware_settings.h"
14
15
16 //debug LED:
17 // set output to VCC, red LED off
18 #define LEDOFF PORTD|=(1<<PORTD0)
19 // set output to GND, red LED on
20 #define LEDON PORTD&=~(1<<PORTD0)
21 // to test the state of the LED
22 #define LEDISOFF PORTD&(1<<PORTD0)
23 static volatile uint8_t currentcontrol=1; // 0=voltage control, otherwise current control
24 // adc measurement results (11bit ADC):
25 static volatile int16_t analog_result[2];  
26
27
28 // target_val is the value that is requested (control loop calibrates to this).
29 // We use the same units a the ADC produces.
30 static volatile int16_t target_val[2];  // datatype int is 16 bit
31
32 static volatile int16_t dac_val=800; // the current dac setting
33
34 // You must enable interrupt with sei() in the main program 
35 // before you call init_analog 
36 void init_analog(void) 
37 {
38         // initialize the adc result to very high values
39         // to keep the control-loop down until proper measurements
40         // are done:
41         analog_result[0]=0; // I
42         analog_result[1]=20;  // U
43         target_val[0]=0; // initialize to zero, I
44         target_val[1]=0; // initialize to zero, U
45         /* enable analog to digital conversion in free run mode
46         *  without noise canceler function. See datasheet of atmega8a page 210
47         * We set ADPS2=1,ADPS1=1,ADPS0=0 to have a clock division factor of 64.
48         * This is needed to stay in the recommended range of 50-200kHz 
49         * ADEN: Analog Digital Converter Enable
50         * ADIE: ADC Interrupt Enable
51         * ADIF: ADC Interrupt Flag
52         * ADFR: ADC Free Running Mode
53         * ADCSR: ADC Control and Status Register
54         * ADPS2..ADPS0: ADC Prescaler Select Bits
55         * REFS: Reference Selection Bits (page 203)
56         */
57
58         // int-ref with external capacitor at AREF pin: 
59         // 2.56V int ref=REFS1=1,REFS0=1
60         // write only the lower 3 bit for channel selection
61         
62         // 2.56V ref, start with channel 0
63         ADMUX=(1<<REFS1)|(1<<REFS0);
64
65         ADCSR=(1<<ADEN)|(1<<ADIE)|(1<<ADFR)|(1<<ADIF)|(1<<ADPS2)|(1<<ADPS1)|(0<<ADPS0);
66
67         //  start conversion 
68         ADCSR|=(1<<ADSC);
69 }
70
71 int16_t get_dacval(void) 
72 {
73         return(dac_val);
74 }
75
76 uint8_t is_current_limit(void) 
77 {
78         // return 1 if current control loop active
79         if (currentcontrol){
80                 return(1);
81         }
82         return(0);
83 }
84
85 /* set the target adc value for the control loop
86  * values for item: 1 = u, 0 = i, units must be of the same as the values 
87  * from the dac.
88  */
89 void set_target_adc_val(uint8_t item,int16_t val) 
90 {
91         // here we can directly write to target_val 
92         target_val[item]=val;
93 }
94
95 int16_t getanalogresult(uint8_t channel) 
96 {
97         return(analog_result[channel]);
98 }
99
100 // the control loop changes the dac:
101 static void control_loop(void){
102         int16_t tmp;
103         int8_t ptmp=0;
104         tmp=target_val[0] - analog_result[0]; // current diff
105         if (tmp <0){
106                 // stay in currnet control if we are
107                 // close to the target. We never regulate
108                 // the difference down to zero otherweise
109                 // we would suddenly hop to voltage control
110                 // and then back to current control. Permanent
111                 // hopping would lead to oscillation and current
112                 // spikes.
113                 if (tmp>-4) tmp=0;
114                 currentcontrol=40; // I control
115                 if (analog_result[1]>target_val[1]){
116                         tmp=-20;
117                         currentcontrol=0; // U control
118                 }
119         }else{
120                 // if we are in current control then we can only go
121                 // down (tmp is negative). To increase the current
122                 // we come here to voltage control. We must slowly
123                 // count up.
124                 tmp=1 + target_val[1]  - analog_result[1]; // voltage diff
125                 //
126                 if (currentcontrol){
127                         currentcontrol--;
128                         if (currentcontrol%8==0){
129                                 // slowly up, 20 will become 1 further down
130                                 if (tmp>0) tmp=20;
131                         }else{
132                                 tmp=0;
133                         }
134                 }
135         }
136         if (tmp==0){
137                 return; // nothing to change
138         }
139         if (tmp> -5 && tmp<5){ // avoid LSB bouncing if we are close
140                 if (tmp>0){
141                         ptmp++;
142                         tmp=0;
143                         if (ptmp>1){
144                                 tmp=1;
145                                 ptmp=0;
146                         }
147                 }
148                 if (tmp<0){
149                         ptmp--;
150                         tmp=0;
151                         if (ptmp<-1){
152                                 tmp=-1;
153                                 ptmp=0;
154                         }
155                 }
156         }
157         // put a cap on increase
158         if (tmp>1){
159                 tmp=1;
160         }
161         // put a cap on decrease
162         if (tmp<-1){
163                 tmp=-1;
164         }
165         dac_val+=tmp;
166         if (dac_val>0xFFF){
167                 dac_val=0xFFF; //max, 12bit
168         }
169         if (dac_val<400){  // the output is zero below 400 due to transistor threshold
170                 dac_val=400;
171         }
172         dac(dac_val);
173 }
174 /* the following function will be called when analog conversion is done.
175  * It will be called every 13th cycle of the converson clock. At 8Mhz
176  * and a ADPS factor of 64 this is: ((8000 kHz/ 64) / 13)= 9.6KHz intervalls
177  *
178  * We do 4 fold oversampling as explained in atmel doc AVR121.
179  */
180 //SIGNAL(SIG_ADC) {
181 ISR(ADC_vect) {
182         uint8_t i=0;
183         uint8_t adlow;
184         int16_t currentadc;
185         static uint8_t channel=0; 
186         static uint8_t chpos=0;
187         // raw 10bit values:
188         static int16_t raw_analog_u_result[8];  
189         int16_t new_analog_u_result=0;
190         adlow=ADCL; // read low first !! 
191         currentadc=(ADCH<<8)|adlow;
192         // toggel the channel between 0 an 1. This will however
193         // not effect the next conversion as that one is already
194         // ongoing.
195         channel^=1;
196         // 2.56V ref
197         ADMUX=(1<<REFS1)|(1<<REFS0)|channel;
198         // channel=1 = U, channel=0 = I
199         if (channel==1) {
200                 raw_analog_u_result[chpos]=currentadc;
201                 //
202                 // we do 4 bit oversampling to get 11bit ADC resolution
203                 chpos=(chpos+1)%4; // rotate over 4 
204                 //analog_result[1]=0;
205                 while(i<4){
206                         new_analog_u_result+=raw_analog_u_result[i];
207                         i++;
208                 }
209                 new_analog_u_result=new_analog_u_result>>1; // 11bit
210                 // mean value:
211                 analog_result[1]=(new_analog_u_result+analog_result[1])/2; 
212         }else{
213                 analog_result[0]=currentadc; // 10bit
214         }
215         // short circuit protection does not use the over sampling results
216         // for speed reasons.
217         // short circuit protection, current is 10bit ADC
218         if (channel==0 && currentadc > SH_CIR_PROT){
219                 dac_val=400;
220                 dac(dac_val);
221                 currentcontrol=20;
222                 return;
223         }
224         //
225         if (channel==1){
226                 // only after full measurement cycle
227                 control_loop();
228         }
229         // end of interrupt handler
230 }
231