summaryrefslogtreecommitdiff
path: root/firmware/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/drivers')
-rw-r--r--firmware/drivers/adc.c85
1 files changed, 37 insertions, 48 deletions
diff --git a/firmware/drivers/adc.c b/firmware/drivers/adc.c
index 107674348d..4c9206e62b 100644
--- a/firmware/drivers/adc.c
+++ b/firmware/drivers/adc.c
@@ -22,25 +22,38 @@
22#include "thread.h" 22#include "thread.h"
23#include "adc.h" 23#include "adc.h"
24 24
25static int current_channel; 25/* This driver updates the adcdata[] array by converting one A/D channel
26 group on each system tick. Each group is 4 channels, which means that
27 it takes 2 ticks to convert all 8 channels. */
28
29static int current_group;
26static unsigned short adcdata[NUM_ADC_CHANNELS]; 30static unsigned short adcdata[NUM_ADC_CHANNELS];
27static unsigned int adcreg[NUM_ADC_CHANNELS] =
28{
29 ADDRAH_ADDR, ADDRBH_ADDR, ADDRCH_ADDR, ADDRDH_ADDR,
30 ADDRAH_ADDR, ADDRBH_ADDR, ADDRCH_ADDR, ADDRDH_ADDR
31};
32 31
33static void adc_tick(void) 32static void adc_tick(void)
34{ 33{
35 /* Read the data that has bee converted since the last tick */ 34 /* Copy the data from the previous conversion */
36 adcdata[current_channel] = 35 if(current_group)
37 *(unsigned short *)adcreg[current_channel] >> 6; 36 {
37 adcdata[4] = ADDRA >> 6;
38 adcdata[5] = ADDRB >> 6;
39 adcdata[6] = ADDRC >> 6;
40 adcdata[7] = ADDRD >> 6;
41 }
42 else
43 {
44 adcdata[0] = ADDRA >> 6;
45 adcdata[1] = ADDRB >> 6;
46 adcdata[2] = ADDRC >> 6;
47 adcdata[3] = ADDRD >> 6;
48 }
38 49
39 /* Start a conversion on the next channel */ 50 /* Start converting the next group */
40 current_channel++; 51 current_group = !current_group;
41 if(current_channel == NUM_ADC_CHANNELS) 52 ADCSR = ADCSR_ADST | ADCSR_SCAN | (current_group?4:0) | 3;
42 current_channel = 0; 53
43 ADCSR = ADCSR_ADST | current_channel; 54 /* The conversion will be ready when we serve the next tick interrupt.
55 No need to check ADCSR for finished conversion since the conversion
56 will be ready long before the next tick. */
44} 57}
45 58
46unsigned short adc_read(int channel) 59unsigned short adc_read(int channel)
@@ -48,44 +61,20 @@ unsigned short adc_read(int channel)
48 return adcdata[channel]; 61 return adcdata[channel];
49} 62}
50 63
51/* Batch convert 4 analog channels. If lower is true, convert AN0-AN3,
52 * otherwise AN4-AN7.
53 */
54static void adc_batch_convert(bool lower)
55{
56 int reg = lower ? 0 : 4;
57 volatile unsigned short* ANx = ((unsigned short*) ADDRAH_ADDR);
58 int i;
59
60 ADCSR = ADCSR_ADST | ADCSR_SCAN | ADCSR_CKS | reg | 3;
61
62 /* Busy wait until conversion is complete. A bit ugly perhaps, but
63 * we should only need to wait about 4 * 14 µs */
64 while(!(ADCSR & ADCSR_ADF))
65 {
66 }
67
68 /* Stop scanning */
69 ADCSR = 0;
70
71 for (i = 0; i < 4; i++)
72 {
73 /* Read converted values */
74 adcdata[reg++] = ANx[i] >> 6;
75 }
76}
77
78void adc_init(void) 64void adc_init(void)
79{ 65{
80 ADCR = 0x7f; /* No external trigger; other bits should be 1 according to the manual... */ 66 ADCR = 0x7f; /* No external trigger; other bits should be 1 according
67 to the manual... */
81 68
82 current_channel = 0; 69 /* Make sure that there is no conversion running */
70 ADCSR = 0;
83 71
84 /* Do a first scan to initialize all values */ 72 /* Start with converting group 0 by setting current_group to 1 */
85 /* AN4 to AN7 */ 73 current_group = 1;
86 adc_batch_convert(false);
87 /* AN0 to AN3 */
88 adc_batch_convert(true);
89 74
90 tick_add_task(adc_tick); 75 tick_add_task(adc_tick);
76
77 /* Wait until both groups have been converted before we continue,
78 so adcdata[] contains valid data */
79 sleep(2);
91} 80}