Interested in ESP32 Audio: ua-cam.com/play/PL5vDt5AALlRfGVUv2x7riDMIOX34udtKD.html Looking for all my ESP32 projects: ua-cam.com/play/PL5vDt5AALlRdN2KyL30l8j7kLCxhDUrNw.html
when the ESP8266's first hit the public, as essentially a "wireless serial cable", I immediately wondered about the likelihood of using one of the direct-communication methods they offered to turn a pair of them into an ultra-low-latency wireless audio 'cable'. It's quite nice to see someone else with at least a similar-ish thought, and since I gave up on the idea long ago, it's even nicer to see someone do more than just have a thought about it :)
Wow I didn't know that ADC of ESP32 was connected to DMA with I2S. It's an incredible piece of equipment. They've put a lot of things in it. Some stuff is being discovered just recently. For the price tag, it's almost overwhelming.
Thanks very much for this, very useful. My project is a 24/7 field recorder, solar-powered, i need to stream the audio to a Pi for storage and this is really helpful.
Very interesting video. Thanks for taking the time to make it. I have used the esp32 to read battery voltages which is about as far away from music as you can get. But I was faced with considerable noise as well. What I found worked for me was a filter of 8 readings where did this: (sum of 8 readings - max - min) / 6. This helped because the noise was random very large errors and nowhere near Gaussian noise that benefits from simple averaging.
That's really useful to know - I'm going to try increasing the number of samples I take to get a larger number for the averaging. Also need to work on the power supply to get the noise down even more.
Awesome piece of hardware the ESP32... I've developed for such hi frequency sampling applications for the ESP8266 through an SPI ADC (MCP3202), but here you can do it in background thanks to the I2S peripheral and the DMA... that's great
@@Kalanchoe1 yeah you can, it sounds well if you're able to sample fast enough, but you need a whole core to do it properly (polling), so I discourage it. Alternatively, maybe you can use the SPI master driver wich should support DMA
I would suggest the vocabulary "Interference" to describe the power supply signal getting into the audio signal. It makes some sense to differentiate and use the word "noise" for signals that are of random nature such as the thermal noise associated with resistors or the shot noise associated with current through semiconductor junctions. Why? because speaking this way makes you always remember to use design countermeasures appropriate for each type of undesirable signal. Interference is also the right word to use when a signal from another source is getting into another signal. Such as One radio station in the background of another. Or AC power line hum getting into audio. An interesting characteristic (while not often practical) is that you can some times cancel out interference by adding a scaled and inverted (the negative) interfering signal back into the contaminated signal. You cannot cancel thermal or shot noise because they are in your circuit components and never isolated. Hope this helps.
Great informative video, looking forward to the next one. I've stumbled upon this while looking into the possibility of streaming audio from an intercom to a server (and then to my phone) - and also in reverse - via tapping into the handset speaker and microphone wires (among some others). Using an ESP32. I assume the noise wouldn't be an issue in my case. And your sample code does appear to do exactly what I want, sending the audio to a server :). Of course I would still have to find out if it has the power to do full duplex audio, streaming in both ways simultaneously.
Should be possible - for voice you probably don't need to be sampling at 40KHz, you'll get away with 10KHz pretty easily. If you want to get fancy you could take a look at some very low bitrate codecs. Even without that you should be able to do full duplex over WiFi. You may want to look at using UDP for streaming the data as it's a bit more lightweight. I'm going to be investigating my noise issues some more to see how far I can get and I've also got an I2S microphone break out board which will let me bypass the ADC completely. For your project there's also an I2S amplifier breakout board on Adafruit that might be worth looking at.
@@atomic14 could that be the reason why the ESP-CAM has noise in the images too? The power supply noise should also affect the camera, shouldn't it? Interesting...
@@atomic14 I used two mics to do SSL (sound source localization using the FFT) let me know if you are interested and I can share with you the details/code
@@raguaviva That sounds really interesting! I'd definitely be interested. We've got a discord group going for the channel if you'd like to jump into that: discord.gg/DJ8EQRXU
Awesome video! Thanks a lot! I have a question about the .raw files getting transmitted to my local PC. Which software do you use to listen to the sound tracks. Do I need to convert the format to a different one than .raw before?
I use Audacity - www.audacityteam.org/ - it has an option for importing raw audio data - you just need to tell it the sample format, number of channels and sample rate.
It would be interesting to record the audio at the same time with a separate isolated device to see how much of the poor quality is caused by the ADC of the ESP32, versus due the noise on Vin. And it would also be interesting to play a recording into the ADC and see how well it comes out. And also interesting to power the microphone from a separate battery as you mentioned in the video. It's a shame the ESP32 ADCs are so weak compared to the rest of it!
I need to do a proper followup video to this series - I've got a really good collection of mics and pre-amps to use. It's definitely in the schedule. I'm also quite keen on actually quantifying how bad the ADC actually is. Separate the performance of the ADC from the mics and see if it really is as bad as everyone says.
@@atomic14 That would be useful. I've read that it is only capable of: 7 Bits ENOB out of the box, closer to 10 Bits with the recommended capacitor and 64 sample averaging as described in the Espressif docs 6 kHz signal bandwidth (presumably the 3 dB cut-off 150 kHz samplerate Non-linear resoonse and unable to read below about 0.15 V Reading 254 samples continuosly and then skipping 2 samples whilst it does something internally Or reading in "continuous mode" which Espressif recommends against because it drops the quality substantially. Also, apparently, once every 17 seconds there is a window when there is much less noise for a second or so; so any quality measurements will be very different depending on whether you happen to hit that window! I'd really like to see them improve the ADC in future ESP32 versions.
Excellent video... came looking for info on MAX Mic modules... got it and more... Just a note, you could power the MAX with a little isolated DC-DC converter (B0505S), often used in USB speakers to remove supply noise and it's not too pricy...
It's worth a try, I found that that I was getting quite a low volume on the voice but it's definitely worth another look. I'm going to do a follow-up video in the next few days as I have some I2S microphones that I want to try out so I'll revisit the MAX9814 at the same time.
@@atomic14 The 60db with a pi and soundcard is very noisy its 40db or 50db with the Max9814. The timing on the A/R is also really too fast for voice the 100nf cap prob should be 680nf or 1uf.
Thank you so much for making this video! I am working on it receently. I want to know if you have any suggestions about external ADC for audio transmission? And how do you record time data when you receive the audio data via WIFI? Thanks again!
I would use an I2S microphone for input in preference to the internal ADCs as the noise seems to be much lower - (ua-cam.com/video/3g7l5bm7fZ8/v-deo.html). For transmitting the audio data, depending on how much bandwidth you have then you can just send the raw audio samples to another device using TCP (or HTTP).
@@atomic14 Around 4:15 of this video you mention picking up the audio on your desktop. Could you explain that setup a little? I'm having trouble getting the I2S audio data to transmit on WiFi. My goal is to have one ESP32 with a digital mic communicate wirelessly to a second ESP, and then play the audio out the I2S amp on that one. I had an analog mic setup working this way with the 8266 version of this card (NodeMCU), but can't seem to do the same with the ESP32 version. Thank you for your excellent videos!!
At 7:36, you show your line conditioner/noise filter you built. Do you have any fotos or more detailed diagrams on this? Especially how connected to the ESP32 and the audio modules? Thanks!
Great video @atomic14. I'm getting the first part of the manual sampling going on a new ESP32 S3, but it seems like the I2S direct link to the onboard ADC has changed. Have you done any work with the S3 to see how to use efficient analog audio sampling without going directly to the DMA buffers?
@@saranyaasuresh5710 in the end I used a digital microphone instead (that does the AD conversion) linked to I2S on the ESP32 S3. The S3 does not have the capability to use its internal ADC with I2S. As far as I understand this is preferable because the ESP32 ADC is not very good.
Thank you, it is a great series of video that helps understand how the audio system works. I have one question about your server for capturing the audio data, can you please help teach me how is the server setup and how to communicate with ESP32?
So what part of this was I2S? These MAX modules are just microphone amplifiers, no? The way this was hooked up there is no way this was I2S. I guess maybe internally it is as if it was I2S, perhaps all we care about here is a way to read audio from the ADC pin in DMA mode. That's cool. I like the thorough work you did on cleaning up the signal. I am currently designing my own board and thinking I will integrate the MAX9814 as well as an audio amplifier on the DAC line. But not sure, maybe the trick is to keep all audio stuff off the digital PCB to avoid the noise coming in.
Congratulations. Really interesting and right now I should make an I2S encoder to transmit audio with telephone quality via UDP to and from another device on the network. I would like to start trying direct sampling via the internal ADC of the ESP32. Where can I find the complete example indicated in the video (04:08)?
Thanks so much for the awesome video, you've helped me immensely with my current project. I have a question regarding the internal ADC, is it possible to sample two or more ADC pins simultaneously or close to (i.e. not stopping and starting repeatedly)? I've tried to enable I2S1, but now see it is incompatible the built-in ADC, and i2s_set_adc_mode can only accept a single pin as an argument. Thanks again.
@@atomic14 It's good to hear 😃 I'm waiting for another video. Btw, is there a place where I can learn about how to use the ESP32's i2s with the arduino IDE?
@@avieleliyahu6199 You should be able to use all the sample code in the Arduino IDE without any problem. Just copy the contents from main.cpp into the sketch file and then create new tabs for the extra files (WiFiCredentials.h, I2SSampler.h, I2SSampler.cpp) and copy the contents of each file in. You create a new tab using the little down arrow on the right - imgur.com/a/nYwfGwS
How do you manage to get 3.3v after passing 5 volts through those two inductors? I tried the circuit you suggested in your other video, but the voltage drop is more than intended and once reaches the microphone, it is around 2.7v not 3.3v.
Hello Cris, your video is incredible, with very important information for anyone who wants to understand a little about audio with ESP32. I am very grateful for the class! I'm new and I'm learning, I'm wanting to use an ESP32 with max9814 to listen to a specific frequency range, like 100mhz to 150mhz, is this possible? When listening would activate a trigger. Thank you very much!
Very nice video, thanks! Do you think it is feasible to subtract the noise with and OPAmp? One of the opamp imput connected to the mic audio out and the other to the power line? Or, could it be possible to use two adcs as the same concept? Of course losing wifi, but just for curiosity.
I think the best solution is really putting in a good clean power supply for the microphones. I did find that using the 5v supply with a good LC filter followed by an LDO would give a very clean 3v3 supply for the microphones.
Thnx for this illustrative video. I want to know if Is it possible to work with an analog microphone like MAX9814 using I2S and internal ADC with micropython? Thanks again.
I presume it is useful (or essential) to have at least two DMA buffers to allow reading one whilst writing to the other. But what is the reason for using more than 2 buffers (i.e., 4 in your case)? Or when could this be useful?
There's a maximum size that you can specify for each DMA buffer (I think from memory it's 1024 bytes) so you can use multiple DMA buffers if you want something larger.
@@atomic14 That explains it! Thanks for responding so fast. I didn't know there was a limit on buffer length. Is there a limit on number of DMA buffers (memory permitting)?
After "yarn start" in the console .Console window is stuck at this message "server started at 0.0.0.0:5003" and nothing is happening after that.There is no raw file created in server section. What can be the issue?
Hello Its a great explanation tutorial, I am using ESP32 s3 korvo 2 where there are 2 mics, embedded in it. Can I select and use one mic and what changes should I need to do in the code to get input using i2s
Great video. I'm using I2S just to measure one analog input. However, I'd like to measure two but have no idea how to set this up. So far all I've managed is to get loads of crashes or no data at all. Can you assist? Not sure if it's even possible. Cheers. Matt
Thanks for that video, TIL something new! 👍 'd and subbed. I'm currently working on a very similar esp32 project (even using the same Microphones 😀), but when measuring the duration i2s_read(), I get very weird timings which are not correlating with the sample rate set in the i2s config. Do you maybe know what's happening here? e.g. sample_rate = 40000, I get 6.3ms for an average i2s_read of 512samples (1024 bytes) buffer. Which is odd, because 512/40000 is ~ 12.8ms already. So I thought "okay, it's maybe twice as fast as I expected because I use only one channel" So when I turn the sample_rate down to 20000, I would expect the duration of i2s_read to be DOUBLE (~12.6ms) for the same amount of data (which almost matches the calculation for 40kHz). but instead it goes down to ~5.9 to 6ms for 20kHz@512 samples ??? Okay, let's turn it down to 10kHz, I get ~5.4ms ... 1kHz, I get 825µs... . Are you familiar with that kind of issue? I need my data to be as exactly timed as possible, and these measurements make absolutely no sense to me. Thanks for reading, and if you can explain that one to me, you'll have my eternal gratitude. Great video, animations and explaining!
Hi, I am also facing similar issue. Did you find any solution? We can get in touch and discuss. Please ping back so that I can share my email Id with you.
Hi Atomic14 Thanks for this great Video! I'am working on a projekt where i have to write down audio data to an SD card. I managed it with the help of your tutorial. But there are still some point where i get confused: It's the DMA buffer count and buffer size. I also read the ESP32 manual/ datassheet but it does not explain the DMA Buffer very well. Questions in my head: why a buffer count of 4 with a size of 1024? Why not just 2. I also getting confused, why its just not 2 buffers? Is it to reduce the latency? And then you use a local buffer to store the content of the DMA Buffer. Here you use also a double Buffer!? Why? And how to caculate the local buffer size and so on is fucking my brain a litte bit. Seems to be a bit tricky.... maybe because the i2s periphirial always uses stereo? I just want to record mono sound. If you want/can do, i would love to get some more explanations about the DMA buffer and the local buffers and their sizes. Anyway, thank you very much for this and your other tutorials. (Just to mention.... i studied informatics... but its a long time ago and i didnt used my knowledge for a long time... but iam familliar with the basics of bits an bytes... and also with C++... i know the difference between stack and heap and so on. What i try to say: I'am not an copy paste arduino newbe... i have some background. But this i2s DMA buffer stuff is compleatly new to me and its bad documentated... and tutorials on this topic very rar. And i never did audio things befor.)
Hi Dominik, I was thinking of doing exactly that for my next project - I've had a few people ask about writing audio to an SD Card and thought it might be quite good. On the DMA buffer size and count - there's a maximum size for each buffer of 1024 so if you want more space then you need multiple buffers. The amount of space you allocate for the DMA buffers is a bit of a trade-off. More space means the CPU has to service the I2S device less frequently. But comes at the cost of increased latency. You are correct to pick up on the fact that I also have the double buffers where I'm storing the audio data before it gets transmitted over the HTTP request. My thinking around this was as follows: I wanted to send a reasonable amount of data in one go so that I wasn't trying to make too many HTTP requests in rapid succession. So I needed to buffer up the audio data before sending it. I picked quite a large amount for the DMA buffers to reduce the load on the CPU to as small as possible to make sure the data would be transmitted successfully. It's likely that I could get away with a much smaller total DMA size as there's not really much CPU work going on but I wasn't too concerned about latency. The size of my local buffers where I hold the audio data before sending over HTTP was down to a tradeoff between how rapidly I wanted to send the HTTP requests and how much free RAM the device has for holding the audio data. Potentially, you could increase the total DMA buffer size to the point where you have enough time to send the audio data without double buffering. This is the approach I've taken in my Walkie-Talkie code where accumulate the samples into one buffer before sending them out and rely on the DMA buffers to hold the samples that are coming in. In my Walkie-Talkie project, I've used 4 DMA buffers of 64 bytes which gives about 16ms of audio data when sampling at 16KHz - I'm actually thinking of increasing the size of the DMA buffers to give a bit more time. There's quite a bit of guesswork and assumptions on my side around a lot of how this works. Hope that helps!
@@atomic14 Wow, thank you very much for this fast and explaining anser! The first answer which helped me A LOT was the fakt that the max size of each each DMA Buffer is 1024. I played around with the buffer size but then i got a "paniced" error from my ESP32. Now i know why. However, when i specify the Buffer count and size, it gets allocated at one block in the RAM? Or how does it work? To sad that there is not a good documentaion from espressive. :( Or is there any i didn't found? ). I think it is task controlled. So every time one DMA buffer is full, the task get notified and can read the bytes into a local buffer!? Sad to say, but I'am also not familiar with the FreeRTOS and Task things. I know about multithreading in Java... like race conditions... deathlock situations an so on. In that past i had build an Java Project which was connected to over 3000 gameservers simultainisly with more than 50000 Threads and and including a selfe written HTTP Server to provide an interface for the users. Well... some time went along since I did this... However... I understand now why you use a "local" buffer. I faced some problems while writing 44100hz Audio Data to the SD card. I made some mistakes. Frist Problem was, that i opened the File to write every time when the buffer was full. Second problem was that i wrote every bye as a single byte. The "overhead" from the SD library was way the high. Now i changed the code too write the samples from the local buffer to the file in bigger chunks with the File::file.write(bytesToWrite, numberOfBytesToWrite) funktion. That was the key to get rid of loosing samples. But overall, i didnt really understand the DAM buffers in detail. I would apreciate if you would share your knowlage about it in detail! :) Another think i didn't really get is the const uint32_t usStackDepth from the xTaskCreatePinnedToCore funktion. Seems like to be bit of trail and error, to not run out of stack!? But is has nothing to do with the DMA buffer oder the "local" Buffer, right? THanks a LOT!
@@dominikwinkler2718 No problem - happy I can help! There are some docs here that explain the workings of the DMA system - section 6 is quite interesting www.espressif.com/sites/default/files/documentation/esp32_technical_reference_manual_en.pdf It's basically created a linked list in memory. So each buffer is allocated separately. I think under the hood it's all interrupt driven but with the I2S driver you can give it a handle to a queue and get notified via that when things have happened (a buffer has been filled/emptied etc...). On the stack size - I've found that's very much trial and error as you really don't have any way of really knowing how much stack space you're going to need. I've ended up with the classic programmer approach of using powers of two - 1024, 2048, 4096 until it stops crashing :) As you say though, it's completely independent of the DMA buffer size and only relates to stack usage - so local variables and function calls. You can easily accidentally blow the stack by doing a large local array variable. I must admit, I'm still learning about the embedded world. There are some things I still find very odd in the embedded world. I'm finding Arduino libraries particularly strange - they really love their global variables.
@@atomic14 So nice to getting i touch with you! Thanks! I didn't found THIS reference manual you linked so far! That, helps me again a lot. Sorry... as i mentioned... I'am quite new to this ESP stuff! Another thing: Shouldn't we call call i2s_stop(I2S_NUM_0) befor we call i2s_read(....., ...) ? and then - after reading from the DMA buffer - call i2s_start(I2S_NUM_0) to prevent reading interrupted data? About the stack thing.... i dont worry at the moment... but i was right that it has nothing to do with the DMA buffer, thats good so far! THank you! However: You might be new to the embedded world... but you are definitly NOT new to c++ programming. You are using classes... sub- or child classes ... using pointers where ever you can to safe time and memory. Thats great if you are a good c++ coder.... but to be honest, for a youtube tutorial, it might be a little bit of overkill for some viewers. It took me some time get back into all that c++ class stuff. For an easy tutorial video for the "mainstream" .... for most of the Arduino "Makers"... it might be hard to understand. I think that is the reason why "Arduino" lover their global variables so much. They want to keep it as simple as possible to make it possible fore everyone to get started with coding and electronics. During my informatics studies i faced a LOT of fellow students who didn't even unterstandstand what a pointer is. Things like * or & ...... ooooohhhhh they got feared :D . What is an memory address ? Why can i cast any number to a void* and just put data at this point of the memory (if exists ^^) .... and why can i user [x] brackets on a pointer and just write to another adress even if i never declared an array ^^ ? An What the heck is malloc()? In Java or any other managed language I don't even care.... i just declare an var... or list... and the garbage with take care about it. What i try to say is: for many people (including me) its hard to understand all this deep C++ or asm stuff. Well, in the past i reengineered .exe files with ollydbg and wrote sometimes memory cheats for games. So when you wrote your frist on the fly memory hack/cheat to make a JUMP to a part of the free heap and placed your own peace of code there in asm or placed some NOP's to get rid of damage if you are tackled .... then you know what I'am talking about. but... thats totally nerd shit! ^^ . But i did it about 20 years ago. If iam allowed to give you a hint: Try to make your brilliant video tutorials even better if you write the code you present as EASY as possible! This might give you even more subscribes! Especcially on this i2s topic.... because there aren't much good tutorials. Lets keep in contact :) .... I'am looking forward to your next tutorials! :)
@@dominikwinkler2718 Thanks Domonik - I think you are right. I sometimes forget that I have a lot more experience of C++ than a lot of people. Once you've learned something it's sometimes hard to remember what it was like when you didn't know it. The i2s_read takes care of any synchronisation - I believe it will only read from completed buffers. Though I'm not sure what happens if the i2s peripheral wraps around the DMA buffers. My C++ is actually very out of date now. The last time I worked in C++ was probably about 15 years ago! But I am thinking of doing a series of "basic" C++ videos.
Very informative video. I've learnt a lot about audio sampling on the ESP32 from it. I have a question about the MAX9814 calibration though. There is a 1.25V DC bias built into the MAX9814 which I can see in the loop_sampling code serial print voltage output. When I use the same device using your i2s_sampling code the raw sound data I capture on the server is also biased when I look at it in Audacity, (positive 0.5). Is this something I can calibrate out using i2s_read?
Nice tutorial. I have a simple question. The way that you've connected the output of the max9814 to the esp32 aren't we clipping the part of the audio signal that goes below 0v? I have an max9814 and connected to my scope and I can see min of -250mV to 720mv (for some random sound). Aren't we losing the signal in this config? I hooked mine up and I can record audio and it sounds fine (I guess) but I'm curious if we are losing information without some sort of offset for the output of the max9814 to push it above 0V.
That's interesting, the output should not be able to go negative at all provided you have the GND connected to 0v and VCC to 3.3V. It should be biased at 1.25V on the output and go 2Vpp (so 0.25 to 2.25 volts) - cdn-learn.adafruit.com/downloads/pdf/adafruit-agc-electret-microphone-amplifier-max9814.pdf
@@atomic14 I made a noob mistake. I connected the MAX9814 to my scope and had AC coupling enabled. Switching to DC coupling I see the signal hovering around 1.28V (avg) which is inline with the spec. Thank you again for a great video!
HI there, I got a problem for Esp32S3 with Max9814 and when i first say hello it will display and when I second time it diaplay null, how can i slove it? I use arduino to code it. So please help❤
Hi, great video Thanks I have a doubt regarding the i2s ADC with potentiometer are you using DMA or by creating task. in my project I need to use DMA for my ECG sensor can this also be implemented this way since i2s is Audio can this be used directly with the Internal ADC. please do reply asap. Thanks in advance
Hi! Could you please tell me, what components did you use to filter the signal? I mean the diagram in the 7:32 video. What LRD chip did you use? and what capacitance of the capacitor did you use on the right?
Thanks for all the great info. I am a 'bit' confused about the bit per sample of 16/32 vs the 12bit wide adc of the esp32. How do they relate if at all? What's the difference? I'd also like to understand the fixed mclk and intr alloc flag better. If anyone can explain.
Hey I was wondering if you could make a video or two on how to setup the local server using node.js cause its my first time using it and I'll be honest I'm having some real issues with setting it up. I was hoping that the instructions you posted on github would suffice but i only got as far as having "node ---version" and "yarn --version" giving me a good response. When trying to do "cd server" in node.js command prompt it just tells me that it couldn't find the specified path and now I don't really know what to do. Some help would be much appreciated.
I actually have an I2S MEMS Microphone (www.mouser.com/datasheet/2/218/ph0645lm4h-b-datasheet-rev-c-1525723.pdf) on an Adafruit breakout board on order right now! Soon as it arrives I'll do a video to compare the performance.
I have a newer ESP32-S3 I'm looking for a way to transfer readings from the internal ADC to memory the fastest way possible I can't get DMA to work for me. Is there anyone that can assist me or guide me in the right way. I am also using Arduino IDE.
I am using a condenser microphone not a i2s one and made a amplifier circuit using that. I manage to get that signal in matlab an tried to play it but I am not able to hear clear signal. I think there is a problem in arduino coding . Can you help me to get clear signal using condenser microphone amplifier?
Hi Dhiman, it really depends on the sample rate and the number of bits you want to store. If it's just voice then you could get away with 8-bit samples at 10KHz. That would give you around 8KB per second. The WROOM has 520KB of SRAM built-in, but typically I find I only have around 150KB free once my code is running. So that would give you around 15 seconds or audio. You could try and stream the audio to the built-in flash which is 4MB - the amount of space available depends on the partition scheme you set up, but if you set aside 2MB then you'd have about 200 seconds so around 3 minutes or so. Hope that helps. There's no reason why you couldn't compress the audio as it comes in - there are some very good audio codecs that will compress voice down to very low bit rates (search for 3gpp voice codecs).
I have a simple animation library I've written to help me show waveforms and run simple processing. Unfortunately it's not really suitable for sharing as the code is very messy.
At 04:45, what is the function of "this" as the pvParameters argument for xTaskCreatePinnedToCore()? The Espressif documentation says "pvParameters: Pointer that will be used as the parameter for the task being created."
On the task function definition, you'll see that it's defined as void task_function(void *param) - the value of the param is what you pass into xTaskCreatePinnedToCore. So this allows you to pass data to the task you are creating. In my case, I'm just passing in a pointer to the current instance.
@@atomic14 Thanks. Makes more sense after downloading the source files and seeing the full thing. I'm used to using plain C as much as possible and didn't realise it was inside a method of a class.
hi atomic14, I come from Indonesia.. I really like this world.. I often watch your videos, can you make a video tutorial for a good multi track audio record using Arduino or ESP32... for music recording or just make a prototype? Thanks
Do you know if it's possible to connect a i2s MIC (or use the MAX9814 via i2s) and an i2s output module. I wondering if it would be possible to create a 2 way intercomm type device, where I could speak and listen at the same time. Ideally I would connect the i2s output module to headphones to avoid feedback going into the i2s MIC. I suspect it's not to hard to create a walkie talkie (either record or output audio at any time but not both), but I am intrigued by the idea of the intercomm type setup.
Definitely possible - you can run input and output simultaneously. In theory you can use a single I2S peripheral for both input and output - though in practice this can be a bit difficult depending on the devices you have. In my Alexa project I'm actually running both an I2S microphone and and I2S amplifier at the same time using both the I2S peripherals. When I don't need any output I just play silence and when I don't need any input I just ignore the samples coming in. Have a look at ua-cam.com/video/At8PDQ3g7FQ/v-deo.html and ua-cam.com/video/3g7l5bm7fZ8/v-deo.html - you can also have a look at the code for the Alexa project - ua-cam.com/video/FZ4ayyTXM2s/v-deo.html
I dont know how to combine the code for using ADC through I2S. I tried it but I am getting a lot of errors. Could somebody please send me the complete code which is ready to use. Thank you. (newbie here)
The Max9814 is definitely better but its a shame the boards come with A/R capacitor it has as its a bit too fast and reactive for voice. On the Pi into a soundcard the Max9814 sounds as good as your later I2S ones unless you start turning up the gain but that is a lot of gain with it already onboard. Did you set the programable gain to 40/50db as the 60db gain is noisy. I am still a big fan of electrets as if you can still get really good quality directional (cardoid) ones and that can really help other omni directional when you don't have beamforming. My old eyes and clumsy hands went off the Max9814 board as really the A/R timing cap should be bigger and my preference for directional electrets means a lot of fiddly soldering especialy that smd cap. Max9812 doesn't have AGC and often doesn't come with an electret which for me is actually preferential on a sound card with a PI they are far better than what seems the ESP ADC. I wonder if other boards have cleaner lines and track spacings?
I think a lot of the noise is just poor power supply rejection on the breakout boards. I did try adjusting hte gain and got similar results. I have heard from a few people using ICS microphones who have also got a lot of noise. I think it's quite easy to pick up interference from all sorts of places.
@@atomic14 Dunno we look like we where usuing the same 'aliexpress' max9814 and yeah the top 60db gain is rather horrible. I also found some weird gnd loops depending on how I had things. On a Pi using the 5v I think maybe 3.3 (forgot) the max9814 can sound much cleaner, I have the sound card gain really low 0-9db max I think with the lowest gain setting as each sample is still loud at desktop distance. I did have a rockpiS (rk3088) and the adc sucked for some reason and was actually worse than your getting.
I'm afraid that's a bit more complicated than what I've done here. This might help www.reddit.com/r/esp32/comments/ah9c2t/has_anyone_played_sound_from_an_esp32_to_a/ but it is for ESP32 not Adruino.
Hey, thanks for the information it was very helpfull. I came to your channel looking for esp cams that can also manage audio, maybe you have some information that can be usefull about it?.
could you please help i'v got this error TypeError: Cannot read property 'length' of undefined at /Users/mac/Documents/Arduino/esp32_audio-master/server/src/index.js:22:35
If you've got it set to read from both channels then every other sample will be 0 unless you have something hooked up. Feel free to raise an issue on GitHub though and we can take a look at what's going on.
@@atomic14 i did on the arduinofft github, i will add the code although it is based on your example except that i changed it to read from the internal adc
This is a very good contribution to the community. Thanks and congrats. So I am trying to port your IS2 over ADC code to ESP-IDF but I am facing some difficulties ... that might be related to my basic skills on this ... so could you help me understanding what is being handling in this function and what it is required? Also do you have any comments on porting this code to ESP-IDF? /** * Process the raw data that have been read from the I2S peripherals into samples **/ void ADCSampler::processI2SData(uint8_t *i2sData, size_t bytesRead) { uint16_t *rawSamples = (uint16_t *)i2sData; for (int i = 0; i < bytesRead / 2; i++) { addSample((2048 - (rawSamples[i] & 0xfff)) * 15); } }
Hi Rafael, I should add some commends to the code base explain what is happening - it is a bit weird. When reading from the ADC you get a 16bit value from the I2S interface. The top 4 bits of that are the ADC channel that is being read from. So to get the ADC sample we need to remove those top 4 bits This is what this line of code does: sample = sample & 0xfff That give us 12 bits with sample information in it. The values run from 0 to 4095 and are inverted - so 0 is the maximum value and 4095 is the minimum value. So the next line of code translates that into 2048 for the maximum value and -2047 for the minimum value: sample = 2048 - sample The * 15 is just amplifies the value up so we can hear it clearly - in theory I think we could just shift left by 4 bits to get the full 16 bit range. I think the code should just work on the ESP-IDF - you will need to remove any reference to Arduino.h - I think the only thing it is bringing in are types like uint16_t which you can get from #include If you have any problems them it's probably easier to open an issue on the GitHub repo as it's a bit easier to share code there. Good luck with your project! Chris
Very nice video, thank you. There is something I want to ask. I want to observe the data received using Max4466 in a graph that I will create myself. And I plan to see the values of time on the x axis and Frequency (Hz) on the y axis. Now the datas that I measure range is from 0-1023 on the y-axis. How can I convert this 0-1023 range to Hz? Or can it be translated?
Take a look at this - ua-cam.com/video/KaJ4b3HJ3NA/v-deo.html and ua-cam.com/video/CwIWpBqa-nM/v-deo.html I think you are talking about something called a spectrogram.
Hi! I'm starting a project to use an ESP32 as a wireless corded phone. i see that it has an 12-bit ADC and 8-bit DAC. its as good as an old corded phone? do i need another board or something i2s? Iwanted a simple project, i want to focus on integration with alexa. can you help me?? ty!
No, but I think it would definitely be worth trying something like this. I think the ideal setup would be a completely separate power supply and audio isolation as you suggest. I have found though that the I2S microphones seem to have much better power supply rejection making the power supply filtering unnecessary.
Interested in ESP32 Audio: ua-cam.com/play/PL5vDt5AALlRfGVUv2x7riDMIOX34udtKD.html
Looking for all my ESP32 projects: ua-cam.com/play/PL5vDt5AALlRdN2KyL30l8j7kLCxhDUrNw.html
Wow this has to be the best video ever. Sooo cleanly explained
when the ESP8266's first hit the public, as essentially a "wireless serial cable", I immediately wondered about the likelihood of using one of the direct-communication methods they offered to turn a pair of them into an ultra-low-latency wireless audio 'cable'. It's quite nice to see someone else with at least a similar-ish thought, and since I gave up on the idea long ago, it's even nicer to see someone do more than just have a thought about it :)
I found this while planning a project, thanks! Saves at least a few hours of development.
this is a wonderful video!!! i absolutely love audio stuff in electronics! The explanation and the video are amazing!
Thank you! That's very kind of you to say and I really appreciate it.
I agree 100%. Great work!
Interesting, very interesting, I look forward to more videos on this topic, thank you very much for your efforts on our behalf.
Wow I didn't know that ADC of ESP32 was connected to DMA with I2S. It's an incredible piece of equipment. They've put a lot of things in it. Some stuff is being discovered just recently. For the price tag, it's almost overwhelming.
What about the specs? Don't they mention it?
Thanks very much for this, very useful. My project is a 24/7 field recorder, solar-powered, i need to stream the audio to a Pi for storage and this is really helpful.
Glad I could help!
Very interesting video. Thanks for taking the time to make it. I have used the esp32 to read battery voltages which is about as far away from music as you can get. But I was faced with considerable noise as well. What I found worked for me was a filter of 8 readings where did this: (sum of 8 readings - max - min) / 6. This helped because the noise was random very large errors and nowhere near Gaussian noise that benefits from simple averaging.
That's really useful to know - I'm going to try increasing the number of samples I take to get a larger number for the averaging. Also need to work on the power supply to get the noise down even more.
Man you're amazing
This was the best tutorial I've ever seen
Hands down
Please make more videos in subject of electronics
Coming soon!
Awesome piece of hardware the ESP32... I've developed for such hi frequency sampling applications for the ESP8266 through an SPI ADC (MCP3202), but here you can do it in background thanks to the I2S peripheral and the DMA... that's great
could you do real time audio sampling with the MCP3202? it seems like you could.
@@Kalanchoe1 yeah you can, it sounds well if you're able to sample fast enough, but you need a whole core to do it properly (polling), so I discourage it. Alternatively, maybe you can use the SPI master driver wich should support DMA
@@LoZiooo thanks for the knowledge drop. You just expanded my options!
@@Kalanchoe1 you're welcome ✌️
I would suggest the vocabulary "Interference" to describe the power supply signal getting into the audio signal.
It makes some sense to differentiate and use the word "noise" for signals that are of random nature such as the thermal noise associated with resistors or the shot noise associated with current through semiconductor junctions.
Why? because speaking this way makes you always remember to use design countermeasures appropriate for each type of undesirable signal.
Interference is also the right word to use when a signal from another source is getting into another signal. Such as One radio station in the background of another. Or AC power line hum getting into audio. An interesting characteristic (while not often practical) is that you can some times cancel out interference by adding a scaled and inverted (the negative) interfering signal back into the contaminated signal. You cannot cancel thermal or shot noise because they are in your circuit components and never isolated.
Hope this helps.
This is why I love the viewers of this channel. This is a really informative and useful comment.
Great informative video, looking forward to the next one. I've stumbled upon this while looking into the possibility of streaming audio from an intercom to a server (and then to my phone) - and also in reverse - via tapping into the handset speaker and microphone wires (among some others). Using an ESP32. I assume the noise wouldn't be an issue in my case. And your sample code does appear to do exactly what I want, sending the audio to a server :). Of course I would still have to find out if it has the power to do full duplex audio, streaming in both ways simultaneously.
Should be possible - for voice you probably don't need to be sampling at 40KHz, you'll get away with 10KHz pretty easily. If you want to get fancy you could take a look at some very low bitrate codecs.
Even without that you should be able to do full duplex over WiFi. You may want to look at using UDP for streaming the data as it's a bit more lightweight.
I'm going to be investigating my noise issues some more to see how far I can get and I've also got an I2S microphone break out board which will let me bypass the ADC completely. For your project there's also an I2S amplifier breakout board on Adafruit that might be worth looking at.
please, post link if you have chance. thanks sir
Ahh, this has shown to me that I cannot do what I had in mind with an esp32. Thank youuu
What were you thinking of doing?
Amazing graphics here mate. I'm starting out on esp32 as well. Great job bud
Thank you - it's really hard to describe any of this stuff in just words.
Awesome! Thank you very much for sharing your knowledge!
This channel is gold
Your guitar playing is amazing!
May I ask if MAX4466 can be connected to a 5V power supply?
Thanks for mentioning the noise issue, that saved me a lot of time,
Yeah, a good clean power supply is essential for anything audio. I2S microphones seem to be a bit better, but I've still seen some noise issues.
@@atomic14 could that be the reason why the ESP-CAM has noise in the images too? The power supply noise should also affect the camera, shouldn't it? Interesting...
@@atomic14 I used two mics to do SSL (sound source localization using the FFT) let me know if you are interested and I can share with you the details/code
@@raguaviva That sounds really interesting! I'd definitely be interested. We've got a discord group going for the channel if you'd like to jump into that: discord.gg/DJ8EQRXU
@@raguaviva could be yes, depends on what kind of noise you are seeing.
Very well explained. Was helpful to get a first grip on this subject area. Thank you very much!
Glad it was helpful!
Great video. Easy to understand. You forgot to mention what software was used to make this amazing video. Thanks.
Awesome video! Thanks a lot! I have a question about the .raw files getting transmitted to my local PC. Which software do you use to listen to the sound tracks. Do I need to convert the format to a different one than .raw before?
I use Audacity - www.audacityteam.org/ - it has an option for importing raw audio data - you just need to tell it the sample format, number of channels and sample rate.
It would be interesting to record the audio at the same time with a separate isolated device to see how much of the poor quality is caused by the ADC of the ESP32, versus due the noise on Vin. And it would also be interesting to play a recording into the ADC and see how well it comes out. And also interesting to power the microphone from a separate battery as you mentioned in the video. It's a shame the ESP32 ADCs are so weak compared to the rest of it!
I need to do a proper followup video to this series - I've got a really good collection of mics and pre-amps to use. It's definitely in the schedule. I'm also quite keen on actually quantifying how bad the ADC actually is. Separate the performance of the ADC from the mics and see if it really is as bad as everyone says.
@@atomic14 That would be useful. I've read that it is only capable of:
7 Bits ENOB out of the box, closer to 10 Bits with the recommended capacitor and 64 sample averaging as described in the Espressif docs
6 kHz signal bandwidth (presumably the 3 dB cut-off
150 kHz samplerate
Non-linear resoonse and unable to read below about 0.15 V
Reading 254 samples continuosly and then skipping 2 samples whilst it does something internally
Or reading in "continuous mode" which Espressif recommends against because it drops the quality substantially.
Also, apparently, once every 17 seconds there is a window when there is much less noise for a second or so; so any quality measurements will be very different depending on whether you happen to hit that window!
I'd really like to see them improve the ADC in future ESP32 versions.
Excellent video... came looking for info on MAX Mic modules... got it and more...
Just a note, you could power the MAX with a little isolated DC-DC converter (B0505S), often used in USB speakers to remove supply noise and it's not too pricy...
That’s a good suggestion.
very good. what about tinkering with the gain pin on the MAX9814 ? left unconnected it's 60db so if lowered could result in a cleaner sound.
It's worth a try, I found that that I was getting quite a low volume on the voice but it's definitely worth another look. I'm going to do a follow-up video in the next few days as I have some I2S microphones that I want to try out so I'll revisit the MAX9814 at the same time.
@@atomic14 The 60db with a pi and soundcard is very noisy its 40db or 50db with the Max9814. The timing on the A/R is also really too fast for voice the 100nf cap prob should be 680nf or 1uf.
Thank you so much for making this video! I am working on it receently. I want to know if you have any suggestions about external ADC for audio transmission? And how do you record time data when you receive the audio data via WIFI? Thanks again!
I would use an I2S microphone for input in preference to the internal ADCs as the noise seems to be much lower - (ua-cam.com/video/3g7l5bm7fZ8/v-deo.html). For transmitting the audio data, depending on how much bandwidth you have then you can just send the raw audio samples to another device using TCP (or HTTP).
@@atomic14 Around 4:15 of this video you mention picking up the audio on your desktop. Could you explain that setup a little? I'm having trouble getting the I2S audio data to transmit on WiFi. My goal is to have one ESP32 with a digital mic communicate wirelessly to a second ESP, and then play the audio out the I2S amp on that one. I had an analog mic setup working this way with the 8266 version of this card (NodeMCU), but can't seem to do the same with the ESP32 version. Thank you for your excellent videos!!
At 7:36, you show your line conditioner/noise filter you built. Do you have any fotos or more detailed diagrams on this? Especially how connected to the ESP32 and the audio modules? Thanks!
Great video @atomic14. I'm getting the first part of the manual sampling going on a new ESP32 S3, but it seems like the I2S direct link to the onboard ADC has changed. Have you done any work with the S3 to see how to use efficient analog audio sampling without going directly to the DMA buffers?
Hi Pieter Snyman
Am also trying to work with esp32 s3, How to work on it, with using i2s on board ADC?
@@saranyaasuresh5710 in the end I used a digital microphone instead (that does the AD conversion) linked to I2S on the ESP32 S3. The S3 does not have the capability to use its internal ADC with I2S. As far as I understand this is preferable because the ESP32 ADC is not very good.
Thank you, it is a great series of video that helps understand how the audio system works.
I have one question about your server for capturing the audio data, can you please help teach me how is the server setup and how to communicate with ESP32?
So what part of this was I2S? These MAX modules are just microphone amplifiers, no? The way this was hooked up there is no way this was I2S. I guess maybe internally it is as if it was I2S, perhaps all we care about here is a way to read audio from the ADC pin in DMA mode. That's cool. I like the thorough work you did on cleaning up the signal. I am currently designing my own board and thinking I will integrate the MAX9814 as well as an audio amplifier on the DAC line. But not sure, maybe the trick is to keep all audio stuff off the digital PCB to avoid the noise coming in.
Congratulations. Really interesting and right now I should make an I2S encoder to transmit audio with telephone quality via UDP to and from another device on the network. I would like to start trying direct sampling via the internal ADC of the ESP32. Where can I find the complete example indicated in the video (04:08)?
Looking forward to use the adc2 I'll search the playlist for that no-wifi version
Very practical, thumbs up my friend, great video.
thank you for the great video! would it be possible to use a contact mic?
Could you make a video explaining how to convert these samples to dB values?
Thanks so much for the awesome video, you've helped me immensely with my current project. I have a question regarding the internal ADC, is it possible to sample two or more ADC pins simultaneously or close to (i.e. not stopping and starting repeatedly)? I've tried to enable I2S1, but now see it is incompatible the built-in ADC, and i2s_set_adc_mode can only accept a single pin as an argument. Thanks again.
Hi Mike, it looks like it should be possible - there's a bunch of information here that might be useful - github.com/espressif/esp-idf/pull/1991
Hello, nice project, can i use esp 32 cam??
I really enjoyed this video! Thank you :)
I'm glad you enjoyed it - I had a lot of fun making it!
@@atomic14
It's good to hear 😃 I'm waiting for another video.
Btw, is there a place where I can learn about how to use the ESP32's i2s with the arduino IDE?
@@avieleliyahu6199 You should be able to use all the sample code in the Arduino IDE without any problem. Just copy the contents from main.cpp into the sketch file and then create new tabs for the extra files (WiFiCredentials.h, I2SSampler.h, I2SSampler.cpp) and copy the contents of each file in. You create a new tab using the little down arrow on the right - imgur.com/a/nYwfGwS
8:40 Testing, testing. In Mars surface.
How do you manage to get 3.3v after passing 5 volts through those two inductors? I tried the circuit you suggested in your other video, but the voltage drop is more than intended and once reaches the microphone, it is around 2.7v not 3.3v.
Nice video! Is it possible to capture stereo audio by the internal ADC? Thanks
Hello Cris, your video is incredible, with very important information for anyone who wants to understand a little about audio with ESP32. I am very grateful for the class! I'm new and I'm learning, I'm wanting to use an ESP32 with max9814 to listen to a specific frequency range, like 100mhz to 150mhz, is this possible? When listening would activate a trigger. Thank you very much!
Nice video. It had to go to my like list. Will this module be able to stream both video and audio at the same time ?
For audio streaming you can take a look at my walkie-talkie video. I’ve got video streaming coming soon!
Best ever and very useful video,thanks❤
Great video but shouldn't the thumbnail say ADC instead of DAC?
Very nice video, thanks!
Do you think it is feasible to subtract the noise with and OPAmp? One of the opamp imput connected to the mic audio out and the other to the power line?
Or, could it be possible to use two adcs as the same concept? Of course losing wifi, but just for curiosity.
I think the best solution is really putting in a good clean power supply for the microphones. I did find that using the 5v supply with a good LC filter followed by an LDO would give a very clean 3v3 supply for the microphones.
Thnx for this illustrative video. I want to know if Is it possible to work with an analog microphone like MAX9814 using I2S and internal ADC with micropython? Thanks again.
I presume it is useful (or essential) to have at least two DMA buffers to allow reading one whilst writing to the other. But what is the reason for using more than 2 buffers (i.e., 4 in your case)? Or when could this be useful?
There's a maximum size that you can specify for each DMA buffer (I think from memory it's 1024 bytes) so you can use multiple DMA buffers if you want something larger.
@@atomic14 That explains it! Thanks for responding so fast. I didn't know there was a limit on buffer length. Is there a limit on number of DMA buffers (memory permitting)?
from where noise is? If you connect your mic with MAX preamp to line input of your laptop, it's pretty clean sound yet!
After "yarn start" in the console .Console window is stuck at this message "server started at 0.0.0.0:5003" and nothing is happening after that.There is no raw file created in server section. What can be the issue?
thank you so much, Interesting content, you earned one more subscriber
Hello
Its a great explanation tutorial, I am using ESP32 s3 korvo 2 where there are 2 mics, embedded in it. Can I select and use one mic and what changes should I need to do in the code to get input using i2s
Great video. I'm using I2S just to measure one analog input. However, I'd like to measure two but have no idea how to set this up. So far all I've managed is to get loads of crashes or no data at all. Can you assist? Not sure if it's even possible. Cheers. Matt
Thanks for that video, TIL something new! 👍 'd and subbed.
I'm currently working on a very similar esp32 project (even using the same Microphones 😀), but when measuring the duration i2s_read(), I get very weird timings which are not correlating with the sample rate set in the i2s config. Do you maybe know what's happening here?
e.g. sample_rate = 40000, I get 6.3ms for an average i2s_read of 512samples (1024 bytes) buffer. Which is odd, because 512/40000 is ~ 12.8ms already. So I thought "okay, it's maybe twice as fast as I expected because I use only one channel"
So when I turn the sample_rate down to 20000, I would expect the duration of i2s_read to be DOUBLE (~12.6ms) for the same amount of data (which almost matches the calculation for 40kHz). but instead it goes down to ~5.9 to 6ms for 20kHz@512 samples ???
Okay, let's turn it down to 10kHz, I get ~5.4ms ... 1kHz, I get 825µs... . Are you familiar with that kind of issue? I need my data to be as exactly timed as possible, and these measurements make absolutely no sense to me.
Thanks for reading, and if you can explain that one to me, you'll have my eternal gratitude. Great video, animations and explaining!
Hi, I am also facing similar issue. Did you find any solution? We can get in touch and discuss. Please ping back so that I can share my email Id with you.
is it plausible for a ESP32 to operate on wifi with audio streamed (I2S) and control a neopixel strip simultaneously
Incredible thank you!
incredible work...
Hi Atomic14
Thanks for this great Video!
I'am working on a projekt where i have to write down audio data to an SD card.
I managed it with the help of your tutorial.
But there are still some point where i get confused:
It's the DMA buffer count and buffer size. I also read the ESP32 manual/ datassheet but it does not explain the DMA Buffer very well.
Questions in my head: why a buffer count of 4 with a size of 1024? Why not just 2. I also getting confused, why its just not 2 buffers? Is it to reduce the latency?
And then you use a local buffer to store the content of the DMA Buffer. Here you use also a double Buffer!? Why? And how to caculate the local buffer size and so on is fucking my brain a litte bit. Seems to be a bit tricky.... maybe because the i2s periphirial always uses stereo? I just want to record mono sound.
If you want/can do, i would love to get some more explanations about the DMA buffer and the local buffers and their sizes.
Anyway, thank you very much for this and your other tutorials.
(Just to mention.... i studied informatics... but its a long time ago and i didnt used my knowledge for a long time... but iam familliar with the basics of bits an bytes... and also with C++... i know the difference between stack and heap and so on. What i try to say: I'am not an copy paste arduino newbe... i have some background. But this i2s DMA buffer stuff is compleatly new to me and its bad documentated... and tutorials on this topic very rar. And i never did audio things befor.)
Hi Dominik, I was thinking of doing exactly that for my next project - I've had a few people ask about writing audio to an SD Card and thought it might be quite good.
On the DMA buffer size and count - there's a maximum size for each buffer of 1024 so if you want more space then you need multiple buffers.
The amount of space you allocate for the DMA buffers is a bit of a trade-off. More space means the CPU has to service the I2S device less frequently. But comes at the cost of increased latency.
You are correct to pick up on the fact that I also have the double buffers where I'm storing the audio data before it gets transmitted over the HTTP request.
My thinking around this was as follows: I wanted to send a reasonable amount of data in one go so that I wasn't trying to make too many HTTP requests in rapid succession. So I needed to buffer up the audio data before sending it. I picked quite a large amount for the DMA buffers to reduce the load on the CPU to as small as possible to make sure the data would be transmitted successfully. It's likely that I could get away with a much smaller total DMA size as there's not really much CPU work going on but I wasn't too concerned about latency.
The size of my local buffers where I hold the audio data before sending over HTTP was down to a tradeoff between how rapidly I wanted to send the HTTP requests and how much free RAM the device has for holding the audio data.
Potentially, you could increase the total DMA buffer size to the point where you have enough time to send the audio data without double buffering. This is the approach I've taken in my Walkie-Talkie code where accumulate the samples into one buffer before sending them out and rely on the DMA buffers to hold the samples that are coming in.
In my Walkie-Talkie project, I've used 4 DMA buffers of 64 bytes which gives about 16ms of audio data when sampling at 16KHz - I'm actually thinking of increasing the size of the DMA buffers to give a bit more time.
There's quite a bit of guesswork and assumptions on my side around a lot of how this works.
Hope that helps!
@@atomic14 Wow, thank you very much for this fast and explaining anser!
The first answer which helped me A LOT was the fakt that the max size of each each DMA Buffer is 1024. I played around with the buffer size but then i got a "paniced" error from my ESP32. Now i know why.
However, when i specify the Buffer count and size, it gets allocated at one block in the RAM? Or how does it work? To sad that there is not a good documentaion from espressive. :( Or is there any i didn't found? ). I think it is task controlled. So every time one DMA buffer is full, the task get notified and can read the bytes into a local buffer!?
Sad to say, but I'am also not familiar with the FreeRTOS and Task things. I know about multithreading in Java... like race conditions... deathlock situations an so on. In that past i had build an Java Project which was connected to over 3000 gameservers simultainisly with more than 50000 Threads and and including a selfe written HTTP Server to provide an interface for the users. Well... some time went along since I did this... However...
I understand now why you use a "local" buffer. I faced some problems while writing 44100hz Audio Data to the SD card. I made some mistakes. Frist Problem was, that i opened the File to write every time when the buffer was full. Second problem was that i wrote every bye as a single byte. The "overhead" from the SD library was way the high. Now i changed the code too write the samples from the local buffer to the file in bigger chunks with the File::file.write(bytesToWrite, numberOfBytesToWrite) funktion. That was the key to get rid of loosing samples.
But overall, i didnt really understand the DAM buffers in detail. I would apreciate if you would share your knowlage about it in detail! :)
Another think i didn't really get is the const uint32_t usStackDepth from the xTaskCreatePinnedToCore funktion. Seems like to be bit of trail and error, to not run out of stack!? But is has nothing to do with the DMA buffer oder the "local" Buffer, right?
THanks a LOT!
@@dominikwinkler2718 No problem - happy I can help!
There are some docs here that explain the workings of the DMA system - section 6 is quite interesting www.espressif.com/sites/default/files/documentation/esp32_technical_reference_manual_en.pdf
It's basically created a linked list in memory. So each buffer is allocated separately.
I think under the hood it's all interrupt driven but with the I2S driver you can give it a handle to a queue and get notified via that when things have happened (a buffer has been filled/emptied etc...).
On the stack size - I've found that's very much trial and error as you really don't have any way of really knowing how much stack space you're going to need. I've ended up with the classic programmer approach of using powers of two - 1024, 2048, 4096 until it stops crashing :) As you say though, it's completely independent of the DMA buffer size and only relates to stack usage - so local variables and function calls. You can easily accidentally blow the stack by doing a large local array variable.
I must admit, I'm still learning about the embedded world. There are some things I still find very odd in the embedded world. I'm finding Arduino libraries particularly strange - they really love their global variables.
@@atomic14 So nice to getting i touch with you! Thanks!
I didn't found THIS reference manual you linked so far! That, helps me again a lot. Sorry... as i mentioned... I'am quite new to this ESP stuff!
Another thing: Shouldn't we call call i2s_stop(I2S_NUM_0) befor we call i2s_read(....., ...) ? and then - after reading from the DMA buffer - call i2s_start(I2S_NUM_0) to prevent reading interrupted data?
About the stack thing.... i dont worry at the moment... but i was right that it has nothing to do with the DMA buffer, thats good so far! THank you!
However: You might be new to the embedded world... but you are definitly NOT new to c++ programming. You are using classes... sub- or child classes ... using pointers where ever you can to safe time and memory. Thats great if you are a good c++ coder.... but to be honest, for a youtube tutorial, it might be a little bit of overkill for some viewers. It took me some time get back into all that c++ class stuff. For an easy tutorial video for the "mainstream" .... for most of the Arduino "Makers"... it might be hard to understand. I think that is the reason why "Arduino" lover their global variables so much. They want to keep it as simple as possible to make it possible fore everyone to get started with coding and electronics.
During my informatics studies i faced a LOT of
fellow students who didn't even unterstandstand what a pointer is. Things like * or & ...... ooooohhhhh they got feared :D . What is an memory address ? Why can i cast any number to a void* and just put data at this point of the memory (if exists ^^) .... and why can i user [x] brackets on a pointer and just write to another adress even if i never declared an array ^^ ? An What the heck is malloc()? In Java or any other managed language I don't even care.... i just declare an var... or list... and the garbage with take care about it.
What i try to say is: for many people (including me) its hard to understand all this deep C++ or asm stuff.
Well, in the past i reengineered .exe files with ollydbg and wrote sometimes memory cheats for games. So when you wrote your frist on the fly memory hack/cheat to make a JUMP to a part of the free heap and placed your own peace of code there in asm or placed some NOP's to get rid of damage if you are tackled .... then you know what I'am talking about. but... thats totally nerd shit! ^^ . But i did it about 20 years ago.
If iam allowed to give you a hint: Try to make your brilliant video tutorials even better if you write the code you present as EASY as possible! This might give you even more subscribes! Especcially on this i2s topic.... because there aren't much good tutorials.
Lets keep in contact :) .... I'am looking forward to your next tutorials! :)
@@dominikwinkler2718 Thanks Domonik - I think you are right. I sometimes forget that I have a lot more experience of C++ than a lot of people. Once you've learned something it's sometimes hard to remember what it was like when you didn't know it. The i2s_read takes care of any synchronisation - I believe it will only read from completed buffers. Though I'm not sure what happens if the i2s peripheral wraps around the DMA buffers. My C++ is actually very out of date now. The last time I worked in C++ was probably about 15 years ago! But I am thinking of doing a series of "basic" C++ videos.
Very informative video. I've learnt a lot about audio sampling on the ESP32 from it. I have a question about the MAX9814 calibration though. There is a 1.25V DC bias built into the MAX9814 which I can see in the loop_sampling code serial print voltage output. When I use the same device using your i2s_sampling code the raw sound data I capture on the server is also biased when I look at it in Audacity, (positive 0.5). Is this something I can calibrate out using i2s_read?
Nice tutorial. I have a simple question. The way that you've connected the output of the max9814 to the esp32 aren't we clipping the part of the audio signal that goes below 0v? I have an max9814 and connected to my scope and I can see min of -250mV to 720mv (for some random sound). Aren't we losing the signal in this config? I hooked mine up and I can record audio and it sounds fine (I guess) but I'm curious if we are losing information without some sort of offset for the output of the max9814 to push it above 0V.
That's interesting, the output should not be able to go negative at all provided you have the GND connected to 0v and VCC to 3.3V. It should be biased at 1.25V on the output and go 2Vpp (so 0.25 to 2.25 volts) - cdn-learn.adafruit.com/downloads/pdf/adafruit-agc-electret-microphone-amplifier-max9814.pdf
@@atomic14 I made a noob mistake. I connected the MAX9814 to my scope and had AC coupling enabled. Switching to DC coupling I see the signal hovering around 1.28V (avg) which is inline with the spec. Thank you again for a great video!
Brilliant code. Thanks a lot
I am not using i2s microphone . I am just using condenser microphone and I made amplifier using that .Will your code work for me?
HI there, I got a problem for Esp32S3 with Max9814 and when i first say hello it will display and when I second time it diaplay null, how can i slove it? I use arduino to code it. So please help❤
i am trying to replicate this but on a esp32 cam. so many GPIOs are inaccessible is it possible?
Hi, great video Thanks I have a doubt regarding the i2s ADC with potentiometer are you using DMA or by creating task.
in my project I need to use DMA for my ECG sensor can this also be implemented this way since i2s is Audio can this be used directly with the Internal ADC.
please do reply asap.
Thanks in advance
Apologies for the delay in replying - yes, the DMA and I2S can be used directly with the internal ADC - it doesn't have to be an audio signal.
Thank you for this video
Hi! Could you please tell me, what components did you use to filter the signal? I mean the diagram in the 7:32 video. What LRD chip did you use? and what capacitance of the capacitor did you use on the right?
did you figure this out? 🙈
is it a 470 microfarad capacitor?
Thanks for all the great info. I am a 'bit' confused about the bit per sample of 16/32 vs the 12bit wide adc of the esp32. How do they relate if at all? What's the difference? I'd also like to understand the fixed mclk and intr alloc flag better. If anyone can explain.
great !!! . good luck .
Thank you! You too!
Hey I was wondering if you could make a video or two on how to setup the local server using node.js cause its my first time using it and I'll be honest I'm having some real issues with setting it up. I was hoping that the instructions you posted on github would suffice but i only got as far as having "node ---version" and "yarn --version" giving me a good response. When trying to do "cd server" in node.js command prompt it just tells me that it couldn't find the specified path and now I don't really know what to do. Some help would be much appreciated.
Extremely Fruitful for me , i have one question . Why you are not using INMP441 I2S microphone!?
Also please make a same video for that too.
I actually have an I2S MEMS Microphone (www.mouser.com/datasheet/2/218/ph0645lm4h-b-datasheet-rev-c-1525723.pdf) on an Adafruit breakout board on order right now! Soon as it arrives I'll do a video to compare the performance.
@@atomic14 extremely excited to see the comparison bcoz yesterday i see that inside a samsung earbuds they used the INMP441 microphone 😎
@@Dharm1999 Will do!
The Code at 3:44 is missing in the github, can some one please make the code in the video available? thanks a lot!
I have a newer ESP32-S3 I'm looking for a way to transfer readings from the internal ADC to memory the fastest way possible I can't get DMA to work for me. Is there anyone that can assist me or guide me in the right way. I am also using Arduino IDE.
I am using a condenser microphone not a i2s one and made a amplifier circuit using that. I manage to get that signal in matlab an tried to play it but I am not able to hear clear signal. I think there is a problem in arduino coding . Can you help me to get clear signal using condenser microphone amplifier?
Can someone tell me without any external SD/Memory, how long of an audio message can the ESP32 record while it's on?
Hi Dhiman, it really depends on the sample rate and the number of bits you want to store. If it's just voice then you could get away with 8-bit samples at 10KHz. That would give you around 8KB per second. The WROOM has 520KB of SRAM built-in, but typically I find I only have around 150KB free once my code is running. So that would give you around 15 seconds or audio. You could try and stream the audio to the built-in flash which is 4MB - the amount of space available depends on the partition scheme you set up, but if you set aside 2MB then you'd have about 200 seconds so around 3 minutes or so. Hope that helps. There's no reason why you couldn't compress the audio as it comes in - there are some very good audio codecs that will compress voice down to very low bit rates (search for 3gpp voice codecs).
@@atomic14 thanks mate. Great content. Subbed. 👍
What software did you used to simulate that median filter
I have a simple animation library I've written to help me show waveforms and run simple processing. Unfortunately it's not really suitable for sharing as the code is very messy.
@@atomic14 I understand. Thank you so much for replying !
Is it possible to connect multiple mics to the internal ADC since it have multiple channels? And how does the hardware connection look like? Thanks!
possible, but looks pretty complicated - esp32.com/viewtopic.php?t=17547
Could you please include the I2SOutput file/directory
At 04:45, what is the function of "this" as the pvParameters argument for xTaskCreatePinnedToCore()? The Espressif documentation says "pvParameters: Pointer that will be used as the parameter for the task being created."
On the task function definition, you'll see that it's defined as void task_function(void *param) - the value of the param is what you pass into xTaskCreatePinnedToCore. So this allows you to pass data to the task you are creating. In my case, I'm just passing in a pointer to the current instance.
@@atomic14 Thanks. Makes more sense after downloading the source files and seeing the full thing. I'm used to using plain C as much as possible and didn't realise it was inside a method of a class.
Could you kindly show me how to read the files for ADC from the DMA??
hi atomic14, I come from Indonesia.. I really like this world.. I often watch your videos, can you make a video tutorial for a good multi track audio record using Arduino or ESP32... for music recording or just make a prototype? Thanks
Hey, how do I connect the I2S pins on the hardware?
Thank you for sharing
SIR this system can coccected with LORA and able to transmit voice data and receve
Do you know if it's possible to connect a i2s MIC (or use the MAX9814 via i2s) and an i2s output module. I wondering if it would be possible to create a 2 way intercomm type device, where I could speak and listen at the same time. Ideally I would connect the i2s output module to headphones to avoid feedback going into the i2s MIC. I suspect it's not to hard to create a walkie talkie (either record or output audio at any time but not both), but I am intrigued by the idea of the intercomm type setup.
Definitely possible - you can run input and output simultaneously. In theory you can use a single I2S peripheral for both input and output - though in practice this can be a bit difficult depending on the devices you have.
In my Alexa project I'm actually running both an I2S microphone and and I2S amplifier at the same time using both the I2S peripherals. When I don't need any output I just play silence and when I don't need any input I just ignore the samples coming in. Have a look at ua-cam.com/video/At8PDQ3g7FQ/v-deo.html and ua-cam.com/video/3g7l5bm7fZ8/v-deo.html - you can also have a look at the code for the Alexa project - ua-cam.com/video/FZ4ayyTXM2s/v-deo.html
I dont know how to combine the code for using ADC through I2S. I tried it but I am getting a lot of errors. Could somebody please send me the complete code which is ready to use. Thank you. (newbie here)
Superb 🤩
The Max9814 is definitely better but its a shame the boards come with A/R capacitor it has as its a bit too fast and reactive for voice. On the Pi into a soundcard the Max9814 sounds as good as your later I2S ones unless you start turning up the gain but that is a lot of gain with it already onboard.
Did you set the programable gain to 40/50db as the 60db gain is noisy.
I am still a big fan of electrets as if you can still get really good quality directional (cardoid) ones and that can really help other omni directional when you don't have beamforming.
My old eyes and clumsy hands went off the Max9814 board as really the A/R timing cap should be bigger and my preference for directional electrets means a lot of fiddly soldering especialy that smd cap.
Max9812 doesn't have AGC and often doesn't come with an electret which for me is actually preferential on a sound card with a PI they are far better than what seems the ESP ADC.
I wonder if other boards have cleaner lines and track spacings?
I think a lot of the noise is just poor power supply rejection on the breakout boards. I did try adjusting hte gain and got similar results. I have heard from a few people using ICS microphones who have also got a lot of noise. I think it's quite easy to pick up interference from all sorts of places.
@@atomic14 Dunno we look like we where usuing the same 'aliexpress' max9814 and yeah the top 60db gain is rather horrible.
I also found some weird gnd loops depending on how I had things.
On a Pi using the 5v I think maybe 3.3 (forgot) the max9814 can sound much cleaner, I have the sound card gain really low 0-9db max I think with the lowest gain setting as each sample is still loud at desktop distance.
I did have a rockpiS (rk3088) and the adc sucked for some reason and was actually worse than your getting.
@@atomic14 drive.google.com/open?id=1FVU1xSI3D8-53yYh9oen5L53PKoPJCiA Thats a Max9814 powered direct from the Pi into a soundcard.
How to use channel 1 of i2s with adc1? Thanh you so much
How to use arduino, 16bit adc and Bluetooth module to transmit digital audio to bluetooth earphone?
I'm afraid that's a bit more complicated than what I've done here. This might help www.reddit.com/r/esp32/comments/ah9c2t/has_anyone_played_sound_from_an_esp32_to_a/ but it is for ESP32 not Adruino.
Could i use this to read 16 bit pcm sound coming out of an old disc changer?
You'd need something to convert the signal to I2S - it depends on what format the data is coming out in.
Hey, thanks for the information it was very helpfull. I came to your channel looking for esp cams that can also manage audio, maybe you have some information that can be usefull about it?.
could you please help i'v got this error
TypeError: Cannot read property 'length' of undefined
at /Users/mac/Documents/Arduino/esp32_audio-master/server/src/index.js:22:35
I think this is now resolved in the GitHub issue - github.com/atomic14/esp32_audio/issues/6
How did you deal with the I2s buffer? seems to always return the second half as 0
If you've got it set to read from both channels then every other sample will be 0 unless you have something hooked up. Feel free to raise an issue on GitHub though and we can take a look at what's going on.
@@atomic14 i did on the arduinofft github, i will add the code although it is based on your example except that i changed it to read from the internal adc
Btw i think i double posted this question.... sorry about that
@@TheElectronicEngineer No worries!
@@TheElectronicEngineer Post a link to the issue and I'll take a look and see if I can help.
Espressif documentation link no longer works
This is a very good contribution to the community. Thanks and congrats. So I am trying to port your IS2 over ADC code to ESP-IDF but I am facing some difficulties ... that might be related to my basic skills on this ... so could you help me understanding what is being handling in this function and what it is required? Also do you have any comments on porting this code to ESP-IDF?
/**
* Process the raw data that have been read from the I2S peripherals into samples
**/
void ADCSampler::processI2SData(uint8_t *i2sData, size_t bytesRead)
{
uint16_t *rawSamples = (uint16_t *)i2sData;
for (int i = 0; i < bytesRead / 2; i++)
{
addSample((2048 - (rawSamples[i] & 0xfff)) * 15);
}
}
Hi Rafael,
I should add some commends to the code base explain what is happening - it is a bit weird.
When reading from the ADC you get a 16bit value from the I2S interface. The top 4 bits of that are the ADC channel that is being read from. So to get the ADC sample we need to remove those top 4 bits
This is what this line of code does:
sample = sample & 0xfff
That give us 12 bits with sample information in it. The values run from 0 to 4095 and are inverted - so 0 is the maximum value and 4095 is the minimum value. So the next line of code translates that into 2048 for the maximum value and -2047 for the minimum value:
sample = 2048 - sample
The * 15 is just amplifies the value up so we can hear it clearly - in theory I think we could just shift left by 4 bits to get the full 16 bit range.
I think the code should just work on the ESP-IDF - you will need to remove any reference to Arduino.h - I think the only thing it is bringing in are types like uint16_t which you can get from
#include
If you have any problems them it's probably easier to open an issue on the GitHub repo as it's a bit easier to share code there.
Good luck with your project!
Chris
Very nice video, thank you. There is something I want to ask. I want to observe the data received using Max4466 in a graph that I will create myself. And I plan to see the values of time on the x axis and Frequency (Hz) on the y axis. Now the datas that I measure range is from 0-1023 on the y-axis. How can I convert this 0-1023 range to Hz? Or can it be translated?
Take a look at this - ua-cam.com/video/KaJ4b3HJ3NA/v-deo.html and ua-cam.com/video/CwIWpBqa-nM/v-deo.html I think you are talking about something called a spectrogram.
Hi! I'm starting a project to use an ESP32 as a wireless corded phone. i see that it has an 12-bit ADC and 8-bit DAC. its as good as an old corded phone? do i need another board or something i2s? Iwanted a simple project, i want to focus on integration with alexa. can you help me?? ty!
They are probably good enough for your use case. The quality won't be amazing, but it's pretty hard to get good quality anyway.
Did you try using a B0505S for isolation?
No, but I think it would definitely be worth trying something like this. I think the ideal setup would be a completely separate power supply and audio isolation as you suggest. I have found though that the I2S microphones seem to have much better power supply rejection making the power supply filtering unnecessary.
is esp8266 have adc_get_raw?