The Raspberry Pi as DVB-S digital TV transmitter.

Some extra hardware and software changes the Raspberry Pi into a DVB-S digital TV transmitter.

The code and diagrams are released under the GPL license.

This project would not have been possible without the pioneering done by Jean-François Fourcadier, F4DAY.
I also made use of simplifications made by F4AGC, I simply simplified things some more.
The windows TS188ToIQ.exe software written by Evariste, F5OEO proved valueable to compare my ts2iq.c software output against.

symbolrate can be specified on command line

the 6 MHz crystal oscillator is no longer needed.


transmitter board block diagram
The transmitter board block diagram

transmitter board circuit diagram
transmitter board circuit diagram, btw that coil is 184 nH, not uH.

transmitter board component view, test setup, Raspberry Pi (model 2) on the left
test setup
The 2 FIFOs are mounted on top of each other as all data lines are in parallel.
The Analog devices DAC and QAM chip are not used for this project.
There is a little prescaler all the way to the right that gives about 6 MHz out for use with a PLL to be added maybe later to stabilize frequency.
There are a lot of small electrolytics around the VCO for decoupling to reduce phase noise, do NOT use ceramic SMDs here, those are so microphonic that breathing on the board changes frequency already.
New in this version: the clock for the symbolrate is generated by the Raspbperry Pi and output on GPIO_4 pin 7, fed into the 4040 counter, the 6 MHz crystal oscillator is no longer needed.
This allows one to specify the symbolrate on the command line!
There is an XOR gate inserted in the Q line so it flips the constellation to what seems the normal way for a DVB-S receiver,
If you connect the other input to +5V the XOR inverts, that way there is no need for the software to invert I or Q (-i command line flag), and that saves processor cycles, we will need those for the camera.
As time goes by I come up with improvements.
The other XOR gate is used here as a buffer, I think it can be omitted, but maybe the gate delay is needed (it drives the FIFO read pins), so why not leave it..... :-)

receiving a movie
Receiving a movie, laptop is ssh -Y to other PC running the modified xdipo with the Hauppauge wintvnova PCI card as receiver.
I do all programming on the raspi via ssh -Y too, as the keyboard sucks via USB and is slow and always drops characters.

test board wiring side
test board wiring side, you can see the little white mixer on the right,
RF wiring is very short with lots of SMDs (that you can see if you look close), those fit nicely on this type of board exactly between 2 isles,
the 'low frequency' wiring is just wires stripped from a piece of flat cable.
Power required is about 9 V DC at <300 mA (with the AD chips), a lot less if you leave those out.

How to make a valid transport stream

A very simple way to make almost any format file into a .ts usable for transmission with this transmitter is this script:
ffmpeg -i $1 -f mpegts -acodec mp2 -ac 1 -ab 64000 -ar 48000 -s 720x576 -deinterlace -r 25 -aspect 4:3 -vcodec mpeg2video -b 1200k -maxrate 1200k -minrate 1200k -bf 2 -bufsize 1343488 -y my.ts
where $1 is your input file, it produces a transport stream with very close to 1500 kbps bitrate, mono audio, 720x576 progressive.
Adjust the 1200k so the total bitrate of the generated .ts is exactly 1500k, so no cache underflow or overflow on reception, needs a bit of experimenting.
This example uses different audio and video input files, this bitrate plays nice on my system with sybmolrate 1500k:
ffmpeg -i b.mpv -i b.mp2 -f mpegts -acodec mp2 -ac 1 -ab 64000 -ar 48000 -s 720x576 -deinterlace -r 25 -aspect 4:3 -vcodec mpeg2video -b 1200k -maxrate 1200k -minrate 1200k -bf 2 -bufsize 1343488 -y my.ts

