Transmit FM using Raspberry Pi and no additional hardware

Now here’s a project that actually hacks the Rapsberry Pi rather than just using it as an embedded computer. [Londons Explorer] figured out how to turn the RPi into an FM transmitter. For now it’s done entirely in the user space, but we’re sure it could be improved if someone wanted to drill down further into the hardware. For those wanting to give it a try he’s rolled everything into a simple python package.

The technique requires nothing additional except a 20cm wire to serve as an antenna. The trick is to map GPIO pin number 4 to a position in memory. The clock generator is then used to toggle this pin at 100 MHz, which is the frequency to which your radio should be tuned. A fractional divider adjusts the frequency based on the sound file being transmitted.

The proof of concept for this was able to reliably transmit at a distance of about fifty meters through several walls. The problem is that this technique is limited in the amount of data which can be sent. Right now it’s only about 6-bit audio. But descending deeper through the abstraction layers to put DMA (Direct Memory Access) to use may be able to improve upon this.

Probably not. You can almost certainly do this with any computing device (computer, micro controller, etc) with a GPIO pin. Attach a length of wire to any GPIO pin and toggle the voltage, you WILL generate RF. The FCC certification is for stray or unwanted RF leakage/generation.

I was thinking more like another way to do short range transmission of instructions to nearby microcontroller projects, instead of music. Say… have xbmc tell my blind closer to open or close, right from the tv. ;)

I imagine you’d need to use some kind of checksum and such. Any thoughts?

I can’t edit your talk page as the wiki requires you to enter some Imperial College password that only you guys (presumably) know, and I don’t want to be googling around for dodgy passwords at this time in the evening.

I just wanted to say that by default, this continues spitting out a carrier wave after it finishes until the Pi is rebooted. I added the following code to prevent this:

* setdown_fm() – function the same as setup_fm() but with struct GPCTL setupword = {6/*SRC*/, 0, 0, 0, 0, 0,0x5a}; and add an exit(0); at the bottom, as this function only gets called as part of exiting.
* To the top of main, I added: signal(SIGTERM, &setdown_fm); signal(SIGINT, &setdown_fm); atexit(&setdown_fm); . This registers the setdown function for the following events:
** Program is killed with SIGTERM
** Program is stopped by pressing Ctrl+C
** Program exits normally

(Sorry if I’ve made a mistake writing this, it’s late and I don’t have the code on me).

I also note that if you want this to actually be legal, you can get it to transmit in the amateur bands if you have a suitable licence (and comply to the terms of your licence, of course). Calculate the desired frequency as described on the Wiki, then you’ll probably also want to turn the bandwidth down as the default is far too much for amateur radio by changing the 25.0 in this line:

float dval = (float)(data[j])/65536.0*25.0;

I got good results on wideband mode on my VHF handheld by changing it to 6.25, YMMV as I don’t know if that’s actually the correct value or if perhaps there’s another (better) way I should be changing it (I only skim-read the code and changing this value seems to work so meh).

The reason we kept transmitting the carrier is so people could write little python games or something and would get silences between calls to play_sound rather than fuzz, but obviously it would be better to make it an option as you have done.

When transmitting in the amateur radio bands, do remember that since it is a square wave you’ll still get lots of other sidebands, some of which will fall into all kinds of random bands.

If you have the required kit, it would be great if you could post frequency spectra of the transmitted signal. When I made this proof of concept, the only equipment I had to check signals was a speaker and a guitar tuner… (We literally ran it super-slow and measured the frequency with the guitar tuner)

Obviously I could calculate it, but I guess due to nonlinearity in the gpio pin drivers the harmonics won’t be quite as theory states.

The only equipement that I have right now, is a TV-Tuner used a SDR receiver. I will se wath I can try to do with that ! But I’m quite sure there is on this site some people who have better equipement for this type of work.

I love how the microprocessor is eating everything in its path. Everything is becoming a software problem. Years ago the debate was between the big iron people and the uP people. Then between the dedicated function logic people and the uP people and in years to come between the radio people and the uP people (actually the radio people seem to be jumping on this bandwagon big-time).

This is a neat hack. London’s Explorer, how do you recon a supersampled 9.5 bits compares with traditional FM radio (aside from not being in stereo)?

Quality is currently mediocre, but it’s mostly a software problem (due to linux running other apps on the cpu instead of ours…). With that fixed, it is nearly the same quality as broadcast FM. We can probably get to around 13 bits precision.

