Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

I2S Support #427

Closed
4refr0nt opened this issue Jun 14, 2015 · 22 comments · Fixed by #7874
Closed

I2S Support #427

4refr0nt opened this issue Jun 14, 2015 · 22 comments · Fixed by #7874

Comments

@4refr0nt
Copy link

4refr0nt commented Jun 14, 2015

Now, we know how work I2S on ESP8266
https://github.com/espressif/esp8266_mp3_decoder/blob/master/mp3/include/i2s_reg.h

Want to back this issue? Post a bounty on it! We accept bounties via Bountysource.

@alecapu
Copy link

alecapu commented Sep 28, 2015

I've a test app that use I2S TX and RX in loopback using the ESP8266 SDK...
I'm try to migrate it to Arduino, but I've some problem with interrupt calls. Can some one help me ?

@Links2004 Links2004 added the I2S label Nov 27, 2015
@torntrousers
Copy link
Contributor

I'd really love to have I2S from the ESP/Arduino code to play saved audio/sounds. Here's a naive attempt that makes some buzzes and whistles so shows it compiles and runs, if nothing else maybe it might prompt someone who knows what they're doing to write an example that works ...

(I connect an 8ohm headphone directly to gpio3 (i2s output) and its quiet but easily audible. The mp3 demo says thats probably not advisable but it hasn't broken anything for me.)

Also, sketch uploads fail while the headphone is connected to gpio3 so need to disconnected to upload.

#include <ESP8266WiFi.h>
#include <i2s.h>
#include <i2s_reg.h>

void setup() {
   Serial.begin(115200); Serial.println();
   Serial.println("setup");

   // don't know if WiFi interupts will interfere with the i2s timing so for now switch it off
   Serial.println("WiFi off");
   WiFi.disconnect(true);
   delay(2000);

   // need to do something like i2sInit like i2s_freertos.c at: https://github.com/espressif/ESP8266_MP3_DECODER/blob/master/mp3/driver/i2s_freertos.c
   // i2sInit(); 
   // init doc in ESP I2S Module Description, looks a bit complicated, see http://bbs.espressif.com/download/file.php?id=658

//   i2c_writeReg_Mask_def(i2c_bbpll, i2c_bbpll_en_audio_clock_out, 1);

}

void loop() {
   Serial.println("loop");
   playIt();
   delay(5000);   
}

void playIt() {
   Serial.println("i2s begin");
   i2s_begin();

   Serial.println("i2s set rate");
 //  i2s_set_rate(22050);
  i2s_set_rate(8000);

   // read PCM samples from array or spiffs ...

   Serial.println("i2s write sample");
   for ( int i=0; i<65536; i++) {
      i2s_write_lr(i, i);   // this gives a steady buzzing
//      int sx = sampToI2sPwm(i); // this gives clicks and high pitch tones
//      i2s_write_lr(sx, sx);   
      if ((i % 1000) == 0) yield(); // without this get WDT resets
   }

   Serial.println("i2s end");
   i2s_end();
}

// These from the i2s demo look useful  https://github.com/espressif/ESP8266_MP3_DECODER

//Array with 32-bit values which have one bit more set to '1' in every consecutive array index value
const unsigned int ICACHE_RODATA_ATTR fakePwm[]={ 0x00000010, 0x00000410, 0x00400410, 0x00400C10, 0x00500C10, 0x00D00C10, 0x20D00C10, 0x21D00C10, 0x21D80C10, 
  0xA1D80C10, 0xA1D80D10, 0xA1D80D30, 0xA1DC0D30, 0xA1DC8D30, 0xB1DC8D30, 0xB9DC8D30, 0xB9FC8D30, 0xBDFC8D30, 0xBDFE8D30, 
  0xBDFE8D32, 0xBDFE8D33, 0xBDFECD33, 0xFDFECD33, 0xFDFECD73, 0xFDFEDD73, 0xFFFEDD73, 0xFFFEDD7B, 0xFFFEFD7B, 0xFFFFFD7B, 
  0xFFFFFDFB, 0xFFFFFFFB, 0xFFFFFFFF};

int sampToI2sPwm(short s) {
  //Okay, when this is enabled it means a speaker is connected *directly* to the data output. Instead of
  //having a nice PCM signal, we fake a PWM signal here.
  static int err=0;
  int samp=s;
  samp=(samp+32768);  //to unsigned
  samp-=err;      //Add the error we made when rounding the previous sample (error diffusion)
  //clip value
  if (samp>65535) samp=65535;
  if (samp<0) samp=0;
  //send pwm value for sample value
  samp=fakePwm[samp>>11];
  err=(samp&0x7ff); //Save rounding error.
  return samp;
}

//Reformat the 16-bit mono sample to a format we can send to I2S.
static int sampToI2s(char s) {
  //We can send a 32-bit sample to the I2S subsystem and the DAC will neatly split it up in 2
  //16-bit analog values, one for left and one for right.

  //Duplicate 16-bit sample to both the L and R channel
  int samp=s;
  samp=(samp)&0xffff;
  samp=(samp<<16)|samp;
  return samp;
} 

@igrr igrr removed the I2S label Feb 27, 2016
@bbx10
Copy link
Contributor

bbx10 commented Sep 14, 2016

http://www.esp8266.com/viewtopic.php?f=11&t=11790

Here is an example for playing WAV files via I2S interface.

@devyte
Copy link
Collaborator

devyte commented Oct 20, 2017

Arduino reference for the class is here.

@Protonerd
Copy link

Is there an easy way to convert mono wav files to I2S format in run time? The referenced Arduino I2S lib can only play stereo files but most of the files I want to play are mono coded.
Or does I2S have a mono operating mode?

@devyte devyte added this to the 2.6.0 milestone Jan 10, 2018
@tedhsieh1966
Copy link

Is there any way to play 20, 24, 32 bits audio?

@teaalltr
Copy link

teaalltr commented Sep 9, 2019

Any news on i2s audio input?

@tedhsieh1966
Copy link

tedhsieh1966 commented Sep 9, 2019 via email

@earlephilhower earlephilhower modified the milestones: 2.6.0, 3.0.0 Oct 15, 2019
@earlephilhower
Copy link
Collaborator

Moving to 3.0. The pure Arduino I2S setup is immensely different than the current setup. The support for add'l bitrate/bps is not difficult, but the way that blocks are xfered to the app is quite different than the simple roud-robin async process we have now.

@artua
Copy link

artua commented Nov 5, 2019

Hi,
@earlephilhower can we use i2s input to get data from PDM mics? Any examples?

Thanks!

@earlephilhower
Copy link
Collaborator

There is an i2sinput example in the repo already. Take a look at it. I've run out on an i2s microphone taken from the Google AIY cardboard box project, and it seemed to go just fine.

@artua
Copy link

artua commented Nov 5, 2019 via email

@earlephilhower
Copy link
Collaborator

Ah, didn't see PDM. That's not I2S, that's pulse density modulation which is an analog (timing/duty cycle) based protocol as far as I understand it.

I2S is not the right way to read them, but I suppose with a lot of post-processing you could do it by calculating bit-by-bit density and translating into a 0-N code. It would be horribly CPU inefficient, though.

@artua
Copy link

artua commented Nov 5, 2019 via email

@earlephilhower
Copy link
Collaborator

earlephilhower commented Nov 5, 2019

Yes, you could supersample by setting as high a clock frequency as possible (remember the frequency will be 16-bits * the Fs) then use a popcount (I think there's a GCC internal, if not lots of algorithms are available on DSP processing sites). Filtering this will also be interesting as you will pick up harmonics due to the processing.

There's no code or hardware in the 8266 or in my audio libraries to anything like this, though, you will be on your own. If you do get something working, feel free to make a PR for the core or examples.

@artua
Copy link

artua commented Nov 5, 2019 via email

@earlephilhower
Copy link
Collaborator

No, it won't give you anything other than the binary waveform. No integer values. You need to find a way to postprocess the entire recording from a bitstream into ints of some precision. It's complicated to do properly. And slow since you're processing things bit-by-bit on a moving window.

Real I2S microphones just return a nice stream of 16- or even 32-bit samples every clock period and "just work." No processing/etc, the ADC is done inside the mike and it returns the real PCM sample each period which you can use, plot, etc.

@artua
Copy link

artua commented Nov 5, 2019 via email

@devyte
Copy link
Collaborator

devyte commented Nov 6, 2019

@artua I suggest looking at the i2s input example.
Also, use of PDM is off-topic for this issue. If you would like to investigate it and contribute an implementation, please open a new issue, and discussion can proceed there.

@artua
Copy link

artua commented Nov 6, 2019 via email

@artua
Copy link

artua commented Mar 24, 2020

hi, should I post it here?
#7164

earlephilhower added a commit to earlephilhower/Arduino that referenced this issue Feb 13, 2021
Fixes esp8266#427

Adds a basic I2S class based off of the Arduino-SAMD core.  The raw
i2s_xxx functions are still a better  way to use I2S due to their
flexibility, but this will allow basic Arduino sketches to work.
earlephilhower added a commit that referenced this issue Mar 7, 2021
Fixes #427

Adds a basic I2S class based off of the Arduino-SAMD core.  The raw
i2s_xxx functions are still a better  way to use I2S due to their
flexibility, but this will allow basic Arduino sketches to work.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

13 participants