петак, 1. новембар 2019.

Fan control on the Raspberry Pi 4

I have recently purchased Raspberry Pi 4. It goes quite hot when working (even in idle), so I had to obtain a cooler. I have got one with big aluminum heat sink, and two small fans. They are meant to be connected to 5V and to work all the time. I didn't like that so I have decided to make a fan control.

The easiest way I could find was on this video:
https://www.youtube.com/watch?v=Pw1kSS_FIKk

The idea is quite simple: use one MOSFET to control the fan. I have connected the fan connector to the drain and GPIO pin to the gate and it looks like this:

The schematics of the circuit.

I have used IRF640N MOSFET, since I could not find the IRF530N, which was shown in the video. Here is the photo of the actual contraption:

MOSFET-based fan control

The software for the fan control is basic: turn on the fan if the temperature goes over the high threshold, and turn off the fan if the temperature goes lower than the low threshold.

#!/usr/bin/env python

import RPi.GPIO as GPIO
import time
import threading
import os
import sys

from subprocess import * 

# Fan control port (GPIO 23)
PORT_FAN = 23
HOT  = 55
COLD = 50
OFF = 0
ON  = 1
GPIO.setmode(GPIO.BCM)
GPIO.setup(PORT_FAN, GPIO.OUT)

GPIO.output(PORT_FAN, OFF)   # turn off the fan

def getTemp():
p = Popen("vcgencmd measure_temp|cut -c 6-7", shell=True, stdout=PIPE)
t = "" + p.communicate()[0]
t = t.strip()
t = int(t)
return t

while True:
temp = getTemp()
print temp
if temp > HOT:
GPIO.output(PORT_FAN, ON)   # turn on the fan
print "Turning the fan ON"
if temp < COLD:
GPIO.output(PORT_FAN, OFF)   # turn off the fan
print "Turning the fan OFF"
time.sleep(0.1)

GPIO.cleanup() 

 As you can see, the software is simple. If the temperature goes over 55 degrees of Celsius, the fans are turned on. When the CPU temperature goes below 50 degrees, the fans are turned off.

With this big aluminum heat sink, the idle CPU gets between 48 and 50 degrees.

One note: you can see on the photo above that I have connected +5V and GND of the power supply directly on the GPIO pins for +5V and GND, instead of using USB-C power cord. I have done that because I have quite decent 5V power supply which is not USB-C, so if I connect the USB-C cable to it, the additional voltage drop happens across that cable. Lower the quality of the cable, bigger voltage drop becomes.



субота, 5. октобар 2019.

Flashing DE0-NANO FPGA board and using DEV_CLRn reset functionality

In this post I am going to talk about programming DE0-NANO FPGA board two ways:
1. temporary programming, meaning that the design will not survive powering off, and
2. permanently storing (flashing) the design, so it will survive power off.

I will also address the idea of a mega-reset using the DEV_CLRn feature at the bottom of this post.

Disclamer: You are doing all of this at your own risk. I am not responsible for any problem caused by these examples. To prevent problems, check the documentation of your DE0-NANO to see if you have the same type of Programmer and EEPROM chips.

1. Temporary programming

Whenever you compile your design at the Quartus II IDE, you can send the design to the FPGA board via Programmer:

1. double click on the Program Device in the table:

2. When the Programmer opens, look for the USB blaster right to the Hardware Setup... button:


3. If you see the "No Hardware" text, click on the Hardware Setup... button. That would open the Hardware Setup dialog:

4. Double click the USB Blaster and Close. The Programmer should look like this:


5. Now the USB Blaster is present right to the Hardware Setup... button.

6. Click on the Start button to send the design to the FPGA board.

All this is temporary, meaning that the design will be erased when you power off the board.

Alternative way of temporary programming

An alternative way of doing this is by executing the following program:

C:\altera\13.0\quartus\bin\quartus_pgm.exe

You need to supply that program with the following command line parameters:

-c usb-blaster -m jtag -o P;<path_to_the_SOF_file>

That could be typed like this:


C:\altera\13.0\quartus\bin\quartus_pgm.exe -c usb-blaster -m jtag -o P;<path_to_the_SOF_file>

I have done that in my FPGARaspbootin program (the Run FPGA manually button, and Auto Run FPGA check box):


2. Permanent programming (flashing)

To flash the DE0-NANO device, you need to:

1. convert the SOF file into the JTAG Indirect Configuration File (*.jic file), by choosing File -> Convert Programming Files... menu option. That would open the Convert Programming File Dialog.

