McuOnEclipse Components: 03-Feb-2015 Release

It has been a while since the last version, but finally there is a new release available on SourceForge, with the following highlights:

  • FreeRTOS V8.2.0 with task notification
  • New VS1053 component to play MP3 and MIDI data/files
  • Shell with command history support
  • Percepio Trace V2.7.0 for FreeRTOS
Components Release

Components Release

FreeRTOS Task Notification

FreeRTOS V8.2.0 is out, and it comes with a cool task notification feature, see http://www.freertos.org/RTOS-task-notification-API.html. With the upgrade to V8.2.0, the Processor Expert component has now the extra API calls included:

FreeRTOS Task Notification API

FreeRTOS Task Notification API

Additionally there is now a setting to enable/disable the configASSERT macro:

configASSERT Setting in FreeRTOS Component

configASSERT Setting in FreeRTOS Component

This enables/disables the configASSERT() macro in FreeRTOSConfig.h:

/* Normal assert() semantics without relying on the provision of an assert.h header file. */
#define configASSERT(x) if((x)==0) { taskDISABLE_INTERRUPTS(); for( ;; ); }

Disabling that macro with the above setting will reduce the code size of the kernel by few hundred bytes of code, but of course there won’t be any assertion if things are going wrong ;-).

Percepio Trace V2.7.0

See “Updated Percepio Tracealyzer and Trace Library to Version V2.7.0” for details.

VS1053 Component

In “Tutorial: Playing MP3 Files with VS1053B and FRDM Board” I used the Adafruit Music Maker Shield without a dedicated component. Because more and more of my projects are using that shield, I have created a Processor Expert component for it:

VS1053 Component

VS1053 Component

The component features access to a shared SPI bus (OnActivateSPI() and OnDeactivateSPI(), as on the Adafruit MusicMaker Shield both the VS1053 and the SD card share the same SPI bus.

A cool feature of the VS1053 is the ability to play MIDI (Musical Instrument Digital Interface) data and files. I’m using it in the following project:
https://github.com/ErichStyger/mcuoneclipse/tree/master/Examples/KDS/FRDM-KL25Z/FRDM-KL25Z_NeoShield

The VS1053 has a feature called ‘realtime MIDI’ where it is possible to directly send MIDI notes to the device. With this, it is like driving a synthesizer with a microcontroller :-). To enable MIDI, a small code applet gets loaded into the device which is a cool concept!. This is done with the VS1_LoadRealtimeMidiPlugin() of the component.

In my application I’m having MIDI data in FLASH. Below is a single track of a multi-track music melody:

static const MIDI_MusicLine track0[] =
{
/* beat,ticks, event,          note,              value */
  {0,  0, MIDI_BANK,      0, 0},
  {0,  0, MIDI_PATCH,     VS1_MIDI_INSTR_Default, 0},
  {0,  0, MIDI_PAN,       64, 0},
  {0,  0, MIDI_VOLUME,    127, 0},
  {0,  0, MIDI_NOTE_ON ,  VS1_MIDI_NOTE_Fh6, 127},
  {0, 64, MIDI_NOTE_OFF,  VS1_MIDI_NOTE_Fh6, 100},
  {0, 96, MIDI_NOTE_ON ,  VS1_MIDI_NOTE_G6 , 127},
  {0,160, MIDI_NOTE_OFF,  VS1_MIDI_NOTE_G6 , 100},
  {0,192, MIDI_NOTE_ON ,  VS1_MIDI_NOTE_G6 , 127},
  {0,256, MIDI_NOTE_OFF,  VS1_MIDI_NOTE_G6 , 100},
  {0,288, MIDI_NOTE_ON ,  VS1_MIDI_NOTE_G6 , 127},
  {0,352, MIDI_NOTE_OFF,  VS1_MIDI_NOTE_G6 , 100},
  {1,  0, MIDI_NOTE_ON ,  VS1_MIDI_NOTE_Fh5, 127},
  {1, 64, MIDI_NOTE_OFF,  VS1_MIDI_NOTE_Fh5, 100},
  {1, 96, MIDI_NOTE_ON ,  VS1_MIDI_NOTE_G5 , 127},
  {1,160, MIDI_NOTE_OFF,  VS1_MIDI_NOTE_G5 , 100},
  {1,192, MIDI_NOTE_ON ,  VS1_MIDI_NOTE_G5 , 127},
  {1,256, MIDI_NOTE_OFF,  VS1_MIDI_NOTE_G5 , 100},
  {1,288, MIDI_NOTE_ON ,  VS1_MIDI_NOTE_G5 , 127},
  {1,352, MIDI_NOTE_OFF,  VS1_MIDI_NOTE_G5 , 100},
  {2,  0, MIDI_NOTE_ON ,  VS1_MIDI_NOTE_Fh4, 127},
  {2, 64, MIDI_NOTE_OFF,  VS1_MIDI_NOTE_Fh4, 100},
  {2, 96, MIDI_NOTE_ON ,  VS1_MIDI_NOTE_G4 , 127},
  {2,160, MIDI_NOTE_OFF,  VS1_MIDI_NOTE_G4 , 100},
  {2,192, MIDI_NOTE_ON ,  VS1_MIDI_NOTE_G4 , 127},
  {2,256, MIDI_NOTE_OFF,  VS1_MIDI_NOTE_G4 , 100},
  {2,288, MIDI_NOTE_ON ,  VS1_MIDI_NOTE_G4 , 127},
  {2,352, MIDI_NOTE_OFF,  VS1_MIDI_NOTE_G4 , 100},
  {3,192, MIDI_NOTE_ON ,  VS1_MIDI_NOTE_G6 , 127},
  {3,256, MIDI_NOTE_OFF,  VS1_MIDI_NOTE_G6 , 100},
  {3,288, MIDI_NOTE_ON ,  VS1_MIDI_NOTE_G6 , 127},
  {3,352, MIDI_NOTE_OFF,  VS1_MIDI_NOTE_G6 , 100},
  {4,  0, MIDI_NOTE_ON ,  VS1_MIDI_NOTE_G6 , 127},
  {4, 64, MIDI_NOTE_OFF,  VS1_MIDI_NOTE_G6 , 100},
  {4, 96, MIDI_NOTE_ON ,  VS1_MIDI_NOTE_G6 , 127},
  {4,160, MIDI_NOTE_OFF,  VS1_MIDI_NOTE_G6 , 100},
  {4,288, MIDI_NOTE_ON ,  VS1_MIDI_NOTE_E6 , 127},
  {4,352, MIDI_NOTE_OFF,  VS1_MIDI_NOTE_E6 , 100},
  {5, 96, MIDI_NOTE_ON ,  VS1_MIDI_NOTE_G6 , 127},
  {5,160, MIDI_NOTE_OFF,  VS1_MIDI_NOTE_G6 , 100},
  {5,192, MIDI_NOTE_ON ,  VS1_MIDI_NOTE_E6 , 127},
  {5,256, MIDI_NOTE_OFF,  VS1_MIDI_NOTE_E6 , 100},
  {6,  0, MIDI_NOTE_ON ,  VS1_MIDI_NOTE_G6 , 127},
  {6, 64, MIDI_NOTE_OFF,  VS1_MIDI_NOTE_G6 , 100},
  {6, 96, MIDI_NOTE_ON ,  VS1_MIDI_NOTE_A6 , 127},
  {6,160, MIDI_NOTE_OFF,  VS1_MIDI_NOTE_A6 , 100},
  {6,192, MIDI_NOTE_ON ,  VS1_MIDI_NOTE_E6 , 127},
  {6,256, MIDI_NOTE_OFF,  VS1_MIDI_NOTE_E6 , 100},
  {6,288, MIDI_NOTE_ON ,  VS1_MIDI_NOTE_E6 , 127},
  {6,352, MIDI_NOTE_OFF,  VS1_MIDI_NOTE_E6 , 100},
  {7,  0, MIDI_NOTE_ON ,  VS1_MIDI_NOTE_E6 , 127},
  {7, 64, MIDI_NOTE_OFF,  VS1_MIDI_NOTE_E6 , 100},
  {7,192, MIDI_NOTE_ON ,  VS1_MIDI_NOTE_D6 , 127},
  {7,256, MIDI_NOTE_OFF,  VS1_MIDI_NOTE_D6 , 100},
  {7,288, MIDI_NOTE_ON ,  VS1_MIDI_NOTE_C6 , 127},
  {7,352, MIDI_NOTE_OFF,  VS1_MIDI_NOTE_C6 , 100},
  {8, 96, MIDI_NOTE_ON ,  VS1_MIDI_NOTE_Ch6, 127},
  {8,160, MIDI_NOTE_OFF,  VS1_MIDI_NOTE_Ch6, 100},
  {8,288, MIDI_NOTE_ON ,  VS1_MIDI_NOTE_G5 , 127},
  {8,352, MIDI_NOTE_OFF,  VS1_MIDI_NOTE_G5 , 100},
  {9, 96, MIDI_NOTE_ON ,  VS1_MIDI_NOTE_Ch6, 127},
  {9,160, MIDI_NOTE_OFF,  VS1_MIDI_NOTE_Ch6, 100},
  {9,192, MIDI_NOTE_ON ,  VS1_MIDI_NOTE_G5 , 127},
  {9,256, MIDI_NOTE_OFF,  VS1_MIDI_NOTE_G5 , 100},
  {10,  0, MIDI_NOTE_ON,   VS1_MIDI_NOTE_Ch6, 127},
  {10, 64, MIDI_NOTE_OFF,  VS1_MIDI_NOTE_Ch6, 100},
  {10,192, MIDI_NOTE_ON ,  VS1_MIDI_NOTE_D6 , 127},
  {10,256, MIDI_NOTE_OFF,  VS1_MIDI_NOTE_D6 , 100},
  {10,288, MIDI_NOTE_ON ,  VS1_MIDI_NOTE_D6 , 127},
  {10,352, MIDI_NOTE_OFF,  VS1_MIDI_NOTE_D6 , 100},
  {11,  0, MIDI_NOTE_ON ,  VS1_MIDI_NOTE_D6 , 127},
  {11,256, MIDI_NOTE_OFF,  VS1_MIDI_NOTE_D6 , 100},
  {11,256, MIDI_END_OF_TRACK, 0,  0}
};
  • The first two numbers are the beat and ticks information: in music notation, this gives the timing when something should happen.
  • The next item is the event: with MIDI_BANK I can switch between different music/instrument banks (e.g. percussion or music instruments).
  • MIDI_PATCH selects an instrument in the bank.
  • MIDI_PAN sets the left/right stereo position, with 64 in the middle.
  • MIDI_VOLUME sets the music volume.
  • With MIDI_NOTE_ON a note is turned on (e.g. teh G4) with a velocity (e.g. 127). This is like pressing a key on a keyboard.
  • With MIDI_NOTE_OFF the note is turned off again.

