{"id":3968,"date":"2025-03-06T13:22:40","date_gmt":"2025-03-06T18:22:40","guid":{"rendered":"https:\/\/www.yorku.ca\/professor\/drsmith\/?p=3968"},"modified":"2025-03-06T13:22:40","modified_gmt":"2025-03-06T18:22:40","slug":"writing-to-the-oled-with-firmata-and-firmata4j","status":"publish","type":"post","link":"https:\/\/www.yorku.ca\/professor\/drsmith\/2025\/03\/06\/writing-to-the-oled-with-firmata-and-firmata4j\/","title":{"rendered":"Writing to the OLED with Firmata and Firmata4j"},"content":{"rendered":"\n<p>While demonstrating the OLED display in class this week, I messed up the lesson -- twice -- because I forgot a really important detail: timing.  <\/p>\n\n\n\n<p>When putting information on the OLED display it's important to take into consideration timing.  But that timing is not always important to consider.  Where I messed up was in demonstrating the OLED display without refreshing it... just updating the value once and then exiting the program.  What happened in that case is that I didn't give the SSD1306 OLED controller sufficient time to fill the screen with information before the Firmata program ended... resulting in a glitched OLED display.<\/p>\n\n\n\n<p>You can see this in the following display, where I have the update-to-update time reduced to really small values (in the millisecond range).  The updates are fine.<\/p>\n\n\n\n<p>But, then, when I try to finish the program and apply the stop() method, I don't provide sufficient time for the SSD1306 to finish its work.  I gave it 200ms... that's not enough.  So a glitch occurs:<\/p>\n\n\n\n<figure class=\"wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-4-3 wp-has-aspect-ratio\"><div class=\"wp-block-embed__wrapper\">\n<iframe loading=\"lazy\" title=\"Firmata OLED Timing Glitch\" width=\"1333\" height=\"1000\" src=\"https:\/\/www.youtube.com\/embed\/3y_IXw-SckI?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" referrerpolicy=\"strict-origin-when-cross-origin\" allowfullscreen><\/iframe>\n<\/div><\/figure>\n\n\n\n<p>The trick is to extend that last delay to between 500 and 1000 ms.    Here's the code that shows the failure:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/* Project: Firmata_Demo_OLED_TimingFail\n *\n * Dependencies (via Maven) :\n *      JSSC 2.9.4\n *      Firmata4j 2.3.8\n *      SLF4J-JCL; 1.7.3\n *\n * Reference:\n *      1. https:\/\/www.yorku.ca\/professor\/drsmith\/2022\/02\/25\/easy-java-arduino-with-firmata\/\n *      2. https:\/\/youtu.be\/RVUjxVQkkh4?feature=shared\n *\n * Author: James Andrew Smith.  Date: March 6, 2025\n * --------------------------------------------------------------- *\/\n\npackage ca.yorku.eecs.eecs1021;\n\nimport org.firmata4j.I2CDevice;\nimport org.firmata4j.I2CListener;\nimport org.firmata4j.Pin;\nimport org.firmata4j.firmata.FirmataDevice;\nimport org.firmata4j.ssd1306.MonochromeCanvas;\nimport org.firmata4j.ssd1306.SSD1306;\n\nimport java.io.IOException;\nimport java.util.Random;\n\npublic class MainClass {\n\n    static final String USBPORT = \"\/dev\/cu.usbserial-0001\";\n    static final int POTA0 = 14;\n    static final int BUTTOND6 = 6;\n    static final byte OLEDI2Caddress = 0x3C;\n    static final int BUTTON_DOWN = 1;\n    static final int BUTTON_UP = 0;\n    static final int DRAWDELAY_SHORT = 200;\n    static final int DRAWDELAY_LONG = 800;\n    static final int DRAWDELAY_REALLY_LONG = 3000;\n\n    public static void main(String&#91;] args) throws IOException, InterruptedException {\n\n        var myArduino = new FirmataDevice(USBPORT);\n\n        myArduino.start();\n\n        myArduino.ensureInitializationIsDone();\n\n        \/* set up the pot and the button *\/\n        Pin myPot = myArduino.getPin(POTA0);\n        Pin myButton = myArduino.getPin(BUTTOND6); myButton.setMode(Pin.Mode.INPUT);\n\n        I2CDevice thei2ccomms =  myArduino.getI2CDevice((byte)0x3c);\n        SSD1306 myOled = new SSD1306(thei2ccomms, SSD1306.Size.SSD1306_128_64);\n        myOled.init();      \/\/ initialize the OLED.\n        myOled.clear();     \/\/ blank out the memory for hte controller.\n        Thread.sleep(DRAWDELAY_SHORT);   \/\/ Required to clear out the buffer properly.\n\n        myOled.getCanvas().setTextsize(1);\n        myOled.getCanvas().setCursor(0,10);\n        \/\/myOled.getCanvas().write(\"Hello\");\n        myOled.display();\n        Thread.sleep(DRAWDELAY_LONG);       \/\/ Required to ensure that the text gets placed correctly.\n\n\n        \/\/ loop as long as the button is not pressed down.\n        System.out.println(\"Printing nine values to the OLED...\");\n\n        for (int m = 1; m &lt;= 10; m++) {\n            int fraction_short_delay = (int)( ((float)DRAWDELAY_SHORT) \/ ((float)m));\n            System.out.println(\"Delay value of DRAWDELAY_SHORT divided by \" + m + \" = \" + fraction_short_delay + \" ms.\");\n\n            System.out.println(\"Printing five times....\");\n            for (int i = 0; i &lt; 5; i++) {\n\n                \/\/ Create 9 random numbers\n                int&#91;] randomNumbers = new Random().ints(9, 100, 1000).toArray();\n\n                for (int j = 0; j &lt; 3; j++) {\n                    for (int k = 0; k &lt; 3; k++) {\n                        myOled.getCanvas().setCursor(j * 50, k * 25);\n                        myOled.getCanvas().write(String.valueOf(randomNumbers&#91;j * 3 + k]));\n                    }\n                }\n\n\n                \/\/ Now that buffer is written, run the display() method &amp; wait\n                myOled.display();\n                Thread.sleep(fraction_short_delay);\n            }\n\n        }\n\n        \/\/ wait before exiting....\n        Thread.sleep(DRAWDELAY_SHORT);       \/\/ 200ms : this will glitch out.\n        \/\/Thread.sleep(DRAWDELAY_REALLY_LONG);       \/\/ 3000ms : this will result in no glitch\n\n\n        myArduino.stop();\n\n\n    }\n}\n\n\n\n<\/code><\/pre>\n\n\n\n<p>Now, if I set the last delay from 200 to 3000... or DRAWDELAY_SHORT to DRAWDELAY_REALLY_LONG, then it's okay.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"alignleft size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"128\" height=\"128\" src=\"https:\/\/www.yorku.ca\/professor\/drsmith\/wp-content\/uploads\/sites\/444\/2021\/12\/noun-signature-1720818-2.png\" alt=\"a pen\" class=\"wp-image-2116\"\/><\/figure>\n<\/div>\n\n\n<p>James Andrew Smith is a Professional Engineer and Associate Professor in the Electrical Engineering and Computer Science\u00a0<a href=\"http:\/\/eecs.lassonde.yorku.ca\">Department<\/a>\u00a0of York University\u2019s\u00a0<a href=\"http:\/\/lassonde.yorku.ca\">Lassonde School<\/a>, with degrees in Electrical and Mechanical Engineering\u00a0from the University of Alberta and McGill University.\u00a0\u00a0Previously a program director in biomedical engineering, his research background spans robotics, locomotion, human birth, music and\u00a0engineering\u00a0education. While on sabbatical in 2018-19 with his wife and kids he lived in Strasbourg, France and\u00a0he\u00a0taught at the\u00a0<a href=\"https:\/\/www.insa-strasbourg.fr\/en\/\">INSA Strasbourg<\/a>\u00a0and\u00a0<a href=\"https:\/\/www.hs-karlsruhe.de\">Hochschule Karlsruhe<\/a>\u00a0and wrote about his\u00a0<a href=\"https:\/\/twitter.com\/search?q=(%23sabbaticallife)%20(from%3Aonnimikki)&amp;src=typed_query\">personal<\/a>\u00a0and\u00a0<a href=\"https:\/\/twitter.com\/search?q=insa%20(from%3Ajasmith_yorku)&amp;src=typed_query\">professional\u00a0<\/a><a href=\"https:\/\/twitter.com\/search?q=karlsruhe%20(from%3Ajasmith_yorku)&amp;src=typed_query\">perspectives<\/a>.\u00a0\u00a0James is a proponent of using social media to advocate for justice, equity, diversity and inclusion as well as evidence-based applications of research\u00a0in the public sphere.\u00a0<s>You can find him on\u00a0Twitter.\u00a0\u00a0<\/s>You can find him on\u00a0<a href=\"https:\/\/bsky.app\/profile\/drsmith.bsky.social\">BlueSky<\/a>. Originally from Qu\u00e9bec City, he now lives in Toronto, Canada.\u00a0<\/p>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>While demonstrating the OLED display in class this week, I messed up the lesson -- twice -- because I forgot a really important detail: timing. When putting information on the OLED display it's important to take into consideration timing. But that timing is not always important to consider. Where I messed up was in demonstrating [&hellip;]<\/p>\n","protected":false},"author":762,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_kad_blocks_custom_css":"","_kad_blocks_head_custom_js":"","_kad_blocks_body_custom_js":"","_kad_blocks_footer_custom_js":"","footnotes":""},"categories":[42],"tags":[10,403,610,164],"class_list":["post-3968","post","type-post","status-publish","format-standard","hentry","category-arduino","tag-arduino","tag-firmata","tag-firmata4j","tag-java"],"taxonomy_info":{"category":[{"value":42,"label":"arduino"}],"post_tag":[{"value":10,"label":"arduino"},{"value":403,"label":"firmata"},{"value":610,"label":"firmata4j"},{"value":164,"label":"java"}]},"featured_image_src_large":false,"author_info":{"display_name":"drsmith","author_link":"https:\/\/www.yorku.ca\/professor\/drsmith\/author\/drsmith\/"},"comment_info":"","category_info":[{"term_id":42,"name":"arduino","slug":"arduino","term_group":0,"term_taxonomy_id":42,"taxonomy":"category","description":"","parent":0,"count":30,"filter":"raw","cat_ID":42,"category_count":30,"category_description":"","cat_name":"arduino","category_nicename":"arduino","category_parent":0}],"tag_info":[{"term_id":10,"name":"arduino","slug":"arduino","term_group":0,"term_taxonomy_id":10,"taxonomy":"post_tag","description":"","parent":0,"count":17,"filter":"raw"},{"term_id":403,"name":"firmata","slug":"firmata","term_group":0,"term_taxonomy_id":403,"taxonomy":"post_tag","description":"","parent":0,"count":7,"filter":"raw"},{"term_id":610,"name":"firmata4j","slug":"firmata4j","term_group":0,"term_taxonomy_id":610,"taxonomy":"post_tag","description":"","parent":0,"count":5,"filter":"raw"},{"term_id":164,"name":"java","slug":"java","term_group":0,"term_taxonomy_id":164,"taxonomy":"post_tag","description":"","parent":0,"count":10,"filter":"raw"}],"_links":{"self":[{"href":"https:\/\/www.yorku.ca\/professor\/drsmith\/wp-json\/wp\/v2\/posts\/3968","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.yorku.ca\/professor\/drsmith\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.yorku.ca\/professor\/drsmith\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.yorku.ca\/professor\/drsmith\/wp-json\/wp\/v2\/users\/762"}],"replies":[{"embeddable":true,"href":"https:\/\/www.yorku.ca\/professor\/drsmith\/wp-json\/wp\/v2\/comments?post=3968"}],"version-history":[{"count":1,"href":"https:\/\/www.yorku.ca\/professor\/drsmith\/wp-json\/wp\/v2\/posts\/3968\/revisions"}],"predecessor-version":[{"id":3969,"href":"https:\/\/www.yorku.ca\/professor\/drsmith\/wp-json\/wp\/v2\/posts\/3968\/revisions\/3969"}],"wp:attachment":[{"href":"https:\/\/www.yorku.ca\/professor\/drsmith\/wp-json\/wp\/v2\/media?parent=3968"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.yorku.ca\/professor\/drsmith\/wp-json\/wp\/v2\/categories?post=3968"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.yorku.ca\/professor\/drsmith\/wp-json\/wp\/v2\/tags?post=3968"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}