-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathadc.ceu
129 lines (101 loc) · 3.55 KB
/
adc.ceu
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
///////////////////////////////////////////////////////////////////////////////
// EXTERNAL INTERFACE
///////////////////////////////////////////////////////////////////////////////
output on/off ADC;
output int ADC_REQUEST;
input none ADC_DONE;
code/await Adc (none) -> NEVER;
code/await Adc_Conversion (var int pin) -> int;
///////////////////////////////////////////////////////////////////////////////
// INTERNAL INTERFACE
///////////////////////////////////////////////////////////////////////////////
#ifndef CEU_ADC_IRQ_N
#error missing `CEU_ADC_IRQ_N`
#endif
native/pre do
void ceu_adc_init (void);
void ceu_adc (bool v);
void ceu_adc_request (int pin);
u16 ceu_adc_done (void);
end
///////////////////////////////////////////////////////////////////////////////
// INITIALIZATION
///////////////////////////////////////////////////////////////////////////////
#define ADC_N 6
var int? adc_channel_busy; // current working channel
var byte adc_pending = 0; // bit vectors with requested pending channels
data ADC_Channel with
var bool is_available = false;
var bool is_busy = false;
var int value;
end
var[ADC_N] ADC_Channel adc_channels;
do
var ADC_Channel ch = val ADC_Channel(_,_,_);
adc_channels = adc_channels .. [ ch, ch, ch, ch, ch, ch ];
end
{ ceu_adc_init(); }
///////////////////////////////////////////////////////////////////////////////
// INPUT / OUTPUT
///////////////////////////////////////////////////////////////////////////////
output (on/off v) ADC do
{ ceu_adc(@v); }
end
output (int pin) ADC_REQUEST do
var int idx = (pin - _A0);
_ceu_assert(idx>=0 and idx<ADC_N, "pin is out of range");
if outer.adc_channel_busy? then
outer.adc_pending = outer.adc_pending | (1 << idx);
escape;
end
outer.adc_channel_busy = idx;
{ ceu_adc_request(@pin); }
end
spawn async/isr [CEU_ADC_IRQ_N, 0] do
var int idx = outer.adc_channel_busy!;
outer.adc_channel_busy = _;
var u16 value = { ceu_adc_done() };
outer.adc_channels[idx].value = value as int;
outer.adc_channels[idx].is_available = true;
emit ADC_DONE;
// gets next conversion in queue
outer.adc_pending = outer.adc_pending & ((1 << idx) ^ 0xFF);
do
var byte mask = {0b00000001};
var int i;
loop i in [0 -> ADC_N[ do
if (outer.adc_pending & mask) != 0 then
emit ADC_REQUEST(_A0+i); // starts new conversion
escape; // prevents interrupt clear below
end
mask = mask << 1;
end
end
end
///////////////////////////////////////////////////////////////////////////////
// ABSTRACTIONS
///////////////////////////////////////////////////////////////////////////////
code/await Adc (none) -> NEVER do
emit ADC(on);
do finalize with
emit ADC(off);
end
await FOREVER;
end
code/await Adc_Conversion (var int pin) -> int do
var int idx = (pin - _A0);
_ceu_assert(idx>=0 and idx<ADC_N, "pin is out of range");
_ceu_assert(not outer.adc_channels[idx].is_busy, "bug found");
{ceu_pm_set(CEU_PM_ADC, 1);}
outer.adc_channels[idx].is_busy = true;
do finalize with
if outer.adc_pending == 0 then
{ceu_pm_set(CEU_PM_ADC, 0);}
end
outer.adc_channels[idx].is_busy = false;
end
emit ADC_REQUEST(pin);
await ADC_DONE until outer.adc_channels[idx].is_available;
outer.adc_channels[idx].is_available = false;
escape outer.adc_channels[idx].value;
end