using another nano 3 via spi to drive an i2c only oled display - Page 1
Forum section: electronics / general

author: Johnny B Good
author_rank: Frequent Contributor
timestamp: June 10, 2025, 12:14:49 am
content: I've spent the past four years developing a temperature stabilised and pressure compensated LPRO 101 based RFS using an Arduino nano3 to control a cooling fan and servo controlled flap diverter valves and an intake damper to stabilise the fan's intake plenum air temperature against raw ambient air temperature fluctuations over the sub zero to 32 degree range which raises the plenum temperature low limit to 18 degrees to allow the fan to tick over without overcooling the LPRO's base plate below the 37.050 deg C set point.The "Fly in the ointment" in this case being the need to drive an I2C only SSD1306 oled to display plenum and base plate temperatures along with absolute air pressure. The display code consumes some 68ms in total per update once every second which delays the 7.1ms per base plate temperature reading stream each time the display code is allowed to execute.Surprisingly, these display update interruptions don't seem to be disrupting the temperature control despite the obvious syncopation effect on the serial plotter's output. However, I'd like to eliminate the syncopation effect and minimise whatever influence it may still have on the temperature control algorithm and free up some ram which is already stretched uncomfortably close to its breaking point.I'd had to comment out the pressure display code segment in the display section before I could test whether there'd be any conflict with my existing code by adding Nick Gammon's SPI hello world example (without an attached slave - output only with no return response over the MISO wire requirement). This ran ok, justifying the hassle of soldering wires onto the RFS's nano's pins that would allow me to test the slave code using an Uno. Once I'd completed this part of the test setup, I was able to confirm that these code examples for the master and slave did work as advertised and most importantly, without ill effect on the main control code.This left me looking for a method of sending the three float variables to the slave driving the display to offload the oled display task onto a second nano via a one way (master to slave) spi data transfer but I can't find any suitable code examples that remotely fit the bill by way of inspiration.The fact is, I've searched and searched til my eyes bled, hence this plea for some help and advice. The Arduino forum is awash with slave to master data transfers with no reference to one way master to slave data transfers not requiring the use of the MISO wire.You might well be wondering why I don't simply throw a bit more cash at the project and upgrade to an SSD1306 that includes the SPI interface option and the answer is that this doesn't solve the problem of eliminating the display formatting code burden on an already over-stretched memory resource even supposing it eliminates most of the existing display code induced delay. The freed up memory will probably be needed for the SPI data formatting code anyway so it makes more sense to throw another nano 3 at the task and carry on using the I2C oled (all my spare oleds are of the I2C only type).Plus, offloading this task means I can afford to toggle the heartbeat dot every half second (instead of every time I update the display which had resulted in a less than pleasing half a Hz blink rate) by virtue of simply refreshing the display twice a second. I might even be able to offload some of the functions in the primary nano onto this second nano or possibly even add additional, less time critical features.For added interest / amusement, I've attached my code plus a couple of short 4 minute movie clips of the serial plotter displaying a 'live' action of the base plate temperature samples. The Y axis shows milli Kelvins against a 37 deg reference temperature. The spikes are a deliberate artifact to sabotage the serial plotter's mission to auto zoom to "infinitesimal and below!" (to paraphrase Buzz Lightyear) to keep the base plate setpoint temperature centred within a 20mK wide window. The x axis represents a 500 plot point wide window rather than a set time period as per an oscilloscope trace. The syncopation effect is less obvious in these plots since I separated the formatting operations time-wise from the display update action. It's still there but spread out over the one second averaging interval rather than appear in one lump.Incidentally, the second 4 minute plot run was some five to ten minutes after the first run to allow the plenum temperature to stabilise. Inevitably, with this method of controlling the plenum temperature, there is some interaction between the base plate temperature controller and the independently servo controlled diverter valve settings.

author: Johnny B Good
author_rank: Frequent Contributor
timestamp: June 16, 2025, 06:37:15 pm
content: Although there was some interest being shown in my problem, no one had been prepared to offer any advice. However, it was only after resorting to chat gpt that I did eventually find a solution after asking it for a more contemporary solution on the 6th attempt.I've reached the stage where I just have to add the 2nd nano3 and oled to the BOM. I'm not going to show the code changes. Instead. I'll attach a couple of short movies which will clearly display the benefit of offloading the display code via SPI onto a 2nd microcontroller dedicated to this task.At first looking at the plots in real time I was a little unsure as to whether this had made much of a difference. I'd guessed it was just a mismatch between the monitor refresh rate (120fps) and the improved sps plotting rate (now at 140sps). This was borne out by the before and after videos that I've attached despite the 60 fps maximum frame rate limit of blue recorder used to capture the movies.

