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.
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:
|Output activated (low)|
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).
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.
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)
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);
|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|