Mercurial > hg > beaglert
changeset 189:7144c5594d16
Added loopback digital/analog test. This (randomly) fails for the first loopback sample received when -p2. Maybe some stale memory somewhere?
author | Giulio Moro <giuliomoro@yahoo.it> |
---|---|
date | Tue, 26 Jan 2016 00:02:15 +0000 |
parents | c706be7daad7 |
children | 3b8a28edae41 b3a306da03e0 |
files | projects/gpioAnalogLoopbackTest/render.cpp |
diffstat | 1 files changed, 210 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/projects/gpioAnalogLoopbackTest/render.cpp Tue Jan 26 00:02:15 2016 +0000 @@ -0,0 +1,210 @@ +#include <BeagleRT.h> +#include <Utilities.h> +#include <cmath> +#include <rtdk.h> +#include <sys/time.h> +#include <sys/types.h> +#include <unistd.h> +#include <stats.hpp> +// setup() is called once before the audio rendering starts. +// Use it to perform any initialisation and allocation which is dependent +// on the period size or sample rate. +// +// userData holds an opaque pointer to a data structure that was passed +// in from the call to initAudio(). +// +// Return true on success; returning false halts the program. + + +// digital inputs can be changed at will (as they are all being processed at the same time) +// analog channels must be as per below +int gAnalogOutCh = 1; +int gDigitalOutCh = 2; +int gDigitalInACh = 0; +int gDigitalInDCh = 3; +int gAnalogOutLoopDelay; +int gDigitalOutLoopDelay; +bool setup(BeagleRTContext *context, void *userData) +{ + rt_printf("For this test you need the following connections:\n" + "analog%d out->digital%d in, analog%d out->analog%d in, " + "digital%d out -> digital%d in, digital%d out-> analog%d in\n", + gAnalogOutCh, gDigitalInACh, gAnalogOutCh, 0, gDigitalOutCh, gDigitalInDCh, gDigitalOutCh, 0); + rt_printf("Running test with %d analog channels and a buffer size of %d\n", + context->analogChannels, context->audioFrames); + + for(unsigned int n = 0; n < context->digitalFrames; n++){ + pinModeFrame(context, n, gDigitalInACh, INPUT); + pinModeFrame(context, n, gDigitalInDCh, INPUT); + pinModeFrame(context, n, gDigitalOutCh, OUTPUT); + } + switch (context->analogChannels){ + case 2: + gAnalogOutLoopDelay = context->audioFrames*2 + 3; + gDigitalOutLoopDelay = context->audioFrames*2 + 2; + break; + case 4: + gAnalogOutLoopDelay = context->audioFrames*2 + 3; + gDigitalOutLoopDelay = context->audioFrames*2 + 2; + break; + case 8: + gAnalogOutLoopDelay = context->audioFrames + 3; + gDigitalOutLoopDelay = context->audioFrames + 1; + break; + default: + exit(2); + } + + return true; +} + +// render() is called regularly at the highest priority by the audio engine. +// Input and output are given from the audio hardware and the other +// ADCs and DACs (if available). If only audio is available, numAnalogFrames +// will be 0. + +const int patternLength = 31; +static int anaErrorCount = 0; +static int digErrorCount = 0; +void render(BeagleRTContext *context, void *userData) +{ + static bool writePattern[patternLength] = { + 0,1,0,1,0,0,1,1, + 0,0,0,1,1,1,0,0, + 1,1,1,1,0,0,0,0, + 1,1,1,1,1,0,0}; +// for(int n = 0; n < patternLength; n++){ +// writePattern[n]=1; +// } + static int inPointer = 0; + static int outPointer = 0; + static int digitalOutPointer = 0; + static int digitalInPointer = 0; + static int analogOut = 1; + /** Checking offset between analog and digital + * how it should be : + * The PRU loop does the following (the loop runs at 88.2kHz): + * - Read/write audio sample (once for the left channel, once for the right channel) + * - Write DAC 0 or 0/2 or 0/2/4/6 + * - Read ADC 0 or 0/2 or 0/2/4/6, 2 samples (@176.4) older than NOW + * - /During/ the line above, every two loops we also Read/Write GPIO, + * therefore reading on ADC 0/2/4/6 a value that is being output from GPIO will lead to undefined results + * - Write DAC 1 or 1/3 or 1/3/5/7 + * - Read ADC 1 or 1/3 or 1/3/5/7, 2 samples (@176.4) older than NOW + */ + if(1) + for(unsigned int n = 0; n < context->audioFrames; n++){ + static bool analog0In = false; + static bool digitalAIn = false; + static int count = 0; + bool doReadWrite = context->analogChannels<=4 ? true : ((context->analogChannels == 8) && (n&1)==0); + if(doReadWrite){ + digitalAIn = digitalReadFrame(context, n, gDigitalInACh); + switch(context->analogChannels){ + case 8: + analog0In = analogReadFrame(context, n/2, 0) > 0.5; + analogWriteFrame(context, n/2, analogOut, writePattern[outPointer]); + break; + case 4: + analog0In = analogReadFrame(context, n, 0) > 0.5; + analogWriteFrame(context, n, analogOut, writePattern[outPointer]); + break; + case 2: + analog0In = analogReadFrame(context, n * 2 + 1, 0) > 0.5; + analogWriteFrame(context, 2 * n, analogOut, writePattern[outPointer]); + analogWriteFrame(context, 2 * n + 1, analogOut, writePattern[outPointer]); + break; + } + gAnalogOutLoopDelay--; + outPointer++; + if(gAnalogOutLoopDelay <= 0){ + if(++inPointer == patternLength){ + inPointer = 0; + } + } + } + bool expectedIn = writePattern[inPointer]; + if(gAnalogOutLoopDelay <= 0 && doReadWrite == true){ + if(analog0In != expectedIn || digitalAIn != expectedIn){ + rt_printf("expected: %d, received: %d %d, pointer: %d, delay: %d, count: %d\n", + expectedIn, analog0In, digitalAIn, inPointer, gAnalogOutLoopDelay, count); + anaErrorCount++; + } + } + count++; + if(analog0In != digitalAIn){ // at any time the analog and digital in should be the same + rt_printf("ana %d_%d %d,\n", analog0In, digitalAIn, n); + } + if(outPointer == patternLength){ + outPointer = 0; + } + } + if(1) + for(unsigned int n = 0; n < context->audioFrames; n++){ + static int count = 0; + static bool analog1In = false; + static bool digitalDIn = false; +/* we need to remember the pastAnalog1In because + * reading GPIO takes place before writing to it, therefore + * when reading a GPIOout, the GPIOin samples will always be one sample late + */ + bool doReadWrite = false; + static bool pastAnalog1In = false; + digitalWriteFrameOnce(context, n, gDigitalOutCh, writePattern[digitalOutPointer]); + if(context->analogChannels == 8){ + if((n&1) == 0){ //do it every other sample + pastAnalog1In = analogReadFrame(context, n/2, 1) > 0.5; + digitalDIn = digitalReadFrame(context, n, gDigitalInDCh); + doReadWrite = true; + } + } + if(context->analogChannels == 4){ + pastAnalog1In = analogReadFrame(context, n, 1) > 0.5; + digitalDIn = digitalReadFrame(context, n, gDigitalInDCh); + digitalWriteFrameOnce(context, n, gDigitalOutCh, writePattern[digitalOutPointer]); + doReadWrite = true; + } + if(context->analogChannels == 2){ + pastAnalog1In = analogReadFrame(context, n * 2, 1) > 0.5; + digitalDIn = digitalReadFrame(context, n, gDigitalInDCh); + digitalWriteFrameOnce(context, n, gDigitalOutCh, writePattern[digitalOutPointer]); + doReadWrite = true; + } + bool expectedDigitalIn = writePattern[digitalInPointer]; + if(doReadWrite == true){ + gDigitalOutLoopDelay--; + if(gDigitalOutLoopDelay <= 0){ + if(expectedDigitalIn != pastAnalog1In || expectedDigitalIn != digitalDIn){ + rt_printf("D expected: %d, received: %d %d, pointer: %d, delay: %d, count: %d\n", + expectedDigitalIn, pastAnalog1In, digitalDIn, inPointer, gDigitalOutLoopDelay, count); + digErrorCount++; + } + if(++digitalInPointer == patternLength){ + digitalInPointer = 0; + } + } + pastAnalog1In = analog1In; + if(++digitalOutPointer == patternLength){ + digitalOutPointer = 0; + } + } + count++; + } + if(context->audioSampleCount > 30000){ + gShouldStop = true; + } +} + + +void cleanup(BeagleRTContext *context, void *userData) +{ + if(anaErrorCount == 0 && digErrorCount == 0){ + rt_printf("Test was succesful with %d analog channels and a buffer size of %d\n", context->analogChannels, context->audioFrames); + } else { + rt_printf("------------------------\n%danalog %ddigital errors over %dsamples while running test with ", + anaErrorCount, digErrorCount, context->audioSampleCount); + rt_printf("%d analog channels and a buffer size of %d \n\n\n", + context->analogChannels, context->audioFrames); + exit(1); + } +}