author: thm_w
author_rank: Super Contributor
timestamp: June 17, 2025, 01:18:18 am
content: For future projects with graphic displays you may consider looking at more modern MCUs.

author: DavidAlfa
author_rank: Super Contributor
timestamp: June 17, 2025, 02:57:06 pm
content: Try using a timer interrupt to drive the plotter etc, let the main loop update the display.Remember, you don't need to update the entire display at once, you can do it in chunks, for example 1 row at a time, just remember to avoid updating the display data when getting new readings, wait until it's done or you'll cause artifacts.

author: Johnny B Good
author_rank: Frequent Contributor
timestamp: June 17, 2025, 04:24:05 pm
content: @thm_wThank you for taking the time to reply.I'd already considered that option when I purchased a couple of Raspberry Pi Picos some two years back from the PiHut shop. After unpacking one from its resealable antistatic package (thanks, PiHut) to test it using the classic Blink sketch, I discovered very few useful example sketches written in C++. Plenty in the more obscure (to me) Thonny language and Python which made me set them to one side until more C++ example sketches start to appear.I've never checked for C++ examples since then, mainly on account of my concentrating on gaining programming expertise with the Arduino nano3 to improve my seemingly unique temperature control and barometric compensation requirements.In the meantime, I'd even been persuaded to buy in a set of three STM32F controllers (Blue Pills afaicr) by their use in making better (fsvo "better") GPSDOs. I may yet find a use for them one of these days but in the meantime my ongoing successes with the nano3 (s) in my current project/obsession continue to keep me occupied. It's not entirely a software issue since I need to improve the hardware layout to attain the minimum of internal temperature gradient variation with variations in ambient temperature.So it's a case of "Better the Devil you know" and the knowledge that two nano3s cost less than a Raspberry Pi Pico (or an STM32F for that matter) which took me to my current solution to eliminate the 70ms disruption per second in the control cycle caused by trying to service the oled display routines in as short a time as possible using I2C.Offloading the display code onto another mcu (a nano3) is in my case the best solution to reduce the disruption to less than a millisecond. The time required by the display's need to process 8Kbits of raw video memory is neatly dealt with by the 2nd dedicated mcu without any impact on the main program.I've attached a timelapse movie capture (Blue Recorder) of a ten hour oscilloscope display I'd recorded over a month ago showing the ZED9FT based gpsdo on CH1, the RFS on CH2 and one of my spare LPRO 101s onCH3, oops! CH4 simply sat on a sheet of aluminium to stop it overheating as an independent free running oscillator to reveal the true source of the random 1 to 2ns 'jumps' on the RFS as originating with the GPSDO due to rogue gps satellites appearing and disappearing from the sky view map.The spare LPRO is of course at the mercy of room temperature variations so shows some drift. Despite this, the drift is sufficiently low enough most of the time to unmask the gpsdo as the culprit for these random 1 to 2ns jumps.

