High frequency GPIO-output from Raspberry Pi 3 using Java

177 views Asked by At

I create for a firma a java game using LibGDX. It will run on a Raspberry Pi 3. It is a clone of a famous arcade cabinet. The game is ready. The joystick control using a port of the evdev library works well. The application will use Pi4j library for interaction with external devices like a coin acceptor, a serial LED-chain based on a chip WS2812 and a 7-segments LED display. But the control of the serial LED-chain has troubles. The LED-chain needs to have a high frequency serial impulses. The control impulses must be between 500 and 1500 nanoseconds long to transfer the data. I have launched a simple test for pin GPIO26 to know the typical frequency of the GPIO-outputs:

long end;
long start = System.nanoTime();
for (int i =0; i++; i<10000){
     ledPin.high();
     ledPin.low();
}
end = System.nanoTime();
double statementChangingTime = (double)(end - start)/(10000*2);

I have got that the time between the statement changings is between 3500 - 9000 nanoseconds. It is too long.

I want to know, is it possible to increase the frequency (make the statementChangingTime smaller) using Pi4J? Maybe I need to select an another pin? Maybe I need change something in the raspi-config? Maybe I can use an another library? I don't know C/C++ and can not write myself a low-level code and a Java-wrapper for it.

1

There are 1 answers

1
Thomas Kläger On

The pi4j library has different code examples. One of them (LED Strip example) seems like the perfect match for your problem.

Generating the required timing for the WS2812 chips with switching a GPIO pin to high / low at the required rate is difficult even when working in C and probably almost impossible when working in Java.

The example from pi4j uses the SPI interface to accurately generate the required timing. (Note that the approach taken is different from the one in the elektormagazine that you linked in a comment.)

The bit timing for the SPI is set to a basic rate of around 156ns per bit and the data for the WS28xx is produced as follows:

  • a 0 bit for the WS2812 (350ns high followed by 900ns low) is written as 0b1100_0000 (2 bits high -> 312ns, 6 bits low -> 936ns)
  • a 1 bit for the WS2812 (900ns high followed by 350ns low) is written as 0xb1111_1000 (5 bits high -> 780ns, 3 bits low -> 468ns low)

The timing this produces is well within the specified limits of the WS28xx chips.

The example takes the RGB codes for all configured chips and creates a byte array where each byte corresponds to one output bit. These bytes are then sent out through the MOSI pin, thereby creating the required waveform.

Note that the driver sends these bytes back-to-back by using the integrated FIFO of the SPI (it keeps that FIFO full for as long as there is some data available for sending).


You are correct in noticing that using a GPIO directly and using the CPU to create the required waveform would allow you to basically send an unlimited length bit stream.

However doing so can prove tricky if you want to

  • produce the data on the fly (using loops and if/else)
  • produce an accurate waveform without to much jitter

And if your CPU / runtime is to slow then you simply cannot use that approach at all.