2. Choose the Programming file type to:
JTAG Indirect Configuration File (*.jic file)

3. Open the Configuration device combo box and choose: EPCS64

4. Click on the Flash Loader in the bottom table and click on the Add Device... button. That would open the Select Devices dialog. Choose Cyclone IV E and EP4CE22:


5. Click on the SOF Data in the table and click on the Add File... button. Choose your SOF file:

6. Click on the chosen SOF file in the table (in my example, the computer.sof file) and click on the Properties. Turn on the compression:

7. After that start the Programmer, delete the SOF file (if existed), and add the JIC file (click on the Add File... button). Make sure that both Program/Configure checkboxes are turned on:

8. Click on the Start button and wait for the 100% at the progress bar (upper right corner).

9. You can power off and then power on the FPGA and it will still have the design in it.

Reset all registers with the Reset button (DEV_CLRn option)

I have experienced some strange behavior regarding resetting my design. I have made my KEY[0] clear all of my registers using the Verilog code. That design, however, failed somehow to completely reset my board. Simply, after the reset, the design would behave unreliable. I have managed to solve this problem by introducing the mega-reset feature. Here is the explanation:

In DE0-NANO, the KEY[0] is connected to the PIN_J15, which is in turn connected to the DEV_CLRn pin. This can be used to reset all registers in the FPGA when you press the KEY[0] key on the DE0-NANO board. That is a kind of mega-reset. However, this feature is turned off by default. You need to enable it. Here is the procedure:

1. right click on the Cyclone IV... in the Project Navigator and choose the Device... option:

2. click on the Device and Pin Options... button:

3. Find and enable the Enable device-wide reset (DEV_CLRn) check box:

4. Open the Pin Planner dialog (Assignments -> Pin Planner menu option), and change the KEY[0] from PIN_J15 to something unassigned, like PIN_G5 (it is unused in my project):

After that, whenever you press the KEY[0] key, you will reset your entire board.

среда, 18. септембар 2019.

Added new VGA graphics mode

This is a follow-up of my original FPGA computer post.

FPGA computer has got a new VGA mode: 640x480 in two colors. One byte of the video memory holds 8 pixels, each being 1 or 0 (white or black):

Pixel 7
Pixel 6
Pixel 5
Pixel 4
Pixel 3
Pixel 2
Pixel 1
Pixel 0

If you want to put four white and four black pixels at the top left corner of the screen (from the (0,0) to the (7,0) coordinates), you need to type:

mov.w r0, 0xF0
st.b [1024], r0

This mode is made out of existing VGA text mode, since it does almost all the job. The text mode shows characters made of 8x8 pixels on the 640x480 VGA screen. I have inserted additional Verilog code inside the text mode module, in a way that when the 640x480x2 mode is set, it shows the pixels, not the characters.

First of all, the programmer needs to set the display mode to 640x480x2:

mov.w r0, 2
out [128], r0

The VGA module detects this and changes the signal generation on the VGA connector:

if (valid) begin
  if (vga_mode == 0)  begin
    r <= inverse ^ (pixels[7 - (x & 7)] ? !curr_char[6+8] : curr_char[2+8]);
    g <= inverse ^ (pixels[7 - (x & 7)] ? !curr_char[5+8] : curr_char[1+8]);
    b <= inverse ^ (pixels[7 - (x & 7)] ? !curr_char[4+8] : curr_char[0+8]);
  end
  else if (vga_mode == 2) begin
    r <= inverse ^ (curr_char[15 - (x & 15)]);
    g <= inverse ^ (curr_char[15 - (x & 15)]);
    b <= inverse ^ (curr_char[15 - (x & 15)]);
  end
end 

What we see above is the Verilog code that sets the R, G and B wires of the VGA connector to the corresponding values, depending of the display mode. If the mode is text (vga_mode == 0), it outputs the font pixels of the character that was found in the video memory (pixels module returns actual pixels of the current_char register). However, if the mode is graphics (vga_mode == 2), then the actual byte found in the video memory is outputted to the wires (actual bits of the byte are pixels).

All this means is that current_char register holds two bytes from the video memory, and it is periodically loaded from the video memory. At the beginning, it is loaded from the very first word of the video memory, and after that VGA module loads two bytes of the video memory periodically:
- at the end of each character in text mode, it fetches the next character,
- at the end of each 16 pixels of the graphics mode, it fetches next 16 bits (pixels),
- at the end of each scan line it fetches the content of the beginning of the next scan line,
- at the lower right corner scanline end, it fetches the content of the top left corner.

