pi4j-v2 icon indicating copy to clipboard operation
pi4j-v2 copied to clipboard

Extend support for Raspberry Pi 5: PWM and SPI

Open FDelporte opened this issue 1 year ago • 5 comments
trafficstars

  • Should be implemented using the Linux Kernel APIs.
  • Integrate in the GpioD plugin added in 2.5.0?

https://docs.kernel.org/driver-api/pwm.html https://www.kernel.org/doc/html/v4.14/driver-api/spi.html

FDelporte avatar Mar 26 '24 14:03 FDelporte

I need SPI support on Pi5 to drive an SSD1306 OLED. I ended up on this ticket when I saw Pi4J doesn't support it yet. I don't have the time to fully integrate a solution, but I did come up with a quick implementation using JNA for the native bindings that demonstrates how to talk to the Linux SPI device. I don't think it would be hard for someone to do the actual integration into Pi4J.

I assume you'd want to rewrite the JNA calls into pure JNI to match the existing pattern, but JNA can save you a good bit of custom native code. The existing LinuxFS class gives you most of what you need, but you'll have to add an ioctl call that can pass a structure and all the JNI magic to read/write the structure.

Thanks for making this library available. Hopefully this helps speed the SPI implementation for Pi5.

JnaSpiPi5.zip

mpilone avatar Oct 03 '24 18:10 mpilone

Hi @mpilone Thanks, that does look easier. Maybe you could put it in a pull request? I don't know JNA, and would really appreciate that a lot! I would then check the code and try and test it with other SPI devices.

eitch avatar Oct 04 '24 11:10 eitch

I have not looked into that zip that was provided.   Early summer I spent sometime researching the kernel API.  The documentation for the new 6.x kernel is terrible.   After a bit of time I decided to use ioctl.   I coded up the library portion and tested I could control a neopixel LED string using ioctl.  I am in the process of debugging the new provider code I wrote so a normal testcase can use the provider and control the neopixel.

My intent with the provider is support the same interfaces and Config as the existing pigpio-spi provider. So a user could simply change the provider used and their existing code would function. But, there are flags bits specific to pigpio provider and no longer applicable to Pi5.

I wasn't sure if the ioctl usage would be rejected as we wanted to move to the APIs.   I used JNA to connect to the 'C' library.   I created needed declarations to use JNA for the structures used by ioctl.
I have some questions to answer as far as the JNA path. Our practice of creating our own version of the kernel library code is needed as we support multiple ways for the .so to be located. This JNA usage requires more code be duplicated. For the moment to test I set the JNA path explicitly in the java code, I want to research setting it when we first determine where the library is located.

The code needs synchronization added, complete decoding flags config values and setting the ioctl based upon those, complete the functions

I will push this code so we have something else to use in this SPI conversation

taartspi avatar Oct 05 '24 23:10 taartspi

I created a PR for my implementation. As the PR says, it introduces a dependency on JNA and I only tested the write operations for use with an OLED. Use it how you like. If you keep the JNA approach, you could do the same with gpiod and remove the custom C JNI code. Just load libgpiod.so and let JNA handle the bindings dynamically.

mpilone avatar Oct 05 '24 23:10 mpilone

#391 PR involving ioctl/JNA Intend is, between mpilone and this we likely have much of the SPI support for Pi5

taartspi avatar Oct 05 '24 23:10 taartspi

@dariuszzbyrad @eitch @FDelporte SPI. I want to select which spi approach to complete. The PR offered by milipone uses system library. The PR i began I implemented my own library thinking it provides more isolation from changes and deprecation by the kernel. But my approach creates a much larger code base to support. Mine also has increased JNA code although comments in milipone code implies more jna is needed in his code. I can see that milipone also needs more investigation of using the config attributes. Both of these use jna and not the new APIs available in later java versions. So your thoughts. Do i do what appears to be a smaller code base to complete spi now and we refactor (rewrite) it later using new APIs or do a more elaborate implementation now and think we stay with that long term ?My thoughts is the smaller implementation so it will be an easier decision to throw it away and rewrite for the new API

taartspi avatar Dec 03 '24 17:12 taartspi

@taartspi Regarding JNA vs the new FFI API in the JDK, I'd recommend using JNA for now and potentially rewriting it in the future. I have a few platforms that don't have a v21 JVM available yet and the new FFI API only became final in v21+. Obviously there's a tradeoff of pulling in the JNA dependency vs the new JVM standard API, but you might not want to tie SPI support to JVM v21+ at this point.

As for the implementation approach, I'll let you all talk that out. My approach doesn't involve much code, but as you said, I'm not sure it is complete as I only needed write support on SPI 0.0. You can see in the PR thread that someone was attempting to test it and I made a couple small fixes but there hasn't been an update for a few days.

Thanks for following up on this. -mike

mpilone avatar Dec 03 '24 19:12 mpilone

From my perspective, consciously taking on technical debt is acceptable, especially when it aligns with the project's immediate goals. Implementing SPI support in a simplified version now seems like a practical choice, as it enables faster progress with adding support for SPI in Pi5

dariuszzbyrad avatar Dec 03 '24 19:12 dariuszzbyrad

As discussed in https://github.com/Pi4J/pi4j-v2/discussions/409, we want to bump Pi4J to Java 21 so it can evolve further to the next LTS 25 and use the Foreign Memory API. This would bring Pi4J to V3.X.Y.

That being said, it would indeed be great if we still could have a good-and-small implementation in Pi4J V2.7.X.

FDelporte avatar Dec 04 '24 06:12 FDelporte

I will pull down Mike’s implementation to test and to see if more is required to let present users easily move to it. As his is a smaller code base it is more attractive for 2.7 as less code usually means easier maintenance.

taartspi avatar Dec 04 '24 16:12 taartspi

I thought i'd ask ChatGPT what it says about SPI, and it came up with simply reading and writing to spidev. Since y'all are busy trying out things, i thought i'd post this here, and see if it works, as i didn't myself yet have time to try it out:

public class SpidevExample {

    private static final Path SPIDEV_PATH = Path.of("/dev/spidev0.0"); // Change to your SPI device

    public static void main(String[] args) {
        byte[] txBuffer = {0x01, 0x02, 0x03}; // Example data to send
        byte[] rxBuffer = new byte[txBuffer.length];

        try (var spiFile = Files.newByteChannel(SPIDEV_PATH,
                StandardOpenOption.READ, StandardOpenOption.WRITE)) {
            // Send and receive data
            spiFile.write(java.nio.ByteBuffer.wrap(txBuffer));
            java.nio.ByteBuffer rxBufferWrapper = java.nio.ByteBuffer.wrap(rxBuffer);
            spiFile.read(rxBufferWrapper);

            // Print received data
            System.out.println("Received Data:");
            for (byte b : rxBuffer) {
                System.out.printf("0x%02X ", b);
            }
            System.out.println();
        } catch (IOException e) {
            System.err.println("SPI communication failed: " + e.getMessage());
            e.printStackTrace();
        }
    }
}

It seems to easy to be true, but who knows? =)

eitch avatar Dec 05 '24 09:12 eitch

@taartspi can this be closed as we have PWM and SPI in LinuxFX?

FDelporte avatar Feb 27 '25 16:02 FDelporte

Yes sir. Plz close

Speaking of pwm. I saw the issue from Dieter about pwm.off() began failing. I will look at that next

taartspi avatar Feb 27 '25 20:02 taartspi