A bit tricky is to play each note at the right time. This is done in the Play() routine of my application:

static void Play(MIDI_MusicTrack *tracks, unsigned int nofTracks) {
  int itemNo;
  uint8_t channel;
  uint32_t currTimeMs;
  TickType_t startTicks;
  unsigned int nofFinished;

  /* init defaults */
  for(channel=0;channel<nofTracks;channel++) {
    VS1_MIDI_SetBank(channel, 0);
    VS1_MIDI_SetInstrument(channel, VS1_MIDI_INSTR_Default);
    VS1_MIDI_SetVolume(channel, 127);
  }
  startTicks = FRTOS1_xTaskGetTickCount();
  itemNo = 0;
  for(;;) { /* breaks */
    currTimeMs = (FRTOS1_xTaskGetTickCount()-startTicks)/portTICK_RATE_MS;
    nofFinished = 0;
    for(channel=0;channel<nofTracks;channel++) {
      if (!PlayTrackItem(&tracks[channel], currTimeMs, channel)) {
        nofFinished++;
      }
    }
    if (nofFinished==nofTracks) { /* all finished */
      break;
    }
    FRTOS1_vTaskDelay(1/portTICK_RATE_MS);
    itemNo++;
  }
}

The code goes through the (multiple) tracks of the MIDI data, and sends the MIDI data to the device. The loop calls PlayTrackItem() for each item in the table:

static bool PlayTrackItem(MIDI_MusicTrack *track, unsigned int currTimeMs, uint8_t channel) {
  uint32_t beatsPerSecond = 2; /* 120 bpm */
  uint32_t currentMillis;
  uint32_t ppqn; /* ticks per beat/quarter note */
  uint32_t tempo = 110;
  uint8_t event;
  unsigned int itemNo;

  ppqn = track->nofTicksPerQuarterNote;
  for(;;) { /* breaks */
    itemNo = track->currLine;
    if (itemNo>=track->nofLines) { /* out of list */
      return FALSE; /* do not continue any more */
    }
    currentMillis = ((uint32_t)track->lines[itemNo].beat*1000UL)/beatsPerSecond;
    currentMillis += ((uint32_t)track->lines[itemNo].tick*60000UL)/ppqn/tempo;
    if (currentMillis>currTimeMs) {
      return TRUE; /* continue */
    }
    event = track->lines[itemNo].event;
    switch(event) {
      case MIDI_BANK:
        VS1_MIDI_SetBank(channel, track->lines[itemNo].val1);
        break;
      case MIDI_NOTE_ON:
        VS1_MIDI_NoteOn(channel, track->lines[itemNo].val1, track->lines[itemNo].val2);
        break;
      case MIDI_NOTE_OFF:
        VS1_MIDI_NoteOff(channel, track->lines[itemNo].val1, track->lines[itemNo].val2);
        break;
      case MIDI_PATCH:
        VS1_MIDI_SetInstrument(channel, track->lines[itemNo].val1);
        break;
      case MIDI_VOLUME:
        VS1_MIDI_SetVolume(channel, track->lines[itemNo].val1);
        break;
      case MIDI_PAN:
        VS1_MIDI_SetPan(channel, track->lines[itemNo].val1);
        break;
      case MIDI_END_OF_TRACK:
        VS1_MIDI_AllSoundOff(channel);
        break;
    }
    track->currLine++;
  } /* for */
  return TRUE;
}

The result is that I can play tunes and melodies, with multiple tracks and easily mix sound effects. This was a problem for my yet-to-be-finished game: with playing MP3 files I’m not able to mix them on the device, as I cannot play another MP3 file while one is already playing. Using MIDI was the solution for me :-).

Shell Command History

The newly added history commands in the shell were already presented in “Shell Component with History Function” is included in this release too:

Shell with History

Shell with History

Since then, several issues have been fixed, and now the history works with multi-command and silent mode prefix:

  • Multi Commands: Ability to send multiple commands in a single string, separated e.g. by ‘;’, for example “FAT1 mkdir myDir;FAT1 cd myDir
  • Silent Prefix to suppress prompt printing, useful for automation, e.g. “#LED1 On”

Summary

I hope the new/extended/updated components are useful. Instructions how to download and install them are here: “McuOnEclipse Releases on SourceForge

Happy SourceForging 🙂

8 thoughts on “McuOnEclipse Components: 03-Feb-2015 Release

  1. Hi,

    I very much appreciate your great work in the Kinetis field, and I think that the release of ProcessorExpert Beans is a great idea. I’ve installed it in KDS-1.1, but have not done so in the KDS-2.0. One question I had from then is how to select beans. From what I remember your beans will be interleaved with the one from Freescale, some are almost equal. So what I’m missing is a commonn prefix, I don’t know if it’s possible to have PEx to make categories of beans but that would be nice.

    Like

    • Hi Ole,
      yes, I know this is a kind of problem. Unfortunately adding a prefix will create incompatibilities. A better way would be that the components would have an attribute you can sort for. I had submitted such a feature request a while back, but it has not been implemented it.
      Erich

      Like

  2. Hello Eric, really appreciate you sharing this, it makes getting a simple base line working fun.
    Couple of issues have come up for me –
    1)perphaps not related to this release
    When using CLS1:Shell and TMDT1:GenericTimeDate – to set date requires
    TMDT1 time 11:28:00
    However CLS1:shell is rejecting the ‘:’ in
    CLS1.c CLS1_ReadLine() isalnum()
    My solution right now is to refactor TMDT1 to write to internal RTC and eliminate TMDT1:

    2)Longer term I’d like to be able to understand how to update the beans and be able to put it onto github. I’ve not been able to get the hang of Processor Expert “Driver Suite” to do this. It would be great if you could do a tutorial on doing a bug fix and then if posted on github, can be brought back into your code.

    3) and this may be related to this releases USB changes; I’m running an ADC then writing to a USB Drive – and its getting a hardFault after about 1minute or 12writes – not consistent.
    It used to work OK for me.
    Last night I removed the USB Drive – and everything ran fine for 12hrs. So will post when I can dig into it and find out where the hardFault is occurring.
    many thanks

    Like

  3. Pingback: McuOnEclipse Components: 22-Mar-2015 Release | MCU on Eclipse

What do you think?

This site uses Akismet to reduce spam. Learn how your comment data is processed.