6 days ago •
Hi everybody, PCBs finally arrived.
I ordered them from JLCPCB, this was the first time that I had PCBs assembled.
Visual inspection and I have nothing to say, quality is pretty good, a quick check with the multimeter to make sure there are no shorts on the power rails and I'm ready to solder the connectors.
Time to program the microcontroller, as a programmer I'm using the same STM32 Discovery board that I was using for testing. By removing the two jumpers on CN4, the integrated ST-LINK programmer is disconnected from the board and the programming signals are exposed on CN2.
So I applied power with an external power supply, connected to the programmer, and... the micro wasn't detected.
Ok, troubleshooting time. The first step is to check voltages, I measured the VDD on one of the bypass caps and it was 3V, power is good. Next, I measured the VDD on the programming connector and it was 1.6V. The only thing in series with the connector is a 100 Ohm resistor, maybe I connected something wrong and the programmer is loading it down? Disconnected the programmer and measured again, no change, still 1.6V. Ok, this doesn't make any sense, there's a voltage drop across a resistor without any current. Let me check the resistor value just to make sure, switch the meter into resistance mode, take a measure and... 10 MOhm.
Ok, so what's happening is that what was supposed to be a 100 Ohm resistor is instead 10 MOhm, now it makes more sense, when I measure the voltage the meter is loading down the circuit. Next question is, how has this happened, I double-checked the BOM before placing the order, this can't be my fault, right? Let me check on the schematic and... no It's my fault, I had specified the wrong part number for all the 100 Ohm resistors.
Now that I know what's wrong, it's time to fix it. The only problem is that I don't have a stock of 100 Ohm 0603 resistors, luckily I have salvaged plenty of boards, time to disorder some resistors.
Does anybody need 10 MOhm resistors?
I've replaced all the resistors, let's try again. This time I connected the programmer, the micro was detected correctly and I was able to program it.
This is my current setup. In the middle is my new board connected to the display. the STM32 Discovery on the right is used as a programmer, the USB to Serial converter is used to send commands to the micro. Power comes from 6 NiMH AA cells.
03/18/2021 at 15:30 •
Hi, everybody. With this log, I want to address how I go about generating the image files to load into the SD card and its folder structure. One of my goals was to be able to load more than one movie at a time. The solution I come up with is to have a folder for each movie in which the frames are stored.
/-FOLDER1/ | |-0000.jpg | |-0001.jpg | |-0002.jpg | |-... | |-FOLDER2/ | |-0000.jpg | |-0001.jpg | |-0002.jpg | |-... | -FOLDER2/ |-0000.jpg |-0001.jpg |-0002.jpg |-...
To extract the images from the video file I use a command-line program called ffmpeg. The nice thing about this program is that it has some predefined filter that you can apply in sequence to achieve practically anything you can imagine.
ffmpeg -hwaccel auto -i input_file.mp4 -vf "fps=1,\ scale='if(gt(a,600/448),-1,600)':'if(gt(a,600/448),448,-1)',crop=600:448,\ histeq=strength=0.08:intensity=0.2,\ eq=saturation=1.5:contrast=1.2:gamma=1.6:gamma_weight=0.8"\ -pix_fmt yuvj420p -q:v 6 %04d.jpg
What the command does is best explained by the following diagram. First, the input file is decoded, then the frame rate is dropped to 1 frame per second. The frames are then scaled and cropped to the display resolution. After that, some color correction is applied before finally saving the images as jpegs. Preprocessing the images by raising the contrast and color saturation makes the images on the display appear more natural and compensates for the display low color count.
JPEG quality test
The ffmpeg program lets you specify how much compression to apply. The -q:v option accepts a parameter in the range 2 to 32, where 2 is the highest quality and 32 is the lowest quality. In the following test, I loaded on the display four images with different quality. The side-by-side comparison shows the compressed image on the left with the capture of the display on the right. It is noted that the quality of the overall picture is quite good even with the highest compression though the fine details are lost. This is particularly noticeable in the fence links that tend to disappear at higher compressions.
03/01/2021 at 11:02 •
PCB layout is done, design files are sent to JLCPCB for manufacturing and assembling.
There is a timelapse video of the layout if you are interested.
3D Printed Enclosure
I designed an enclosure to hold the display, the circuit board, and 6 AA batteries.
The PCB is held in place by 4 M3x6 screws while the two halves are held together by 4 M3x8 screws.
The following video shows how the enclosure goes together.
I put the display in its case and connected it to the STM32 Discovery. Now I can enjoy a movie while I wait for the circuit boards.
02/22/2021 at 13:41 •
I spent the last two days working on the schematic for the first prototype, here is what I came up with.
I finally decided on what battery to use, the board will be powered by 6 AA. I have a design in mind for a case in which 6 AAs fit well.
The plan is to have the board assembled by JLCBCB and so I tried to optimize the BOM.
The board can be powered either from batteries or from the USB connector. The power supply is divided into two paths, there is a switching regulator and an LDO to supply power during sleep. The reason for having two regulators is that the MP2451DT DC-DC converter has an efficiency greater than 85% with a 100mA current load but, due to the switching losses, the efficiency drops drastically at low loads. The datasheet for the microcontroller states a power consumption of 4uA in Stand-By mode. The HT7533 LDO has a quiescent current of only 2.5uA. The two SY6280A are power-distribution switches. U2 switches power to the microcontroller and is used to isolate VDD from the 3.3V when the DC-DC converter is disabled. U3 switches power to the SD-Card, it is used to disable the SD-Card while the screen is busy updating to save power.
R16, R17, R18, R24 form a potential divider that's used to measure the battery voltage. This makes it possible to detect when the batteries are running low and to display a low battery icon on the screen.
R10 is a Light Dependent Resistor, it's used to measure the ambient light. Since e-paper displays have no backlight and are not visible in the dark, there's no point in updating the display if nobody is able to see it. An LDR has a resistance that varies with the amount of light that shines on it. The resistance varies from a couple of hundred ohms, when shining a bright flashlight on it, to hundreds of kiloohms, when in complete darkness. The way the resistance is measured is by determining how long a known capacitor takes to charge from a fixed supply voltage. This mechanism is quite clever and doesn't consume any power when the resistor is not measured.
The microcontroller is an STM32F405RG, it has 1024KB of FLASH and 192 KB of RAM plus all the required peripherals. There are two quarts crystals, the 8MHz one is the main oscillator, the USB requires an external crystal. The 32.768KHz one drives the RTC that's used to wake the microcontroller every 24 minutes to update the display.
All unused pins are connected to test pads in case they are needed in the future.
C19, C20, C30 in conjunction with the 47mF supercapacitor C31, provide the energy required to power the microcontroller when the batteries are removed. C31 has enough stored energy to power the microcontroller for 24 minutes in standby mode when the power consumption is 4uA. The additional 30uF of capacitance on the VDD line are enough to power the microcontroller for 10ms after it exits standby mode. This is used to store the currently displayed frame in the internal FLASH so that the movie doesn't restart from the beginning every time the batteries are changed.
Programming the Microcontroller
There are three ways to program the microcontroller. The first is using the SWD debug interface, the second and third methods involve the bootloader. STM32 MCUs ship with a preprogrammed bootloader that can be used to program the device, in this case, either from the serial port or through the USB.
The MCU automatically enters into boot loader mode the first time it is powered on when the flash memory is empty. By pressing the BOOT button while performing a reset, the bootloader can be started at any time.
Power consumption estimation
The display updates every 24 minutes, that period of time is divided into 5 steps.
- DISPLAY INIT: The MCU wakes from sleep, enables the DC-DC converter, and initializes the display.
- DISPLAY CLEARING: During this phase, the display is busy clearing itself, the MCU is not needed.
- JPEG DECODE: The SD-Card is initialized, a new frame is loaded and decoded.
- DISPLAY UPDATE: During this phase, the display is busy updating itself, the MCU is not needed.
- SLEEP: Between every update, the MCU sleeps for 23.5 minutes.
The following table shows the power consumption for each component over each phase. Values are taken from the datasheet typical values. (Supply voltage is assumed to be 10V).
LDO 2.5 uA 2.5 uA 2.5 uA 2.5 uA 2.5 uA BAT PDIV 2.5 uA 2.5 uA 2.5 uA 2.5 uA 2.5 uA DC-DC 85% eff + 3 uA 85% eff + 3 uA 85% eff + 3 uA 85% eff + 3 uA 3 uA MCU 40 mA 4 uA 40 mA 4 uA 4 uA Display 0.2 mA 24 mA 0.2 mA 24 mA 0 mA SD-Card 0 mA 0 mA 10 mA 0 mA 0 mA TOTAL ENERGY 35 uWh 337 uWh 433 uWh 337 uWh 48 uWh
Summing the energy required for each phase we obtain 1.19 mWh over a period of 24 minutes, this gives an average power consumption of 2.975 mW.
Knowing this it is possible to estimate the battery life. With 6 AA batteries, each with an average capacity of 3Wh, the total capacity is 18000 mWh.
252 days of battery life is not bad. Looking at the table above it can be seen that there are three phases that consume the majority of the power. The DISPLAY CLEARING and DISPLAY UPDATE phases are dictated by the display. The only optimization that can be done is in the JPEG DECODE phase, perhaps with some more code optimization or by swapping the microcontroller for a lower power one.
For now, I'm happy with 252 days.
02/17/2021 at 15:53 •
The frames to be displayed will be stored on an SD-Card as a sequence of jpeg files. Considering the time it takes to refresh the display and that I want to maximize battery life, I decided to update the display every 24 minutes, showing only one every 24 frames. This will make the battery last 24 times longer. The display resolution is 600x448 and, since only one every 24 frames must be stored on the SD-Card, the storage requirement is 144MB/hour (with 60% quality). An average length of 90 minutes movie can be stored in 200MB.
Time to implement a jpeg decoder and... I wrote my own from scratch. You see I want to learn something new with each project, this was the perfect opportunity for learning how jpegs work. The best resource that I can find on the subject is a video series entitled Everything You Need to Know About JPEG.
If you are not familiar with how jpeg works here is a brief overview. The first step in the encoding process is to convert the image from RGB to YCbCr, each color component is encoded independently. Next, each color component is divided into blocks of 8x8 pixels, each block goes through to the encoding process independently. The encoding starts with the forward DCT that converts the 8x8 block into a frequency domain representation. After that, the quantization step removes high-frequency data, and then the entropy coding is used to more efficiently store the coefficients.
The decoding process works the same way only backward, it starts with the compressed data stream, the first step is to undo the entropy coding then the coefficients are dequantized and, after that, the inverse DCT returns an 8x8 block of pixels. The final step is to convert back from the YCbCr color space to RGB.
The tricky part is how to interpret the bytes in the file since to decode the compressed data more information is needed other than the compressed bitstream. To undo the entropy coding the decoder must have a copy of the Huffman table that has been used by the encoder and to dequantize, the decoder must have a copy of the quantization table. This information is encoded into the file and is separated by markers. Markers are two-byte codes that precede and identify a block of data.
The implementation of a decoder on a microcontroller poses some challenges, there is not enough RAM for a frame buffer and so the pixels must be sent to the display as they are decoded. Fortunately, the way 8x8 blocks from each color component are interleaved makes this straightforward.
The problem is that the pixels to the display must be sent in order from left to right top to bottom and the decoder produces 8x8 blocks of pixels instead. The solution is to have a small buffer, with the height of a block and the width of the screen. The decoder fills the buffer with pixels and, when it's full, it is sent to the display.
To make the images look good with only 7 colors, before sending the buffer to the display, the Floyd Steinberg dithering algorithm is applied.
The following video shows the display updating with some test images. It is noted that even if the display has only 7 colors, the dithering algorithm does a good job. If viewed from a couple of meters away the image looks almost perfect.
02/13/2021 at 16:25 •
Quick update on the test setup.
I was tired of having the display and the development board floating around on the bench, I wanted to make some kind of a test fixture. My first thought was to 3D print something to keep it all together but I didn't want to design and 3D print a frame only to be used one time. The idea I came up with is to have a perforated base on which all the components are placed. The advantages of this are quite obvious, it is possible to rapidly move components around and it can be reused for future projects.
The base is made of squares that can be joined together. Each square has a 15x15 grid of 6mm holes. The spacing between holes is 10mm
The squares are joined with round pins.
The display and the discovery board are kept in place by holders with pins on the bottom.
The 3D models for this test fixture are available on this site. If you like the concept, feel free to use it for your own prototypes. For now, I only printed a holder for the discovery board, in the future I'll make holders for the boards that I'm working on.
The following video shows the display mounted in the test fixture, as it goes through some test patterns.
02/06/2021 at 19:13 •
Being this an ePaper display, it draws power only when the image is changing. When the display is in deep sleep mode, the datasheet gives a typical current draw of 1µA but it doesn't say anything about the power consumption during an update. The only thing it says is that the inrush current is 100mA. I guess that means that when the display comes out of reset and powers on it will draw up to 100mA, but that's not what I'm looking for, I want to know how much energy it takes to update the display.
To measure the current waveform, as the display is updating, I put a small resistor in series with the power supply and measured the voltage drop with an oscilloscope.
The diagram on the left shows the test circuit.
The datasheet specifies a typical inrush current of 100mA, with a 10Ω resistor the voltage drop will be 1V living enough margin. Plus having the resistance power of 10 makes the maths easier.
Energy is measured in Joules 1[J] = 1[W]*1[sec], to compute the energy is just a matter of integrating the power over time.
The breakout board for the display has an integrated LDO that regulates the input voltage to 3.3V. The quiescent current for the LDO is 130µA, it is so low that can be ignored, the current flowing through the resistor should be almost identical to that flowing into the display. In the final application, the display will be powred from 3.3V thus it is important to use 3.3V in the formula above otherwise we are taking into account the power that is dissipated by the regulator.
After connecting the oscilloscope I was able to capture some waveforms. Note that the scale is 20mA/div, I'm using a 1x probe across a 10Ω resistor, setting the probe multiplier on the oscilloscope to 0.1x makes it possible to read the current directly without conversion. It is also noted that the display draws current in bursts as it goes through the update sequence.
display update current waveform
Here is a video showing the update sequence. It is noted that as the display updates, it goes through more than 7 colors. Maybe it's possible to modify the lookup tables to increase the available colors or to change the displayable colors. Sounds like a future project ;)
The datasheet specifies two test patterns, one for the typical and one for the maximum power consumption. To make it easy to display different patterns quickly, I wrote a simple command parser on the STM32 that listens for commands from the serial port and updates the display accordingly.
Typical Power Consumption
The typical power consumption is measured as the displayed image changes from full white to the colored horizontal stripes shown in the picture above. Using the maths function of the oscilloscope it's straightforward to integrate the current during the update cycle. Using the cursors the total energy required is determined to be 0.864J.
Maximum Power Consumption
The maximum power consumption is measured as the displayed image changes from full white to a sequence of horizontal black and white lines. Applying the same procedure as above, the energy required is determined to be 1J.
The typical and maximum energy required to update the display are respectively 0.864J = 240µWh and 1J = 278µWh.
To wrap this up let's now roughly estimate how many update cycles we can get out of a battery. Since the rest of the circuit is not designed yet let's assume for now that the display is the only load. Let's also assume that we have a 2000mAh battery whose voltage is 3.3V. The energy stored inside the battery is
Since the display uses 1J for each update the total number of updates is 23760. The display will be updated once every 24 minutes so the total run time is 23760 * 24 min = 396 days. This is in the ideal case where only the display draws power and at least shows that this display is suitable for the project.
Next step will be to read from the SD-Card and display some pictures.