Audio Library

Status
Not open for further replies.
DMA ISR conflict?

I'm now attempting to integrate OctoWS2811 (actually, due to pin conflicts, it should now be HexWS2811 :)) I've run into an apparent conflict:

OctoWS2811/OctoWS2811.cpp.o: In function `dma_ch3_isr':
/home/rscott/misc/hw/pjrc_teensy_3.0/utils/arduino-1.0.5_x64/libraries/OctoWS2811/OctoWS2811.cpp:191: multiple definition of `dma_ch3_isr'
Audio/output_pwm.cpp.o:/home/rscott/misc/hw/pjrc_teensy_3.0/projects/sketchbook/libraries/Audio/output_pwm.cpp:100: first defined here
collect2: error: ld returned 1 exit status

Since I'm not using the PWM audio, is it possible to free up this DMA channel?
 
Great, thank you! I tried with receiveReadOnly and it works, saving a little bit of memory.


Now I would like to run a sketch that uses AudioInputAnalog as input, but I'm not finding a way to make it work.
First of all, how to define the pin to use for the input? In the PassThroughAnalog example I read "analogPinInput(16); //analog A2 (pin 16)", but in the comments of the AudioInputAnalog object I read "pin must be 0 to 13 (for A0 to A13)". Finally, in the example DialTone_7segment I read "audioIn(A0);". Which one is correct?

Thanks,
Enrico
 
Hey Enrico, I was playing with AudioInputAnalog the other day and came across that - the caper that appears true to me is "pin must be 0 to 13 (for A0 to A13)" so, I think, 'A0' might be effectively equ 0 (I should write a sketch and have it Serial.println(A0,DEC); before being too sure of myself tho!)
 
I've reworded the comment:

Code:
       // pin specified in user sketches should be A0 to A13
       // numbers can be used, but the recommended usage is
       // with the named constants A0 to A13
       //   constants A0-A9 are actually 14 to 23
       //   constants A10-A13 are actually 34 to 37
 
oh that's odd - when I tried using '15' there I got nothing like my input but when I changed it to '1' (after reading the original comment) I got a result awfully close to my expectation.

Edit: gotta be me, musta been something else I touched at the same time perhaps :)
 
Last edited:
Thank you!
Anyway, I was not getting any input because I was using in my sketch both an analog input and an analog output. If I remove the dac output, I start getting something from the adc. Basically, the update() method of the adc was never being called. What could be the reason? Could it be related to the "update_responsibility"?

How can I have both adc and dac (mutually exclusively running) in the same sketch? Let's say I have two chains of object, on for playing and one for listening. One button (or command) start playing, and one start listening (no both at the same time). How does the update responsibility work in this case? Does this take into account the two separate chains? It seems that the dac of one chain also triggers the update of the adc of the other chain (EDIT, this happens if I remove the begin method called during the initialization of the adc)...

As an alternative, we could create and destroy the chain every time a "button" is selected. Is is possible to undo and redo the connections between objects "at runtime"?

Thanks,
Enrico
 
Last edited:
I was interested in a similar enough sort of implementation. Seems that AudioOutputAnalog clobbers AudioInputAnalog, or they clobber each other, and that seems to clobber (disable perhaps?) the entire update chain afaict; I looked through the files involved and just didn't want to 'dig in' far enough to even hope to spot the problem.

Perhaps you can pursue your idea by using an input off the Audio Adapter - ie., for now, just comment out 'AudioInputAnalog xxx(y);' and use AudioInputI2S and connect the left input to your intended chain? Just until the 'clash' is fixed...


If they would cooperate I think I can make a fairly neato audio attenuation analyser using a Teensy 3.1 on its own (ie., no Audio Adapter) with a couple of opamps and a few passives. As they don't work together at the moment I am pursuing that idea by adding the Audio Adapter to the project for now.


In brighter news AudioFilterBiquad now supports multiple filter sets per instance and somebody might like one of my peak meter examples I submitted over the weekend :)
 
I'm not using the audio adapter, so I have to solve this in a different way. At the moment, I'm thinking to follow one of these possible solutions;
1) I noticed that the method connect (in core/AudioStream.cpp) set active src and dest as soon as the AudioConnection is created. Maybe this can be avoided, and set them active only when we are actually using them?
2) Do not call the method connect when the AudioConnection is initialized, and call it as soon as we need to use that chain. Also create some sort of disconnect method.
3) Finally, to have total reconfiguration, we might have an AudioConnection constructor without inputs, and call an overloaded method connect that get the inputs and create the connections. Again, a disconnect method would be needed.