I ended up on the wrong end of the argument on the Parallax Propeller forum because, while you can use a trick like this to generate RF (and in fact a lot more flexibly) the PLL jitter creates birdies around the carrier which cannot effectively be filtered out. It’s a cool demonstration but not really legal or practical for regular use. Until someone puts the RPI version on a spectrum analyzer we simply don’t know whether the output is acceptable.

The out output is going to be pretty bad. Assuming you can radiate all of the square wave only about 2/3rds of the energy will be on the desired frequency, the rest wll be unwanted EMI. That doesn’t even allowing for the jitter in the signal.

Square waves are rich in odd harmonics. How long will it be until somebody figures out that if you spew junk on 1575.42MHz (fifth harmonic of 324MHz) you can build your very own Raspberry Pi powered GPS jammer?

Clean square waves aren’t so bad… no you don’t want to send them to the antenna but harmonics are easy to filter out with a few passive components. It’s spurs that are near but not on the actua desired frequency that you need to worry about.

You can probably get some good stats on this with matlab. Consider an ideal 100Mhz FM signal, sample in time to 500Mhz, and then quantize in amplitude to 1 bit. then do an FFT on the result. Post pictues… :-P

Ok – matlabbing done… Assuming the Rpi gpio is linear (which is with lack of further info the best we can do), the FM transmitter also transmits at the 3rd, 5th, etc. harmonics as expected. The power of these transmissions is 1/3, 1/5 etc. again as expected.

There is also noise near the FM signal (ie. hard to filter) as you state, but it is 40dB down from the main signal, so shouldn’t be too bad.

Yes, and Yes. It was a hack, and the lfsr was a nice one-liner. You would get better quality with delta sigma for certain. The DMA version we have been thinking about will use Pulse width modulation (since that is implementable, whereas delta sigma isn’t really possible with the dma command set within a sensible amount of memory).

It’d be interesting to see if you could receive FM broadcasts using a similar technique. Even if you couldn’t make it into an FM tuner you might be able to make a simple short-range wireless connection between two devices.

I am concerned that a floating input with no filtering at all may pick up 50Hz way way way more than it picks up 100Mhz, so you won’t get any of the signal you want… It could work with a basic filter and amplifier on the input though. Processing data in real time at 100Mhz will be challenging though…

EXCELLENT work and it’s a wonderful demonstration of less being more. Commented code is one of those pass/fail deals for those who want praise instead of anger. The time to comment while writing code- Vs time spent needlessly reverse engineering can be a hugely nonlinear swap. Good show by posting commented code !

The comments about FCC/Regulatory oversight sort of fall short of strong enough warnings. Anyone doing this is welcomed, nay begged..to do some range testing for us! That’s a quickest real world test of if we’ve worries ahead or not at all. In theory- it’s damned unlikely that ranges in tens of feet will ever be there for dumb wire bits or board foils. But let’s be sure. Past reasons?

We used a concept of best situational practices. Defines shortest form as a brutal crude proof -of-concept can get away as is but not to push it past just that.

More than that initial run deserves some care about consequences. As broader use above the “yes- it works” demos and/or minimal operating testing needs attention to what you are doing to others around you. So you don’t replicate what 6m did to TV decades ago.

Harmonics of Hacked gear WILL shower bandwidth with General Cruddy Splatter Badness to a damage level often way understimated. Examples are out there for examination. Especially when Hack/Make spaces are having Colo with Repeater inputs. Or someone gets the why not.. of trying this on Six Meters and doing things to TV and Aircraft bandspace!

There’s good reasons for being careful but not too careful in many areas. RF’s reach is a damage multiplier even if we’d think it stupidly paranoid at first glance. The risk of Hackerdom getting bad press or people getting hurt is why being mindful about range is a Very Good Idea.

I’m working on a better version, using the pasive ADC on a VGA’s R, G or B output, a sine table, and DDR outputs to generate a 600MHz, 4-bit RF signal.
Using the FPGA allows for 16 bit modulation. Should be pretty sweet.

Does the RPi’s GPIO pin violate this? Well, the GPIO pin can provide more power than that. The 3.3 V GPIO pin has a current limit of 16 mA, so the pin can theoretically provide 0.0528 W (3.3 V * 16 mA = 0.0528 W).

I’m not sure how that relates to the output power of the transmitter though. Does anyone who knows more about RF have any ideas about this?

