2012-09-24

Revealing hidden awesomeness of the TI MSP430 LaunchPad

TI (Texas Instruments) is awesome, I've always known it. What I like the most is their extremely low-cost ($4.30, who beats that?) Launchpad development kit that includes 2 "value line" (pronounced "super-cheap") micro-controllers, USB programmer and development software. That is everything you need to dive into the wonderful world of the super-lower-power microcontrollers.


Picking the test project
There are so many options for the first project: flashing LED, doomsday device, iSomething…
Hm, iSomething sounds like a cool idea. How about making a poor-guy MP3 player? Maybe downgraded to the extreme: one song, poor audio quality, no control buttons?
To make digital audio player we need two major components: storage memory for digital audio and Digital-to-Analog  Converter (DAC). Expectedly, such a simple microcontroller does not have a built-in DAC, so sounds like I would need a separate chip. But wait,

Who needs a DAC for lousy quality audio?
There is an easy alternative to DAC – Pulse Width Modulation (PWM). The idea is to generate audio signal with variable-width digital pulses, with high enough pulse frequency it should produce acceptable quality audio. Sure enough TI has an application note to demonstrate exactly that (PWM for audio application). Since I decided not to worry about audio quality, I picked 8 bit for audio resolution (as a side note - it is supposed to be roughly equal to AM radio quality). 8 bit resolution gives me 256 possible PWM widths (for example, value 10 means that output stays on for 10 cycles and after that turns off for 255-10=245 cycles).
Assuming that my TI chip runs at the max speed (16 MHz) my complete PWM cycle would be: 16,000,000Hz/256=62,500 Hz. Wow, at such high PWM frequency I should be able to generate sound with frequencies up to 62,500Hz/2=31,250 Hz (this calculation is based on Whittaker–Nyquist–Kotelnikov–Shannon sampling theorem). But it also means that I have to store 31,250 bytes of data for 1 second of music. Where am I going to store my music?

External storage
MSP430G2231 only has 2KB of memory. Because I need 31,250 bytes to store 1 second of music, I could store the whole 0.06 seconds using internal storage. This is definitely not enough. Well, it just means that I need an external storage. How about  SD/MMC Card? It is a perfect external storage for microcontrollers because it is inexpensive and supports very microcontroller friendly SPI protocol. The Launchpad came with 2 chips: MSP430G2211 and MSP430G2231 the latest has built-in universal serial interface that supports SPI protocol, perfect! And of course after checking TI website, I found this application note to interface between MSP430 and SD Card. Now I need to decide how to store the music.

Audio format battle: mp3 vs au
It would be really cool to play mp3 files on the Launchpad, but it's not going to work. For example, the smallest Helix mp3 decoder needs ~20K of program memory, and my microcontroller has only 2K. Of course I could add an external mp3 decoder - but that's not fun.
Since mp3 is not going to work, I could just write audio as a stream of samples (bytes) and add simple header to tell how many samples in my file, sample rate, etc. But it would be nice to use a standard audio file format, so I choose arguably the simplest audio file format ever created: au format. Even it is a quite old format, but still is supported by many applications including my favorite (open source) audio editor – audacity.

Getting audio file to the SD card
To store file to a SD card is also tricky. For multiple reasons I decided not to use a file system on the SD card, so I have to write .au file to the card as a raw data. This could be done by HDD imaging tools, I had good experience with DiskImage, although other disk imaging software (such as dd) should work.

Hardware
There are only two external components to the Launchpad used: SD card and earbuds headphone. I connected SD card power to one of the Launchpad pins, so I can reset the card by toggling its power. Earbuds headphone connected to the Launchpad PWM output pin through a current limiting resistor. "But where is your low-pass filter?" curious reader will ask. Well, yes, I should be using a low-pass filter to smooth-out PWM pulses. But headphones work well enough as a low-pass filter due to their mechanical nature. So, cancel the filter and connect everything together!

SD card access time issue
After fixing a few software bugs I finally heard something in the headphones. It was sort-of a music, but with some strange clicking noise. Such a disappointment! I though I was done with it.
It turned out that data on the SD card stored in 512 byte blocks and sometimes switching these blocks takes some time, so every so often I was missing a few samples and it caused those clicks. I added a small (16 samples) FIFO buffer between SD card and PWM. Buffer made its magic and I was enjoying AM quality music for a whole 15 minutes or so.

