microPAM software#
The microPAM software differs from the software presented for the Teensy 4.1 version
No use of Teensy audio library
complete 32 bit data storage
RP2040 specific implementation of the I2S interface
Use of dedicated real-time-clock for RP2040
use of SPI for disk access
The software is work-in-progress and will be maintained on WMXZ-EU/microPAM in subdirectory microPAM_V2.
The software can run on on both hardware systems: the microPAM-T4 and the micrPAM-pico.
Also, the V2 software is developed from scratch with the rp2040 MCU (symbol TARGET_RP2040) as primary processor and the Teensy 4.1 (symbol __IMXRT1062__ ) as a alternative processor. Consequently, the main functionality may differ from the dedicated mocroPAM-T4 software.
Arduino environment#
to facilitate the development of microPAM for the RP-2040 MCU, the *.ino file is maintained containing setup() and loop() functions.
microPAM_V2.ino#
The main software that is here in microPAM_V2.ino contains
Preparations#
#include "Arduino.h"
#if defined(__IMXRT1062__)
#include <CrashReport.h>
#endif
#if defined(TARGET_RP2040)
#include "pico/stdlib.h"
#endif
#include "src/mConfig.h"
#include "src/mQueue.h"
#include "src/mAcq.h"
#include "src/mRTC.h"
#include "src/mCompress.h"
#include "src/mFiling.h"
#include "src/menu.h"
#if defined(__IMXRT1062__) && defined(AUDIO_INTERFACE)
#include "AudioStream.h"
#include "usb_audio.h"
#include "src/mAudioTrigger.h"
#include "src/mAudioIF.h"
AudioTrigger trigger;
AudioIF acqIF(FSAMP);
AudioOutputUSB usb;
AudioConnection patchCord1(acqIF, 0, usb, 0);
AudioConnection patchCord2(acqIF, 1, usb, 1);
#endif
In case of use of Teensy and selection of “Serial + Midi + Audio” in “Tools > USB type” the AUDIO_INTERFACE symbol is declared and data are streamed to USB audio. This allows to listen to the microphone from PC or to use program like Audacity to visualize microphone data
Setup function#
/***************************************************************************/
volatile int ready=0;
void setup1();
//
void setup()
{
// put your setup code here, to run once:
#if defined(TARGET_RP2040)
set_sys_clock_khz(48000, true);
#endif
Serial.begin(115200);
// wait for a minute to allow USB-Serial connection
while(millis()<60000) if(Serial) break;
// Teensy has a crash report
#if defined(__IMXRT1062__)
if(CrashReport) Serial.print(CrashReport);
#if defined(AUDIO_INTERFACE)
AudioMemory(8);
#endif
#endif
rtc_setup();
Serial.println("rtc_setup() done");
datetime_t t;
if(!rtc_get_datetime(&t)) Serial.println("failing get_datetime");
Serial.printf("RTC-main: %4d-%02d-%02d %02d:%02d:%02d",
t.year,t.month,t.day,t.hour,t.min,t.sec); Serial.println();
Serial.println("checking rtc_get()");
time2date(rtc_get(), &t);
Serial.printf("Now-sec: %4d-%02d-%02d %02d:%02d:%02d",
t.year,t.month,t.day,t.hour,t.min,t.sec); Serial.println();
Serial.print("Week Day (may not be correct)"); Serial.println(t.dotw);
Serial.println("filing_init");
filing_init();
Serial.println("Setup done");
ready=1;
// in case of single core teensy 4.1 start acquisition
#if defined(__IMXRT1062__)
setup1();
#endif
}
The setup is special as the RP2040 is a dual core MCU and the acquisition functionality is delegated to the 2nd core. In case of Teensy, this 2nd setup1() is callend at the end of the regular setup().
Loop function#
void loop()
{
// put your main code here, to run repeatedly:
static uint32_t loopCount=0;
loopCount++;
static int16_t monitor=0;
// obtain some statistics on Queue usage
static uint16_t mxb=0;
uint16_t nb = getDataCount();
if(nb>mxb) mxb=nb;
static volatile int16_t status=CLOSED;
// basic menu to start and stop archiving
if(Serial.available())
{
char ch=Serial.read();
if(ch=='s') status=CLOSED;
if(ch=='e') status=MUSTSTOP;
if(ch=='m') monitor=1-monitor;
if(ch==':') menu1(); // returns only when menu1 gets not handled character
if(ch=='?') menu2(); // returns only when menu2 gets not handled character
if(ch=='!') menu3(); // returns only when menu3 gets not handled character
}
// save data (filing will be handled inside saveData)
status=saveData(status);
// if(status<0) return;
// once a second provide some information to User
static uint32_t t0=0;
uint32_t t1;
if((t1=millis())>(t0+1000))
{ datetime_t t;
rtc_get_datetime(&t);
if(monitor)
{
Serial.printf("\n%4d-%02d-%02d %02d:%02d:%02d %d",
t.year,t.month,t.day,t.hour,t.min,t.sec,t.dotw); Serial.print(" : ");
Serial.print(loopCount); Serial.print(" ");
Serial.print(procCount); Serial.print(" ");
Serial.print(procMiss); Serial.print(" ");
Serial.printf("%3d",mxb); Serial.print(" ");
Serial.printf("%4d",acqbias); Serial.print(" ");
Serial.print(disk_count); Serial.print(" ; ");
#if PROC_MODE==0
for(int ii=0; ii<8;ii++){ Serial.printf("%8X ",logBuffer[ii]);}
#else
for(int ii=0; ii<MB;ii++){ Serial.printf("%2d ",proc_stat[ii]);}
Serial.printf("%2d",max_stat);
for(int ii=0; ii<MB;ii++){ proc_stat[ii]=0;}
max_stat=0;
#endif
}
loopCount=0;
procCount=0;
procMiss=0;
mxb=0;
disk_count=0;
t0=t1;
}
}
Second core#
// rp2040 has dial core. let acq run on its own core
void setup1()
{ while(!ready) {delay(1);} // wait for setup() to finish
i2s_setup();
dma_setup();
Serial.println("Setup1 done");
}
void loop1(){} // nothing to be done here
As mentioned above, the aquisition is started within the second core of RP2040, or in case of Teensy at the end of promary setup.