You can get flawless reception by sending the received stream to a file (use xdipo record function if you use xdipo for receiving), and then start xine (or mplayer) on that file a bit later, timeshift :-):
cat /dev/dvb/adapter0/dvr0 > rx.ts
wait a few seconds, in an other terminal:
xine rx.ts
In fact it does not matter at all what is IN the transport stream, as long as there is a hex 0x47 byte each 188 bytes, not even the program stream pids are needed.
That makes it easy to write a program to transfer large files... send 0x47 send 187 bytes of data, send 0x47, send next 187 bytes of data,
and on the receive side, wait for 0x47, skip it, write 187 bytes to output, test if 0x47, skip it, write next 187 bytes...
But that would not conform to any standard that I know about, but who cares...
As to standards,
you probably also need to add PAT, PMT, other things.
I have been trying things with opencaster, it is free open source,
try downloading the manual, it gives more information than I can give here in a few lines of how to make a valid transport stream.
To check your mediafiles there is the mediainfo program for Linux, I use it a lot, gives good info on transport streams you encode.

The math:
We are sending 1500k symbols per second, that makes 3,000,000 data bits per second.
With a FEC of 1/2 that makes 1,500,000 real data bits per second, as for every data bit convolution has added a correction bit.
Because of Reed Solomon encoding we added 16 correction bytes to every 188 bytes, so that leaves us 1,500,000 * (188 / 204) = 1,382,350 usable data bits.
When we run the above generated my.ts through the mediainfo program we see (among many other things):
mediainfo my.ts
Overall bit rate: 1392 Kbps
So we are very close to the required 1,382,350, that is why I wrote 'experiment with the 1200'.
Mediainfo also shows that the video bitrate is 1,231,000, and the audio bitrate is 64,000.
When we add audio and video bitrate we get 1,295,000, where is the rest?
The rest is in PAT (PID 0) and PMT (PID 4096) packets and packets containing the service ID (PID 17), generated by ffmpeg.
Media info does not show all pids, but I wrote a nice little utility jpfilter-0.3.tgz that can filter and show pids ( try jpfilter -p < my.ts ).
Filter out PID 17:
jpfilter < my.ts -a 17 > q1
Use a hex editor to see what is in q1: hexedit q1 , or type: strings q1.
FFmpeg Service01

So what should we do to be exactly at the right bitrate? 1,392,000 - 1,382,350 = 9650,
subtract this from the 1200k as we are too fast, makes 1,190,350, change the 1200k to 1190350 in the script and re-encode.

Other FECs
With a FEC of 7/8 we need (7 / 8) * 3000000 * (188 / 204) = 2419117.647058823 bits per second (I use wcalc -c).
Experimenting gives 2150000 as a close value in the above script to make a ts that mediainfo reports as: Overall bit rate: 2415 Kbps.
Replace 7/8 with 2/3, 3/4, 5/6 for the required bitrates for the other FECs.
There is also the accuracy of the 6 MHz crystal oscillator (symbolrate), and on the receiving end the soundcard crystal oscillator that has an effect.
When receiving such a file with xdipo -f 11350.42 -s 1500 -a 8192 -o | mplayer -cache 8192 - , look at the last % indicator on the command line, it is the cache fill,
should be stable around 20%, if it increases or decreases a lot then you need to re-encode the ts with a different bitrate, that is how I test.

Transmitting a transport stream

Download ts2iq_pi.c, this allows you to send a transport stream format movie from the Raspberry Pi SDcard.
Current version is 10^-97.81_pi.
also added the IQ file read function, and tested all FEC modes (see examples section below).
Full source in C, compile it on the Raspberry Pi (NOT on the PC, the Raspberry has an ARM processor!), compile instructions are in the source file:

Transmitting a transport stream file made with ffmpeg:
ts2iq_pi < my.ts

Making an IQ format file on the PC with ts2iq

This ts2iq program does the same as the TS188ToIQ.exe, but this one supports all allowed FEC modes, and in Unix you can pipe the stream through it!.
The full source code, compile instructions are in the source file, current version is 10^-97.1:
Making an IQ file on the PC from a .ts file:
ts2iq < my.ts >

It is no problem to for example do this on the Raspberry:
netcat -l 1024 | ts2iq_pi -p
And on the PC then start this:
ts2iq <my.ts -f 7/8 | netcat IP_ADDRESS_OF_RASPBERRY 1024
This does the CPU intensive part on the PC, and the simple sending it to the hardware part on the Raspberry, allowing live 7/8 transmission!

