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