1 /* vim: set sw=8 ts=8 si : */
2 /*********************************************
3 * Author: Guido Socher, Copyright: GPL
5 * Digital analog conversion of channel ADC0 and ADC1 in
7 **********************************************/
8 #include <avr/interrupt.h>
13 #include "hardware_settings.h"
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];
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
32 static volatile int16_t dac_val=800; // the current dac setting
34 // You must enable interrupt with sei() in the main program
35 // before you call init_analog
36 void init_analog(void)
38 // initialize the adc result to very high values
39 // to keep the control-loop down until proper measurements
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)
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
62 // 2.56V ref, start with channel 0
63 ADMUX=(1<<REFS1)|(1<<REFS0);
65 ADCSR=(1<<ADEN)|(1<<ADIE)|(1<<ADFR)|(1<<ADIF)|(1<<ADPS2)|(1<<ADPS1)|(0<<ADPS0);
71 int16_t get_dacval(void)
76 uint8_t is_current_limit(void)
78 // return 1 if current control loop active
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
89 void set_target_adc_val(uint8_t item,int16_t val)
91 // here we can directly write to target_val
95 int16_t getanalogresult(uint8_t channel)
97 return(analog_result[channel]);
100 // the control loop changes the dac:
101 static void control_loop(void){
104 tmp=target_val[0] - analog_result[0]; // current diff
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
114 currentcontrol=40; // I control
115 if (analog_result[1]>target_val[1]){
117 currentcontrol=0; // U control
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
124 tmp=1 + target_val[1] - analog_result[1]; // voltage diff
128 if (currentcontrol%8==0){
129 // slowly up, 20 will become 1 further down
137 return; // nothing to change
139 if (tmp> -5 && tmp<5){ // avoid LSB bouncing if we are close
157 // put a cap on increase
161 // put a cap on decrease
167 dac_val=0xFFF; //max, 12bit
169 if (dac_val<400){ // the output is zero below 400 due to transistor threshold
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
178 * We do 4 fold oversampling as explained in atmel doc AVR121.
185 static uint8_t channel=0;
186 static uint8_t chpos=0;
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
197 ADMUX=(1<<REFS1)|(1<<REFS0)|channel;
198 // channel=1 = U, channel=0 = I
200 raw_analog_u_result[chpos]=currentadc;
202 // we do 4 bit oversampling to get 11bit ADC resolution
203 chpos=(chpos+1)%4; // rotate over 4
204 //analog_result[1]=0;
206 new_analog_u_result+=raw_analog_u_result[i];
209 new_analog_u_result=new_analog_u_result>>1; // 11bit
211 analog_result[1]=(new_analog_u_result+analog_result[1])/2;
213 analog_result[0]=currentadc; // 10bit
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){
226 // only after full measurement cycle
229 // end of interrupt handler