Help I2S!

DanielMastroleo

New member
Hey everyone, i recently bought the teensy 4.0 and have for some time developed my own library for synthesizing different waveforms, filters and envelopes. Or lets say - all the fundamental parts in audio synthesis. I've seen the huge audio library that is available but feel that I'd rather use that which i have created on my own. Rather than integrating my code with the audio.h library my idea was to just setup DMA with I2s and go from there. The DMA is working correctly and at the moment is sending blocks of data from my audio chain (16 bit samples). Since my build is gonna be in mono i duplicate the samples and store them in an uint32. With the serial monitor i can confirm that the DMA buffer is being filled with the correct samples.

All the data is being sent to the I2S1_TDR0 register and I've tried setting up the I2s hardware by reverse engineering from what i read in the output_i2s.h library. This is where the problems appear. I can see that both clock pins are sending out a signal but the data pin is acting strange. Even if i fill the DMA buffer with all 0 is still get a signal on the data pin and a high pitched sound if i plug in my headphones to the uda1334 that i have hooked up on the breadboard. Im kind of a newbie and this is the first microcontroller that I've bought (aside from some school projects), so im really not getting anything from the imxrt manual or understanding how i should configure the hardware registers for my purposes.

Thanks in advance!
Daniel
 
Which hardware do you have connected to listen to the I2S data?

Have you tried simply running the normal audio library examples? Even if you want to write all the code from scratch, simply running the known-good examples could let you verify your hardware really works before you spend a lot of time on the software side.
 
The officially supported CODECS are listed below. With other hardware you'll need to search around for a driver that can set up your UDA1334a to work a 16-bit 44.1kHz stereo I2S stream.

It looks like the UDA1334a doesn't have any registers to program, so it might work by just connecting the appropriate pins up to the Teensy. See the pin listings at https://www.pjrc.com/store/teensy3_audio.html

It's also possible that the Adafruit Arduino tutorial will help you set things up. The Raspberry Pi set up is very different - being a Linux platform.

I hope that helps!
1748645112869.png
 
Yes, i tried running the examples that come with the arduino environment and i get audio on my speakers

At least you can look at the audio library source code for a known-good example!


Even if i fill the DMA buffer with all 0 is still get a signal on the data pin and a high pitched sound if i plug in my headphones to the uda1334 that i have hooked up on the breadboard

Just to be realistic, even if you showed the complete program, I really can't spend a lot of time to track down where it's going wrong, when we have the officially published audio library that works out-of-the-box.

But if you can post your code as just a single chuck of code I can quickly copy and paste into Arduino IDE and upload, I'll probably take a quick look and see if I can reproduce the problematic waveforms. Who knows, maybe if the code is small (just 1 copy-paste into Arduino IDE) there's a chance I might notice something. If the code is large and several files, odds of noticing the problem become much less...


This may or may not help, but here are some prior threads about using I2S to implement a different protocol. You can find some discussion of the I2S transmit registers and working example code.


 
Help me too with I2S. As Daniel, I need very few things of audio library, just an I2S input from a monophonic microphone. I will probably modify the interrupt routine to my needs and pass entered data to the main program with some "dataa available" flag, avoiding multiple copies of data from a buffer to another. But I want a 48 kHz sample rate. Where is it defined ? In which function does it acts on hardware clocks ? Even more (not my actual case), some extreme case could be a system where this frequency is not known at compile time, but choosen by the user at run time, and even modified when running : that is "hardwardly" possible ...
 
At least you can look at the audio library source code for a known-good example!




Just to be realistic, even if you showed the complete program, I really can't spend a lot of time to track down where it's going wrong, when we have the officially published audio library that works out-of-the-box.

But if you can post your code as just a single chuck of code I can quickly copy and paste into Arduino IDE and upload, I'll probably take a quick look and see if I can reproduce the problematic waveforms. Who knows, maybe if the code is small (just 1 copy-paste into Arduino IDE) there's a chance I might notice something. If the code is large and several files, odds of noticing the problem become much less...


This may or may not help, but here are some prior threads about using I2S to implement a different protocol. You can find some discussion of the I2S transmit registers and working example code.


Well i appreciate any guidance at all! Honestly i managed to just create a new audioobject that passes my data into the stream that is configured by the audio.h library - everything seems to working fine for my purposes. Someday maybe I'll get back to trying to setup all the hardware myself but for now i have enough on my hands with building my first synthesizer. I'll get back to you when i have something to show ^^


Thanks again!
 
Thanks, now I located it. It is so difficult to find libraries in arduino system (with Windows), in subdirectories in subdirectories in subdirectories (for me :C:\Users\denib\AppData\Local\Arduino15\packages\teensy\hardware\avr\1.59.0\cores\teensy4). Better than to know "how to do", I want to "know how it works" and see where hardware registers are trimmed ... So, which functions uses "AUDIO_SAMPLE_RATE_EXACT" or "AUDIO_SAMPLE_RATE" elsewhere ? In AudioStream I see only others #define ...
I found in ...Arduino15\packages\teensy\hardware\avr\1.59.0\libraries\Audio\utility two files "imxrt_hw.h" and "imrxt_hw.cpp" where a function is defined:

void set_audioClock(int nfact, int32_t nmult, uint32_t ndiv, bool force = false); // sets PLL4

Is it this one which is used ? Where is it called ?
 
Last edited:
difficult to find libraries in arduino system (with Windows), in subdirectories in subdirectories in subdirectories
When a verbose build completes the libraries used are noted at the tail of the build like IDE 2:
Using library Audio at version 1.3 in folder: C:\Users\aUser\AppData\Local\Arduino15\packages\teensy\hardware\avr\0.60.4\libraries\Audio
or IDE 1:
Using library Audio at version 1.3 in folder: T:\T_Drive\arduino-1.8.19\hardware\teensy\avr\libraries\Audio

That is for libraries not CORES files from the ABOVE ... which on both is ..\..\cores\teensy4

Like: C:\Users\aUser\AppData\Local\Arduino15\packages\teensy\hardware\avr\0.60.4\cores\teensy4
 
I've started using VSCode for more complex editing tasks (though I do try to ensure all my example code works out of the box using the Arduino IDE...).

Anyway, if you install that, and open the folder C:\Users\denib\AppData\Local\Arduino15\packages\teensy\hardware\avr\1.59.0\, that should show you both the as-installed cores and libraries. You can then do a search across all files to find where things are used and start to get an idea of how stuff hangs together.

This is not an easy journey, and you will spend a lot of time Googling, looking at poorly commented code, puzzling over the reference manual, and generally tearing your hair out :eek:
 
What I guess is that 44100 Hz frequency is not set by software. Registers of the "CLOCK CONTROL MODULE" have default values after hardware reset, wich may correspond to 44100. So that fonction "set_audioClock(...)" in "imxrt_hw.h" library has to be called only to change this frequency. Am I True ?

Now, how changing "#define AUDIO_SAMPLE_RATE_EXACT 44100.0f" in AudioStream library acts on hardware ? Or is it just an information for computations in audio function ?

BTW, I am far of beeing a C++ specialist, just a white haired beginner, but I am a specialist of frequency synthesis, fractional PLL's and low phase noise systems for telecoms. I love this IRMTX1062 processor which has SEVEN PLL's : that's paradise !
 
Last edited:
So, which functions uses "AUDIO_SAMPLE_RATE_EXACT" or "AUDIO_SAMPLE_RATE" elsewhere ?

This is the sort of question best answered by software searching. Many good programs exist, but they mostly fall into 2 broad categories.

Modern IDEs can create search indexes of all the code you're using, which means you can highlight a function and click in some way to find the place it's defined, where it's implemented, and what other places make use of it. I can't help too much with the precise details, because I mostly use the other way.

That other way is command line tools. This way has a steep learning curve and sometimes quite cryptic syntax. Everything is text only, which can feel comforting in its simplicity or frustratingly archaic if you're accustomed to the pretty visual appearance of GUI-based software. But if you can understand how, you would use the "find" command to create a list of all files to search, and the "grep" command to do the actual searching. For example, on my Linux desktop these are the 2 commands to run:

Code:
cd ~/.arduino15/packages/teensy/hardware/avr/0.60.4
grep AUDIO_SAMPLE_RATE_EXACT `find . -type f`

I've attached the output from those commands as a ZIP file, which can hopefully give you a direct answer to your "which functions uses" question. The indirect answer is a "a lot of them"... enough that copying the entire list into the message exceeds the forum's message size limit, so I had to put them into a file for you.

But to try to give a more useful understanding, usage of AUDIO_SAMPLE_RATE_EXACT more or less falls into a few categories.

1: Hardware init like the various input_xyx.cpp functions use it to set up the actual clocks and other hardware config. Since you're interested in IS2, you would look at input_i2s.cpp and output_i2s.cpp. As you can see in this long list of files, many other non-I2S inputs and output are supported. All of them need to use AUDIO_SAMPLE_RATE_EXACT to configure the hardware.

2: Library functions use it to convert their API (like setting a filter's cut-off frequency) to actual coefficients the DSP code uses. The many wavetable example files, even though part of user examples, could be considered API conversion since they're automatically generated rather that code a programmer simply using the library would type.

3: User level programs rarely use AUDIO_SAMPLE_RATE_EXACT (all the library API functions should use actual frequency or time), but it is sometimes used in rare cases.

Hopefully this answers your question? As much as I'd like to help, I really can't write a book that would explain every possible detail. But many years ago I did write this page about adding new features to the audio library, which explains some of the internals of how the library is supposed to work. Hopefully it can also shine some light on more of the questions this relatively quick answer will raise.
 

Attachments

  • AUDIO_SAMPLE_RATE_EXACT_usage.zip
    5.4 KB · Views: 87
Last edited:
Thanks, Paul, for your guidance. I have found, at last what I was looking for. I2S hardware is configured in AudioOutputI2S2::config_i2s() wich is called by AudioInputI2S2::begin ... So, even if I do not uses any audio output, "#include "output_i2s2.h" is somewhere necessary.
And now (2 hours later) I see this thread : https://forum.pjrc.com/index.php?threads/setting-up-custom-i2s-communication.65229/ with a bunch of intersting things ...
 
Last edited:
Back
Top