Lab 1-The Artemis board

Objective

The purpose for lab 1 is help us to be more familiar with the Arduino IDE and Artemis board. In this lab, there are 4 regular tasks and one task for graduate student only. I need to check the LED, temperature sensor, serial message, and microphone seperately.

Setup

In lab 1, we are required to use 1 USB C-to-C or A-to-C cable to connect with the SparkFun RedBoard Artemis Nano. To be well perpared, the lastest version of Arduino and Aruduino Core for Apollo3 should be downloaded.

The example code can be found in Example-Basics-Blink. Then I change the port to the correct one and click upload button. This code is using the loop to make the voltage change between low and high on every certain delay time. With low voltage, the light is off and vice versa. In this example, I use the default delay time 1000 miliseconds as the time between the light on and off. So the frequency is 1000Hz.

Example 2: Serial

The example code is found in Example-Apollos3-Example04_serial. After uploading the code to the board, I can communication with the Artemis board by using the serial monitor. As shown is the video below, whatever I typed in, it appears in the serial monitor. Notice, it is essential to change to the correct BAUD for the serial monitor. Otherwise, it shows messy code.

Example 3: AnalogRead

The example code is found in Example-Apollos3-Example2_AnalogRead. It is used to test the temperature sensor for the Artemis board. The specific temperature is still shown in the serial monitor. The BAUD value locates in the setup part. When touching the chip, the temperature read increase immediately. When leaving the chip, the temperature read decrease dramatically.

Example4: Microphone Output

The example code can be found in Example-PDM-MicrophoneOutput. This task can help to be familiar with the Artemis board to receive the voice using a pulse-density microphone. The serial monitor shows the loudest frequency the board received. I test it by knocking on my laptop. The frequency value increases from 0 dramatically.

Example 5: 5000 level tasks

The additional task required the light of the LED on when playing a musical "A" note. I modify the code from the 'MicrophoneOutput' and combine it with the 'blink'. In the setup section, I add "pinMode(LED_BUILTIN, OUTPUT)" to initialize the LED pin mode. Then, I also changed the if loop in the later part. I set if ui32LoudestFrequency equals to 440Hz, the voltage of LED is high, so the light is on. Otherwise, it is off.

Code Appendix for Example 5


//Global variables needed for PDM library
#define pdmDataBufferSize 4096 //Default is array of 4096 * 32bit
uint16_t pdmDataBuffer[pdmDataBufferSize];

//Global variables needed for the FFT in this sketch
float g_fPDMTimeDomain[pdmDataBufferSize * 2];
float g_fPDMFrequencyDomain[pdmDataBufferSize * 2];
float g_fPDMMagnitudes[pdmDataBufferSize * 2];
uint32_t sampleFreq;

//Enable these defines for additional debug printing
#define PRINT_PDM_DATA 0
#define PRINT_FFT_DATA 0

#include  //Include PDM library included with the Aruino_Apollo3 core
AP3_PDM myPDM;   //Create instance of PDM class

//Math library needed for FFT
#include 

void setup()
{

  pinMode(LED_BUILTIN, OUTPUT);
  Serial.begin(115200);
  Serial.println("SparkFun PDM Example");

  if (myPDM.begin() == false) // Turn on PDM with default settings, start interrupts
  {
    Serial.println("PDM Init failed. Are you sure these pins are PDM capable?");
    while (1)
      ;
  }
  Serial.println("PDM Initialized");

  printPDMConfig();
}

void loop()
{

  

  //digitalWrite(LED_BUILTIN, LOW); 
  //delay(1000);
  
  if (myPDM.available())
  {
    myPDM.getData(pdmDataBuffer, pdmDataBufferSize);

    printLoudest();
  }

  // Go to Deep Sleep until the PDM ISR or other ISR wakes us.
  am_hal_sysctrl_sleep(AM_HAL_SYSCTRL_SLEEP_DEEP);
}