Conclusion
It's totally possible to play an acceptable quality audio using the most basic microcontroller. Sample rate could be pretty high (~31kHz in my case) and allows to achieve a much better audio quality, although PWM resolution (8 bit) is a limiting factor.
One of the options to drastically improve audio quality would be to use two independent 8 bit PWMs and summing up their signals. This would increase audio resolution to 16 bits which should sound (almost) like a CD quality. Although, MSP430G2231 has only one PWM channel, so it's not an option here.

Video
Here is a video of the Launchpad playing (kind of) music, enjoy.



Source Code
Grab it here.

60 comments:

  1. Hello, I downloaded the source code few days ago and I am currently having hard time understanding "Disk Imaging".
    I made an .AU file for the music and I made a raw file of SD card after puting AU file on it. What would be the next step? Should I copy the raw file into the SD card by just copying and pasting or should I copy the file using the Disk Imaging as well?
    My question seems vague, but I am really stuck on this problem and it is really hard to move forward without understanding this. Thanks,

    _Yi
    wldnjs61114@hotmail.com

    ReplyDelete
    Replies
    1. You have to use your .au file instead of the raw file to write it to the SD card. For example, in the Dubaron DiskImage select your SD card in the "physical drives" and click "import from file" button.

      Delete
  2. Please post the wiring connection diagram!

    There any electronic component in your scheme, beyond TI MSP430 LaunchPad and SD Card?

    Regards,
    Igor Isaias Banlian

    ReplyDelete
    Replies
    1. Unfortunately I don't have a schematic, sorry.

      This is how TI chip connected to the SD Card:

      TI P1.7(9)-SD MISO(7);
      TI DVSS(14)-SD GND(6);
      TI P1.5(7)-SD CLK(5);
      TI P1.3(5)-SD 3.3V(4);
      TI DVSS(14)-SD GND(3);
      TI P1.6(8)-SD MOSI(2);
      TI P1.4(6)-SD CS(1);

      SD card pinout: http://www.interfacebus.com/Secure_Digital_Card_Pinout.html

      One side of the headphone is connected to the TI pin P1.2 through the resistor (330 ohm should work), the other side is connected to the DVSS (GND).

      Delete
  3. Great project! What is the maximum capacity of SD that is supported?

    ReplyDelete
    Replies
    1. Thank you.
      It should support all standard SD cards (up to 2GB).

      Delete
  4. Hey Boris, have you tried the MSP430G2553? It has 2 timers so 2 PWM channels. It's shipped with newer Launchpads.

    Also, what should I change from your original code to loop the sound on the SD card forever?

    ReplyDelete
    Replies
    1. No, I haven't tried MSP430G2553. I got the original launchpad that came with MSP430G2211 and MSP430G2231.
      Actually it should already be doing that, playing .au file in a loop.

      Delete
  5. This comment has been removed by the author.

    ReplyDelete
  6. I have one of the 2553's and after reading about this project, I was wondering if you might have any thoughts on how one might go about making an audio recording and play back device in this fashion.

    ReplyDelete
    Replies
    1. I think it should be relatively easy to implement.
      My example doesn't have any routines to write to SD card, but I guess you could get a full SD card library (mmc.h and mmc.c) from TI website and its probably supports write functionality.
      Rest of it should be simple. We don't need to worry about any particular file format, just sample ADC and save each sample to the SD card.

      Actually, 2553 has a whole lot more FLASH memory (16Kb) than 2231, so you could get fancy and add a file system support, so you could read/write files on the SD card on the PC.

      Delete
  7. Hi you. I have some problems with your project.
    I was wrote au file into SD Card but when I run this app, I don't hear anything from headphone although on-board red led still on.
    Then I debug to find the faul, I found that it loop forever at mmc_GoIdle() function (in initMMC() fuction, in initMMC() funtion, in au_Init() function , in main() function). when run step by step at mmc_GoIdle() function i cant what happen with code, compiler pass some line code and goto wherever in this function.
    I think the reason is that the compiler is not compatible.
    Do you give me a version of your compiler?
    if not the reasons you can help me put out a solution rather
    sorry for the ability to write my english is not good and thanks you !!!

    ReplyDelete
    Replies
    1. I was using Code Composer Studio (CCS) v4.
      http://processors.wiki.ti.com/index.php/Category:Code_Composer_Studio_v4

      Delete
    2. This comment has been removed by the author.

      Delete
    3. This comment has been removed by the author.

      Delete
    4. I still do not get a response CMD0? Can you tell me the reason of this error? (I tried to read the card with my PC and everything ok)
      I am using a SD card with 4GB capacity, Is this a problem?
      Can you help me slove this problem? Please!

      Delete
    5. 4GB would definitely be a problem. Technically your card is SDHC (SD High Capacity) and it's not supported by the MMC library used in this project, sorry.

      Delete
    6. Thansk you very much, i was solved my problem !
      But now I can read header of au file, au_ReadHeader()function always return false, I think it dont read a magic number because it return at the first if statement.
      May be I streamed an au file in a wrong way.
      I was "Write to file" an au file (17,9KB) and then the au file have a same size with sd card. Finally, I "Import to file" it into sd card.
      The above way have some wrong?
      You can help me one more time :)

      Delete
    7. Just be sure that your .au file is in a right format:
      Encoding: 8-bit linear PCM
      Sample rate: 32000
      Channels: 1 (mono)

      Delete
    8. How to create a au file have right format?

      I have tried creat it as follow:
      + Convert file .mp3 to file .au by this app (http://www.convertfiles.com/convert/audio/AU-to-MP3.html)
      + Write file .au into SD Card by Diskimage

      According above way, I dont know about informations of file?

      Delete
    9. I am not sure about this online tool, but any standard audio editor should work. Personally, I am using free, open source audio editor "Audacity" (http://audacity.sourceforge.net).

      Delete
    10. This comment has been removed by the author.

      Delete
    11. In this tool, I can edit sample rate, encoding format, number of channels but my input is a au file which was converted from a mp3 file.

      When converting finshed, I read au file by VS C++ and didn't find a header. I wonder that Is this approach will not create the file header au?

      Can you give me a au file sample which you write into sd card? Thank you
      my email: ddt.khtn@gmail.com

      Delete
    12. This is how I create .au file:
      1. Start Audiacity (I am using v2.0.0)
      2. File/Open your mp3 file.
      3. Tracks/Stereo Track to Mono.
      4. Left Bottom corner "Project Rate" - select 32000
      5. File/Export, select "Other uncompressed files" format.
      6. Click "Options": select "AU (Sun/NeXT)" header, "Signed 8-bit PCM" encoding, click "OK".
      7. Enter file name, click "Save"
      8. On the edit metadata popup click "OK"

      Delete
    13. .au file I used for testing: https://sites.google.com/site/boris0attachments/PF.au

      Delete
    14. Now all was OK.
      But when read header of au file. I always get 0 from lTemp variable.
      I sure that I was write data successfully (I View Hex)
      What's wrong? You can help me ?

      Delete
    15. Maybe you somehow wrote file to the wrong location?
      The file should starts at the first (physical) block.

      Delete
    16. This comment has been removed by the author.

      Delete
    17. i'm sure that i wrote (by tool) and read (by MCU) at first block
      But when i write file, my SD Card is in "Logical volumes" not in "Phisical drivers".
      What's wrong here?

      Delete
    18. This comment has been removed by the author.

      Delete
    19. You have to write to Physical drive.
      Your SD card should be listed in the physical drives section as "removable" media.
      Try different tool (dd or similar), maybe it'll work better.

      Delete
    20. How to my SD Card be listed in "Physical drivers"?

      Delete
    21. I don't know why it's not listed as physical drive.
      I am using Diskimage on Windows XP, maybe it's not compatible with your windows version?
      Maybe you'll have better luck with other disk imaging tools.

      Delete
    22. Ok, I'll try it with another tool.
      Thank you very much :)

      Delete
  8. This comment has been removed by the author.

    ReplyDelete
    Replies
    1. I was ok with writing file au into sd card.

      Now I just listen about 1 second music and then nothing to listen.
      Whats wrong here?

      Delete
    2. Don't know. Maybe verify that it reads an .au file size properly?

      Delete
  9. one doubt

    is it possible to play different files based on some condition
    for instance if a parameter a is passed to the function it plays different files based on the value of a??.

    ReplyDelete
    Replies
    1. It is possible and would be easy to implement. Although, I am not sure that there is enough program (FLASH) memory left on this microprocessor. So maybe you have to upgrade to the bigger chip (e.g. MSP430G2452)

      Delete
    2. i am using 2553

      what changes should be done in the code to incorporate this

      Delete
    3. I am using USI (Universal Serial Interface) to communicate to SD card. 2553 does not have USI, but have 2 USCIs instead. So the first thing you have to do is to modify the code to use USCI instead of USI.

      Delete
    4. i am using g2553 ,, what changes should be done in the code

      Delete
    5. As I mentioned earlier, you have to rewrite SD communication functions (mmc.c: spiSendByte, MMC_initSPI).

      Delete
  10. Dear Sir,

    I use diskimage tool to import file Audio, but it show error.
    File size does not match target device size.
    Filesize: 26773 Target size: 1985740800


    ReplyDelete
    Replies
    1. Just ignore this error. It complains that your .au file is smaller than the SD card size.

      Delete
  11. Hello Boris, i need ur help. I use msp430g2231 coding on Iar Embedded Workbench. I read all of ur writing, ur gived links, but i cant play audio with g2231. When i compile codes, it is error occured like:
    Error[e104]: Failed to fit all segments into specified ranges. Problem discovered in segment CODE. Unable to place 37 block(s) (0x87e byte(s) total) in 0x7c8 byte(s)
    of memory. The problem occurred while processing the segment placement command "-P(CODE)CODE=F800-FFDF", where at the moment of placement the
    available memory ranges were "CODE:f818-ffdf"
    Error while running Linker

    what must i do :( need help

    ReplyDelete
    Replies
    1. It sounds like the compiled code does not fit the FLASH. Verify your optimization settings (it should be set to maximum optimization).

      Delete
  12. Hi Boris, Can I use a .wav file instead of an .au file? could you please give me some hints?

    ReplyDelete
    Replies
    1. I am using 43oh SD Card Reader Booster pack v1.2 and G2553

      Delete
    2. wav file format is pretty simple. Just parse a few values from the header (number of channels, sample rate, etc).

      Delete
  13. Great project!! I've learned so much about audio and msp430 here!
    I just have a question - any hint on how I can have forward/back buttons so that I can go up or down the list of audio files on the disk?

    Thanks in advanced!!!

    ReplyDelete
    Replies
    1. Currently, there is no logic to handle multiple tracks. It sounds like you need something more advanced than this example, probably file system support, searching for audio files, etc. But it won't be possible to do so on this tiny microcontroller.

      Delete
  14. Intresting project, but I can only hear the clicking noise.
    I wrote the .au.raw with DiskImage on the card and used CSS to get the source code onto the mikrocontroller.

    Has anyone an idea, what the problen may be?

    ReplyDelete
    Replies
    1. Don't know what is going on, verify that you getting a valid samples from the SD card.

      Delete
  15. Is there an AC coupling capacitor between the pwm pin and the headphones?

    ReplyDelete
  16. This comment has been removed by the author.

    ReplyDelete
  17. Could we play music in list?
    And.. How to write list of music to SD Card and play one by one
    Thanks for sharing your project :D

    ReplyDelete
  18. Awesome project, thanks a lot for sharing!
    I've seen lots of misinformation earlier about smallish MSP430 chips not being able to handle an SD card due to the 512 byte sector size -- now we can finally see for sure how that is totally irrelevant in cases like this. Thanks again!

    ReplyDelete
  19. This is great, I'm going to try to get it up and running.
    One question: why do you say PWM resolution is 8 bit? Timers are 16 bit so PWM is also 16 bit.

    ReplyDelete
  20. Can you send the code for this mail id (manimuruganvbc@gmail.com) pls

    ReplyDelete