I haven't been putting up new logs since I was actually concentrated on getting work done on the software side. Last week I got almost all hardware components (only missing the temperature sensor) I was planning for first version. With these, I have a mostly complete protoboard prototype (next log will include a picture detailing components). So, here's the situation now... Prepare for long post =)
This is where I spent the majority of the effort last weeks. As I said, I'm using NuttX RTOS for development, since I wanted something nicer than simply coding everything using Arduino Libraries. This required adding support for several modules to NuttX, since Teensy 3.x was not fully supported. What was already there, though, was an I2C driver and a graphics subsystem (nxgraphics) which I started to use.
The first problem was due to the bizarre distribution of bits/bytes to rows/columns of the device. One would expect that, since the display is expected to be used in portrait mode, consecutive bits of conscutive bytes would correspond to columns of the display. However, it is exactly opposite. The problem is that the whole graphics system assumes the former layout and this requires the SSD1306 NuttX driver to map one layout to the other, performing quite wasteful computation. As an added annoyance, nxgraphics is not intended to be used for drawing to a memory or canvas and only later redrawing on demand. Generally, every drawing operation would trigger a transfer to the device. Since I'm using I2C, this is not really fast. Moreover, complex graphics usually require many primitive drawing operations, so I did not like this approach.
After lots of thinking and hitting my head against the wall, while balancing my idea of not reinventing the wheel and using already existing code with the fact that these issues where quite difficult to work with; I decided to code my own simple graphics system tailored to this particular layout and controlling myself the transfer to the device (I'm doing a full refresh after the frame is finished).
After lots of coding I finally managed to get it working. In retrospective I might re-visit this choice since I was considering alternative display hardware anyway. Mainly, I would like a bigger screen (maybe twice the size) and possibly with more than 1 bit-per-pixel. Dealing with bits can become quite tedious and, contrary to initial belief, quite inefficient since operations on many bits can be performed faster than on individual bits. One possibility here is to use a SSD1351 device, which is usually found as a 1.5'' color OLED device with 16bpp and 128x128 pixels. I like the fact that it is square and larger. At the moment, though, after the considerable effort, I will use the SSD1306 and re-visit these ideas when everything else is working as expected.
Being something similar to a bicycle computer, I could not miss this feature so it was important to pass the proof of concept. For the odometer, I chose to use a latching hall-sensor, which means that it output a digital value which only transitions when the sensor encounters a magnetic field with opposite polarity than the previous one. Thus, this would work with two magnets (mounted with opposed polarity). This type of sensing allows for reducing false triggers of the sensor to almost zero and eliminates issues such as when the bicycle is stopped and the magnet is near the sensor, which would generate many false triggers.
To test the odometer, I mounted two magnets on a small plastic lid, and printed the state of the hall sensor. You can see this in the video below (please don't laugh at my crafting skills, this is extreme DIY)
You can see that the sensor does not change unless I perform another half rotation where the magnet with opposite polarity sits.
Battery / Power
As the device is supposed to be battery powered, I wanted to be able to support charging from the device itself. Also, I wanted to allow normal usage of the device while being charged. The device thus includes a TP4056 charger module, with the added DW01 protection IC. This means that when the device is powered, the battery is charged. Otherwise, battery power is used but controlled by the DW01, which disables the output if the battery is (extremely) drained at 2.4v. The charger also stops charging after reaching 4.2v. Since I'm using a 460mAh LiPo cell, 4.2v stop voltage is correct. However, 2.4v is really low and I would never want to get there. This means that is the device's responsibility of measuring battery voltage while discharging and turn of the teensy after maybe 3.4-3.6 volts or so.
The first problem here was that, since the charger board required replacing a SMD resistor which determines the charging current (by default at 1A, and which I set to below 400mAh for safety), after performing de- and re-soldering, the device did not seem to charge the battery (no LED turned on). After careful inspection, it seems that the re-soldering was not correct and the solder did not fully touch the tiny resistor. So, after a quick fix, the device was working correctly.
Second issue to be solved was to deal with powering the device while charging. While the carger includes a micro USB port, the Teensy already has one so I took the Vusb output of the teensy and sent that to the IN+ port of the carger. However, since the teensy cannot be powered by USB and battery at the same time, I cut the VIN-Vusb trace at the teensy as suggest. Finally, I've added a DPDT switch which allows to select "charge/off" or "on". In the "on" state, the battery powers the device and plugging the USB port does not bother (the device can be normally used and reflashed if necessary). In the "carge/off" state, if the cable is not plugged, the device is completely off. Otherwise, when the cable is plugged, charging starts and the device takes power from the USB port, not from the charger out, since this impedes fully charging the battery (parasite load).
Finally, my idea was to have charging state detection from the teensy (which was easy, simply connect Vusb to a digital pin, which is 5V tolerant) and also to measure battery voltage. Unexpectedly, the second step proved to be a bit difficult. One annoyance is that the DW01 protection IC does not like having a load (such as the resistor divider which is used to read the battery voltage) before the battery is plugged. In this case, when the battery is plugged, no output is generated. So, I had to always remove the resistor, plug the battery and re-plug the resistor... I figured that since the battery will be always plugged, I would not bother myself with this issue further. Moreover, as I wanted to monitor the battery not only during discharge (to display battery remaining) but also during charging. The latter seemed to be more involved since it is not just a matter of monitoring voltage, but would also require to measure current. While the charger module does this, it would require soldering a small cable directly to an IC pin, so I decided to leave this feature out. This means that the charger's LEDs (which indicate when charging is complete) will have to be exposed in the final device. Not so bad in the end.
Current work / thoughts
At the moment I'm considering acquiring the small temperature sensor, which is difficult to find here, since it has to be a 3.3v capable IC (such as TMP36). However, I like to be able to measure temperature from the device during riding. The remaining two components are: 3v coin battery for RTC backup and bluetooth HC05 module. I have both but have yet to include these to the protoboard, as space is getting tight (will probably buy a second one). I only found a CR2032 battery which is a bit big but which will do for the moment. The only difficulty here is that the VBat pin is inconveniently placed on the teensy and cannot be exposed via the breadboard easily. For the bluetooth module, my main concern is to test whether the total current of the device is within the teensy 3.1 limits of 100mAh. Anyway, I figure that eventually I can get the teensy 3.2, which has a 250mAh capable regulator and has the exact same chip as the 3.1.
After completing the protoboard build I will focus on finishing the graphic UI. I have thought (and already started to work on it) of a page-based UI, switchable from buttons. For example, one page would be the odometer, another one the time, another temperature and so on. Each page will have sub-pages to switch, for example, the speed units, and related measurements such as traveled distance. I will probably also include some combined data screen, although at 0.96'', there isn't much I would see (another reason for a larger screen). Finally, while complex configuration would be performed by the future companion Android app (via bluetooth), I decided to include some basic menu-based configuration on the device, to choose some settings which would be annoying to change only from the device.
The final thought was to consider actually building a PCB holding everything together (I was thinking of a small perfboard first) since I've looked at the prices at OSHpark and they seem amazingly cheap. The PCB would allow for a smaller package and cleaner build. But for this, I would like to be very sure of the hardware layout on the protoboard. However, I think that I will complete this soon.
Stay tuned for more project updates, and I hope the next one will include at least a nicer picture =D