//*****************************************************************************
//
// Analyze and print frequency data.
//
//*****************************************************************************
void printLoudest(void)
{
  float fMaxValue;
  uint32_t ui32MaxIndex;
  int16_t *pi16PDMData = (int16_t *)pdmDataBuffer;
  uint32_t ui32LoudestFrequency;

  //
  // Convert the PDM samples to floats, and arrange them in the format
  // required by the FFT function.
  //
  for (uint32_t i = 0; i < pdmDataBufferSize; i++)
  {
    if (PRINT_PDM_DATA)
    {
      Serial.printf("%d\n", pi16PDMData[i]);
    }

    g_fPDMTimeDomain[2 * i] = pi16PDMData[i] / 1.0;
    g_fPDMTimeDomain[2 * i + 1] = 0.0;
  }

  if (PRINT_PDM_DATA)
  {
    Serial.printf("END\n");
  }

  //
  // Perform the FFT.
  //
  arm_cfft_radix4_instance_f32 S;
  arm_cfft_radix4_init_f32(&S, pdmDataBufferSize, 0, 1);
  arm_cfft_radix4_f32(&S, g_fPDMTimeDomain);
  arm_cmplx_mag_f32(g_fPDMTimeDomain, g_fPDMMagnitudes, pdmDataBufferSize);

  if (PRINT_FFT_DATA)
  {
    for (uint32_t i = 0; i < pdmDataBufferSize / 2; i++)
    {
      Serial.printf("%f\n", g_fPDMMagnitudes[i]);
    }

    Serial.printf("END\n");
  }

  //
  // Find the frequency bin with the largest magnitude.
  //
  arm_max_f32(g_fPDMMagnitudes, pdmDataBufferSize / 2, &fMaxValue, &ui32MaxIndex);

  ui32LoudestFrequency = (sampleFreq * ui32MaxIndex) / pdmDataBufferSize;

    if (ui32LoudestFrequency == 434)
      {
       digitalWrite(LED_BUILTIN, HIGH);   
       Serial.printf("'A' detected"); 
      }

    else
      {
       digitalWrite(LED_BUILTIN, LOW);
       Serial.printf("none");  
      }

  if (PRINT_FFT_DATA)
  {
    Serial.printf("Loudest frequency bin: %d\n", ui32MaxIndex);
  }

  Serial.printf("Loudest frequency: %d         \n", ui32LoudestFrequency);
}

//*****************************************************************************
//
// Print PDM configuration data.
//
//*****************************************************************************
void printPDMConfig(void)
{
  uint32_t PDMClk;
  uint32_t MClkDiv;
  float frequencyUnits;

  //
  // Read the config structure to figure out what our internal clock is set
  // to.
  //
  switch (myPDM.getClockDivider())
  {
  case AM_HAL_PDM_MCLKDIV_4:
    MClkDiv = 4;
    break;
  case AM_HAL_PDM_MCLKDIV_3:
    MClkDiv = 3;
    break;
  case AM_HAL_PDM_MCLKDIV_2:
    MClkDiv = 2;
    break;
  case AM_HAL_PDM_MCLKDIV_1:
    MClkDiv = 1;
    break;

  default:
    MClkDiv = 0;
  }

  switch (myPDM.getClockSpeed())
  {
  case AM_HAL_PDM_CLK_12MHZ:
    PDMClk = 12000000;
    break;
  case AM_HAL_PDM_CLK_6MHZ:
    PDMClk = 6000000;
    break;
  case AM_HAL_PDM_CLK_3MHZ:
    PDMClk = 3000000;
    break;
  case AM_HAL_PDM_CLK_1_5MHZ:
    PDMClk = 1500000;
    break;
  case AM_HAL_PDM_CLK_750KHZ:
    PDMClk = 750000;
    break;
  case AM_HAL_PDM_CLK_375KHZ:
    PDMClk = 375000;
    break;
  case AM_HAL_PDM_CLK_187KHZ:
    PDMClk = 187000;
    break;

  default:
    PDMClk = 0;
  }

  //
  // Record the effective sample frequency. We'll need it later to print the
  // loudest frequency from the sample.
  //
  
  sampleFreq = (PDMClk / (MClkDiv * 2 * myPDM.getDecimationRate()));

  frequencyUnits = (float)sampleFreq / (float)pdmDataBufferSize;

  Serial.printf("Settings:\n");
  Serial.printf("PDM Clock (Hz):         %12d\n", PDMClk);
  Serial.printf("Decimation Rate:        %12d\n", myPDM.getDecimationRate());
  Serial.printf("Effective Sample Freq.: %12d\n", sampleFreq);
  Serial.printf("FFT Length:             %12d\n\n", pdmDataBufferSize);
  Serial.printf("FFT Resolution: %15.3f Hz\n", frequencyUnits);  
}