Or like this on the PC:
ffmpeg -i almost_any.format -f mpegts -acodec mp2 -ac 1 -ab 64000 -ar 48000 -s 720x576 -deinterlace -r 25 -aspect 4:3 -vcodec mpeg2video -b 2150000 -maxrate 2150000 -minrate 2150000 -bf 2 -bufsize 1343488 -y - | ts2iq -f 7/8 | netcat 1024
Possibly you can have ffmpeg read from a /dev/videoX, some camera, webcam, whatever.

Receiving the transmitter

I can play this no problem with:
xdipo -f 11350.42 -s 1500 -a 8192 -o | mplayer -cache 8192 -
A modifed version of my dish positioner program xdipo I made, with a control panel for the STV0299 chip.
click here to download xdipos.0.x
This should work on budget DVB-S cards with that chip, I use a Hauppauge wintvnova PCI card.
I wrote this code to be able to see a little better what was going on receiving the DVB-S signal from the Raspberry Pi.
This version is a modified old version that does not support HD.
The newer version is here, and does support HD, but as my HD receiver has a different chipset, the STV0299 control panel is not provided.
You also need to recompile the kernel, and load a different kernel module so the program can read and write the chip registers.
Sort of a Linux clone to Tutioune, but hey it is not complete, I wrote this is a week, Tutioune has been at it for years... and this was all I needed for my tests.
Feel free to improve on - and add to it :-)
If xdipos does not work for you, then you are on your own, for me it is just a test program, it requires in depth knowledge of Linux, the STV0299 chip, and the kernel drivers.

Some examples

Using the Raspberry Pi DVB-S transmitter remotely:
Connect the transmitter hardware and power, and make sure you have ts2iq_pi installed.
Connect to the Raspberry with ssh:
it will ask for a password, normally that should be: raspberry
You will perhaps need root access for the I/O (cannot remember I am always root, changed the /etc/passwd entry for pi to root: pi:x:0:0:,,,:/root:/bin/bash ), or type: sudo su -
netcat -l -p 1024 | ts2iq_pi
Leave the ssh connection alive.
Now on the PC send your video file like this:
netcat <video.ts IP_ADDRESS_OF_RASPBERRY 1024
Start a DVB-S receiver and tune to the right frequency with symbolrate 1500,
if you used the above described way to make a .ts with ffmpeg, then specify PID 256 for video, PID 257 for audio, PMT is 4096,
or simply service ID 1, service name Service01, at least for my version of ffmpeg 0.11.1.
If in Linux on a PC you can record everything, all PIDs, by selecting PID 8192, record the transmission like this:
cat /dev/dvb/adapter0/dvr0 > rx.ts
Or you can view it live with:
mplayer -cache 8192 /dev/dvb/adapter0/dvr0
To receive the transmitter, in case of the latest xdipo, all you have to do is type this in a terminal, with 11350.42 of course replaced by the frequency you use in MHz:
xdipo -f 11350.42 -s 1500 -a 8192 -o | mplayer -cache 8192 -

Due to lack of processor power of the Raspberry Pi we can for now only use a .ts with FEC 1/2, maybe optimizing the software will improve that, I had FEC 2/3 working.
However you can make an IQ format file from a .ts with this ts2iq_pi program, with any of the allowed FECs, and then play it back from the SDcard.
Make an IQ format file with FEC 7/8:
ts2iq_pi < my.ts -f 7/8 -o >
Play back the IQ file (looping here, could be station ID for example):
while [ 1 ] ; do ts2iq_pi -p <; done
Please note that you need to encode your transport stream with a different bitrate if you use an other FEC than 1/2, see the math section above.

Notes on receiving transmissions with a DVB-S receiver

Using the DVB-S receiver without LNB, so sending the signal directly into the IF input (= LNB connection),
we need to add a blocking capacitor for the 12 to 18 V DC on that line that is there to power and control the LNB.
At these high frequencies a few pF is already enough.

The receiver will assume an LNB, and subtract the selected local oscillator frequency from the requested frequency to get the correct IF frequency.
This means if your transmitter is at for example 1600.42 MHz, you will need to specify 1600.42 + 9750 = 11350.42 MHz.

The 9.750 GHz is for a normal European Universal LNB local oscillator, in other areas of the world things may be different,
there is more info on LNBs at wikipedia/Low-noise_block_downconverter.

return to main page (and check out the downloads link for more GPL programs and hardware)

Copyright Jan Panteltje 2013-always