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>
14 #include "hardware_settings.h"
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];
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
33 static volatile int16_t dac_val=800; // the current dac setting
35 // You must enable interrupt with sei() in the main program
36 // before you call init_analog
37 void init_analog(void)
39 // initialize the adc result to very high values
40 // to keep the control-loop down until proper measurements
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)
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
63 // 2.56V ref, start with channel 0
64 ADMUX=(1<<REFS1)|(1<<REFS0);
66 ADCSR=(1<<ADEN)|(1<<ADIE)|(1<<ADFR)|(1<<ADIF)|(1<<ADPS2)|(1<<ADPS1)|(0<<ADPS0);
72 int16_t get_dacval(void)
77 uint8_t is_current_limit(void)
79 // return 1 if current control loop active
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
90 void set_target_adc_val(uint8_t item,int16_t val)
92 // here we can directly write to target_val
96 int16_t getanalogresult(uint8_t channel)
98 return(analog_result[channel]);
101 // the control loop changes the dac:
102 static void control_loop(void){
104 tmp=target_val[0] - analog_result[0]; // current diff
106 // ** current control:
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
116 currentcontrol=10; // I control
117 if (analog_result[1]>target_val[1]){
118 // oh, voltage too high, get out of current control:
120 currentcontrol=0; // U control
123 // ** voltage control:
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
129 tmp=1+ target_val[1] - analog_result[1]; // voltage diff
132 // do not go up immediately after we came out of current control:
136 if (tmp> -3 && tmp<4){ // avoid LSB bouncing if we are close
139 if (tmp==0) return; // nothing to change
140 // put a cap on increase
144 // put a cap on decrease
152 dac_val=0xFFF; //max, 12bit
154 if (dac_val<400){ // the output is zero below 400 due to transistor threshold
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
163 * We do 4 fold oversampling as explained in atmel doc AVR121.
170 static uint8_t channel=0;
171 static uint8_t chpos=0;
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
182 ADMUX=(1<<REFS1)|(1<<REFS0)|channel;
183 // channel=1 = U, channel=0 = I
185 raw_analog_u_result[chpos]=currentadc;
187 // we do 4 bit oversampling to get 11bit ADC resolution
188 chpos=(chpos+1)%4; // rotate over 4
189 //analog_result[1]=0;
191 new_analog_u_result+=raw_analog_u_result[i];
194 new_analog_u_result=new_analog_u_result>>1; // 11bit
196 analog_result[1]=(new_analog_u_result+analog_result[1])/2;
198 analog_result[0]=currentadc; // 10bit
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){
211 // only after full measurement cycle
214 uart_poll_getchar_isr();
216 // end of interrupt handler