This is the photo of the actual monitor:

And, this is the screenshot of the emulator:


Conclusion

Before this feature was introduced, the FPGA computer had two video modes:
- text 80x60 mode characters text mode (made of 640x480 pixels and each character is 8x8 pixels in size).
- graphics 320x240 mode, each pixel being in one of 8 colors.

This new mode is added to the existing VGA text module (80x60 characters) since that module already works with 640x480 pixels. The only additional thing was to show pixels, not characters. So, the computer now has one more mode: 640x480 in two colors (black and white). You can look at the Verilog code:

https://github.com/milanvidakovic/FPGAComputer32/blob/master/vga_module.v

And, you can look at the assembly code which draws everything here:

https://github.com/milanvidakovic/Assembler32/blob/master/raspbootin/graphics640.asm

субота, 17. август 2019.

The ultimate read-only file system on the SD card

This is a kind of follow-up of my previous post:
https://mvidakovic.blogspot.com/2019/01/read-only-file-system-on-raspberry-pi.html

I have recently stumbled upon this tool:
https://github.com/BertoldVdb/sdtool

I immediately forked it:
https://github.com/milanvidakovic/sdtool

The main idea behind this tool is to set one of the following command bits of the CSD register (very low level communication) of the SD card (via SPI interface):

  • TMP_WRITE_PROTECT - temporarily enable/disable write protection for the SD card,
  • PERM_WRITE_PROTECT - permanently enable write protection for the SD card (cannot be reversed).
The behavior of the temporary write protection is quite interesting: when you enable it, it will silently fail when writing to the SD card. In reality, it means that when you try to write to a file (or create a new file), you will not get any error, and you might even be able to read that file (probably because it was placed in the cache of the file system), but as soon as you reboot, you will see that there have not been any changes.

How can this be used? First of all, you should set up your Raspberry Pi file system to read-only (for example, you can use this), so it would be normal not to have writes to the SD card. Then you can use the sdtool to enable the write protection. With those two steps, you should get the ultimate protection of your SD card.

Why is this important? I have couple of RPIs which work constantly for years. My experience with SD cards and RPIs is that they eventually corrupt the SD card. Sooner or later it will happen. If you just enable the read-only file system, it seems that the SD card still gets corrupted. I don't know why, but it happened to me several times. I have changed several SD cards (different vendors, different models), and several power adapters, and still got SD cards corrupted at some point. I thought that having the file system set to read-only would not corrupt the SD card during power loss (unattended shutdown), but, unfortunately, the SD card would get corrupted anyway. 

