субота, 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.

понедељак, 17. јун 2019.

Digital Wrist Watch using AtTiny85

I have recently found a great tutorial how to make a wrist watch using AtTiny85 microcontroller here: https://www.instructables.com/id/ATtiny85-Ring-Watch/

That was an inspiration to make my own wrist watch using the same IC. Here is it:

The watch consists of four elements:
1. AtTiny85 MCU
2. OLED display with  SSD1306 controller, 128 x 64 pixels
3. Two buttons, and
4. CR 2025 3V lithium battery.

Here is the schematics:


I have used the original plastic box for the OLED display to put all the components inside. Here is the bottom view of the same watch:
At the bottom, there is a battery, then the wrist belt, and then comes the MCU and the display at the top:

As you can see from the image above, I haven't soldered the MCU to the wires; instead I have soldered a socket (two halves, actually), so I could remove the MCU from the watch in order to program it.

Programming AtTiny85

Regarding programming, here is the link to the github repo (my own rework of the original code):
https://github.com/milanvidakovic/AtTiny85Watch

When speaking of programming AtTiny85, I have followed instructions from the https://www.instructables.com/id/ATtiny85-Ring-Watch/ site to install the support for the AtTiny85 into the Arduino IDE.

I have also decided to use my Arduino as a programmer for the AtTiny85. It is not necessary to use the Arduino, but I decided to do so, because it looked like the easier solution.

Here are the instructions:
1. Install the Arduino IDE.
2. Install the ArduinoTiny add-on from the: https://github.com/milanvidakovic/ArduinoTiny
    Unzip ArduinoTiny-master.zip
    Copy the tiny folder to the hardware folder under Arduino path
3. Add EEPROM support:
    In Arduino path, copy hardware\arduino\avr\libraries\EEPROM\EEPROM.h to 
    hardware\tiny\avr\cores\tiny folder
4. Install TinyWireM Library:
    Run Arduino
    Select Sketch Menu -> Include Library sub-menu -> Manage Libraries...
    Search TinyWireM
    Select TinyWireM and click Install button
    Close Library Manager and close Arduino
5. Install the Arduino as ISP project on the Arduino board
6. Use the Arduino as ISP to burn Bootloader to the AtTiny85 MCU
7. Use the Arduino as ISP to send the AtTiny85Watch project to the AtTiny85 MCU

Arduino as ISP

If we want to program AtTiny85 using Arduino, then we need to install the Arduino as ISP sketch on the Arduino:
1. Open File -> Examples -> ArduinoISP -> ArduinoISP
2. If you use SPI on expansion port, not on the 6-pin connector at the top of the Arduino, then you need to uncomment the following line:
// Uncomment following line to use the old Uno style wiring
// (using pin 11, 12 and 13 instead of the SPI header) Nano, Due...
#define USE_OLD_STYLE_WIRING
3. Click on the Upload button to make your Arduino an AtTiny85 programmer.

Use Arduino as ISP for programming AtTiny85

To use the Arduino as a programmer for the AtTiny85, you need to connect AtTiny85 to the Arduino like this:


Before uploading any program to the AtTiny85 using Arduino, it is necessary to burn the Bootloader on the AtTiny85:
1. Plug the Arduino to the USB port of your PC
2. Connect the AtTiny85 to the Arduino as shown on the image below
3. Choose Tools -> Board -> AtTiny85 as a Board
4. Choose Tools -> Programmer -> Arduino as ISP
5. Choose Tools -> Clock -> 8 MHz (Internal oscillator...)
6. Choose Tools -> Burn Bootloader

After this, you are ready to Upload your programs on the AtTiny85 using the Arduino as ISP. Just open the sketch, and then click on the Upload button. One note: for the AtTiny85Watch, it is necessary to choose Tools -> Clock -> 1 MHz (Internal oscillator...).

Conclusion

Programming AtTiny85 is perhaps the easiest if you are able to do everything in the Arduino IDE. Also, it is easier to use the Arduino as a programmer, instead of some proprietary hardware. AtTiny85 is quite interesting MCU. It is powerful enough to be used for the project like this.

уторак, 14. мај 2019.

32-bit FPGA-based computer

Going 32-bit

There are follow-ups:
- implemented BLIT instruction,
- adding SPI interface to my FPGA computer,
- making BASIC interpreter for my FPGA platform,
- using GCC on my FPGA platform,
- added cache controller,
- new VGA display mode,
- booting from the SD card.


I have upgraded my FPGA-based computer from 16-bit to 32-bit. It now has 16 registers, each 32-bit. It uses 32MB SDRAM which exists on the DE0-NANO board, but it also uses static RAM for the video memory (frame buffer), for both text and graphics mode. It is approx. 40 KB of static RAM.

FPGA Computer Schematics

Memory management

If was quite painful to make the computer work with the SDRAM. The 32MB SDRAM needs a special controller to be used. I have found one useful controller on the github:

