WMXZ, you are a gentleman and a scholar.
WMXZ, you are a gentleman and a scholar.
Here you go. I just uploaded an update adding the TDM mode (change in config.h) and correcting the hibernate issue discussed in other thread.
As said, I have no means to test TDM mode here, but at least it compiles and runs without crashing.
Note: when using 5 Microphones, you may have channel rotation issues (128 does not divide by 5 without remainder) So, every 5 audio blocks you should have the same channel sequence. let me know if there are any issues.
I was able to compile, flash and test the code, this is what it sounds like:
https://drive.google.com/open?id=1T0...GyRmXPEAW1zk2X
It sounds pretty jumbled. Could this be the channel rotation issue you mentioned?
could a number of mics be defined in the configuration file and frames divided up into 32 bit blocks?
also there were no menu configuration items, I'm still trying to read and understand how the code is setup, so maybe this is just how it is supposed to be. I checked the timing with an oscilloscope and it looks good. So it is probably just bit shuffling issues. Where should I investigate?
Also, I noticed that the Teensy shuts down every so often, is this the hibernation issue?
@dreggory,
there are a couple of issues:
1) wav header is not correct (will change that); best is to skip the first 50 bytes, then chan 1 should be first.
2) the microphones are clipping, looks like bad power connection, and also data connection; what is exactly your setup, can you post a picture?
channel 1 is for half the file some low level signal, than it goes to clipping, so I think there is no rotation going on, at least there is no indication in the data.
during the same test session I used a different recording program and I verified that the microphones were configured properly. you can hear that the audio is okay.
https://drive.google.com/open?id=1Fx...VdYIoXzFHhGc6p
this is the code I used:
this was provided by a user here on this forum named Pedro. I think it misses samples and is limited by what it can capture. But it shows that my setup is valid.Code:// Record TDM input sound as raw data (16ch, Signed 24-bit little-endian PCM, 44.1kHz, little-endian) to a SD card. // Note: Format is modified so that mics align their 24 bit data to 32 bit slots, half of the 16 bit // channels end up being the 8 low bits, and 8 more zeros which are discarded. // // Hardware: // Mic Pin 6 (SD_O) to Teensy Pin 9 SCLK (Output, 11.3 MHz, Checked) // Mic Pin 8 (SCK_I) to Teensy Pin 13 SDATA (Input, 11.3 Mbit/sec) // Mic Pin 10 (WS_I) to Teensy Pin 23 FS (Output, 44100 Hz, Checked) // // Mic GND Pins (1, 3, 5, 7 and 9) to Teensy GND // Mic VDD to Teensy 3.3V // At startup of the ICS-52000, the start of the frame sync (WS_I) signal should be delayed from the start of the serial clock (SCK_I) by at // least 10 ms. This enables the microphone’s internal circuits to completely initialize before starting the synchronization sequence // with other microphones in the TDM array. This delay can be implemented either by enabling the WS output (FS) on the clock master at // least 10 ms after the SCK_I is enabled, or by externally controlling the signals given to the ICS-52000s. // // // This example code is in the public domain. #include <Audio.h> #include <Wire.h> #include <SPI.h> #include <SD.h> #include <SerialFlash.h> // GUItool: begin automatically generated code AudioInputTDM tdm1; //xy=359,317 //AudioRecordQueue queue13; //xy=620,615 //AudioRecordQueue queue14; //xy=620,649 //AudioRecordQueue queue15; //xy=620,682 //AudioRecordQueue queue12; //xy=621,581 //AudioRecordQueue queue16; //xy=622,716 //AudioRecordQueue queue9; //xy=623,480 //AudioRecordQueue queue10; //xy=623,514 //AudioRecordQueue queue11; //xy=623,547 //AudioRecordQueue queue4; //xy=624,315 AudioRecordQueue queue5; //xy=624,348 AudioRecordQueue queue6; //xy=624,381 //AudioRecordQueue queue7; //xy=624,414 //AudioRecordQueue queue3; //xy=625,281 //AudioRecordQueue queue8; //xy=625,447 //AudioRecordQueue queue2; //xy=626,248 //AudioRecordQueue queue1; //xy=627,214 //AudioConnection patchCord1(tdm1, 0, queue1, 0); //AudioConnection patchCord2(tdm1, 1, queue2, 0); //AudioConnection patchCord3(tdm1, 2, queue3, 0); //AudioConnection patchCord4(tdm1, 3, queue4, 0); AudioConnection patchCord5(tdm1, 4, queue5, 0); AudioConnection patchCord6(tdm1, 5, queue6, 0); //AudioConnection patchCord7(tdm1, 6, queue7, 0); //AudioConnection patchCord8(tdm1, 7, queue8, 0); //AudioConnection patchCord9(tdm1, 8, queue9, 0); //AudioConnection patchCord10(tdm1, 9, queue10, 0); //AudioConnection patchCord11(tdm1, 10, queue11, 0); //AudioConnection patchCord12(tdm1, 11, queue12, 0); //AudioConnection patchCord13(tdm1, 12, queue13, 0); //AudioConnection patchCord14(tdm1, 13, queue14, 0); //AudioConnection patchCord15(tdm1, 14, queue15, 0); //AudioConnection patchCord16(tdm1, 15, queue16, 0); //AudioControlSGTL5000 sgtl5000_1; //xy=369,479 // GUItool: end automatically generated code // Use these with the Teensy Audio Shield //#define SDCARD_CS_PIN 10 //#define SDCARD_MOSI_PIN 7 //#define SDCARD_SCK_PIN 14 // Use these with the Teensy 3.5 & 3.6 SD card #define SDCARD_CS_PIN BUILTIN_SDCARD #define SDCARD_MOSI_PIN 11 // not actually used #define SDCARD_SCK_PIN 13 // not actually used // Use these for the SD+Wiz820 or other adaptors //#define SDCARD_CS_PIN 4 //#define SDCARD_MOSI_PIN 11 //#define SDCARD_SCK_PIN 13 // Remember which mode we're doing int mode = 0; // 0=stopped, 1=recording int choice = 0; int sample_number = 0; unsigned int tsamplemillis = 11000; String typeofsound; // The file where data is recorded File frec; void setup() { Serial.begin(9600); // Audio connections require memory, and the record queue // uses this memory to buffer incoming audio. AudioMemory(512); // Initialize the SD card SPI.setMOSI(SDCARD_MOSI_PIN); SPI.setSCK(SDCARD_SCK_PIN); if (!(SD.begin(SDCARD_CS_PIN))) { // stop here if no SD card, but print a message while (1) { Serial.println("Unable to access the SD card"); delay(500); } } while(!Serial); Serial.println("Welcome to the beta version of Viband's TDM sound recorder, 11 second clips are going to be recorded, be \ncareful introducing a new type of sound already introduced since previous samples will be overwritten."); Serial.println("\nNote: SD Library uses short 8.3 names (12 characters). Filename (i.e baby/baby24) can't be longer."); } void loop() { if(choice==0){ Serial.println("\nIntroduce new type of sound (i.e baby): "); while(!Serial.available()); typeofsound = Serial.readString(); sample_number = 0; record(typeofsound,sample_number); } else if(choice==1){ sample_number++; record(typeofsound,sample_number); } else { //Do nothing } Serial.print("\nIntroduce 1 to take another sample or 0 to introduce a new type of sound: "); while(!Serial.available()); choice = Serial.readString().toInt(); Serial.println(choice); } void record(String type, int number){ Serial.println("Recording " + type + String(number) + "..."); elapsedMillis recordingTime = 0; String sname = type + number + ".RAW"; String path = type + "/" + type + number + ".RAW"; startRecording(sname, path, type); while(recordingTime<tsamplemillis) continueRecording(); stopRecording(); } void startRecording(String sname, String path, String type) { int str_len = path.length()+1; char charpath[str_len]; path.toCharArray(charpath,str_len); if (SD.exists(charpath)) { // The SD library writes new data to the end of the // file, so to start a new recording, the old file // must be deleted before new data is written. SD.remove(charpath); } str_len = type.length()+1; char chartype[str_len]; type.toCharArray(chartype,str_len); if(!SD.exists(chartype)){ SD.mkdir(chartype); } frec = SD.open(charpath, FILE_WRITE); if (frec) { Serial.println("File Open"); // queue1.begin(); // queue2.begin(); // queue3.begin(); // queue4.begin(); queue5.begin(); queue6.begin(); // queue7.begin(); // queue8.begin(); // queue9.begin(); // queue10.begin(); // queue11.begin(); // queue12.begin(); // queue13.begin(); // queue14.begin(); // queue15.begin(); // queue16.begin(); mode = 1; } } void continueRecording() { if (queue5.available() >= 2 && queue6.available() >=2) { uint16_t buffer1[128]; uint16_t buffer2[128]; memcpy(buffer1, queue5.readBuffer(), 256); memcpy(buffer2, queue6.readBuffer(), 256); queue5.freeBuffer(); queue6.freeBuffer(); for(int i = 0; i < 128; i ++){ frec.write(highByte(buffer2[i])); // LSB frec.write(lowByte(buffer1[i])); // Middle Byte frec.write(highByte(buffer1[i])); // MSB //frec.write(lowByte(buffer2[i])); // Zeros } } } void stopRecording() { Serial.println("Finished recording."); queue5.end(); queue6.end(); queue5.clear(); queue6.clear(); frec.close(); mode = 0; }
I copied the program and will compare.
I will have no internet the next 2/3 days so you have to wait for an answer
But that program uses only 2 channels!
It actually only uses one channel. It stitches the two 16 bit queues together after shifting out the 8 least significant bits making a 24 bit mono recording. This program also has issues, it seems to miss samples and only record 11 seconds or so. But it does show that my setup works. I also used a program that I wrote that just records 1280 samples for each of the 5 mics, it works perfectly so this shows that my microphone array is working. now I would like to record longer clips and for all 5 mics, that's where your program is needed.
Maybe useful for others to know about the signal-to-noise-ratio of the whole setup:
microSoundRecorder based on Teensy 3.6 @96MHz F_CPU without audio board using one ICS43434 digital microphone:
* imported the recorded mono WAV-file into audacity [16-bit, little endian, mono, 48000ksps sample rate]
* highpass filtered the file [cutoff frequency 150Hz, 48dB/octave]
* loudest signal has an amplitude of about 1 without audible clipping/distortion
* noise/weakest signal at an average amplitude of about 0.0007
* 1 / 0.0007 = 1428
* 20 * log (1428) = 63dB SNR
* this is very close to the physically achievable SNR of the microphone, which is given in the datasheet as 65dBA
--> so my conclusion would be that with the ICS43434 the microSoundRecorder records everything that the ICS43434 is able to pick up.
Very nice!
Have fun with the Teensy,
Frank DD4WH
@dreggory
I tried to generate a better program, that compiles, runs and does not produce rubbish.
could you try it out?
you can find it under the development branch on github
I will have to try it tomorrow evening.
Frank B
post#2
One could try to add a SPI-RAM as buffer for the SD-Card to the audio-shield. It has the same pinout as FLASH, so the existing pads will work.Just curious how this memory would work for a buffer: Everspin MR20H40 - 50MHz 4Mb SPI Interface MRAM https://www.everspin.com/serial-peripheral-interfaceWMXZ
post#3
I have thought about it and have done it on another project (using T3.2), but this limits the overall bit rate to half the SPI-RAM clock rate (write to RAM and read from RAM).
The T3.6 allows already for about 200 kB buffer, so for the 23LC1024 to be useful one needs data rates > 2 MB/s while covering 0.1 s uSD delays. As the 23LC1024 access is limited to 20 MHz, this supports up to 10 MBit/s or 1.25 MB/s data rate (write and read)
In the absence of quad SPI (SQI) on Teensy, this results to an interesting design. I may think about it, as I have an application where 200 kB buffer is not large enough (high speed multichannel acquisition totalling a datarate of 30 MBit/s), but I still have some 23LC1024 available, so I even may try it.
4,194,304-bit (524.288 KB) magnetoresistive random access memory.
@digikey Unit Price $16.17 https://www.digikey.com/product-deta...043-ND/4047456
FEATURES:
No write delays
Unlimited write endurance
Automatic data protection on power loss
Fast, simple SPI interface, up to 50 MHz clock rate with MR20H40.
3.0 to 3.6 Volt power supply range
Direct replacement for serial EEPROM, Flash, and FeRAM
It could work up to say 20 MHz (<50 MHz/2) bit clock (that is aggregated sampling rate of 1.25 MHz @16 bit, or 625 kHz @ 32 bit data words)
how it would work:
ACQ ISR would directly write data to MRAM
uSD disk write part would access data von MRAM and copy to uSD
So, for each data word the MRAM has to be accessed twice (that why throughput is half max clock rate)
I did this with multiple 1 MBit 23LC1024 but access sped was limited to 10 MHz
Okay, I think I see improvement. Now when I import the audio to Audacity, I can see all 5 channels look like real data.
-However, it sounds terrible. I'm just guessing, but I think that it sounds like the MSB's and the LSB's got switched or maybe shifted out.
-I noticed that the import only worked if 32 bit sample setting was used. Just to clarify, these mics send the data from each mic in 32bit frames but only the first 24 bits are the actual sample, so there are 8 bits following each sample that must be discarded.
-Here is a link to the folder that has the recorded audio using your latest code:
https://drive.google.com/open?id=1gS...cA21dsd9Kk0mXS
Okay sounds great. I'm still not sure why the audio has to be imported to Audacity as 32 bit float, but it works. There is some popping in each mic's tracks (isolated to a track or two, not evenly spread throughout). I think the popping may be a problem on my end, unless there is something in the code that could cause this?
I was wondering, when I import the audio in audacity and it splits the tracks up, does it keep them in order or does it mix them up? could you could explain how Audacity splits the tracks?
here are the latest recordings:
https://drive.google.com/open?id=1rZ...MwFFbqbXJfdJrK
Thank you for your excellent work. Now I can start processing!
Hi WMXZ. What a wonderful project you have going here. It’s impressive how many of us are doing these things and interested in solutions that are extensible and affordable. I am really pleased to see the weather sensing in conjunction with sound recording - it will help me immensely.
I have a system running with a single MEMS mic on a 3.6. All good. It is outdoors now to test battery life over the next few days.
On the other hand I have had no luck getting the Tympan version to work. It compiles but if I turn it off and on again it never boots. Even if I compile to the Teensy and leave connected on USB, mothering is ever recorded and that is when leaving the time window to cover 24 hrs and making the setup standard 120, 60, 180. The console reports the loop in this case but the numbers re mostly 0. I have a Rev C board and I checked to see if the pins are correct. I am not cleare where they re defined though?
- IMO this is a bug Audacity, or better when using 'open' (or import wav file) then the sampling frequency is correct, the data (16 bit integer) are also correct displayed (10 s audio data), but format is shown as 32 bit float (I used Audacity 2.1.3).
- Popping, no idea where this is from, the first 3 channels are fine, the last two have similar but not identical spikes (you can see that if you zoom into a single spike)
- splitting channels, they should be in the order they are written to disk. No, I have no idea how Audacity works. If you wanted to know which microphone is which channel, you should do the standard test, touching gently a single microphone and note on which channel it shows up.
You surely tell use the results, right?
I just ordered a Tympan, but it will need some time to arrive here.On the other hand I have had no luck getting the Tympan version to work. It compiles but if I turn it off and on again it never boots. Even if I compile to the Teensy and leave connected on USB, mothering is ever recorded and that is when leaving the time window to cover 24 hrs and making the setup standard 120, 60, 180. The console reports the loop in this case but the numbers re mostly 0. I have a Rev C board and I checked to see if the pins are correct. I am not cleare where they re defined though?
I did see that it was 16 bit samples when I imported the data to octave. I am wondering why you went with 16 bit values instead of 24 bit that the ics-52000 mics send. Though it does look like it is not an issue, since I don't see any clipping. Anyway I am grateful for what I can do with your code, thank you.
I tried touching each mic to see what order they are in, and it looks like there is a problem of mixed tracks. I recorded myself saying the mic number, before touching each mic in order ("mic 1" *touch 1*, "mic 2" *touch 2*, "mic 3" *touch 3*, "mic 4" *touch 4*, "mic 5" *touch 5*).If you wanted to know which microphone is which channel, you should do the standard test, touching gently a single microphone and note on which channel it shows up.
Here is the recorded audio:
https://drive.google.com/open?id=1fq...pwomRa5ce7YrEK