I do not believe the technique used by Thumby is applicable to the Arduboy (an explanation follows), nevertheless I am thinking of trying it to confirm.
The technique relies on setting up unused (off-screen) lines above and below the on-screen lines. This is possible on Thumby because only 40 of the 64 lines are used while the Arduboy uses all 64 lines. So I would expect the Arduboy to:
End up with a mostly solid always-on first line (or last line, if the controller is setup to refresh bottom-up instead of top-down). This happens because the line used to lock and sync the refresh is visible on the Arduboy.
Maybe show more flickering than Thumby at the top or bottom of the screen. This may happen because the command used to “lock” the refresh line and re-sync has to happen in a much narrower time-window on the Arduboy. i.e. during T(front porch) + T(back porch) instead of T(front porch) + T(back porch) + T(offscreen lines).
EDIT: On second thoughts brightness (or contrast) could be set to zero while locking the scanline or the vertical timing settings could be updated so that the locked line is in a region where the controller doesn’t allow it to drive the display. So many things to try …
No dice. I am not 100% done with testing but I can confirm the appearence of (the expected) artifacts on screen. One of the artifacts presents itself as a very bright bottom row on the display which can likely damage that specific row of OLEDs. This approach (on the Arduboy’s full size screen) is IMO worse than the existing solutions, both visually and in terms of CPU usage.
@dxb Picking your brain here because you understand this method much better than I:
Could a grayscale picture be achieved using this method with 8px tall black “anamorphic bars” on the top and bottom? Like using +8px vertical scroll and the bottom 16ish rows for the timing variation zone with all zeros written to the controller buffer for those rows. Then usable grayscale screen is 128x48.
Alternatively, 16px wide bars on the sides with +16px horizontal scroll and vertical addressing mode, with a 96x64 usable space.
Hi, short answer is no. The reason is that in order to avoid artifacts the artifacts have to occur off-screen. Always-off bars would not be enough because those lines are still driven by the controller. The Thumby has a smaller screen so the lines where the glitches occur are not visible because they are physically not connected to the display.
If you are ok with half-screen grayscale (top, center, bottom or streched) then the method implemented in this demo works fairly well and is easy on the CPU.
Three variations selected by the macro GRAYSCALE_OPTION:
0: 4-level in 2 frames using contrast (slight noise at border between 01 and 10)
1: 4-level in 3 frames (slight flicker due to lower refresh rate)
2: 3-level in 2 frames (no visual artifacts for me but only 3 levels)
It currently uses a timer for precise frame timing but I don’t think this is necessary. The usable area is cut to 128x55 pixels (the last page and the first row have to be kept zeroed out) and requires 1792 bytes to buffer, an increase of 768 bytes. If starved for RAM you could probably pre-render the appropriate plane each frame.
I was hoping to be able to sacrifice columns instead of rows to have a nicer aspect ratio left to work with. Unfortunately I don’t think this can work… I’ve learned the controller only drives entire rows so this approach needs extra rows to sacrifice for the timing variation.
Great work. I’m glad you proved me wrong. My test code isn’t using a timer and the result is far cry from yours.
FYI the acceptable range for BLAH on my Arduboy is [406, 443] using GRAYSCALE_OPTION 0 and the default Fosc setting (see 0xD5 command). Outside that range flickering, or other undesirable artifacts appear.
Hopefully there is a subset of values for BLAH that works OK for most Arduboys out there.
It is possible that setting Fosc to the maximum allowed value using 0xD5, 0xF0 will result in less dotclock jitter.
Adding 0x7C (see ‘10.1.6 Set Display Start Line’ in the SSD1306 datasheet) to SETUP_CMDS and disabling wiping of the first scan-line centers the usable area vertically in the screen and makes the first line of the frame buffer available for use (usable area: 128x56 px).
On my Arduboy, using both your original gist and one with my vertical alignment change, I am observing an anomalous burst (1 or more subsequent frames) every so often (approx. every 1 minute or so). The glitch looks like a black (partial?) frame to the naked eye. I wish I had a camera with a high enough frame rate to see what is going on exactly.
Out of curiosity: is the external clock input pin brought out?
The Thumby technique implemented by @brow1067 could be combined with a display clock signal we can count (or control) using a combination of PWM and timers. This way the frame duration would be known and we’d likely be able to use the entire 128x64 screen.
Thanks a lot for the display start line command! I’m still learning my way around the controller.
I see the occasional missed frame too. I think it’s the millis/micros ISR occasionally causing the frame ISR to miss its timing window, because disabling the timer0 overflow ISR seems to fix it.
I’ve updated the gist to incorporate display start line and disable the timer0 ISR. This means that none of millis/micros/delay can be used anymore but I think this is OK since the update/render loop is tied to the frame ISR to avoid tearing, which negates the need for Arduboy2::nextFrame or similar. Are there any other vital uses for timer0?
@dxb I noticed that the display start line of 0x7C results in some artifacts at the bottom of the screen. I don’t have full understanding but from playing with the value it seems like each pixel shifted steals a row from the timing window at the bottom – does that sound right? I changed it to 0x7F at any rate just in case.
Yes, you are correct. For each row shifted the window at the bottom shrinks. However, because of the wraparound having an 8 rows split between the bottom and the top of the screen should still result in a time window that is still 8 rows worth of “time”.
The artifacts you mentioned do not appear on my Arduboy when using 0x7C, but I am using a different value for timer_counter. So the artifacts do not disappear increasing or decreasing timer_counter?
Later today I am going to update this comment with the ranges for all the cases you tested. In the meantime I can say that using rev 10 of your gist, the valid range for 0x7C on my Arduboy is [421, 444].
There is almost no overlap! According to the datasheet Fosc has a quite large range of expected values even for a given setting, so maybe that’s where the difference comes from. Time for @bateske to spin a new hardware rev using CL/CLS pins