comparison examples/11-Extras/gpioAnalogLoopbackTest/render.cpp @ 464:8fcfbfb32aa0 prerelease

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