IOIO: TwiMaster.write() with an array as parameter
Joe7M opened this issue · 8 comments
I want to use TWI write with an array (Framebuffer of an oled display). A program could look like this:
dim buffer(16)
for ii = 0 to 16
buffer[ii] = ii
next
TWI.write(ADDRESS, buffer)
I modified TwiMasterImpl.java to get some debug output (sorry, no idea how to debug java):
public void write(int address, final byte[] write, int len) {
handleError();
lock.invoke((i) -> {
for(int ii=0; ii< write.length ; ii++) {
System.out.print(write[ii] +" ");
}
System.out.println("len = " + len);
System.out.println();
twiMaster.writeRead(address, false, write, len, null, 0);
});
}
When I run the program, I will get the following output: 0 1 2 3 4 5 6 7 8 9 len = 1
Problems:
lenis always the number of arguments - 1, not the length of the array. There is now way to give 'len' as a parameter.- the array has only 10 elements, not 16 as defined
The problem was related to a fixed sized array used for the java native interface (JNI). I've increased this to 32 elements. There is now also an error if this is exceeded. Let me know if 32 is a reasonable value. I've also changed SPI.write to also take an array argument.
Btw, here's some rough notes on debugging with intellij
- Open the
ioio/ioio/pom.xmlto create a project - Don't allow intellij to process the gradle build script - these are used for the android build
- either configure the c/module project with --with-debug or change include/javaproxy.h to
vm_args.nOptions = 6; - create an intellij debug config to listen on localhost/5005
- run your SB code, then start the intellij debugger
oops - still not quite right. address is a separate field/concept in TWI, but not for SPI. I will make some more changes.
I tested a little bit the TWI implementation. The OLED display SSD1306 seem to work now. I can transfer 32 bytes in one go, which speeds up the display refresh a lot compared to single pixel transfer. I'm want to use the canvas unit to draw on the display. For this I have to figure out how to convert the framebuffer of canvas to the 1bit pixel representation of the OLED framebuffer.
You asked if 32 is a reasonable value. If I can have a wish, I would like to have much larger values. For example the framebuffer array of the I2C OLED has 1024 bytes. The SPI TFT display SD7789 has in total 240x240 pixels with 16bit per pixel. I haven't tried yet, but transferring this amount of data will (even with 32 bytes in one go) take a long time. I don't know how complicate it will be to implement this. Could be, that driving SPI displays with IOIO is not a good idea.
I've changed the buffer to 1024 bytes. I don't think this will matter too much for memory usage etc.
I've made a few more commits to the SPI APIs. Hopefully this doesn't break anything for you.
I will try to get my st7735s to display something, then I can use java profiling tools to see if there's anything else to address performance.
I realized, that for I2C (TWI) buffers larger than 115 don't work. I always get a timeout error. But I think it is a problem of IOIO and not your code. In the end I used a 33 bytes buffer (1 command and 32 bytes of framebuffer) to transfer the data in chunks to the display, because with larger buffers, the transfer time gets surprisingly longer.
I found one bug: twi.write(add, register, array) doesn't work. I think that just the first element of the array is transferred. My workaround was, that the first element of the array is the register (or command in the case of the oled) followed by the data: twi.write(add, array)
The ioio.TwiMaster.writeRead interface doesn't actually have a separate register field so I thought this abstraction should be extended to the SB API. It's all just data arrays for reading and writing.
Here's something to try to speed up the LCD performance:
Change TimerUtil.tick to this:
public static long tick(long lastAccessMillis) throws InterruptedException {
Thread.sleep(0, 10);
}
The multi-thread handling doesn't seem to work without some very short sleep here. This improved my st7735s experiments but not sure if it breaks anything else.
Another thing to try: https://visualvm.github.io/
You can attach this to the running JVM without any special setup and then watch thread handling/performance.
Some other things I tried but without much difference in display time:
- SerialPortIOIOConnection setBaudRate
- Different values for SpiMaster.Rate.RATE_1M
Maybe you'll spot something I missed.