author: Johnny B Good
author_rank: Frequent Contributor
timestamp: June 17, 2025, 05:50:03 pm
content: @DavidAlfaThank you for those suggestions. I'm plotting the individual temperature samples in real time using the less ancient baud rate of 115200 which, if I'm not mistaken adds a mere 700 microseconds (possibly less) to each sampling period. I've not yet tried faster baud rates for (probably needless) fear of possible corruption over a 6 metre usb cable connection. However...Having just tested the 2000000 and 9600 baud options, the higher speed only gave a marginal improvement (140 up to a 141 sps rate) but the 9600 baud dropped it right down to a mere 108 sps. I've set it to 500000 baud for now (fingers crossed that uploading a modified sketch doesn't result in disaster).I'm using the Adafruit graphics library which may not have been my best option in view of my desire for best loop cycling speed. However, since the issue has now been rendered somewhat academic by offloading the display code onto a 2nd mcu, I no longer care for what might have been if I had chosen a character only display mode in the first place.Actually, the graphics library code was only needed to draw a couple of degree symbols just once during the setup and never ever refreshed thereafter until the program was restarted so this was irrelevant in regard of its speed. The heartbeat dot came along much later and only gets toggled once a second so has a vanishingly small effect anyway.I don't require nor desire a display update rate any faster than once a second anyway, since I'm generating once per second averages to improve on the BMP280's 10mK resolution whilst allowing time for it to respond to plenum temperature changes and avoid counter-productively trying to update the servo position any faster than once a second and provide a more meaningful second by second average of the base plate temperature readout.All of the above means I could take as long as 970ms or so to update the display if I so desired, without any impact whatsoever on the loop speed running on the primary mcu.

author: Johnny B Good
author_rank: Frequent Contributor
timestamp: June 18, 2025, 05:46:05 pm
content: After cleaning up the code in my original sketch to remove cruft from the plethora of comments and commented out oled code leftovers with the SPI master proxy for that oled code now included and likewise for the oled code transplanted onto the uno3 slave, I decided to attach both sketches which I think should provide useful hints for anyone else interested in a similar project which could benefit from offloading timehogging code onto a second mcu using SPI data transfers.

author: Johnny B Good
author_rank: Frequent Contributor
timestamp: June 27, 2025, 04:31:46 pm
content: Hi, everyone!By the time I'd succeeded with my spi to 2nd nano3 display driver project, I'd already decided, due to my ageing eyesight, to upgrade to a larger oled, a 1.54 inch CH1116 based one (supposedly ssd1306 compatible according to the AliExpress seller).The original oled was in dire need of replacement after some 4 years worth of 24/7 operation anyway, so it seemed a good opportunity to upgrade to a larger display. I can't blame the seller for assuming compatibility with the SSD1306 since the manufacturer had compared their CH1116 IC to theSSD1306(actually, the SSD1309 ) in their technical specifications implying as much (with some 'minor' changes to the driver software). I guess the seller must have misread ssd1309 as ssd1306The three displays I'd ordered duly arrived on the promised earliest date just two days ago. A quick test with the uno3 revealed that they couldn't simply be swapped in as a larger SSD1306 like the misguided seller had implied so it was yet another hunt for alternative oled support libraries and example sketches.I managed to persuade duck.ai to dish up an example sketch using the <U8g2lib.h> library but I wasn't happy with this, preferring to minimise the effort to adapt my original code to the constraints of the <U8g2lib.h> library. I took another look at the Adafruit alternatives and found it had support for a more compatable driver IC, namely the SH1107.I tracked down an Adafruit graphics demo based on the <Adafruit_SH110X.h> library and was able to duplicate the original graphics demo based on the Adafruit SSD1306 driver that I'd last run some four years ago. "So far so good", I thought.I landed up spending pretty well the whole of yesterday adapting my original sketch before getting it to perform exactly the same as the SSD1306 version (only, surprisingly a little more smoother, as well as consuming only 1% more memory resources (52% program space and a mere 25% of dynamic memory versus 51 and 23 percent for the SSD1306 version). Incidentally, this offloading exercise has reduced the 93% of program space used in the main sketch on the primary nano3 down to a mere 54%I've attached the new sketchalong with the manufacturer's "Data sheet" (web page saved as a pdf - hint: use "Fit to width")and a short one minute video clip of the new display in action.Apologies, trying to send all three of the above exceeded eevblog's pathetic 8000000 byte limit by just over 200 bytes. I'll attach the pdf in the next post.Just found another winstar web page with an alternative driver solution (the name of the pdf I'd saved it to, says it all) which I've attached in lieu of the original much larger file that had taken the total file size beyond the 8000000 byte limit.

author: Johnny B Good
author_rank: Frequent Contributor
timestamp: June 27, 2025, 04:38:28 pm
content: Here's the pdf I tried to send in the previous post.