What do you think about these approaches?
 
How can I have both adc and dac (mutually exclusively running) in the same sketch?

You could post a small (but complete) program that demonstrates / reproduces the problem.

If you've followed this forum at all, or read the first line of the rules when you signed up, you'd see posting a sample program (even if it's trivial) that reproduces whatever problem or error you're seeing is pretty much always required if you want it to be solved.

These 2 objects should be able to work together in the same program. If they're not, it's probably a bug. I will fix it, but the very least you can do is post a small program here which reproduces the problem.
 
Sorry, Paul. You are right!
I'm attaching a modified version of the PlayFromSketch example. This is what I observe:
- I start with an AudioPlayMemory connected to the dac. I have a print in the update() method of the dac that starts printing as soon as the object dac is created.
- As soon as I just create an adc object, the update() method of dac does not get called anymore. No update() of the adc is called.
- Finally, if I connected memory with dac, and adc with filter, I have the same situation as above. If I remove the begin() method from the constructor of the adc, the dac update() start again, but it also triggers the update() of the adc (even though they are not connected together!).

Thank you,
Enrico
 

Attachments

  • PlayFromSketch.ino
    2 KB · Views: 152
I think I have found a solution. I don't know how good this approach is, or how much you will like it, but things seem to work in this way....

1) I removed the begin() methods from the constructors of the adc and dac, and I call them when I actually need the adc and the dac. Before switching between adc and dac I also need to call explicitly AudioStream::update_stop(); (that I changed form protected to public). In this way I can have both adc and dac in the same sketch, and run them in two different chains.
2) However, as I said, one triggers the other, even if they are not connected in the same chain. To solve this, I changed the method connect, such that the src and dst are not activated at that point. Then, I have an activate and deactivate method for AudioConnection that sets src.active and dst.active to true and false, respectively. In this way I'm activating just the chain I need, leaving the other off.

Now, when a command is typed, let's say "send", I stop the update, I deactivate the recording chain with the adc, activate the playing chain with the dac, and start the dac. For the command "rcv", I do the other way around.

Paul, what do you think about this solution? I'm attaching my AudioStream files, and the sketch with the new commands. In input_adc and output_dac I've just remove the begin() from the constructor.

Thanks,
Enrico
 

Attachments

  • AudioStream.cpp
    6.5 KB · Views: 172
  • AudioStream.h
    5.2 KB · Views: 274
  • PlayFromSketch.ino
    2.2 KB · Views: 149
