giuliomoro@301
|
1 #include <Bela.h>
|
giuliomoro@189
|
2 #include <Utilities.h>
|
giuliomoro@189
|
3 #include <cmath>
|
giuliomoro@189
|
4 #include <rtdk.h>
|
giuliomoro@189
|
5 #include <sys/time.h>
|
giuliomoro@189
|
6 #include <sys/types.h>
|
giuliomoro@189
|
7 #include <unistd.h>
|
giuliomoro@189
|
8 #include <stats.hpp>
|
giuliomoro@189
|
9 // setup() is called once before the audio rendering starts.
|
giuliomoro@189
|
10 // Use it to perform any initialisation and allocation which is dependent
|
giuliomoro@189
|
11 // on the period size or sample rate.
|
giuliomoro@189
|
12 //
|
giuliomoro@189
|
13 // userData holds an opaque pointer to a data structure that was passed
|
giuliomoro@189
|
14 // in from the call to initAudio().
|
giuliomoro@189
|
15 //
|
giuliomoro@189
|
16 // Return true on success; returning false halts the program.
|
giuliomoro@189
|
17
|
giuliomoro@189
|
18
|
giuliomoro@189
|
19 // digital inputs can be changed at will (as they are all being processed at the same time)
|
giuliomoro@189
|
20 // analog channels must be as per below
|
giuliomoro@189
|
21 int gAnalogOutCh = 1;
|
giuliomoro@189
|
22 int gDigitalOutCh = 2;
|
giuliomoro@189
|
23 int gDigitalInACh = 0;
|
giuliomoro@189
|
24 int gDigitalInDCh = 3;
|
giuliomoro@189
|
25 int gAnalogOutLoopDelay;
|
giuliomoro@189
|
26 int gDigitalOutLoopDelay;
|
giuliomoro@301
|
27 bool setup(BelaContext *context, void *userData)
|
giuliomoro@189
|
28 {
|
giuliomoro@189
|
29 rt_printf("For this test you need the following connections:\n"
|
giuliomoro@189
|
30 "analog%d out->digital%d in, analog%d out->analog%d in, "
|
giuliomoro@189
|
31 "digital%d out -> digital%d in, digital%d out-> analog%d in\n",
|
giuliomoro@189
|
32 gAnalogOutCh, gDigitalInACh, gAnalogOutCh, 0, gDigitalOutCh, gDigitalInDCh, gDigitalOutCh, 0);
|
giuliomoro@189
|
33 rt_printf("Running test with %d analog channels and a buffer size of %d\n",
|
giuliomoro@189
|
34 context->analogChannels, context->audioFrames);
|
giuliomoro@189
|
35
|
giuliomoro@189
|
36 for(unsigned int n = 0; n < context->digitalFrames; n++){
|
andrewm@310
|
37 pinMode(context, n, gDigitalInACh, INPUT);
|
andrewm@310
|
38 pinMode(context, n, gDigitalInDCh, INPUT);
|
andrewm@310
|
39 pinMode(context, n, gDigitalOutCh, OUTPUT);
|
giuliomoro@189
|
40 }
|
giuliomoro@189
|
41 switch (context->analogChannels){
|
giuliomoro@189
|
42 case 2:
|
giuliomoro@189
|
43 gAnalogOutLoopDelay = context->audioFrames*2 + 3;
|
giuliomoro@189
|
44 gDigitalOutLoopDelay = context->audioFrames*2 + 2;
|
giuliomoro@189
|
45 break;
|
giuliomoro@189
|
46 case 4:
|
giuliomoro@189
|
47 gAnalogOutLoopDelay = context->audioFrames*2 + 3;
|
giuliomoro@189
|
48 gDigitalOutLoopDelay = context->audioFrames*2 + 2;
|
giuliomoro@189
|
49 break;
|
giuliomoro@189
|
50 case 8:
|
giuliomoro@189
|
51 gAnalogOutLoopDelay = context->audioFrames + 3;
|
giuliomoro@189
|
52 gDigitalOutLoopDelay = context->audioFrames + 1;
|
giuliomoro@189
|
53 break;
|
giuliomoro@189
|
54 default:
|
giuliomoro@189
|
55 exit(2);
|
giuliomoro@189
|
56 }
|
giuliomoro@189
|
57
|
giuliomoro@189
|
58 return true;
|
giuliomoro@189
|
59 }
|
giuliomoro@189
|
60
|
giuliomoro@189
|
61 // render() is called regularly at the highest priority by the audio engine.
|
giuliomoro@189
|
62 // Input and output are given from the audio hardware and the other
|
giuliomoro@189
|
63 // ADCs and DACs (if available). If only audio is available, numAnalogFrames
|
giuliomoro@189
|
64 // will be 0.
|
giuliomoro@189
|
65
|
giuliomoro@189
|
66 const int patternLength = 31;
|
giuliomoro@189
|
67 static int anaErrorCount = 0;
|
giuliomoro@189
|
68 static int digErrorCount = 0;
|
giuliomoro@301
|
69 void render(BelaContext *context, void *userData)
|
giuliomoro@189
|
70 {
|
giuliomoro@189
|
71 static bool writePattern[patternLength] = {
|
giuliomoro@189
|
72 0,1,0,1,0,0,1,1,
|
giuliomoro@189
|
73 0,0,0,1,1,1,0,0,
|
giuliomoro@189
|
74 1,1,1,1,0,0,0,0,
|
giuliomoro@189
|
75 1,1,1,1,1,0,0};
|
giuliomoro@189
|
76 // for(int n = 0; n < patternLength; n++){
|
giuliomoro@189
|
77 // writePattern[n]=1;
|
giuliomoro@189
|
78 // }
|
giuliomoro@189
|
79 static int inPointer = 0;
|
giuliomoro@189
|
80 static int outPointer = 0;
|
giuliomoro@189
|
81 static int digitalOutPointer = 0;
|
giuliomoro@189
|
82 static int digitalInPointer = 0;
|
giuliomoro@189
|
83 static int analogOut = 1;
|
giuliomoro@189
|
84 /** Checking offset between analog and digital
|
giuliomoro@189
|
85 * how it should be :
|
giuliomoro@189
|
86 * The PRU loop does the following (the loop runs at 88.2kHz):
|
giuliomoro@189
|
87 * - Read/write audio sample (once for the left channel, once for the right channel)
|
giuliomoro@189
|
88 * - Write DAC 0 or 0/2 or 0/2/4/6
|
giuliomoro@189
|
89 * - Read ADC 0 or 0/2 or 0/2/4/6, 2 samples (@176.4) older than NOW
|
giuliomoro@189
|
90 * - /During/ the line above, every two loops we also Read/Write GPIO,
|
giuliomoro@189
|
91 * therefore reading on ADC 0/2/4/6 a value that is being output from GPIO will lead to undefined results
|
giuliomoro@189
|
92 * - Write DAC 1 or 1/3 or 1/3/5/7
|
giuliomoro@189
|
93 * - Read ADC 1 or 1/3 or 1/3/5/7, 2 samples (@176.4) older than NOW
|
giuliomoro@189
|
94 */
|
giuliomoro@189
|
95 if(1)
|
giuliomoro@189
|
96 for(unsigned int n = 0; n < context->audioFrames; n++){
|
giuliomoro@189
|
97 static bool analog0In = false;
|
giuliomoro@189
|
98 static bool digitalAIn = false;
|
giuliomoro@189
|
99 static int count = 0;
|
giuliomoro@189
|
100 bool doReadWrite = context->analogChannels<=4 ? true : ((context->analogChannels == 8) && (n&1)==0);
|
giuliomoro@189
|
101 if(doReadWrite){
|
andrewm@308
|
102 digitalAIn = digitalRead(context, n, gDigitalInACh);
|
giuliomoro@189
|
103 switch(context->analogChannels){
|
giuliomoro@189
|
104 case 8:
|
andrewm@308
|
105 analog0In = analogRead(context, n/2, 0) > 0.5;
|
andrewm@308
|
106 analogWrite(context, n/2, analogOut, writePattern[outPointer]);
|
giuliomoro@189
|
107 break;
|
giuliomoro@189
|
108 case 4:
|
andrewm@308
|
109 analog0In = analogRead(context, n, 0) > 0.5;
|
andrewm@308
|
110 analogWrite(context, n, analogOut, writePattern[outPointer]);
|
giuliomoro@189
|
111 break;
|
giuliomoro@189
|
112 case 2:
|
andrewm@308
|
113 analog0In = analogRead(context, n * 2 + 1, 0) > 0.5;
|
andrewm@308
|
114 analogWrite(context, 2 * n, analogOut, writePattern[outPointer]);
|
andrewm@308
|
115 analogWrite(context, 2 * n + 1, analogOut, writePattern[outPointer]);
|
giuliomoro@189
|
116 break;
|
giuliomoro@189
|
117 }
|
giuliomoro@189
|
118 gAnalogOutLoopDelay--;
|
giuliomoro@189
|
119 outPointer++;
|
giuliomoro@189
|
120 if(gAnalogOutLoopDelay <= 0){
|
giuliomoro@189
|
121 if(++inPointer == patternLength){
|
giuliomoro@189
|
122 inPointer = 0;
|
giuliomoro@189
|
123 }
|
giuliomoro@189
|
124 }
|
giuliomoro@189
|
125 }
|
giuliomoro@189
|
126 bool expectedIn = writePattern[inPointer];
|
giuliomoro@189
|
127 if(gAnalogOutLoopDelay <= 0 && doReadWrite == true){
|
giuliomoro@189
|
128 if(analog0In != expectedIn || digitalAIn != expectedIn){
|
giuliomoro@189
|
129 rt_printf("expected: %d, received: %d %d, pointer: %d, delay: %d, count: %d\n",
|
giuliomoro@189
|
130 expectedIn, analog0In, digitalAIn, inPointer, gAnalogOutLoopDelay, count);
|
giuliomoro@189
|
131 anaErrorCount++;
|
giuliomoro@189
|
132 }
|
giuliomoro@189
|
133 }
|
giuliomoro@189
|
134 count++;
|
giuliomoro@189
|
135 if(analog0In != digitalAIn){ // at any time the analog and digital in should be the same
|
giuliomoro@189
|
136 rt_printf("ana %d_%d %d,\n", analog0In, digitalAIn, n);
|
giuliomoro@189
|
137 }
|
giuliomoro@189
|
138 if(outPointer == patternLength){
|
giuliomoro@189
|
139 outPointer = 0;
|
giuliomoro@189
|
140 }
|
giuliomoro@189
|
141 }
|
giuliomoro@189
|
142 if(1)
|
giuliomoro@189
|
143 for(unsigned int n = 0; n < context->audioFrames; n++){
|
giuliomoro@189
|
144 static int count = 0;
|
giuliomoro@189
|
145 static bool analog1In = false;
|
giuliomoro@189
|
146 static bool digitalDIn = false;
|
giuliomoro@189
|
147 /* we need to remember the pastAnalog1In because
|
giuliomoro@189
|
148 * reading GPIO takes place before writing to it, therefore
|
giuliomoro@189
|
149 * when reading a GPIOout, the GPIOin samples will always be one sample late
|
giuliomoro@189
|
150 */
|
giuliomoro@189
|
151 bool doReadWrite = false;
|
giuliomoro@189
|
152 static bool pastAnalog1In = false;
|
andrewm@308
|
153 digitalWriteOnce(context, n, gDigitalOutCh, writePattern[digitalOutPointer]);
|
giuliomoro@189
|
154 if(context->analogChannels == 8){
|
giuliomoro@189
|
155 if((n&1) == 0){ //do it every other sample
|
andrewm@308
|
156 pastAnalog1In = analogRead(context, n/2, 1) > 0.5;
|
andrewm@308
|
157 digitalDIn = digitalRead(context, n, gDigitalInDCh);
|
giuliomoro@189
|
158 doReadWrite = true;
|
giuliomoro@189
|
159 }
|
giuliomoro@189
|
160 }
|
giuliomoro@189
|
161 if(context->analogChannels == 4){
|
andrewm@308
|
162 pastAnalog1In = analogRead(context, n, 1) > 0.5;
|
andrewm@308
|
163 digitalDIn = digitalRead(context, n, gDigitalInDCh);
|
andrewm@308
|
164 digitalWriteOnce(context, n, gDigitalOutCh, writePattern[digitalOutPointer]);
|
giuliomoro@189
|
165 doReadWrite = true;
|
giuliomoro@189
|
166 }
|
giuliomoro@189
|
167 if(context->analogChannels == 2){
|
andrewm@308
|
168 pastAnalog1In = analogRead(context, n * 2, 1) > 0.5;
|
andrewm@308
|
169 digitalDIn = digitalRead(context, n, gDigitalInDCh);
|
andrewm@308
|
170 digitalWriteOnce(context, n, gDigitalOutCh, writePattern[digitalOutPointer]);
|
giuliomoro@189
|
171 doReadWrite = true;
|
giuliomoro@189
|
172 }
|
giuliomoro@189
|
173 bool expectedDigitalIn = writePattern[digitalInPointer];
|
giuliomoro@189
|
174 if(doReadWrite == true){
|
giuliomoro@189
|
175 gDigitalOutLoopDelay--;
|
giuliomoro@189
|
176 if(gDigitalOutLoopDelay <= 0){
|
giuliomoro@189
|
177 if(expectedDigitalIn != pastAnalog1In || expectedDigitalIn != digitalDIn){
|
giuliomoro@189
|
178 rt_printf("D expected: %d, received: %d %d, pointer: %d, delay: %d, count: %d\n",
|
giuliomoro@189
|
179 expectedDigitalIn, pastAnalog1In, digitalDIn, inPointer, gDigitalOutLoopDelay, count);
|
giuliomoro@189
|
180 digErrorCount++;
|
giuliomoro@189
|
181 }
|
giuliomoro@189
|
182 if(++digitalInPointer == patternLength){
|
giuliomoro@189
|
183 digitalInPointer = 0;
|
giuliomoro@189
|
184 }
|
giuliomoro@189
|
185 }
|
giuliomoro@189
|
186 pastAnalog1In = analog1In;
|
giuliomoro@189
|
187 if(++digitalOutPointer == patternLength){
|
giuliomoro@189
|
188 digitalOutPointer = 0;
|
giuliomoro@189
|
189 }
|
giuliomoro@189
|
190 }
|
giuliomoro@189
|
191 count++;
|
giuliomoro@189
|
192 }
|
giuliomoro@189
|
193 if(context->audioSampleCount > 30000){
|
giuliomoro@189
|
194 gShouldStop = true;
|
giuliomoro@189
|
195 }
|
giuliomoro@189
|
196 }
|
giuliomoro@189
|
197
|
giuliomoro@189
|
198
|
giuliomoro@301
|
199 void cleanup(BelaContext *context, void *userData)
|
giuliomoro@189
|
200 {
|
giuliomoro@189
|
201 if(anaErrorCount == 0 && digErrorCount == 0){
|
giuliomoro@189
|
202 rt_printf("Test was succesful with %d analog channels and a buffer size of %d\n", context->analogChannels, context->audioFrames);
|
giuliomoro@189
|
203 } else {
|
giuliomoro@189
|
204 rt_printf("------------------------\n%danalog %ddigital errors over %dsamples while running test with ",
|
giuliomoro@189
|
205 anaErrorCount, digErrorCount, context->audioSampleCount);
|
giuliomoro@189
|
206 rt_printf("%d analog channels and a buffer size of %d \n\n\n",
|
giuliomoro@189
|
207 context->analogChannels, context->audioFrames);
|
giuliomoro@189
|
208 exit(1);
|
giuliomoro@189
|
209 }
|
giuliomoro@189
|
210 }
|