Portable Trollmaster 3000

Spreading the voice of Eduard Khil

Similar projects worth following
The official goal of this project is to hack together a trinket and a cheap FM transmitter to broadcast (well, within a 1 meter range, let's call it 'localcast') the famous 'Trololo' sound clip.

The officious goal is to beat my procrastination, stop lurking HaD and finally build something, even if silly and useless.

Besides blinking a led and generating a square sound on an Arduino, this will be my first electronic project. I'm a software guy without physics or electronics academic background, what could go wrong ?

This text explains how to reproduce the project. The first section presents the MMR-70 transmitter, how to open it and where to solder wires. The second section presents the hardware connections between the Trinket pro, the MMR-70, the 7-segments display and the two buttons. The last section presents the software and points you towards parts you might want to change (mainly pins configuration).

Read more after the break ;-)

Read more »

View all 7 components

  • The joy of learning by doing

    Dr Salica01/03/2015 at 17:24 0 comments

    The deadline of the contest is nearly here; it's time for me to post a final project log. During this month, I learned a lot and I had a lot of fun. But the main lesson I learned is : just do it.

    I have spent a lot of time finding good reasons to not start an electronic project. This was a mistake. I have many things to learn, but now I'm convinced that the best way to learn something is by doing it.

    I know that the Portable Trollmaster 3000 is mainly an 'embedded programming' project and not really an 'electronics' project. I have everything to learn in the field of analog electronics and RF. However, I think that the Arduino/Trinket pro is good entry point into this world. It was really fun to use and thus it is a real motivation to go further :-)

  • The joy of portability

    Dr Salica01/03/2015 at 16:50 0 comments

    At the moment, the Portable Trollmaster 3000 is not very ... portable. Time to change this !

    Thanks to the integrated voltage regulator on the Trinket Pro, it can easily be powered with anything up to 16V. A 9V lithium battery will do the trick. I found a nice litte enclosure. It's about 7 cm wide, 6 cm deep and 4.5 cm high. Ok, I admit it, it's a little bit larger than an Altoid enclosure ;-)

    After rewiring everything on a smaller breadboard and cutting the lid of the enclosure, here is the final product :

    Since I had no banana for scale near me, I used a 2 euros coin. I had to use some tape to fix everything in place. It's a little crowded in there ...

    You can see it in action here :

    As you can hear in the video, there is a lot of noise when I move the enclosure. I guess the audio carrying wire is too close from the voltage regulator or another noise source. I guess a major improvement would be to design a clean PCB for this project. I have never done this before and I'm a little afraid to work with chemical products.

  • The joy of seeing the Trollmaster in action

    Dr Salica01/02/2015 at 10:57 0 comments

    Here is a video of the Trollmaster in action. Don't forget to turn Youtube annotations on. Enjoy :-)

    The seven-segments display shows the FM frequency. Two push-buttons allow to change the frequency up or down by steps of 0.5 Mhz.

    The Trinket Pro runs the PCM library of 'low-high tech' and loops a sample of the Trololo song. It also drives the MMR-70 FM transmitter which generates a FM+RDS signal with a station name of "TROLL FM".

  • The joy of using an underdocumented module and using a plan B at the last minute

    Dr Salica01/01/2015 at 22:04 2 comments

    Meet the culprit, the WTV020M01 module :

    (Yes, one pin broke during transport).

    This thing is a "MP3 audio player SD card module". That's for the title. Now a few teeny tiny details :

    • By "MP3", it means that it supports 'next', 'prev', 'stop' and 'play' buttons like classic MP3 players, NOT that it is able to read MP3 files. Really. It does not support the mp3 format.
    • By "SD card", it means that it only works with Sandisk Micro SD card of 1 or 2 GB. According to reviews on the Internet, you have to try dozens of cards to find a compatible one.
    • By "audio player", it means that somebody on the Internet says he knows someone who got it to read a .wav file. But nobody can reproduce that. Instead, you have to use the obscure .ad4 file format
    • The datasheet is written by a Markov chain. It looks like a datasheet, it has the structure of a datasheet, some words seems to make sense, but in the end, it is just pure randomness.

    Caveat emptor : do not buy this thing ;-)

    Ok, maybe it's just me. After all, it's my first real project. But after spending two days to get this thing working, I give up. It is supposed to work in a standalone fashion, it does not. It is supposed to work with a weird two wire interface, it does not. All I managed to get is some kind of static. At least this static lasts the duration of the sound supposedly played. I do not have the tools or the skills to debug what's going on so, time to move to plan B.

    I'm now using the PCM library from "high-low tech". It allows me to load a small (~ 3 sec.) low quality sample in the Trinket Pro flash and play it through an output pin. I'm disappointed that I cannot play the whole Trololo song but the deadline is approaching and I still must deliver a minimum viable product.

    I quickly hacked the PCM library to loop the sample instead of just playing it once. It's really easy : in the ISR after the call to stopPlayback(), just add a call to startPlayback(sounddata_data, sounddata_length); and the sample will loop forever !

    I used Audacity to extract a sample and sox to convert it to 8 Khz :

    sox in.wav -c 1 -r 8000 -u -1 out.wav

    Then, I used the EncodeAudio tool to get the set of bytes to paste into the Arduino sketch and voilà !

    The setback with the nonworking so-called MP3-SD module was annoying, especially with the deadline approaching. But in the end, the PCM library offers a quick work-around, even if it means only playing a part of the Trololo song.

  • The joy of RDS

    Dr Salica12/29/2014 at 21:52 3 comments

    A picture is worth a thousand words. Admire the FM tuner of my AV receiver displaying the name of the famous HACKADAY FM Radio :D

    Basically, the RDS system is a way to send digital information to a FM RDS tuner. The RDS specification defines several types of messages called "groups". Each group type can transmit a given set of information. For example, the station name is transmitted in the "OA" type group.

    I used the Trinket Pro to send a OA group containing the "HACKADAY" string to the MMR-70.

    Well, it's a bit more complicated than that. A OA group can transmit only 2 characters. So I have to send 4 OA groups and keep track of the characters sent. But I cannot sent a OA group directly to the MMR-70. I have to split it in 4 blocks. Oh, and of course, the MMR-70 registers used to send the block varies and depends on the ID of the current block. Oh, and I cannot send the blocks when I want, I have to wait for the RDSINT signal to be LOW.

    I will not use the full RDS protocol in this project. All I need is to transmit the station name, and the OA group is enough for that. Here is the code I wrote. It is fully commented, so I hope you can have a better understanding of the RDS group and the MMR-70 by reading it :-)

    #include <Wire.h>
    // The MMR-70 signals when it's ready to receive the next RDS block by setting 
    // the RDSINT signal to low.
    // Connect this signal to the following pin of the MCU
    const uint8_t RDSINT_pin = 8;
    // Dont forget to connect the I²C pins of the MCU to the MMR-70
    // On the Trinket pro :
    // - connect Analog 4/Digital 18 to the SDA point of MMR-70 
    // - connect Analog 5/Digital 19 to the SCL point of MMR-70
    // FM transmitter I²C address
    #define NS731_I2C_addr 0x66
    // Recommended values for registers initialization
    #define NS731_init_data_size 23
    const uint8_t NS731_init_data [NS731_init_data_size] = {0x02, 0x81, 0x0A, 0x00, 
          0x00, 0x00, 0x00, 0x7E, 0x0E, 0x08, 0xAF, 0x2F, 0x0C, 0xE6, 0x3F, 0x70, 
          0xA0, 0xE4, 0x00, 0x42, 0xC0, 0x41, 0xF4};
    int RDSINT = 0;     // Status of RDSINT signal from FM transmitter
    int RDS_block = 1;  // ID of RDS block inside the current RdS group
    int RDS_group = 1;  // ID of the curret RDS group
    void setup() {
      pinMode(RDSINT_pin, INPUT); 
      // Initialize the wire library
      // Send a reset command to the FM transmitter
      // Initialize the registers of the FM transmitter with the recommanded values
      for (uint8_t i; i<NS731_init_data_size; i++) {
      //Set PE to ON
      //Set ALC to ON
      // Set mute to ON
      // Set frequency
      Wire.write((uint8_t)0xea);    // 0XEA 0X2A is 90.0 Mhz
      Wire.write((uint8_t)0x2a);    // Change those values to change the frequency
      // Set P2 to recommended value
      // Wait for CEX search time
      // Set MAA according to CEX value
      Wire.write((uint8_t)0x21);   // You should first read the CEX value and set 
      Wire.endTransmission();      // MAA accordingly. Here the 0x21 value is good
                                   // for the default 90.0 Mhz transmission 
                                   // frequency. You should change it if you use
                                   // another frequency (see the...
    Read more »

  • The joy of the Bus Pirate

    Dr Salica12/25/2014 at 22:01 0 comments

    The Bus Pirate is a fantastic tool. It gives me an interactive prompt and immediate feedback while playing with the FM transmitter.

    Unlike my previous I2C exploration with the 7-segments display, using the MMR-70 is much more complicated. First, there is no nice Arduino library for this device. Second, I do not know immediately whether what I'm doing is working or not. Finally, 23 (!) registers must be correctly initialized before starting the FM transmission.

    The datasheet has some ambiguities about which register values to use during the initialisation phase; the FMBerry project uses another set of values; and another code uses yet another set of values. I tried many settings but I was never able to get the transmitter working.

    So, I hooked up the Bus Pirate to the SCL and SDA lines of the MMR-70, started the I2C capture mode, plugged it into my phone, started broadcasting a song and, hooray, I captured the whole init section.

    Here is what I found :

    // The following is sent after plugging the MMR-70 into the phone
    [0xCC 0x7F 0xA0] // Reset command
                     // Wait
    [0xCC 0x7F+0xA0] // Reset command again
    // Init for the 23 registers
    [0xCC 0x00 0x02]
    [0xCC 0x01 0x81]
    [0xCC 0x02 0x0A]
    [0xCC 0x03 0x00]
    [0xCC 0x04 0x00]
    [0xCC 0x05 0x00]
    [0xCC 0x06 0x00]
    [0xCC 0x07 0x7E]
    [0xCC 0x08 0x0E]
    [0xCC 0x09 0x08]
    [0xCC 0x0A 0xAF]
    [0xCC 0x0B 0x2F]
    [0xCC 0x0C 0x0C]
    [0xCC 0x0D 0xE6]
    [0xCC 0x0E 0x3F]
    [0xCC 0x0F 0x70]
    [0xCC 0x10 0xA0]
    [0xCC 0x11 0xE4]
    [0xCC 0x12 0x00]
    [0xCC 0x13 0x42]
    [0xCC 0x14 0xC0]
    [0xCC 0x15 0x41]
    [0xCC 0x16 0xF4]
    // The following is sent after selecting the FM Frequency 
    // on the phone (in this case 90.0 FM)
    [0xCC 0x02 0x0B]      // mute ON
    [0xCC 0x0A 0xEA 0x2A] // Select Frequency (90.0 FM in this case)
    [0xCC 0x07 0x7E 0x0E] // P2
    [0xCC 0x70[0xCD 0x00] // Read the CEX value (0x00 in this case)
    [0xCC 0x15 0x39]      // Deviation control
    [0xCC 0x02 0x0A]      // mute OFF
    [0xCC 0x10 0xE0]      // RDS stuff
    [0xCC 0x03 0xE0 0x00] // RDS data
    [0xCC 0x05 0x01 0x24] // RDS data
    [0xCC 0x05 0xE0 0xCD] // RDS data
    // The following is sent after a song is played
    [0xCC 0x02 0x0B]      // mute ON
    [0xCC 0x0D 0xE6]      // ALC
    [0xCC 0x00 0x03]      // Power ON
    [0xCC 0x05 0x20 0x20] // RDS data
    [0xCC 0x02 0x0B]      // mute ON
    [0xCC 0x0A 0xEA 0x2A] // Select Frequency (90.0 FM in this case)
    [0xCC 0x07 0x7E 0x0E] // P2
    [0xCC 0x70[0xCD+0x05] // Read the CEX value (0x05 in this case)
    [0xCC 0x15 0x21]      // Deviation control
    [0xCC 0x02 0x0A]      // mute OFF
    [0xCC 0x10 0xE0]      // RDS
    [0xCC 0x03 0xE0 0x00] // Continuous flow of RDS data
    [0xCC 0x05 0x01 0x21]
    [0xCC 0x05 0xE0 0xCD]
    [0xCC 0x05 0x52 0x2D]

    With this information and the datasheet, I noticed that I forgot to send the [0xCC 0x00 0x03] command to activate the power ! Duh !

    It's interesting to see that some commands are redundant. For example, the frequency selection command is sent right after the frequency is chosen on the phone but is sent again when a song is being played. I wonder why.

    Now I am able to correctly initialize the FM transmitter and broadcast some sound through the analog input pins (although it's really noisy) !

    My setup is the following :

    • Connect the GND, SDA an SCL pins of the Bus Pirate to the GND, SDA and SCL pins of the MMR-70
    • Connect the 5V Bus pirate output to the VIN pin of the MMR-70
    • Connect the GND and RST pins of the MMR-70 to prevent the integrated MCU to use the I²C bus. However, do NOT connect the XTAL and GND pins as I have seen in some documents. It did not work for me.

    Start your Bus pirate. Select the I²C mode, activate the pull-up resistors, activate the power and start playing with the commands.

    To use the I²C sniffer mode while the FM module is connected to the phone, let the phone power the module (so disconnect the Bus Pirate 5V pin from the module), do not connect GNS and RST and do not use the pull-up resistors.

    My next goal is to drive the module from the Trinket and broadcast a RDS FM station name.

  • The joy of I²C

    Dr Salica12/09/2014 at 21:57 0 comments

    Before tackling the task of controlling the FM transmitter, I need to warm up. As I explained earlier, this is my first real electronics project and I never used I²C before.

    Since I need a way to enter the FM frequency and display it back, I ordered a 7-segment display controlled by I²C. I think it's a good start to play and discover I²C.

    Adafruit provides a nice Arduino library for it. After fighting with the Arduino IDE I managed to get some number displayed.

    Before going further, allow me a side note here. I'm used to work with JEE applications, a continuous integration server and an IDE that provides me autocompletion and easy code navigation. The Arduino experience is ... well ... quite the opposite. I wonder how anyone can achieve reproducibility with this tangle of custom Arduino IDE, manual library installation and lack of build system. End of side note.

    Back to the 7-segment LedBackPack library. I was surprised to see C++ code. I thought that only C was possible on Arduino. I don't know C++ but I know enough of C and Java to survive. The library is well written and easy to use.

    However, I don't like how float numbers are displayed on the 7-segment display : the library pads the number with trailing zeros. I want to display FM frequencies and I don't like the way it goes from displaying "99.90" to "100.0". For frequencies under 100Mhz, I just want it to display one decimal digit (" 99.9" for example).

    I could patch the LedBackPack library (or override the method, OO FTW !) but I wanted to understand how it worked. I discovered that the library uses the Wire library to emit I²C commands and it's not really complicated :

    Wire.beginTransmission(I²C address);

    and that's all.

    After reading the datasheet and poking around, I figured how to control the display myself, without the LedBackPack library. Here is a picture of my findings :

    Each 7-segments of the board is located at a specific register. The first 7-segments is at the register location 0x00, the second at 0x02 and so on. To light on or off specific segments of a given 7-segment item, you send a carefully crafted byte at its register address. Each bit of this byte indicates whether the corresponding segment must be on or off.

    Let's do an example :

    I want to send a command to the display controller. Its I²C addres is 0x70, so I write :


    For this display controller, I want to light some segments of the 7-segments item located after the colon sign. Its register address is 0x06, so I write :


    For this 7-segments item, I want to display the character 'H'. I thus must lit the segments number 1,2,4,5 and 6. I must create a byte with the corresponding bits set to 1 : 0111 0110 or 0x76. So I write :


    And finally, I commit the command by writing :


    Don't forget this last line after each I²C command ! I discovered that two I²C commands inside a single transmission worked fine for me, but with three commands I ended up with a garbled display.

    And so, here is my display saying 'Had' in honor to Hack a day :

    I'm now more confident to use the Wire library and try to get the FM transmitter working. However, recompiling and uploading a sketch each time I want to test a new I²C command is not fun. So I'm now the proud owner of a Bus Pirate. That should ease things a bit ;)

  • The joy of soldering

    Dr Salica12/07/2014 at 21:36 3 comments

    This afternoon was placed under the sign of solder.

    The FM transmitter has a lot of test points but I need a way to hook them up to the Trinket. I do not want to solder wires directly to the Trinket and to the FM transmitter. I prefer to use a breadboard.

    So, I need wires that can be easily soldered to the Trinket while being easy to connect and disconnect to a breadbord. I tried using jumper cables but they were difficult to solder. My solution was to reuse an old floppy disk cable.

    The individual wires of the floppy cable can be easily soldered to the test points. Male-male jumper cables can then be connected to the floppy IDC (?) connector on one end, and to the breadboard on the other end.

    I took my old 25W Velleman soldering iron out of its dusty drawer. I cut the floppy cable, separated the individual wires, stripped and pre-tinned them. I also pre-tinned the test points. You can see the result here :

    I'm not very happy of my soldering job. Some wires are barely covered by solder, many solder joints have a matt finish. I hope to get some feedback and tips, so I share my bad soldering job in all its high resolution glory here :

    I probably should flood this with hot glue to strenghten the connections.

    I tripled checked the connections with a continuity tester and everythink was OK and there were no short circuits. I connected the board to my phone and it worked properly. Finally, I wanted to use an seprated power source to test the board.

    The board uses a LP2985 power regulator. It takes about 4V from the phone and outputs 2.8V to the board. The datasheet states that the input voltage can go up to 16 volts. Good news, it means that I can be quite careless about the input voltage :-) As a final test, I connected a 5V power source between the Vin and the Gnd pads, and the led blinked !

    While my soldering iron was still hot, I soldered the headers of the Trinket. I guess Adafruit's board are pre-tinned and pre-fluxed because it went surprisingly well and I ended with nice and shiny solder joints.

    I guess I'm now ready to explore the wonderful world of I²C ;-)

  • The joy of incorrect specifications

    Dr Salica12/02/2014 at 22:15 2 comments

    It's nice to have a fun idea that seems doable (see my previous log entry), but now I need to be a little more concrete. All I have for the moment is an Arduino Uno, so I need to order a Trinket pro. But wait !? There are two flavors : 5v and 3.3v ??

    And so starts the endless stream of questions : which one do I buy ? What is the voltage of the FM transmitter ? Does it matter ? Can I mix voltages ? What about i2c ?

    A look at the FMBerry project page shows the following picture :

    It seems that the MMR-70 works on 3.3 volts and so is the Raspberry Pi. I should probably order the 3.3v Trinket. But can I use my 5 volts Arduino in the meantime ? Maybe, maybe not.

    I found that 5v and 3.3v hardware cannot always be connected together unless the later is "5 volts tolerant". A mere 1.7 volts out of spec might fry the hardware. I also found that some magic device called a level shifter can convert the voltage between two i2c systems. But beware, some shifters are not compatible with i2c ...

    So at this point the plan is to buy a 3.3v trinket, wait for the package to arrive, and stop worrying about this voltage stuff.

    Not so fast.

    I happen to own an old Sony-Ericsson mobile phone compatible with the MMR-70. So I decided to hook it up and check that it runs on 3.3v. I was not pleased with the result :

    ... ... ... 2.8 volts between ground and pin 11 ... Not 3.3v as the photo with the labelled test points stated ! And so starts the endless stream of questions again.

    But in the end I guess it's not so problematic : after all, the FMBerry project works and uses a 3.3v RasPi without problem.

    I think I will order a 3.3v Trinket pro and a level shifter just to be sure, but still try to connect the Trinket and the MMR-70 directly.

  • The joy of ignorance

    Dr Salica12/01/2014 at 16:53 0 comments

    This is all new to me and, to be honest, I'm not prepared. However, I think the project falls into the 'plausible' category :

    • The MMR-70 FM transmitter is controlled via i2c. The trinket can speak i2c. Check
    • The audio input is plain old analog. The trinket has analog outputs. Check
    • Arduinos can output wav files and use SD cards. I guess the trinket can do the same. Sort of check
    • If the previous item does not work, I can ditch the wav approach and generate the melody with square or sin waves. Backup check

    The rest are just details; huge, unexpected, devil-hiding details.

View all 10 project logs

Enjoy this project?



przemowi2002 wrote 01/09/2018 at 09:47 point


could you reupload the source code?

The link stopped working.


  Are you sure? yes | no

Alex wrote 09/11/2015 at 16:02 point


could you reupload the source code? The file in the link does not exists any more


  Are you sure? yes | no

davedarko wrote 09/11/2015 at 16:24 point

I hope I'm not impolite, but there is a log with the code that helped me

  Are you sure? yes | no

Alex wrote 09/11/2015 at 19:57 point


  Are you sure? yes | no

Dr Salica wrote 09/12/2015 at 09:12 point

Hello al1,

I really should take the time to put the code on a github, but in the meantime, I reuploaded it here :

Hope it helps ! 

  Are you sure? yes | no

Alex wrote 09/12/2015 at 12:56 point

Thnak you

  Are you sure? yes | no

Mike Szczys wrote 01/05/2015 at 21:51 point

Just wanted to say that I think "stop lurking HaD" is one of the most noble goals you could have for a project. Nice work sharing the details on this build!

  Are you sure? yes | no

Dr Salica wrote 01/06/2015 at 08:50 point

Thanks for your kind message!

  Are you sure? yes | no

davedarko wrote 01/03/2015 at 20:21 point

Hey! Congratulations to your finished project! There is definitely some space you could get by soldering your project but all in all you killed it in time of the contest! Nice demo video by the way!

  Are you sure? yes | no

Dr Salica wrote 01/04/2015 at 20:42 point

Thanks ! I had to cut corners in order to finish on time. The FM transmitter is soldered to an old floppy disk cable. It's really useful for connecting and disconnecting jumper cables, but the ribbon cable and the IDC connector take a lot of space.

I really should get rid of the cable and solder short wires between the Trinket and the FM transmitter. In a perfect world, I would source a female Sony-Ericson expansion connector and make a cool PCB ;)

  Are you sure? yes | no

davedarko wrote 01/04/2015 at 23:48 point

For this purpose I bought some pre soldered 5cm jumper wires - they are thin, cheap (1,72EUR on ebay) and the length is okay, too. When I want to get extra fancy I have some color-coded ribbon cable. I'd say without the headers and breadboard and with cables soldered from pin to pin you will be able to close the lid. Anyway, good luck!!

  Are you sure? yes | no

Manawyrm wrote 12/04/2014 at 09:56 point

really neat project idea.
I thought about doing that too (altough with a different kind of music to broadcast :D).

Anyway: I figured it is possible without any external electronics.
Because the MMR70 has a ATmega32 processor on its PCB, you can just directly hook up a SD card socket to the SPI pins and have a go there .

The only problem with it is, that the only way to generate fitting audio signals is one of the timer comperator pins, which unfortunatly are not availiable as a test point. (you need to do some fine hand soldering. hard but possible).

After hooking OC1B up to the R/L inputs of the transmitter chip itself, I was able to play beeping sounds from the atmega controller as a standalone unit, but I haven't had time yet to implement a SD card .wav playing routine for m32 MCUs.

Good luck and best wishes with your project,

Note: don't hesitate to contact me via twitter/mail ;)

  Are you sure? yes | no

Dr Salica wrote 12/05/2014 at 15:35 point

using the ATmega32 is tempting, but I do not (yet ;-) ) have the skills to flash it or to solder directly on its pins.

For now, I will take the easy way and use a wave shield clone ( WTV020-SD-16P ) to output the audio to the analog sound inputs of the transmitter.

I will already be very happy if this works :-)

Thanks for your help and your encouragements, I really appreciate it ! :-D

  Are you sure? yes | no

davedarko wrote 01/05/2015 at 00:42 point

Just bought 4 MMR-70s for 4EUR from Germany on eBay rather than 1 for 1,22EUR from China :) so I may clone it using a bubble display and the atmega directly - sending sound from the atmega. That would be well out of my comfort zone :D

  Are you sure? yes | no

Dr Salica wrote 01/05/2015 at 07:37 point

I got them from Germany too (ebay store moobooo) :-)

I didn't know what a bubble display is and looked it up. Wow, they are cool :-)

  Are you sure? yes | no

Similar Projects

Does this project spark your interest?

Become a member to follow this project and never miss any updates