Ok, my solution needed a little bit more of work. In that way I am able to decouple the two chains, and solve the problem of update_responsability. However, even though the dac is going into the update() method, it is not actually outputing samples (I'm using an oscilloscope)!

The problem must be related to the DMA. In particular, things seem to work by changing in input_adc.cpp this line
Code:
	PDB0_SC = PDB_CONFIG | PDB_SC_SWTRIG;
into
Code:
	PDB0_SC = PDB_CONFIG | PDB_SC_SWTRIG | PDB_SC_PDBIE | PDB_SC_DMAEN;

Honesty, I haven't had time to look in detail what those lines mean. I've just checked the differences between output_dac and input_adc, and this was the result. Now I wonder if all the changes mentioned in my previous post are still needed!

-----EDIT
It seems like the changes mentioned in the previous post are not necessary needed. Just change the line above, and adc and dac should work together. However, in this way adc and dac seems to always run (2% max cpu in standby), while with the activate and deactivate methods I can control which chain to run.
 
Last edited:
I am making progress getting the examples inthe audio library to work. However, documentation appears to be sparse as yet. What are the filter parameters ? I want to program a bandpass filter. Is it possible to change the microphone gain ? Maybe it is time to read the SGTL5000 datasheet properly !
 
Microphone gain is AudioControlSGTL5000.micGain, only 4 values 0,1,2,3. Value of 3 is +40 db , 2 is +30 db, 1 is +20 db, 0 is 0 db.
 
@heliboy: perhaps a look at the example(s) CalcBiquadToneControl can help you with filters, and look at this list of defines:
Code:
  #define FILTER_LOPASS 0
  #define FILTER_HIPASS 1
  #define FILTER_BANDPASS 2
  #define FILTER_NOTCH 3
  #define FILTER_PARAEQ 4
  #define FILTER_LOSHELF 5
  #define FILTER_HISHELF 6
Alternatively you could use the online parameter calculator Paul linked in his post which was his first mention of AudioFilterBiquad, page 5 by memory so it is probably on page 4 or 6 :D
 
Hi Paul,
in "pdb.h" i read:
Code:
#define PDB_PERIOD 1087 // 48e6 / 44100
If I'm not wrong this should be the period of the PDB, that is used both by the ADC and the DAC object. Does this setting works only with 48MHz CPU speed setting? Should it be twice for the 96MHz?

Thanks,
Enrico
 
You're right, the I/O runs at 48 MHz when the CPU is at either 48 or 96 MHz. The I/O can't run faster than 50 MHz.

When the CPU is at 24 MHz, the I/O runs at 24 MHz. It can't run faster than the CPU.

The USB can't work if the CPU is slower than 20 MHz (presumably not enough bus bandwidth for the DMA engine to move USB packets to/from RAM), so Teensyduino doesn't support slower than 24 MHz.

Edit: I should mention the PLL always runs at 96 MHz in all 3 modes (simply because I've never written code to run it at any other speed, but it is capable of other speeds). The CPU and I/O clocks are created from the the PLL using dividers, so they must always be integer division of the PLL. The I/O clock is also required to be equal or an integer division of the CPU.

The PDB, ADC, DAC and most I/O stuff runs from the I/O clock. The I2S port runs from the I/O clock, except for the MCLK generator, which is clocked directly from the 96 MHz PLL. So MCLK is the same, even if the CPU changes. Likewise, the USB is clocked using a different dividor from the 96 MHz PLL, so the USB always runs at 48 MHz, regardless of the CPU and I/O clock speeds, even when they're 24 MHz. Both the USB and MCLK dividers offer a multiply by 2 option (presumably by clocking on both edges), so they can effectively divide by integers from 192 MHz. The I2S object uses this this to get 44100 * 256 using 192e6 / 17.

There's a lot of complex stuff in this chip.....
 
Last edited:
Thank you! I was definitely missing something. I tried in the meantime to double the period, and I was actually getting 22050 blocks per second, instead of 44100.

However, I'm still not managing to get input from a microphone (this one http://www.adafruit.com/products/1063). I'm attaching the sketch and a passthru object that I'm using to print the samples.
1) Can you suggest me a better way to "visualize" the signal coming from the microphone? By printing I'm slowing down too much, and I lose I lot of samples.
2) I think there may be something wrong with
Code:
 "analogReference(INTERNAL); // range 0 to 1.2 volts"
in input_adc.cpp. I get always zeros samples, and if i produce noise very close to the mic, the output get constant non-zero values (something to do with the dc level?).
If I set up
Code:
	//analogReference(DEFAULT); // range 0 to 3.3 volts
instead, I get something (limited by the many samples I lose due to point 1), but I also get a lot of noise.

Any idea? Thanks!

Enrico


View attachment PlayFromSketch.ino
View attachment passthru.cpp
View attachment pass.h
 
Last edited:
I use the same mic with no problem. You are aware there is a gain control on the mic circuit board? Also I would comment out the use of POWER_LED_PIN as I believe it is used in the audio library ( at least it is on dim when the library is in use).
 
I use the same mic with no problem. You are aware there is a gain control on the mic circuit board? Also I would comment out the use of POWER_LED_PIN as I believe it is used in the audio library ( at least it is on dim when the library is in use).

Yes, the gain is already set to max. I've also removed the POWER_LED_PIN. Still, I get mostly zero output... How test it without printing out the samples?
Thanks.
 
I tried to save in memory half a second of recording, stop recording and print after. With DEFAULT analog reference I get the right (a bit noisy) audio back (this time I do not lose samples). With INTERNAL, I still get zero output...
 
I can not get any of the examples that use AudioSynthWaveform to compile, suspect the way it should be called has changed and the examples have not been updated.
 
Status
Not open for further replies.
Back
Top