If we use a lambda/2 dipole and we integrate the Poynting vector in order to get the radiated power in the vacuum, we get that P0= 36.6*(I^2), if we use 0.016 A we get P0=9.36mW but we are using a lambda/4 monopole (the wire) we are radiating half of power than the lambda/2 dipole so we have P1=P0/2=4.68mW.
By the Friis transmission equation the power that reach those 3 meters would be:
Prx = Ptx*Grx*Gtx*(lambda/4/pi/R)^2
R= 3 meters
Gtx is the directivity of a lambda/4 monopole == lambda/2 dipole that is 1.64
If we asume an isotropic antenna at the receptor that has a gain of 1
And also we can calcula lambda=c/f=3 we can estimate a recieved power
Prx = 48.65uW which is more than the FCC limit.

1) the FCC is NOT the poliece of the entire world. PERIOUD. end of story. FACT

2) GPIO pins have had the capability of doing this since… well… waaay before 1990. that is for SURE. im pretty sure its been done at lower frequencies by AVR and PIC

3) odd harmonics are nasty little buggers! you _think_ your only transmitting on one freq. when in reality your splattering the entire VHF, 1/8 of the UHF, aircraft, cellphone/900mhz, and anything else that gets in its way! trust me, ive done it accidentally and wondered why all the TV’s radios and 900mhz stuff stops working when powering on my “low bandwidth” transmitter

PS: you _KNOW_ your transmitting _something_ when you touch the antenna and get a mild RF burn ;)

Correct me if I’m wrong, but don’t most commercially available fm radio receivers (for music) only allow tuning at frequencies like 100.1, 100.3, 100.5 and so on… unless it were an sdr or analog tuner? At least my car doesn’t allow even numbers due to bandwidth spacing…

Interesting things can happen on a simple wire antenna at high frequencies.

A while back i soldered about 30cm of bell wire to an IO pin on a Parallax P8X32A microcontroller to generate RF noise (for diagnostic purposes while working in an RF shielded chamber) and it worked beautifully. Fascinating thing was that the measured peak to peak voltage at the end of the antenna wire was over 40 volts. Forty. Four zero. The P8X32A runs off 3.3 volts supply. RF is black magic.

I suspect the accuracy of that 40 V p2p if there’s any “load” applied. Yes- there’s a set of rational models for how the voltage is developed as such. But it’s all about discovering what is a real voltage and what’s a phantom read or just picoamp volts.

That really impressive static spark for example- It’s got V but no W averaged over longer than the discharge event. Stings like hell, can ESD oxide layers even, but it’s not usable bulk power.

BtW, all the comments about harmonics and spurs/spikes et all- They’re often an understated danger by far. Intermod with nearby radios or just exciting any nearby nonlinear junctions can be badness indeed. Playing with crudity like these schemes called “Direct RF” anywhere near oh- Repeater Diplexers that have dicey shielding can spread the ungood. Same with underestimating the crud range..Fifty feet sphere? in one environment is safe. In another place that could be not good for several neighboring rooms.

I perhaps did not make it clear enough:

Be damned aware of what risks really are of viable concern and which are no sweat. And what you’re betting with if you’re wrong. Bunging up someone’s music radio- or a baby monitor- Or life safety radios. All protected by our good practices. Or not.

Anyone want to take a crack at what it would take to port this to one of those stuffy Beaglebones? My first impression was to change the GPIO to what the bone uses, but after looking at the code I’m a little mystified at how it even works…

Yes, it looks like it would be possible (this design would be possible on any system with a clock speed > ~ 200Mhz), but the specifics of how the GPIO’s can be controlled from a clock module in the beaglebone is totally different from the Raspberry Pi, because the chip is TI based rather than Broadcom based, so you would effectively have to re-implement the whole thing. :-(

It looks quite a bit harder to do in the beaglebone, because it doesn’t seem to have the ability to connect a configurable clock signal to a gpio, so instead you’d have to generate the signal in software, which would be pretty tough to do at 100Mhz, and even tougher to do with linux running.

The paragraph before the C program at the bottom of the page states the .wav file should be 16 bit 44.1kHz mono, but the usage comment at the end of the C program states the .wav file should be 16 bit 22.5 KHz mono. Which should it be?

The newest version uses 22 kHz. The reason for this is because during FM transmission, the audio needs to go through a filter (called pre-emphisis). This filter amplifies high frequencies. If the signal were 44kHz, then the highest frequencies would be super amplified and would interfere with the stereo detection circuitry in the receiver.

Obviously, a bandpass filter could solve this, but I couldn’t be bothered to implement one… :-P