• Hardware
  • is anyone successfully using i2c OLED / LCD?

Good news - I've got an application running that can run independently from PD or SC, that translates incoming OSC messages into SSD1306 display commands.

I've been heavily inspired by this conversation: https://forum.bela.io/d/497-how-do-i-get-two-programs-running-at-the-same-time

Also I've read elsewhere on the forum that for starting up a second/background application like this, it should be possible to use a self-made run.sh script in the project directory.

Two questions now that I'm having a challenge figuring out:
- in run.sh, after starting up the OSC->OLED application, how do I resume the normal Run procedure for a PD or SC project?
- is there a similar way to end/kill the application that is triggered by the Stop button in the IDE interface?

    Hey @crosswick & @giuliomoro

    Trying to get an OLED display to work based on the repo @giuliomoro posted in reply #30 (https://github.com/giuliomoro/bela-ssd1306) and I'm actually getting the following warnings and a runide error:

    Build finished
    In file SSD1306_OLED.c: [warning] passing 'const unsigned char *' to parameter of type 'const char *' converts between pointers to integer types with different sign [-Wpointer-sign] column: 33, line: 2419
    In file SSD1306_OLED.c: [warning] passing 'char [3]' to parameter of type 'const unsigned char *' converts between pointers to integer types with different sign [-Wpointer-sign] column: 22, line: 2430
    In file SSD1306_OLED.c: [warning] passing 'const unsigned char *' to parameter of type 'const char *' converts between pointers to integer types with different sign [-Wpointer-sign] column: 30, line: 2442
    In file SSD1306_OLED.c: [warning] passing 'char [3]' to parameter of type 'const unsigned char *' converts between pointers to integer types with different sign [-Wpointer-sign] column: 20, line: 2443
    In file SSD1306_OLED.c: [warning] passing 'char *' to parameter of type 'const unsigned char *' converts between pointers to integer types with different sign [-Wpointer-sign] column: 22, line: 2479
    In file SSD1306_OLED.c: [warning] passing 'char [4]' to parameter of type 'const unsigned char *' converts between pointers to integer types with different sign [-Wpointer-sign] column: 26, line: 2657
    In file SSD1306_OLED.c: [warning] passing 'char [4]' to parameter of type 'const unsigned char *' converts between pointers to integer types with different sign [-Wpointer-sign] column: 26, line: 2659
    In file SSD1306_OLED.c: [warning] passing 'char [4]' to parameter of type 'const unsigned char *' converts between pointers to integer types with different sign [-Wpointer-sign] column: 26, line: 2661
    In file SSD1306_OLED.c: [warning] passing 'char [4]' to parameter of type 'const unsigned char *' converts between pointers to integer types with different sign [-Wpointer-sign] column: 26, line: 2663
    In file SSD1306_OLED.c: [warning] passing 'char [2]' to parameter of type 'const unsigned char *' converts between pointers to integer types with different sign [-Wpointer-sign] column: 24, line: 2686
    In file example_app.c: [warning] passing 'char [7]' to parameter of type 'const unsigned char *' converts between pointers to integer types with different sign [-Wpointer-sign] column: 15, line: 261
    In file example_app.c: [warning] passing 'char [14]' to parameter of type 'const unsigned char *' converts between pointers to integer types with different sign [-Wpointer-sign] column: 15, line: 286
    In file example_app.c: [warning] passing 'char [3]' to parameter of type 'const unsigned char *' converts between pointers to integer types with different sign [-Wpointer-sign] column: 15, line: 293
    In file example_app.c: [warning] passing 'char [19]' to parameter of type 'const unsigned char *' converts between pointers to integer types with different sign [-Wpointer-sign] column: 17, line: 377
    In file example_app.c: [warning] passing 'char [21]' to parameter of type 'const unsigned char *' converts between pointers to integer types with different sign [-Wpointer-sign] column: 17, line: 379
    In file example_app.c: [warning] passing 'char [10]' to parameter of type 'const unsigned char *' converts between pointers to integer types with different sign [-Wpointer-sign] column: 17, line: 382
    /root/Bela/projects/bela-ssd1306/SSD1306_OLED.c:2419:33: warning: passing 'const unsigned char *' to parameter of type 'const char *' converts between pointers to integer types with different sign [-Wpointer-sign]    
         return print(strPtr, strlen(strPtr));                                
                      ^~~~~~
    /usr/include/string.h:394:35: note: passing argument to parameter '__s' here
    extern size_t strlen (const char *__s)
                                     ^
    /root/Bela/projects/bela-ssd1306/SSD1306_OLED.c:2430:22: warning: passing 'char [3]' to parameter of type 'const unsigned char *' converts between pointers to integer types with different sign [-Wpointer-sign]
    return print_str("\r\n");                     
                     ^~~~~~
    /root/Bela/projects/bela-ssd1306/SSD1306_OLED.c:2417:38: note: passing argument to parameter 'strPtr' here
    short print_str(const unsigned char *strPtr)                                     
                                        ^
    /root/Bela/projects/bela-ssd1306/SSD1306_OLED.c:2442:30: warning: passing 'const unsigned char *' to parameter of type 'const char *' converts between pointers to integer types with different sign [-Wpointer-sign]    
    n = print(strPtr, strlen(strPtr));                             
              ^~~~~~
    /usr/include/string.h:394:35: note: passing argument to parameter '__s' here
    extern size_t strlen (const char *__s)                                 
                                     ^
    /root/Bela/projects/bela-ssd1306/SSD1306_OLED.c:2443:20: warning: passing 'char [3]' to parameter of type 'const unsigned char *' converts between pointers to integer types with different sign [-Wpointer-sign]
     n += print_str("\r\n");
                    ^~~~~~
    /root/Bela/projects/bela-ssd1306/SSD1306_OLED.c:2417:38: note: passing argument to parameter 'strPtr' here
    short print_str(const unsigned char *strPtr)
                                        ^
    /root/Bela/projects/bela-ssd1306/SSD1306_OLED.c:2479:22: warning: passing 'char *' to parameter of type 'const unsigned char *' converts between pointers to integer types with different sign [-Wpointer-sign]
    return print_str(str);
                     ^~~
    /root/Bela/projects/bela-ssd1306/SSD1306_OLED.c:2417:38: note: passing argument to parameter 'strPtr' here
    short print_str(const unsigned char *strPtr)
                                        ^
    /root/Bela/projects/bela-ssd1306/SSD1306_OLED.c:2657:26: warning: passing 'char [4]' to parameter of type 'const unsigned char *' converts between pointers to integer types with different sign [-Wpointer-sign]
    return print_str("nan");
    ^~~~~
    /root/Bela/projects/bela-ssd1306/SSD1306_OLED.c:2417:38: note: passing argument to parameter 'strPtr' here
    short print_str(const unsigned char *strPtr)                                     
                                        ^
    /root/Bela/projects/bela-ssd1306/SSD1306_OLED.c:2659:26: warning: passing 'char [4]' to parameter of type 'const unsigned char *' converts between pointers to integer types with different sign [-Wpointer-sign]
    return print_str("inf");                         
                     ^~~~~
    /root/Bela/projects/bela-ssd1306/SSD1306_OLED.c:2417:38: note: passing argument to parameter 'strPtr' here
    short print_str(const unsigned char *strPtr)
                                        ^
    /root/Bela/projects/bela-ssd1306/SSD1306_OLED.c:2661:26: warning: passing 'char [4]' to parameter of type 'const unsigned char *' converts between pointers to integer types with different sign [-Wpointer-sign]
    return print_str("ovf");  // constant determined empirically
                     ^~~~~
    /root/Bela/projects/bela-ssd1306/SSD1306_OLED.c:2417:38: note: passing argument to parameter 'strPtr' here
    short print_str(const unsigned char *strPtr)
                                        ^
    /root/Bela/projects/bela-ssd1306/SSD1306_OLED.c:2663:26: warning: passing 'char [4]' to parameter of type 'const unsigned char *' converts between pointers to integer types with different sign [-Wpointer-sign]
    return print_str("ovf");  // constant determined empirically
                     ^~~~~
    /root/Bela/projects/bela-ssd1306/SSD1306_OLED.c:2417:38: note: passing argument to parameter 'strPtr' here
    short print_str(const unsigned char *strPtr)
                                        ^
    /root/Bela/projects/bela-ssd1306/SSD1306_OLED.c:2686:24: warning: passing 'char [2]' to parameter of type 'const unsigned char *' converts between pointers to integer types with different sign [-Wpointer-sign]
    n += print_str(".");
                   ^~~
    /root/Bela/projects/bela-ssd1306/SSD1306_OLED.c:2417:38: note: passing argument to parameter 'strPtr' here
    short print_str(const unsigned char *strPtr)
                                        ^
    10 warnings generated.
    /root/Bela/projects/bela-ssd1306/example_app.c:261:15: warning: passing 'char [7]' to parameter of type 'const unsigned char *' converts between pointers to integer types with different sign [-Wpointer-sign]    
    print_str("scroll");
              ^~~~~~~~
    /root/Bela/projects/bela-ssd1306/SSD1306_OLED.h:172:45: note: passing argument to parameter 'strPtr' here
    extern short print_str(const unsigned char *strPtr); 
                                               ^
    /root/Bela/projects/bela-ssd1306/example_app.c:286:15: warning: passing 'char [14]' to parameter of type 'const unsigned char *' converts between pointers to integer types with different sign [-Wpointer-sign]    
    print_str("HELLO FELLAS!");
              ^~~~~~~~~~~~~~~
    /root/Bela/projects/bela-ssd1306/SSD1306_OLED.h:172:45: note: passing argument to parameter 'strPtr' here
    extern short print_str(const unsigned char *strPtr);
                                               ^
    /root/Bela/projects/bela-ssd1306/example_app.c:293:15: warning: passing 'char [3]' to parameter of type 'const unsigned char *' converts between pointers to integer types with different sign [-Wpointer-sign]
    print_str("0x");
              ^~~~
    /root/Bela/projects/bela-ssd1306/SSD1306_OLED.h:172:45: note: passing argument to parameter 'strPtr' here
    extern short print_str(const unsigned char *strPtr);
                                               ^
    /root/Bela/projects/bela-ssd1306/example_app.c:377:17: warning: passing 'char [19]' to parameter of type 'const unsigned char *' converts between pointers to integer types with different sign [-Wpointer-sign]    
    print_strln("deeplyembedded.org"); 
                ^~~~~~~~~~~~~~~~~~~~
    /root/Bela/projects/bela-ssd1306/SSD1306_OLED.h:174:47: note: passing argument to parameter 'strPtr' here
    extern short print_strln(const unsigned char *strPtr);
                                                 ^
    /root/Bela/projects/bela-ssd1306/example_app.c:379:17: warning: passing 'char [21]' to parameter of type 'const unsigned char *' converts between pointers to integer types with different sign [-Wpointer-sign]    
    print_strln("Author:Vinay Divakar");
                ^~~~~~~~~~~~~~~~~~~~~~
    /root/Bela/projects/bela-ssd1306/SSD1306_OLED.h:174:47: note: passing argument to parameter 'strPtr' here
    extern short print_strln(const unsigned char *strPtr);
                                                 ^
    /root/Bela/projects/bela-ssd1306/example_app.c:382:17: warning: passing 'char [10]' to parameter of type 'const unsigned char *' converts between pointers to integer types with different sign [-Wpointer-sign]    
    print_strln("THANK YOU");
                ^~~~~~~~~~~
    /root/Bela/projects/bela-ssd1306/SSD1306_OLED.h:174:47: note: passing argument to parameter 'strPtr' here
    extern short print_strln(const unsigned char *strPtr);                                             
                                                 ^
    6 warnings generated.
    Running project...
    (Main)i2c-2: Bus Connected to SSD1306
    Makefile:524: recipe for target 'runide' failed
    make: *** [runide] Error 1

    I also want to just confirm the correct pin connections and I2C bus to be using when using the files in the repo linked above. It seemed at the beginning of the thread that it made most sense to connect to the I2C1 bus, but I noticed in the terminal that it says "(Main)i2c-2: Bus Connected to SSD1306" - so I'm also wondering whether I'm connecting to the wrong bus.

    My breadboard is currently set up with a Bela Mini like this:

    Ground: P2_21
    VIN: P2_23
    SCL: P2_9
    SDA: P2_11

    Is this correct? Or should I be using I2C2? i.e.:
    Ground: P2_21
    VIN: P2_23
    SCL: P1_26
    SDA: P1_28

    Per @crosswick's note concerning the RST pin - I'm using the circuit noted here:
    http://community.axoloti.com/t/spi-i2c-oled-display/638/187

    Specifically - I've got a 10k resistor connected to the 3.3V rail, a 68nf cap connected to ground - I'm running a wire at the junction point on the terminal strip where the 10k resistor meets the 68nf cap to another terminal strip where a 100k resistor is tied to ground and I have a wire from that strip connected to the RST pin.

    Is this the correct way to deal with the RST pin? I've seen other examples where RST is connected to a GPIO pin - but there doesn't appear to be an RST pin noted in the code anywhere and it isn't mentioned in this thread explicitly either.

    Just trying to get this example code running so I can move on to some more fun visuals!

    Hi @kreiff, I also got those errors. It was explained to me by a buddy that this SSD1306 C library does things with unsigned chars which are not permitted in C++. There's apparently several different ways of solving this, amongst which macros - I solved it by editing the SSD1306_OLED.c and -.h files by simply removing the 'unsigned' bit in the relevant places.

    As far as the pinouts, I'm using the same you mention with P2_9 and P2_11.

    Here's a picture of my RST pin setup: (I'm using a dedicated I2S display now btw)

    alt text

      @crosswick - Thanks for the quick reply!

      crosswick As far as the pinouts, I'm using the same you mention with P2_9 and P2_11.

      Thanks for confirming!

      crosswick Here's a picture of my RST pin setup: (I'm using a dedicated I2S display now btw)

      It's a little hard to see the connections - but this looks to be how the RST pin is set up on my breadboard.

      crosswick I solved it by editing the SSD1306_OLED.c and -.h files by simply removing the 'unsigned' bit in the relevant places.

      I tried using your approach from post 32 and downloaded your github repo. I also went through and removed the unsigned pre-cursors on the variables across the files. If I try running via SSH I do get this line in the terminal:

      (Main)i2c-1: Bus Connected to SSD1306

      But I don't have any output on the OLED...

      Alternatively - if I try running the render.cpp - I still get a ton of errors and the same runide error:

      Makefile:524: recipe for target 'runide' failed
      make: *** [runide] Error 1

      @giuliomoro - What is runide Error 1?

        kreiff looks to me like there's something wrong with the physical connection to the display - that's when I get that runide error. I would suggest that you get a (bunch of, they're really cheap) I2C-only versions of this SSD1306 display to be sure.

        BTW like you've probably already seen, the unsigned-alteration is not yet in my github repo.

          @kreiff can you run i2cdetect -y -r 1 ? Does the display show up at the expected address?

          Thew runide failed message is a general message that the program stopped with an error

          crosswick looks to me like there's something wrong with the physical connection to the display - that's when I get that runide error. I would suggest that you get a (bunch of, they're really cheap) I2C-only versions of this SSD1306 display to be sure.

          I came to this conclusion last night as well. I think my OLED is dead. It was from Adafruit - so I figured I would just test their arduino library code to rule out the screen itself being bad...and that looks like the culprit. It doesn't even flicker following the Adafruit instructions exactly...

          I bought a two pack of I2C-only (4-pin / no reset) OLEDs from Amazon - so I'll give this another go when they arrive.

          @crosswick Sorry to be hanging on your coat tails with this - but any luck resolving the latency issue?

          I'm trying to get an Axoloti style minimal oscilliscope working - and I'm getting a ton of latency even just sending the values straight from PD. It's like the OSC messages start piling up and it ends up getting like 30 seconds behind drawing the waveshape.

          I'm wondering whether I2C is just too slow? Or if it's something to do with the driver. I've noticed that even the "demo" animation draws about twice as fast using the Adafruit library vs. the Deeply Embedded one. (granted - this is an Arduino Due running the adafruit library vs. Bela running the DE one - so not apples-to-apples - but I would expect Bela / PocketBeagle to be faster).

            crosswick Can you confirm that sending data from an external computer gives way less latency?

            Unfortunately, I'm actually experiencing the latency even sending directly from my computer. I haven't tried running the OLED code in the background yet. It might be the application though - just that I2C is too slow for an oscilloscope. Might have to find an SPI driver that I can adapt...

            I saw Paul E Long's thread (https://forum.bela.io/d/978-using-an-oled-128x128-rgb-with-belamini/35) using that nice looking RGB OLED screen - but I couldn't get his code to work and it seems like his application was using an LCD and OLED simultaneously and he was doing some GPIO voodoo to get it working.

            Honestly, I might have to wait until Giulio and the Bela team implement some native OLED drivers for SPI. My knowledge of hardware pin management / bit banging is pretty limited and I've struck out adapting all of the rPi and Arduino libraries to PocketBeagle so far.

              kreiff I'm wondering whether I2C is just too slow? Or if it's something to do with the driver. I've noticed that even the "demo" animation draws about twice as fast using the Adafruit library vs. the Deeply Embedded one.

              We came across an SPI library for a similar display here, where the library was written so badly that it was wasting a lot of time by writing one single word per transaction. Speed improved greatly when editing the library to write several words in a row. Maybe you have a similar case here. What library are code are using exactly?

              Late reply:

              crosswick Two questions now that I'm having a challenge figuring out:
              - in run.sh, after starting up the OSC->OLED application, how do I resume the normal Run procedure for a PD or SC project?

              When you do that, it's all up to you. You have to call it manually. Run the program (without run.sh) once adding AT= to the Make options in the IDE. You will then see the actual line that is called to run the program. You could copy that into your run.sh if that helps.

              crosswick > - is there a similar way to end/kill the application that is triggered by the Stop button in the IDE interface?

              The stop button will kill make stop, but that in turn does nothing with run.sh. I guess it would be a good idea if it did that. We can work on it, if you are interested?

                kreiff Honestly, I might have to wait until Giulio and the Bela team implement some native OLED drivers for SPI. My knowledge of hardware pin management / bit banging is pretty limited and I've struck out adapting all of the rPi and Arduino libraries to PocketBeagle so far.

                Happy to help, but I got a bit lost in the thread. Where are you at now exactly? Where is your code?

                kreiff just that I2C is too slow for an oscilloscope.

                You may have your I2c speed slower than it could be. Which I2c channel are you using?

                @giuliomoro - Sorry for the delayed reply - and thanks, as always, for offering to help!

                I've got my current code at the following github repo:
                https://github.com/kreiff/Bela_OLED

                I'm using the same library that @crosswick posted above. All the files are tagged with Vinay Divakar's name - his website is called "www.deeplyembedded.org" - so I was referring to it above as the "Deeply Embedded" library.

                I'm using I2C1 on a Bela Mini (p2.9 - SCL, p2.11 - SDA).

                I have shamelessly stolen @crosswick's OSC code for Pure Data and manipulated it so that rather than filling in a rectangle from left to right based on the value sent from Pure Data - the code plots pixels from left to right.

                My end goal is to essentially recreate a "tabwrite" style oscilloscope for Pure Data patches that I create so I can see more complex modulation wave shapes - (I've been experimenting with wave folding and wavetable based modulation - but I don't often remember the actual wave shapes in the table as I'm changing the parameters)

                As I described above - my current code isn't particularly practical - as the latency to the screen is so severe that it often takes 30 seconds to display parameter changes.

                Would love any ideas for improving the latency or getting something more akin to a pure data "tabwrite" oscilliscope working on the OLED.

                  kreiff I'm using I2C1 on a Bela Mini (p2.9 - SCL, p2.11 - SDA).

                  A good starting point for performance improvement is to edit the file in/opt/bb.org-overlays/src/arm/BB-BELA-00A1.dts and replace the 1 with a 4 in the line that says

                   clock-frequency = <100000>;

                  . Then run

                  rm -rf /opt/bb.org-overlays/src/arm/BB-BELA-00A1.dtbo && make -C /opt/bb.org-overlays/ && make -C /opt/bb.org-overlays/ install

                  to compile it and reboot the board to apply the changes.
                  This will increase the clock speed of the i2c bus from 100kHz to 400kHz. I don' t think this will by itself fix your performance issues, but it should help a bit.

                  I will have a look at the rest more in detail tomorrow.

                    Hi again - sorry for the late reaction, I see that my forum notification settings were different than I thought.

                    giuliomoro The stop button will kill make stop, but that in turn does nothing with run.sh. I guess it would be a good idea if it did that. We can work on it, if you are interested?

                    Well... if it's not too much work... it seems that it would be nice to have a nice/clean method to run & stop 'background' apps like a OSC-driven display. Maybe you know better ways of approaching this general case.

                    BTW in terms of using a specific library for driving displays... I've been looking at u8g2, which seems fitting for several types of monochrome displays over I2C or SPI. It hasn't been ported to Beaglebone yet by the looks of it: https://github.com/olikraus/u8g2/wiki/Porting-to-new-MCU-platform

                      crosswick Well... if it's not too much work... it seems that it would be nice to have a nice/clean method to run & stop 'background' apps like a OSC-driven display. Maybe you know better ways of approaching this general case.

                      The best way is normally to have this process run as systemd service, and run the whole time in the background. The process would have to be "clever" and do not consume unneeded CPU when the Bela program is not running . To set up a systemd service you can follow one of the many tutorials available online. What I would normally do is use one of the existing Bela services as a template. For instance, /lib/systemd/system/bela_ide.service (see source here). You can do

                      cp /lib/systemd/system/bela_ide.service /lib/systemd/system/custom_program.service

                      then edit the file /lib/systemd/system/custom_program.service as needed. You would most likely only need to edit the Description, ExecStart and WorkingDirectory fields.

                      Then you can start it on demand with

                      systemctl start custom_program

                      (use stop instead of start to stop it).
                      Enable it to run automatically at startup with

                      systemctl enable custom_program

                      (use disable instead of enable to disable it).

                      crosswick BTW in terms of using a specific library for driving displays... I've been looking at u8g2, which seems fitting for several types of monochrome displays over I2C or SPI. It hasn't been ported to Beaglebone yet by the looks of it: https://github.com/olikraus/u8g2/wiki/Porting-to-new-MCU-platform

                      There is not much that is BeagleBone-specific, so the "ARM Linux" version should work: https://github.com/wuhanstudio/u8g2-arm-linux

                      Ah yes I was already looking into systemd mechanics for another project, thanks for the suggestion and explanation.

                      Also I will take a shot at compiling u8g2-arm-linux on the Bela, thanks.

                      giuliomoro This will increase the clock speed of the i2c bus from 100kHz to 400kHz. I don' t think this will by itself fix your performance issues, but it should help a bit.

                      Hi @giuliomoro - Made the updates as you detailed. It definitely sped it up! But you're right not quite enough to work for my application.

                      Any other thoughts on improvements? Is the library itself inefficiently displaying each pixel? What improvements could be made to more efficiently write to the screen?

                      I can get changes to reflect within 5 seconds after initially starting up the program, but after 1-2 minutes of it running the latency balloons to 30 seconds and then 1 minute, and so on.

                      Sorry, been a busy week.

                      This (reformatted from your code for improved readability) looks inefficient:

                      	clearDisplay();
                      ....
                      	if (msg.match("/param1").popFloat(floatArg).isOkNoMoreArgs())
                      	{
                      		i++;
                      		j=i;
                      		arrayWidth[i] = floatArg*100;
                      		for(j;j--;j<0)
                      			drawPixel(j, arrayWidth[j], WHITE);
                      		Display();
                      		if(i>127)
                      			i = 0;
                      	}

                      First off, the line for(j;j--;j<0) looks extremely confusing. the j and j<0 expressions are actually unused, It is the equivalent to while(j--), but the latter is actually readable.

                      As far as I understand, in this loop you are drawing all the pixels up to the current index, which means that when i=0 you will only have one pixel displayed. As i increases (as more messages come in), you will progressively fill up the screen, until i reaches 127 (end of the display), at which point you will see the waveform covering the whole display horizontally, and then it restarts. Not sure why you'd want this behaviour.

                      As for performance, for each message that comes in you are calling clearDisplay() (once), drawPixel()(several times), Display() (once). I had a quick look at the content of the SSD13306_OLED.c file. It seems that the library keeps track internally of the value of each pixel on the display, and calls to clearDisplay() or drawPixel() only change this internal representation, therefore they are relatively cheap to call. Display(), however, transmits the whole buffer to the display, and this is the real bottleneck: regardless of how many pixels you changed since the last time you called Display(), calling it will always take the same time. Your messages are coming in about 43 times a second*, and you are therefore asking the display to redraw 43 times a second. This is a very high frame rate for this sort of display. The transfer() function in the SSD13306 library is the one that is actually performing the data transmission, and it looks like it is transmitting 1024bytes=8192bits **. With a clock of 400kHz, this takes at least 8192/400000 = 20ms, giving - if I got the numbers right - a theoretical frame rate of 50Hz, however this number is likely to be much smaller because of overhead involved in I2c transfers.

                      One solution here would be to reduce the frame rate by not calling Display() for every new pixel. The easiest approach (which will also save some CPU by reducing the number of OSC messages to process), would be not to send this many messages each containing one pixel, but rather as a pack of at least 4 pixels per message, though ideally I would send the whole display at one time. This way you would only call Display() when you have a handful of pixels or even a full display to draw. When sending such large buffers you may want to send OSC messages as blob instead of float. Either way, drawing the display less often is going to be a big advantage.

                      Another way to increase the speed is trying to boost the clock of the I2c bus even further. It is unclear to me what the specified max frequency supported by the display is, and it may well vary between different specimens, as pointed out by a comment in the Adafruit library for Arduino, but it seems that it could possibly reach 1MHz or beyond. So you can try and amend the .dts file as you have already done and change the frequency to 1000000 (follow procedure above). This is 1MHz, which is the maximum speed supported by the Bela side. Try to run the display like that and see if it works reliably. This would give about a 2.5x speed increase, allowing much faster transfer rates. Still, I'd encourage you to try out the approach above to throttle the number of times you are calling Display(), as that would also reduce the CPU load.

                      Note: there may be ways of updating exactly one pixel in the display, without redrawing the whole screen, which would be significantly faster, but it doesn't look like neither the DeeplyEmbedded nor the Adafruit libraries support them.

                      * the[env~] object will send out a new message every 1024 samples; assuming that Pd running on the host has a sampling rate of 44100Hz, that is 43 messages per second.

                      ** there are actually more than these many bits, because of the START, STOP and ACK bits. The numbers I mention are therefore optimistic, also because there are actually 1024/16=64 calls to i2c_multiple_writes() (and consequently to write()), each of which comes with its own overhead.