Laser Optical Programmers
The goal of the optical programmer upgrade is to build an eye-safe system to replace the current setup that uses a SFH 4555 IR diode. The suggested approach was to use a (cheap) laser diode after Brad found some success programming SCuM with a handheld laser pointer in the lab.
Hardware:
(1) "large" laser diode modules (e.g. https://www.amazon.com/Qiaoba-Laser-Diode-Module-Diodes/dp/B07L416LV1/)
(2) "small" laser diodes (e.g. https://www.jameco.com/webapp/wcs/stores/servlet/ProductDisplay?storeId=10001&langId=-1&catalogId=10001&pa=2210204&productId=2210204)
(3) visible light LEDs (of various wavelengths)
I initially tested the larger laser diodes (1), but they were too bulky to work with, so I only used the small laser diodes (2). We ordered several different models off Amazon and one from Jameco - they are likely nearly identical to each other, but I chose the Jameco lasers, because they were the only ones rated for 3.3V, which is what the current optical programmer was designed for (using the 3.3V output from the Teensy). As an alternative to lasers, I also tried several visible light LEDs as an alternative. The full list of LEDs tested can be found in 20191104_Jove.pptx. The conclusion is that in theory, all LEDs are weaker than the IR diode in terms of power delivered to the optical receiver, but some are still surprisingly sufficiently strong enough to program SCuM. I did not pursue this approach, but a further investigation of visible LEDs may be worthwhile. Below is an image of a setup using a green LED.
Bootloading a program via the optical programmer normally consists of a preamble followed by a hard reset, another preamble, program data encoded as 4B5B, and finally several '1' bits. Each mode (e.g. hard reset or optical calibration) is initiated via a sequence of 4 magic numbers. Optical calibration is done by repeating a series of calibration packets every 100ms, where the delay is manually tuned and set in the Teensy software (https://github.com/PisterLab/scum-test-code/blob/master/scm_v3c/teensy_uC_programmer/teensy_uC_programmer.ino#L1486). A detailed analysis of bootloading can be found in 20191014_Jove.pptx.
Because the chip and programmer were difficult to modify, most of the parameters that could be tuned were in software and in optical programmer positioning. On the software side, the pulse lengths during programming can be modified in the bootloader code found in https://github.com/PisterLab/scum-test-code/blob/develop/scm_v3c/bootload/bootload.py#L90 by changing the numbers following 'configopt'
. These correspond to the long HIGH, long LOW, short HIGH, and short LOW pulse lengths. The numbers represent the number of NOPs that are used to control the pulse lengths and can vary. A '1' is encoded as a long pulse length and a '0' as a short pulse length. The optical receiver is self-clocked, where the incoming pulse stream is sampled using a delayed pulse stream. See Brad's dissertation for more information.
The default set of numbers for pulse lengths is 80/80/2/80. The likeliest limiting factor is the short pulse length (currently 2), because it must be shorter than the delay set in the hardware (nominally 1μs, but experimentally approx. 1.2μs during my tests). The optimal configuration of pulse lengths depends on, among other factors, the switching speed of the bootloader, the irradiance of the source, and the distance between the source and detector. Correct performance can be visually verified by looking at the GPIO_CLK_RAW and GPIO_DATA_RAW waveforms. If the waveforms show short and long pulses at regular intervals, then programming was likely successful (the current system does not allow for many bit errors, so the waveforms may look correct, but still be corrupted). If the waveforms are 'saturated' (i.e. low or high for long periods of time) or if they unpredictably switch between high and low, then the transmission is not properly working. Using a logic analyzer, it is also possible to decode the bitstream received by sampling DATA_RAW (or DATA) on the rising edge of CLK_RAW (or CLK).
Example of correct waveform:
Example of incorrect waveform:
The default 80/80/2/80 seems to work well for the laser used. I initially set the lengths much higher (as high as 500/500/15/500) and the pulse lengths do change, but the data was significantly more corrupted. This comes as a surprise, because higher values (within the 1μs short pulse length limit) should reduce errors at the cost of transmission rate.
The positioning of the laser relative to SCuM is another major factor in programming. On Q6, I found that an ideal position for the laser is approximately 2cm above the chip with the laser shining along the left side of SCuM where the optical receiver is. However, this changes with boards, so some tuning is required.
Current State:
Using the Jameco lasers, I modified 2 existing and populated 4 new programmers labeled L1 through L6. These work on Q6, but only under when positioned very precisely in a position that is likely board-dependent. An example setup is shown above, where, as previously mentioned, the laser line shines along the left side of SCuM.
References:
Brad's dissertation Appendix B (https://www2.eecs.berkeley.edu/Pubs/TechRpts/2019/EECS-2019-36.pdf)
TODOs/Future Work:
Test lasers at larger distance
Build LED/laser array to increase power delivered (and reduce need to orient laser accurately)
Investigate photodiode response (e.g. why do longer pulse lengths not work well)