-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathexample.c
328 lines (289 loc) · 7.8 KB
/
example.c
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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
/*
This example is not meant to be compiled without errors, but just some lines of code to show how to use the functions. The
code basically samples audio at 16 khz, runs a decimation filter, and outputs audio to a I2C D/A converter at 8 khz rate. If
the wire library were used, you would see on a scope that you are using 3/4 of your processing time just waiting on the
I2C writes to the D/A audio out. The routines here do not waste time.
*/
#define D2A_AUDIO 0x63 // audio output address
// polling I2C implementation
#define I2BUFSIZE 128
int i2buf[I2BUFSIZE];
int i2in, i2out;
setup(){
pinMode( 45, INPUT );
pinMode( 46, INPUT ); // ?? needed for i2c, I do not know if these are needed
I2C1CONSET = 0x8000; // I2C on bit
I2C1BRG = 90; // 400 khz
i2stop(); // clear any extraneous info that devices may have detected on powerup
i2cd( D2A_AUDIO, 8, 0x00 ); // half scale audio out 0x800 for 12 bit d/a converter
attachCoreTimerService( dsp_core ); // audio processing
i2flush(); // although we didn't write anywhere near 128 entries into the queue with this example, if
// we did have many I2C devices to initialize, we would call i2flush to empty the queue when needed.
}
loop(){
i2poll(); // keep the i2c bus running
if( audio_flag ){
// digitalWrite( BACKLIGHT, LOW ); // scope trigger
audio *= 2; // gain
audio += 2048; // 12 bits output D/A mid point
i2cd( D2A_AUDIO, ((audio >> 8 )& 0xff), audio & 0xff );
audio_flag = 0;
// digitalWrite( BACKLIGHT, HIGH );
}
// do more useful work here in loop.....
}
void i2cd( unsigned char addr, unsigned char reg, unsigned char dat ){
i2start( addr );
i2send( (int) reg ); // register or 1st data byte if no registers in device
i2send( (int) dat );
i2stop();
}
uint32_t dsp_core( uint32_t timer ){
long sample;
static long w[32]; // delay line
static int win;
static int flip;
int i,j;
// cw filter variables
static long wc[32];
static int wcin;
sample = analogRead( A0 ); // 10 bits in
// run a decimation filter for 16k to 8k rate
i = win;
w[win++] = sample - 512; // store in delay line, remove dc component of the signal
win &= 31;
flip ^= 1;
if( flip ){ // only need to run the filter at the slower rate
sample = 0; // accumulator
for( j = 0; j < 32; j++ ){
sample += fc[j] * w[i++];
i &= 31;
}
audio = sample >> 15;
if( mode == CW ){ // run the cw filter at 8k rate
sample = 0;
i = wcin;
wc[wcin++] = audio;
wcin &= 31;
for( j = 0; j < 32; j++ ){
sample += fcw[j] * wc[i++];
i &= 31;
}
audio = sample >> 15;
}
audio_flag = 1;
}
return timer + 2500; // 2500 == 16k, 5000 == 8k sample rate, 6250 == 6400 hz sample rate
}
/* I2C write only implementation using polling of the hardware registers */
/* functions do not block */
/* call i2poll() in loop() to keep everything going */
// use some upper bits in the buffer for control
#define ISTART 0x100
#define ISTOP 0x200
void i2start( unsigned char adr ){
int dat;
// shift the address over and add the start flag
dat = ( adr << 1 ) | ISTART;
i2send( dat );
}
void i2send( int data ){ // just save stuff in the buffer
i2buf[i2in++] = data;
i2in &= (I2BUFSIZE - 1);
}
void i2stop( ){
i2send( ISTOP ); // que a stop condition
}
void i2flush(){ // needed during setup, call poll to empty out the buffer. This one does block.
while( i2poll() );
}
int i2poll(){ // everything happens here. Call this from loop.
static int state = 0;
static int data;
static int delay_counter;
if( delay_counter ){ // the library code has a delay after loading the transmit buffer and before the status bits are tested for transmit active
--delay_counter;
return (16 + delay_counter);
}
switch( state ){
case 0: // idle state or between characters
if( i2in != i2out ){ // get next character
data = i2buf[i2out++];
i2out &= (I2BUFSIZE - 1 );
if( data & ISTART ){ // start
data &= 0xff;
// set start condition
I2C1CONSET = 1;
state = 1;
}
else if( data & ISTOP ){ // stop
// set stop condition
I2C1CONSET = 4;
state = 3;
}
else{ // just data to send
I2C1TRN = data;
delay_counter = 10; // delay for transmit active to come true
state = 2;
}
}
break;
case 1: // wait for start to clear, send saved data which has the address
if( (I2C1CON & 1) == 0 ){
state = 2;
I2C1TRN = data;
delay_counter = 10;
}
break;
case 2: // wait for ack/nack done and tbuffer empty, blind to success or fail
if( (I2C1STAT & 0x4001 ) == 0){
state = 0;
}
break;
case 3: // wait for stop to clear
if( (I2C1CON & 4 ) == 0 ){
state = 0;
delay_counter = 10; // a little delay just for fun at the end of a sequence
}
break;
}
// detect any error bits and see if can recover, advance to next start in the buffer
// totally blind for now until we check some error bits
if( i2in != i2out ) return (state + 8);
else return state;
}
// here are the filter coefficients if your interested in them. Normally these would be declared before the dsp_core function.
// lowpass fir decimation filter constants, 3000 cutoff 4000 stop at 16k rate
long fc[ 32 ] = {
// 0 . 006820q15 ,
223,
// , 0 . 011046q15 ,
361,
// , - 0 . 004225q15 ,
-138,
// , - 0 . 016811q15 ,
-550,
// , - 0 . 001921q15 ,
-62,
// , 0 . 021797q15 ,
714,
// , 0 . 012515q15 ,
410,
// , - 0 . 024048q15 ,
-788,
// , - 0 . 028414q15 ,
-931,
// , 0 . 020730q15 ,
679,
// , 0 . 051289q15 ,
1680,
// , - 0 . 006587q15 ,
-215,
// , - 0 . 087749q15 ,
-2875,
// , - 0 . 036382q15 ,
-1192,
// , 0 . 186091q15 ,
6097,
// , 0 . 403613q15 ,
13225,
// , 0 . 403613q15 ,
13225,
// , 0 . 186091q15 ,
6097,
// , - 0 . 036382q15 ,
-1192,
// , - 0 . 087749q15 ,
-2875,
// , - 0 . 006587q15 ,
-215,
// , 0 . 051289q15 ,
1680,
// , 0 . 020730q15 ,
679,
// , - 0 . 028414q15 ,
-931,
// , - 0 . 024048q15 ,
-788,
// , 0 . 012515q15 ,
410,
// , 0 . 021797q15 ,
714,
// , - 0 . 001921q15 ,
-62,
// , - 0 . 016811q15 ,
-550,
// , - 0 . 004225q15 ,
-138,
// , 0 . 011046q15 ,
361,
// , 0 . 006820q15
223
};
// cw filter 400 hz wide centered at about 600 hz
int fcw[ 32 ] = {
// - 0 . 000426q15 ,
-13,
// , - 0 . 003116q15 ,
-102,
// , - 0 . 005389q15 ,
-176,
// , - 0 . 003948q15 ,
-129,
// , 0 . 001048q15 ,
34,
// , 0 . 004523q15 ,
148,
// , - 0 . 001170q15 ,
-38,
// , - 0 . 020961q15 ,
-686,
// , - 0 . 051978q15 ,
-1703,
// , - 0 . 082194q15 ,
-2693,
// , - 0 . 094538q15 ,
-3097,
// , - 0 . 075093q15 ,
-2460,
// , - 0 . 021324q15 ,
-698,
// , 0 . 054266q15 ,
1778,
// , 0 . 127619q15 ,
4181,
// , 0 . 172683q15 ,
5658,
// , 0 . 172683q15 ,
5658,
// , 0 . 127619q15 ,
4181,
// , 0 . 054266q15 ,
1778,
// , - 0 . 021324q15 ,
-698,
// , - 0 . 075093q15 ,
-2460,
// , - 0 . 094538q15 ,
-3097,
// , - 0 . 082194q15 ,
-2693,
// , - 0 . 051978q15 ,
-1703,
// , - 0 . 020961q15 ,
-686,
// , - 0 . 001170q15 ,
-38,
// , 0 . 004523q15 ,
148,
// , 0 . 001048q15 ,
34,
// , - 0 . 003948q15 ,
-129,
// , - 0 . 005389q15 ,
-176,
// , - 0 . 003116q15 ,
-102,
// , - 0 . 000426q15
-13,
};