Since there are two types of memory in this computer (dynamic and static), I had to make a decision how to layout the memory. First 40KBs are used for the static RAM (all interrupt vectors, text and graphics video RAM and sprite definition memory). After that, the rest of the memory is in the SDRAM (up until 32MB).

If there is a need to read from the memory, this is how it is done. Let's suppose that we need to read 16 bits from the PC + 2 address:

addr <= (pc + 2) >> 1;
next_state <= EXECUTE;
state <= READ_DATA;

We need to set the next_state register to the state to which we want to return, when the read is done. Then, the CPU goes to the READ_DATA state.

READ_DATA: begin
if (addr >= SDRAM_START_ADDR) begin
waiting_sdram <= 1;
addr_o <= addr;
rd_enable_o <= 1'b1;
if (busy_i) begin
state <= READ_WAIT;
end
end
else begin
memrd <= 1'b1;
memwr <= 1'b0;
state <= READ_WAIT;
end
end

In this READ_DATA state, the CPU puts the address to the SDRAM address bus (addr_o), and sets the rd_enable to 1. Then it waits until the SDRAM is ready to read (busy_i is 1). When the SDRAM controller starts reading, the CPU goes to the READ_WAIT state. 

READ_WAIT: begin
if (addr >= SDRAM_START_ADDR) begin
rd_enable_o <= 1'b0;
if (rd_ready_i) begin
waiting_sdram <= 0;
data_r <= rd_data_i;
state <= next_state;
end
end
else begin
memrd <= 1'b0;
memwr <= 1'b0;
data_r <= data;
state <= next_state;
end
end

The READ_WAIT state finishes when the data is obtained from the memory (the actual data is in the data_r register).  It takes approx. 6 cycles (at 100 MHz) to fully obtain data from the memory (from READ_DATA to READ_WAIT, both to be finished). Then, the CPU goes to the next_state, as being set before this reading operation has been started.

Regarding writing to the SDRAM memory, let's suppose that we want to put something on the stack:

addr <= (regs[SP] - 2'd2) >> 1;
data_to_write <= regs[ir[11:8]][15:0];
// move sp to the next location
regs[SP] <= regs[SP] - 2'd2;
next_state <= EXECUTE;
state <= WRITE_DATA;

We need to set the next_state register to the state to which we want to return, when the write is done. Then, the CPU goes to the WRITE_DATA state.

WRITE_DATA: begin
if (addr >= SDRAM_START_ADDR) begin
waiting_sdram <= 1;
addr_o <= addr;
wr_data_o <= data_to_write;
wr_enable_o <= 1'b1;
if (busy_i)
state <= WRITE_WAIT;
end
else begin
memrd <= 1'b0;
memwr <= 1'b1;
state <= WRITE_WAIT;
end
end

In the WRITE_DATA state, the CPU would set the address to be written (addr_o), data to be written (wr_data_o), and would set the wr_enable_o to 1. Then it would wait for the controller to notify that it is ready to write (busy_i is 1). Then the CPU goes to the WRITE_WAIT state.

WRITE_WAIT: begin
if (addr >= SDRAM_START_ADDR) begin
wr_enable_o <= 1'b0;
if (~busy_i) begin
waiting_sdram <= 0;
state <= next_state;
end
end
else begin
memrd <= 1'b0;
memwr <= 1'b0;
state <= next_state;
end
end

The WRITE_WAIT state finishes when the data is saved to the memory.  It takes approx. 6 cycles (at 100 MHz) to fully write data to the memory (from WRITE_DATA to WRITE_WAIT, both to be finished). Then, the CPU goes to the next_state, as being set before this writing operation has been started.

CPU redesign

The CPU itself was redesigned, too. It now has quite rich instruction set, 32-bit, 16-bit and 8-bit instructions, floating point (32-bit, single precision), and three interrupts:
- IRQ0 is the timer interrupt (triggered when a given number of milliseconds have been counted),
- IRQ1 is the UART interrupt (triggered when a byte has arrived), and
- IRQ2 is the PS/2 interrupt (triggered, whenever a key is pressed on the PS/2 keyboard).

The timer IRQ was made this way: there is a counter which is incremented every millisecond. There is a timer port which initially holds zero. The programmer needs to set the number of milliseconds to be counted after which the interrupt would occur. It is done using the OUT instruction:

mov.s r0, 0x0001 ; JUMP opcode
mov.s r1, TIMER_HANDLER_ADDR ; timer vector address
st.s [r1], r0
mov.w r0, timer_triggered
mov.s r1, TIMER_HANDLER_ADDR + 2
st.w [r1], r0 ; the timer IRQ handler has been set


move.w r0, 50  ; set the timer interrupt for every 50 milliseconds
out 129, r0

The assembler code above would set the internal timer register to the given value (50). Every millisecond the CPU would increase another internal register, named timer_counter, and when the timer_counter reaches the timer, that would trigger the timer interrupt:

if (timer && (timer_counter < timer)) begin
timer_counter <= timer_counter + 1'b1;
end
else if (timer && (timer_counter == timer)) begin
irq[0] <= 1;
timer_counter <= 0;
end 

At the end of each instruction execution, there is a check for the interrupts:

if (irq_r[0]) begin
// timer
pc <= 16'd8;
addr <= 16'd4;
irq_r[0] <= 0;
end 

If there is a timer interrupt, the CPU would jump to the TIMER_HANDLER_ADDR, which is 8.

FPGA Raspbootin loader

I have modified the FPGA Raspbootin loader so it would now load the FPGA itself, instead of relying on the Quartus II studio for that. This means that I can now control the Computer from a single application - FPGA Raspbootin:


The loader now first loads the design into the FPGA (unless it is flashed - then no loading the design file is needed), and then it loads the selected binary into the computer. Here is the Java code for loading the design into the FPGA (by starting the quartus_pgm.exe program):

public static void runFpga() {
Process process;
try {
process = new ProcessBuilder(qpfPath,
"-c", "usb-blaster",
"-m", "jtag",
"-o", "P;" + sofPath).start();
InputStream is = process.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String line;
while ((line = br.readLine()) != null) {
  System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
}
}

The qpfPath points to the quartus_pgm.exe file, which acutally loads the design into the FPGA. Usually it is something like: C:\altera\13.0\quartus\bin\quartus_pgm.exe

The design file has the *.sof extension, and it is loaded into the FPGA using the quartus_pgm.exe program. The *.sof file is built during the compilation of the design inside the Quartus II studio. In my program, the path to the *.sof file is in the sofPath variable.

More details about loading FPGA design on the DE0-NANO FPGA board can be found here:
https://mvidakovic.blogspot.com/2019/10/flashing-de0-nano-fpga-board.html

Conclusion

The 32-bit rework took more time than I expected, mainly because I wanted to use the built-in 32MB SDRAM. Then I added the floating-point instructions and now it looks quite stable. I have used about 80% of the FPGA, so I could try to do something more later.

The CPU is on the github:
https://github.com/milanvidakovic/FPGAComputer32

The assembler examples are on the github:
https://github.com/milanvidakovic/Assembler32

The Raspbootin64 boot loader is on the github:
https://github.com/milanvidakovic/FPGARaspbootin64Client

The Emulator is on the github:
https://github.com/milanvidakovic/FPGAEmulator32



Hardware watchdog for Raspberry Pi Zero

This is an additional attempt  to make Raspberry Pi more reliable (the fist was to make RPI file system read-only). I have noticed that RPI sometimes does not boot after it was properly powered down. Sometimes it can freeze during the normal operation. The solution for those situations is a watchdog timer. The idea is that the watchdog would reset the device unless the device pings it on a regular basis.

RPI does have a built-in watchdog, but as far as I could understand, it is a part of the OS. But what if the OS did not boot? You would end up with a frozen machine.

That is the reason why I tried to find some hardware-based watchdog implementations for the RPI. To be more precise, I wanted to manage RPI Zero, since Zeros are used to gather sensor data all around my flat.

There are several hardware implementations based on the 555 timer IC. It is a very versatile IC and one setup that I have found useful for the watchdog implementation is shown in the picture below:


The RES wire goes to the reset pin on the RPI Zero (marked as RUN on the board):


The RUN pin on the Zero needs to be connected to the ground in order to reset the device.

The watchdog is pinged via GPIO pin (in this particular example, it is GPIO pin 21). To do so, it is sufficient to periodically ping the watchdog via GPIO pin 21. Here is the Python code which pings the watchdog:

import RPi.GPIO as GPIO
import time
import threading
import os
import sys
# Port which shorts the capacitor in the watchdog(GPIO 21)
# pin 40
PORT_OFF = 21
# GPIO pin enumeration
GPIO.setmode(GPIO.BCM)
GPIO.setup(PORT_OFF, GPIO.OUT)
#short the capacitor
GPIO.output(PORT_OFF, 0)
time.sleep(0.250)
# disconnect
GPIO.cleanup()

RPI pings the watchdog by shorting the 100uF capacitor to the ground. It is done by setting the logical 0 to the GPIO 21. The capacitor is shorted to ground via 200 Ohm resistor, and that just restarts the 555. If the capacitor is not shorted in time, the 555 would send the logical 0 to the RUN pin on the RPI and that would reset the device.

The period for the reset is approx. 2 minutes, and that was set using the 470K resistor and 100uF capacitor. Increase one of them, and you will get the longer period.

I have set the Python script to ping the watchdog at the boot time, and then to be called each minute. The first ping occurs just 15 seconds after the boot.

It is important to set the RPI file system to read-only. If not done so, the reset would probably corrupt the SD card data. I have found a good script for setting up the RPI file system to read-only