author: Johnny B Good
author_rank: Frequent Contributor
timestamp: June 28, 2025, 02:14:04 pm
content: I see some ongoing interest in my mini-projectTBH, I'm not sure whether I'm making a useful contribution or just "Preaching to the Choir"Curiosity as to the SSD1309 reference being a compatible driver led me to starting another duck.ai session on the subject. The AI suggested that I could have used the adafruit graphics library with the Sparkfun SSD1309 library and produced an example which failed with a compiler error telling me it couldn't find the SSD1309 library despite my adding it to the libraries folder via the library manager.For anyone else curious about this, I've attached the TL:DNR AI conversation but, to cut to the chase, I'll quote the final exchange here:====================================================================================================User prompt 9 of 9 - 6/28/2025, 12:49:10 PM:Thanks for your help but since the display works just fine using the adafruit sh110x driver, I'll pass on this one. I was only exploring possible alternative drivers to satisfy my curiosity as to why the ch1116 chip maker had suggested the seemingly "Mythical" SSD1309 driver as a driver solution.GPT-4o mini:You're welcome! It's great to hear that the Adafruit SH1106 driver is working well for your CH1116 display. The mention of the SSD1309 driver by the chip manufacturer might stem from the fact that the CH1116 is designed to be compatible with various OLED drivers, including the SSD1309, which is commonly used in similar displays.### Understanding Driver Compatibility1. **Driver Compatibility**: Manufacturers often list multiple compatible drivers to provide flexibility for developers. The SSD1309 is a well-known driver, and its mention may be intended to indicate that the CH1116 can work with libraries designed for it, even if those libraries are not widely available or well-documented.2. **Library Availability**: Sometimes, libraries for certain drivers may not be as popular or may not have been developed as extensively as others. This can lead to confusion when trying to find the right library for a specific display.3. **Community Support**: The community often develops and shares libraries based on their experiences, which can lead to variations in support for different drivers. The SH1106 library, for example, has gained traction due to its compatibility with various displays, including those using the CH1116 chip.### ConclusionIf you're satisfied with the performance of the Adafruit SH1106 driver, that's a solid choice! Exploring different drivers can be a valuable learning experience, and it's always good to have options. If you have any more questions in the future or need assistance with other projects, feel free to reach out. Happy coding!=====================================================================================================The AI's responses seem to be improving since I started asking such uncommon technical questions just over a week back. I guess that's only to be expected since my / our queries are informing its learning algorithm.In other news, I've just verified that Icanhook another slave onto the SPI bus without any conflict when the MISO line is disconnected in this one way master to slave setup. This is useful because it simplifies adding a wireless or network (cable or Wi-Fi) link to a remote repeater display.I updated the slave code I had been testing on the uno3 and simply paralleled the SPI connection with the nano3 slave and, lo and behold, it works! A temperature and pressure display in glorious stereoscopic vision!Now I'm off to have a close examination of the resistors on the back of the third display to see if I can spot an obvious candidate for the Iref resistor mentioned in the CH1116 documentation. These displays could do with a little more dimming than the minimum available through the contrast setting command and I suspect this might be due to the use of an additional external resistor.Black text on a white background is way more readable than the default white text on a black background and allows a considerable contrast reduction to be applied (I don't normally need it to be legible in direct sunlight) which reduces the wear out rate on the display as a whole.PS: In my search for "pin out" data (flex contact numbers) I just found a more useful winstar information nugget (see attached)I spotted "R1" but it's a 100 ohm smd which suggests that it's merely used as a jumper link. The search for more detail continues.PPS: According to the Newvision datasheet (attached), those resistors must be "stopper" resistors on the SCL and SCD traces going to the flex connector (they are both pulled to Vcc with 10K resistors R3 R4 next to the 3.3v ldo chip. It looks like the Iref resistor is the 560K (marked R5) connected to pad 26 of the flex connection.Another possible way to reduce contrast might be to command a lower Vpp voltage level but I have yet to find a "command" option in the SH110X driver similar to the SSD1306 driver, example vis-à-vis the following:// display.ssd1306_command(0x81); // 0x81 is the poorly documented setcontrast command// display.ssd1306_command(45); // followed by a 1 byte value (1-255 is min to max brightness, 0= off!)I feel yet another AI session is warranted now that I have some more relevant questions to ask it.

author: Johnny B Good
author_rank: Frequent Contributor
timestamp: June 28, 2025, 08:26:44 pm
content: Following on from my previous post, I did manage to extract the additional information from the AI needed to set a reduced Vpp (chargepump) voltage setting saving me any further consideration of any need to unsolder a resistor from off the back of the display module. This change has allowed me to dim it noticeably - enough that I doubt I'll ever feel any need to dim it any further.I've updated the slave sketch to incorporate the required changes to maximise the service life of my oled. I uploaded the new sketch onto the uno3 first to test the various Vpp options before updating the nano3 slave.I noticed a curious disparity between the program space consumption between the two. Initially noting a 49% usage in the Uno3's case followed by a confirmation of the 52% figure in the nano3's case. I'm assuming this is because my 5 year old nano3s came with the old bootloader installed (the recently purchased pack of five nano3s had been upgraded to the current bootloader).Since the Uno3 I'd bought some three or so years ago is just a large format version of the nano3, I'm guessing this must have already been blessed with the current bootloader code. I can easily test this hypothesis by programming one of the new nano3s and swapping it in for the old one I'm using before looking for a way to burn the new bootloader code onto the older nano3s.However, that aside, I'm attaching the latest version for anyone interested in comparing these last two iterations, along with a copy of the AI conversation that had led me to this latest revision for anyone curious enough to download and peruse (it's just a tad over half the size of the previous download).

author: Johnny B Good
author_rank: Frequent Contributor
timestamp: June 30, 2025, 03:25:28 pm
content: Just to let you know, the bootloader has nothing to do with the nano3's additional 3% consumption of program space.I did get around to successfully updating two of my old nano3s to the current bootloader (the third is currently running the temperature control algorithms in the RFS) using the AI's incomplete description of the updating process. I've attached this AI session so you can see what I mean.

author: Johnny B Good
author_rank: Frequent Contributor
timestamp: July 01, 2025, 03:43:25 am
content: I was monitoring the base plate one second averages and wondering how it was varying between the one milli-Kelvin steps of its current resolution. I decided to try adding an extra decimal place so I could observe it at a 100 micro-Kelvin step resolution.The results were a pleasant surprise as you can see from the 3 minute movie clip that I've attached along with the modified sketch.