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){
105 tmp=target_val[0] - analog_result[0]; // current diff
107 // stay in currnet control if we are
108 // close to the target. We never regulate
109 // the difference down to zero otherweise
110 // we would suddenly hop to voltage control
111 // and then back to current control. Permanent
112 // hopping would lead to oscillation and current
115 currentcontrol=40; // I control
116 if (analog_result[1]>target_val[1]){
118 currentcontrol=0; // U control
121 // if we are in current control then we can only go
122 // down (tmp is negative). To increase the current
123 // we come here to voltage control. We must slowly
125 tmp=1 + target_val[1] - analog_result[1]; // voltage diff
129 if (currentcontrol%8==0){
130 // slowly up, 20 will become 1 further down
138 return; // nothing to change
140 if (tmp> -5 && tmp<5){ // avoid LSB bouncing if we are close
158 // put a cap on increase
162 // put a cap on decrease
168 dac_val=0xFFF; //max, 12bit
170 if (dac_val<400){ // the output is zero below 400 due to transistor threshold
175 /* the following function will be called when analog conversion is done.
176 * It will be called every 13th cycle of the converson clock. At 8Mhz
177 * and a ADPS factor of 64 this is: ((8000 kHz/ 64) / 13)= 9.6KHz intervalls
179 * We do 4 fold oversampling as explained in atmel doc AVR121.
186 static uint8_t channel=0;
187 static uint8_t chpos=0;
189 static int16_t raw_analog_u_result[8];
190 int16_t new_analog_u_result=0;
191 adlow=ADCL; // read low first !!
192 currentadc=(ADCH<<8)|adlow;
193 // toggel the channel between 0 an 1. This will however
194 // not effect the next conversion as that one is already
198 ADMUX=(1<<REFS1)|(1<<REFS0)|channel;
199 // channel=1 = U, channel=0 = I
201 raw_analog_u_result[chpos]=currentadc;
203 // we do 4 bit oversampling to get 11bit ADC resolution
204 chpos=(chpos+1)%4; // rotate over 4
205 //analog_result[1]=0;
207 new_analog_u_result+=raw_analog_u_result[i];
210 new_analog_u_result=new_analog_u_result>>1; // 11bit
212 analog_result[1]=(new_analog_u_result+analog_result[1])/2;
214 analog_result[0]=currentadc; // 10bit
216 // short circuit protection does not use the over sampling results
217 // for speed reasons.
218 // short circuit protection, current is 10bit ADC
219 if (channel==0 && currentadc > SH_CIR_PROT){
227 // only after full measurement cycle
230 uart_poll_getchar_isr();
232 // end of interrupt handler