Even if the RPi is on the UPS (doesn't get turned off improperly), it would still corrupt the SD card sooner or later. It happened too many times with my RPIs (and the Odroid, too). 

One way to fix this is to boot the device from the USB hard disk instead of SD card, but then the same problem can occur with the hard disk (although, not that bad as it occurs with the SD card). As a matter of fact, it happened once with my Odroid and once with my RPi 3 (to have the USB hard disk corrupted). In addition, why would you put the USB hard disk on your RPI 0? It is supposed to be a lightweight system, not having a hard disk that consumes more power than RPI 0.

I have found an information on some forums that a special (quite expensive) SD card types do not get corrupted at all: aMLC and SLC type. Both are significantly more expensive than the usual cards, but people claim that they simply do not get corrupted.

One funny thing - my RPI 1 has corrupted the SD card only once in almost five years, while RPI Zero and RPI 2 and 3 can corrupt the SD card in a matter of months (or even sooner). Does it have to do with the speed of the system? Is the SD card overwhelmed with data and then it goes corrupt? Why is it corrupted in the read-only mode, then? I don't know answers to all those questions. What I do know, however, is the fact that the SD card would eventually get corrupted and that is the main reason for this post.

I am now testing this temporary write protection in conjunction with the read-only file system on my RPIs, and I will update this post with my experience.

At the end, just to repeat the fact that the contacts on the SD card are actually the SPI interface contacts, meaning that all the communication with the SD card goes over the SPI interface:




среда, 31. јул 2019.

FPGA computer boots from the SD card

FPGA computer boots now from the SD card

This is a follow-up of my first text about 32-bit FPGA computer.

The 32-bit FPGA computer now has a kind of a hard disk. ESP32 is used as a hard disk controller (I have designed the board to work with the Arduino as well - you can see the empty socket for the Arduino to the right of the ESP32), while the SD card is used as a kind of a hard disk.


The FPGA computer with the ESP32-Arduino board is on the images above and below.


Initially, it was just the Arduino:



Since the FPGA computer is designed to boot from the serial port, I have created a kind of a hard disk controller, which consists of an ESP32 and SD card reader. When started, ESP32 lists files in the root folder of the SD card, and if it finds the file "BOOT.BIN", it reads it and sends the content to the FPGA computer over the serial port, using the Raspbootin protocol (as described in one of my previous posts).


The video above shows the boot from the powerup. Next video shows boot from the reset.


The code is available at the github.

This is the schematics:

The main idea is that the controller behaves just like the PC from which the FPGA computer initally gets its boot code. During the powerup, the FPGA computer will try to load the boot code from the serial interface, using a modified Raspbootin protocol. On the other side of the serial cable, there can be a PC with the corresponding Raspbootin client, or, just like in this case, the microcontroller, which has the following functionality:
  1. wait for the Raspbootin start sequence,
  2. look for the BOOT.BIN file in the SD card, and
  3. send that file content over serial cable, using the Raspbootin protocol.
The FPGA computer would then boot from the loaded BOOT.BIN file. The BOOT.BIN file is the assembled file obtained using the custom assembler also available on my github page.

Conclusion

With this board, the FPGA-based computer can now boot from the SD card. Next step would be to extend the code so it would be used as a real SD controller, allowing the FPGA computer to open files, read, write, delete, etc.


среда, 10. јул 2019.

ENC28J60 with 12-pin connector

I have recently purchased this module, and it has some strange pin names:

As you can see, some pins have wrong names:
LNT is actually INT
ST is actually SI (MOSI)
Q3 is actually 3.3V power
SCK is sometimes referred to SCLK (don't use the CLK for the SPI clock)

I am posting this to help people who, just like me, purchased this strange module.

среда, 3. јул 2019.

Two-way AC control

How to control the AC two way using Raspberry Pi

In my previous posts, I have described my small Home Automation system. It consists of various sensors, connected to several Raspberry Pi computers. The control was initially one-way, meaning that I could only watch sensor data on the Home Automation web site. Then I have added AC remote control support to the system. I have used the lirc library which enables user to record IR commands and then to reproduce them. The initial setup enabled users to remotely control the AC from the Home web site. However, there was no way of knowing the actual AC status (if the AC already works or not). This means that the Home web site could not display the current AC status and instead of turning the AC on, we could turn it off. That is the topic of this post - how to add the support to the Home Automation system, which can read AC status.

By default, the AC is controlled using the IR remote. I have rather old AC, which is not connected to the WiFi, so there is only one way of knowing if the AC is working or not - the status LED at the AC device. I have figured out a way to read the LED status and to feed that information to the RPI. The Idea is quite simple: glue the photo sensitive resistor to the AC status LED, and connect that resistor to the simple circuit which gives an information to the RPI if the AC is working.

This is the photo sensitive resistor - photoresistor:


Here is the circuit:

The photo resistor decreases the resistance when exposed to the light. If there is no light, the resistance is couple of hundred kilo Ohms. When lit by the AC LED, the resistance drops to the approx. 20 kilo Ohms. Since the circuit is actually a voltage divider, when LED is not lit, the voltage at the GPIO port is high, meaning logical 1. If the LED is turned on, the resistance drops, the voltage at the divider drops, and the GPIO port reads 0.

The Python code which reacts to the change of LED operation is here:

PORT_AC = 21
GPIO.setmode(GPIO.BCM)
GPIO.setup(PORT_AC, GPIO.IN)

acStatus = not GPIO.input(PORT_AC)
print 'AC STATUS: ', acStatus

def ac_edge_detected(channel):
  time.sleep(0.25) // give some time to properly read GPIO port
  print 'AC EDGE detected, channel is ', channel
  global acStatus
  acStatus = not GPIO.input(PORT_AC)
  print 'AC STATUS: ', acStatus
  requests.get('http://' + STATUS_HOST + ':8080/setAc/' + str(acStatus))

GPIO.add_event_detect(PORT_AC, GPIO.BOTH, callback=ac_edge_detected, bouncetime=50)

Here is how it looks implemented:

And here is the AC part of the Home Web application:

Conclusion

Initial AC solution provided me with the option of turning on/off AC remotely. However, the system could not know the initial and current AC status, making turning on/off unreliable. This contraption is capable of determining the AC status by observing the AC LED status. It does so by having the voltage over the photo resistor dropping when the LED is turned on.