robert@464: #include robert@464: #include robert@464: #include robert@464: #include robert@464: #include robert@464: #include robert@464: #include robert@464: // setup() is called once before the audio rendering starts. robert@464: // Use it to perform any initialisation and allocation which is dependent robert@464: // on the period size or sample rate. robert@464: // robert@464: // userData holds an opaque pointer to a data structure that was passed robert@464: // in from the call to initAudio(). robert@464: // robert@464: // Return true on success; returning false halts the program. robert@464: robert@464: robert@464: // digital inputs can be changed at will (as they are all being processed at the same time) robert@464: // analog channels must be as per below robert@464: int gAnalogOutCh = 1; robert@464: int gDigitalOutCh = 2; robert@464: int gDigitalInACh = 0; robert@464: int gDigitalInDCh = 3; robert@464: int gAnalogOutLoopDelay; robert@464: int gDigitalOutLoopDelay; robert@464: bool setup(BelaContext *context, void *userData) robert@464: { chris@543: // For this test we need the same amount of audio and analog input and output channels chris@543: if(context->audioInChannels != context->audioOutChannels || chris@543: context->analogInChannels != context-> analogOutChannels){ chris@543: printf("Error: for this project, you need the same number of input and output channels.\n"); chris@543: return false; chris@543: } chris@543: robert@464: rt_printf("For this test you need the following connections:\n" robert@464: "analog%d out->digital%d in, analog%d out->analog%d in, " robert@464: "digital%d out -> digital%d in, digital%d out-> analog%d in\n", robert@464: gAnalogOutCh, gDigitalInACh, gAnalogOutCh, 0, gDigitalOutCh, gDigitalInDCh, gDigitalOutCh, 0); robert@464: rt_printf("Running test with %d analog channels and a buffer size of %d\n", chris@543: context->analogInChannels, context->audioFrames); robert@464: robert@464: for(unsigned int n = 0; n < context->digitalFrames; n++){ robert@464: pinMode(context, n, gDigitalInACh, INPUT); robert@464: pinMode(context, n, gDigitalInDCh, INPUT); robert@464: pinMode(context, n, gDigitalOutCh, OUTPUT); robert@464: } chris@543: switch (context->analogOutChannels){ robert@464: case 2: robert@464: gAnalogOutLoopDelay = context->audioFrames*2 + 3; robert@464: gDigitalOutLoopDelay = context->audioFrames*2 + 2; robert@464: break; robert@464: case 4: robert@464: gAnalogOutLoopDelay = context->audioFrames*2 + 3; robert@464: gDigitalOutLoopDelay = context->audioFrames*2 + 2; robert@464: break; robert@464: case 8: robert@464: gAnalogOutLoopDelay = context->audioFrames + 3; robert@464: gDigitalOutLoopDelay = context->audioFrames + 1; robert@464: break; robert@464: default: robert@464: exit(2); robert@464: } robert@464: robert@464: return true; robert@464: } robert@464: robert@464: // render() is called regularly at the highest priority by the audio engine. robert@464: // Input and output are given from the audio hardware and the other robert@464: // ADCs and DACs (if available). If only audio is available, numAnalogFrames robert@464: // will be 0. robert@464: robert@464: const int patternLength = 31; robert@464: static int anaErrorCount = 0; robert@464: static int digErrorCount = 0; robert@464: void render(BelaContext *context, void *userData) robert@464: { robert@464: static bool writePattern[patternLength] = { robert@464: 0,1,0,1,0,0,1,1, robert@464: 0,0,0,1,1,1,0,0, robert@464: 1,1,1,1,0,0,0,0, robert@464: 1,1,1,1,1,0,0}; robert@464: // for(int n = 0; n < patternLength; n++){ robert@464: // writePattern[n]=1; robert@464: // } robert@464: static int inPointer = 0; robert@464: static int outPointer = 0; robert@464: static int digitalOutPointer = 0; robert@464: static int digitalInPointer = 0; robert@464: static int analogOut = 1; robert@464: /** Checking offset between analog and digital robert@464: * how it should be : robert@464: * The PRU loop does the following (the loop runs at 88.2kHz): robert@464: * - Read/write audio sample (once for the left channel, once for the right channel) robert@464: * - Write DAC 0 or 0/2 or 0/2/4/6 robert@464: * - Read ADC 0 or 0/2 or 0/2/4/6, 2 samples (@176.4) older than NOW robert@464: * - /During/ the line above, every two loops we also Read/Write GPIO, robert@464: * therefore reading on ADC 0/2/4/6 a value that is being output from GPIO will lead to undefined results robert@464: * - Write DAC 1 or 1/3 or 1/3/5/7 robert@464: * - Read ADC 1 or 1/3 or 1/3/5/7, 2 samples (@176.4) older than NOW robert@464: */ robert@464: if(1) robert@464: for(unsigned int n = 0; n < context->audioFrames; n++){ robert@464: static bool analog0In = false; robert@464: static bool digitalAIn = false; robert@464: static int count = 0; chris@543: bool doReadWrite = context->analogInChannels<=4 ? true : ((context->analogInChannels == 8) && (n&1)==0); robert@464: if(doReadWrite){ robert@464: digitalAIn = digitalRead(context, n, gDigitalInACh); chris@543: switch(context->analogInChannels){ robert@464: case 8: robert@464: analog0In = analogRead(context, n/2, 0) > 0.5; robert@464: analogWrite(context, n/2, analogOut, writePattern[outPointer]); robert@464: break; robert@464: case 4: robert@464: analog0In = analogRead(context, n, 0) > 0.5; robert@464: analogWrite(context, n, analogOut, writePattern[outPointer]); robert@464: break; robert@464: case 2: robert@464: analog0In = analogRead(context, n * 2 + 1, 0) > 0.5; robert@464: analogWrite(context, 2 * n, analogOut, writePattern[outPointer]); robert@464: analogWrite(context, 2 * n + 1, analogOut, writePattern[outPointer]); robert@464: break; robert@464: } robert@464: gAnalogOutLoopDelay--; robert@464: outPointer++; robert@464: if(gAnalogOutLoopDelay <= 0){ robert@464: if(++inPointer == patternLength){ robert@464: inPointer = 0; robert@464: } robert@464: } robert@464: } robert@464: bool expectedIn = writePattern[inPointer]; robert@464: if(gAnalogOutLoopDelay <= 0 && doReadWrite == true){ robert@464: if(analog0In != expectedIn || digitalAIn != expectedIn){ robert@464: rt_printf("expected: %d, received: %d %d, pointer: %d, delay: %d, count: %d\n", robert@464: expectedIn, analog0In, digitalAIn, inPointer, gAnalogOutLoopDelay, count); robert@464: anaErrorCount++; robert@464: } robert@464: } robert@464: count++; robert@464: if(analog0In != digitalAIn){ // at any time the analog and digital in should be the same robert@464: rt_printf("ana %d_%d %d,\n", analog0In, digitalAIn, n); robert@464: } robert@464: if(outPointer == patternLength){ robert@464: outPointer = 0; robert@464: } robert@464: } robert@464: if(1) robert@464: for(unsigned int n = 0; n < context->audioFrames; n++){ robert@464: static int count = 0; robert@464: static bool analog1In = false; robert@464: static bool digitalDIn = false; robert@464: /* we need to remember the pastAnalog1In because robert@464: * reading GPIO takes place before writing to it, therefore robert@464: * when reading a GPIOout, the GPIOin samples will always be one sample late robert@464: */ robert@464: bool doReadWrite = false; robert@464: static bool pastAnalog1In = false; robert@464: digitalWriteOnce(context, n, gDigitalOutCh, writePattern[digitalOutPointer]); chris@543: if(context->analogInChannels == 8){ robert@464: if((n&1) == 0){ //do it every other sample robert@464: pastAnalog1In = analogRead(context, n/2, 1) > 0.5; robert@464: digitalDIn = digitalRead(context, n, gDigitalInDCh); robert@464: doReadWrite = true; robert@464: } robert@464: } chris@543: if(context->analogInChannels == 4){ robert@464: pastAnalog1In = analogRead(context, n, 1) > 0.5; robert@464: digitalDIn = digitalRead(context, n, gDigitalInDCh); robert@464: digitalWriteOnce(context, n, gDigitalOutCh, writePattern[digitalOutPointer]); robert@464: doReadWrite = true; robert@464: } chris@543: if(context->analogInChannels == 2){ robert@464: pastAnalog1In = analogRead(context, n * 2, 1) > 0.5; robert@464: digitalDIn = digitalRead(context, n, gDigitalInDCh); robert@464: digitalWriteOnce(context, n, gDigitalOutCh, writePattern[digitalOutPointer]); robert@464: doReadWrite = true; robert@464: } robert@464: bool expectedDigitalIn = writePattern[digitalInPointer]; robert@464: if(doReadWrite == true){ robert@464: gDigitalOutLoopDelay--; robert@464: if(gDigitalOutLoopDelay <= 0){ robert@464: if(expectedDigitalIn != pastAnalog1In || expectedDigitalIn != digitalDIn){ robert@464: rt_printf("D expected: %d, received: %d %d, pointer: %d, delay: %d, count: %d\n", robert@464: expectedDigitalIn, pastAnalog1In, digitalDIn, inPointer, gDigitalOutLoopDelay, count); robert@464: digErrorCount++; robert@464: } robert@464: if(++digitalInPointer == patternLength){ robert@464: digitalInPointer = 0; robert@464: } robert@464: } robert@464: pastAnalog1In = analog1In; robert@464: if(++digitalOutPointer == patternLength){ robert@464: digitalOutPointer = 0; robert@464: } robert@464: } robert@464: count++; robert@464: } robert@464: if(context->audioFramesElapsed > 30000){ robert@464: gShouldStop = true; robert@464: } robert@464: } robert@464: robert@464: robert@464: void cleanup(BelaContext *context, void *userData) robert@464: { robert@464: if(anaErrorCount == 0 && digErrorCount == 0){ chris@543: rt_printf("Test was succesful with %d analog channels and a buffer size of %d\n", context->analogInChannels, context->audioFrames); robert@464: } else { robert@464: rt_printf("------------------------\n%danalog %ddigital errors over %dsamples while running test with ", robert@464: anaErrorCount, digErrorCount, context->audioFramesElapsed); robert@464: rt_printf("%d analog channels and a buffer size of %d \n\n\n", chris@543: context->analogInChannels, context->audioFrames); robert@464: exit(1); robert@464: } robert@464: }