PI-Radio : Vintage but internet connected radio

How it started ?

In the attic of my stepmother, there were an old vintage radio which belongs to its father. This is a Marconi. Definitely a beautiful object. But today with the growing internet of object, it seems like an old thing with a one way to garbage collection.
So how we could transform this old antiquity to a new fashion dedicated internet radio? This is what we will see.

Summary
Hardware
Software

Power supply

Power supply circuit
Power supply circuit schema
There are mainly 3 voltages in the whole circuit: +12v, +5v and +3.3v.

When the SW switch is closed, the power is up, powering audio amplifier (TPA3123) and raspberry pi (RPI).
The raspberry pi through the GPIO 13 close the relay.
The current can now come also from the relay, in addition of the switch.

When the SW switch is opened, the power is still up because of the relay.
But the raspberry pi can detect the power off through the GPIO 6 that is now in low level.
This is possible because of the D diode (1N4001) which prevent the current to flow through the resistors from the relay.
The resistors provide a simple voltage divider to ensure we are below 3.3v (logic voltage of the raspberry pi):

Factor = R1 / (R1 + R2) = 100k / (100k + (100k + 180k)) = 100k/380k = 0.26

So the voltage at GPIO 6 input is 12v * 0.26 = 3.15v

There is no problem with the voltage drop of the diode because we have a step down converter (LM2596) which maintain a constant 5v at its output whatever the input is 11.3v (when powered through the switch and the diode) or 12v (when powered with relay).
The raspberry pi detecting the SW switch is opened can shut-down gracefully (sheltering the screen and halting the operating system).
When the raspberry pi turn off its GPIO 13 pin becomes low, so the relay is opened and the whole circuit is completely stopped.

Inputs: potentiometers, mechanical switch and rotary encoder

Inputs circuit
Inputs circuit schema
Because one of the main requirement restoring the radio was to not change the outside aspect, we have to deal with various (sometimes strange) inputs :

The raspberry pi does not have analog inputs, so we have done analog acquisition through a MCP3008 chip. This chip is responsible for the 2 potentiometers, the mechanical switch (which takes 4 inputs) and the 2 hall effect sensors for motor stop detection. The rotary encoder is handled directly by the raspberry pi and is covered in another section.

The MCP3008 is easy to work with. Every inputs works with logic level voltage (+3.3v). It is a 10 bits ADC so on the raspberry pi side, analog inputs from potentiometers give value from 0 to 1024. The potentiometers are logarithmic which give a better “linear” audio adjustment.
Because it is a SPI device, we interface it on the SPI pin of the raspberry pi. But in the code we bibanged the protocol. The main reason is the loading time of the SPI library is really long, so we tried another way and found the bitbanged version to be very fast to load and as easy to use as the SPI lib version.

Mechanical switch works like a set of buttons with some logic inherited from the time it served for analog functions. As we can see in the schematic, we have placed pullup resistors, so:

Its table is :
Output activated (low)
Position v1 v2 v5 v6
1 LOW LOW LOW HIGH
2 LOW HIGH HIGH LOW
3 HIGH LOW HIGH HIGH
4 LOW HIGH LOW HIGH
5 HIGH HIGH LOW LOW

LCD motorisation

Motor circuit
LCD motor schema
LCD motor schema 2
To open and close the screen we have a 5v motor driven by a L293DNE and 2 hall effect sensors for endpoint feedback.

L293 is a popular quadruple Half-H driver (we will use only 2 of them), designed to drive inductive load (like motors). L293D adds output clamp diodes for inductive transient suppression. The NE means the packaging is PDIP (handy for hobbyist). To know when to stop the motor, we have put 2 magnets on the side of the LCD screen.

Two hall effect sensors (Y3144) on both side will detect when to stop from opening and closing the screen by stopping the motor. The hall effect sensors are driven by the MCP3008 ADC to save some pin from the raspberry pi. The Y3144 seems to be a copy of the popular A3144. It is an open drain collector, it sinks current. This is the reason of the 10k pull-up resistor on the output pin of this sensor. When nothing detected the output voltage is high (pulled up), when a magnet is nearby, the output voltage is low (and current is sunk). We could have connected it directly on a GPIO input with pull-up resistor, but to save some pin, we drive it from the MCP3008. Its datasheet state it works from 4.5v to 24v but I found this version to work well with a 3.3v input voltage. Its typical consumption is 4mA so it can be driven safely by the 3.3v logic supply of the raspberry pi (max 50mA for all).

