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
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:
Additionally there is now a setting to enable/disable the configASSERT macro:
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:
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:
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 🙂
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.
LikeLike
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
LikeLike
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
LikeLike
Hi Neil,
indeed, 1) is a problem created by the shell history functionality :-(. I need to work on a fix on this one.
LikeLike
About hard faults: see
https://mcuoneclipse.com/2012/11/24/debugging-hard-faults-on-arm-cortex-m/
and
https://mcuoneclipse.com/2012/12/28/a-processor-expert-component-to-help-with-hard-faults/
LikeLike
Hello Erich, I’ve had a fire to fight, but got back to the HardFault – many thanks for the pointers.
Really helps to have a starting point.
It turns out it was my stacks. The FreeRTOS default min is 200bytes. I’ve now set the USB “Host” stack to +400(was100), “shell” +300, startup main() stack at 500(was 400) and changed the stack check to method2.
Its run for 13hrs overnight – sampling every 2 seconds and then writing the results to an open file on the USB Stick.
LikeLike
Hi neilh20,
I have fixed now the issue with history (isalnum() character handling in CLS1_ReadLine()), you can find the fix on GitHub (https://github.com/ErichStyger/McuOnEclipse_PEx/commit/6109930e28b5b0819cd701f57a0ed24a61397f91).
Sorry about the hick-up 😦
LikeLiked by 1 person
Pingback: McuOnEclipse Components: 22-Mar-2015 Release | MCU on Eclipse