LCD driver

Inputs circuit
LCD driver schema

The LCD is a 4 lines of 20 columns (4x20) alphanumerical LCD driven by the popular HD44780 chipset.
The driver is used to digitally drive the contrast and brightness through MCP4131-104E/P digital potentiometer. MCP4131 is a 7 bits digital potentiometer. The 104 after the name indicates it is a 10x10^4 ohms potentiometer (100kohms). Because it has an open drain it is safe to output from a raspberry pi GPIO to the SDI of the MCP4131. We don’t want to read from it.

The 2kohms resistor for the contrast is due to the fact that contrast tuning range from 0v to low voltage (<1v). 0v means black screen. 1v means white screen. If we drive it from 0v to 5v, we will not have enough fine precision tuning when adjusting the digital potentiometer. Resistor network

Without adding a 2kohms resistor we have the following equation :
POB = VDD = 5v
POA = GND = 0v
POW = 5v * RAW / 100k
If RAW = set of RS from A to W. RWB = set of RS from W to B.
This is an approximation because we ignore RW which is small.

Adding the 2k in parallel, we have a total resistance of R = R1xR2 / (R1+R2)
R = RAW * 2k / (RAW+2k)

Because of the voltage divider the new equation of voltage at W is :
Equation of voltage divider Uout = Uin x R1 / (R+R2) POW = 5v * ((2k*RAW)/(RAW+2k)) / ((RWB)+((2k*RAW)/(RAW+2k)))
But RWB = 100k - RAW
POW = 5v * ((2k*RAW)/(RAW+2k)) / ((100k-RAW)+((2k*RAW)/(RAW+2k)))
We can simplify:
POW = 5v * (2k*RAW) / ((RAW+2k)*(100k-RAW)+(2k*RAW))
POW = 5v * (2k*RAW) / (100*RAW - RAW² + 200)

So instead of being linear the new curve is :

Resistor network

X being from 0 to 100 (this is in kohms) Y being from 0 to 1.00v This curve of the equation is in blue and it is more interesting than the linear one in yellow.

From the HD44780 datasheet, I found a problem about timing so I give them here :
// Initialise display
bcm2835_delay(20); // Wait for more than 15 ms after VCC rises to 4.5 V
SCREEN_sendQuartet(0x03);
bcm2835_delay(5); // Wait for more than 4.1 ms
SCREEN_sendQuartet(0x03);
bcm2835_delayMicroseconds(150); // Wait for more than 100 µs
SCREEN_sendQuartet(0x03);
bcm2835_delay(1); // THIS TIMING IS NOT INDICATED IN THE DATASHEET BUT NECESSARY
SCREEN_sendQuartet(0x02);
SCREEN_sendCmd(0x06); // 000110 Cursor move direction
SCREEN_sendCmd(0x0C); // 001000 Display On,Cursor Off, Blink Off
SCREEN_sendCmd(0x28); // 101000 Data length(b4), number of lines(b3), font size(b2)
SCREEN_sendCmd(0x01); // 000001 Clear display
bcm2835_delay(5);

Raspberry PI Header

Raspberry PI Header

Audio amplifier modification

Audio before modification
Audio after modification

Early start

All timings are from the moment the on/off button is turned on till the motor begin to move.
Time motor move Description
19'33 to 22'30 First try is a standard systemd service running the python script after network comes up
11'79 to 12'46 Second try is a standard systemd service running a light python script (without many imports) after local-fs
7'65 to 8'19 Third try is a systemd service running a C program without any service dependency

Python VM takes a lot to come into memory and so is not adapted to early start. We can go down to 7'00 with a quiet kernel (added quiet to cmdline.txt). Early start boot
The second python service is launched around 11'20 but waiting for the network to play internet radio so we only start listening at around 20'00. When the network is ready. Early start boot


Back to matthPage