rsta2 / circle

A C++ bare metal environment for Raspberry Pi with USB (32 and 64 bit)
https://circle-rpi.readthedocs.io
GNU General Public License v3.0
1.85k stars 245 forks source link

gpio timing sample #439

Closed pottendo closed 7 months ago

pottendo commented 7 months ago

Hi @rsta2, thought this may be useful for you. bye, pottendo

rsta2 commented 7 months ago

Thanks. I tried it, but I don't think, this should become a Circle sample, because accessing GPIO pins is already shown in other samples.

Please branch off from develop for eventual further PRs. Merging to master is only done for releases (see CONTRIBUTING.md for the branching model).

rsta2 commented 7 months ago

I cherry-picked your commits from the master branch, moved your code from sample/ to the test/ section, did some small modifications and merged it to develop. I think, this is the right place for this tool. Thanks again for this contribution!

pottendo commented 7 months ago

Great. Thanks for the feedback. I may add some more functions to test the comparison to direct register access and maybe other functions (for Pis which are supported). Bye, pottendo

rsta2 commented 7 months ago

There is a way to access the GPIO pins much quicker on the RPi 5 using the RIO module. How it seems, with this you can write all GPIO pins at once or set their mode at once and read them at once in in less than 200µs for each operation. I'm still researching this to provide an improved class CGPIOPin.

pottendo commented 7 months ago

Good news indeed! Does this also allow somehow to switch direction of the I/O.? Thanks for investing more time into this. I hope that it's not only my use case to drive this! Bye pottendo

rsta2 commented 7 months ago

You are welcome. Yes, there will be a method SetModeAll(u32 InputMask, u32 OutputMask). The GPIO pins are set to input, for which the respective bit in InputMask is set. The same for OutputMask (set to output). How it seems, this takes about 125µs, when both masks are != 0. It's always good to have a use case to make something new. I guess, there will be more users for this sooner or later. I'm still working on it.

rsta2 commented 7 months ago

The update is on the develop branch. There are the following new methods in CGPIOPin:

static void SetModeAll (u32 nInputMask, u32 nOutputMask);
static void WriteAll (u32 nValue, u32 nMask);
static u32 ReadAll (void);

The first is only available on the RPi 5 and is described in include/circle/gpiopin2712.h. The other methods were already available for RPi 1-4 and are described in include/circle/gpiopin.h. The old SetMode() and Write() methods also need less time now. Please let me know, if it works for you.

pottendo commented 7 months ago

Thanks, even more good news! Will test, but not before tomorrow... I think SetModeAll could be easily done for all Pi versions to be API compatible... my app does it basically (see first post in the discussion). But probably you're planning this already. Let's see if my app gets happier wit this improvement. Thx pottendo

rsta2 commented 7 months ago

If it helps, I can implement SetModeAll() for earlier RPi versions, but it requires up to 8 register accesses to be accomplished there (only 2 on the RPi 5). So the timing will be different. I should do it anyway to have to same API.

rsta2 commented 7 months ago

CGPIOPin::SetModeAll() is implemented for RPi 1-5 on the develop branch now.

pottendo commented 7 months ago

Hi, here some results: Pi5 & Pi3

logger: Circle 46 started on Raspberry Pi 5 4GB (AArch64)
logger: Revision code is c04170, compiler has been GCC 12.2.1
00:00:00.13 timer: SpeedFactor is 7.69
00:00:00.13 kernel: timing of GPIOs on Raspberry Pi 5
00:00:00.14 kernel: maxed freq to 2400MHz
00:00:00.14 kernel: Temp 30C (max=85C), dynamic adaption possible, current freq = 2400MHz (max=2400MHz)
00:00:00.15 kernel: loop 1 -------------------------------------------------
00:00:00.16 kernel: LED on      ,   1000 loops: 1074us, 1.074us avg.
00:00:00.19 kernel: LED off     ,   1000 loops: 1073us, 1.072us avg.
00:00:00.21 kernel: SetMode(Out),   1000 loops: 105us,  0.104us avg.
00:00:00.23 kernel: Write(H)    ,   1000 loops: 103us,  0.103us avg.
00:00:00.25 kernel: WriteAll(H) ,   1000 loops: 102us,  0.101us avg.
00:00:00.28 kernel: Write(L)    ,   1000 loops: 103us,  0.103us avg.
00:00:00.30 kernel: WriteAll(L) ,   1000 loops: 102us,  0.101us avg.
00:00:00.32 kernel: SetMode(In) ,   1000 loops: 105us,  0.104us avg.
00:00:00.35 kernel: Read()      ,   1000 loops: 194us,  0.194us avg.
00:00:00.37 kernel: ReadAll()   ,   1000 loops: 152us,  0.151us avg.
00:00:00.39 kernel: SetModeAll(Out),    1000 loops: 102us,  0.101us avg.
00:00:00.42 kernel: SetModeAll(In), 1000 loops: 102us,  0.101us avg.

logger: Circle 46 started on Raspberry Pi 3 Model B+ 1GB
logger: Revision code is a020d3, compiler has been GCC 12.2.1
00:00:00.30 timer: SpeedFactor is 3.33
00:00:00.30 kernel: timing of GPIOs on Raspberry Pi 3 Model B+
00:00:00.31 kernel: maxed freq to 1300MHz
00:00:00.31 kernel: Temp 32C (max=85C), dynamic adaption not possible, current freq = 1300MHz (max=1300MHz)
00:00:00.32 kernel: loop 1 -------------------------------------------------
00:00:00.33 kernel: LED on      ,   1000 loops: 018us,  0.017us avg.
00:00:00.36 kernel: LED off     ,   1000 loops: 019us,  0.018us avg.
00:00:00.38 kernel: SetMode(Out),   1000 loops: 161us,  0.160us avg.
00:00:00.40 kernel: Write(H)    ,   1000 loops: 014us,  0.014us avg.
00:00:00.43 kernel: WriteAll(H) ,   1000 loops: 010us,  0.009us avg.
00:00:00.45 kernel: Write(L)    ,   1000 loops: 013us,  0.013us avg.
00:00:00.48 kernel: WriteAll(L) ,   1000 loops: 010us,  0.009us avg.
00:00:00.50 kernel: SetMode(In) ,   1000 loops: 161us,  0.160us avg.
00:00:00.53 kernel: Read()      ,   1000 loops: 067us,  0.067us avg.
00:00:00.55 kernel: ReadAll()   ,   1000 loops: 057us,  0.057us avg.

the Pi3 doesn't like: u32 i, o; i = 0xffffffff, o=0x0; (void)CGPIOPin::SetModeAll(i, o); and crashes. Probably wrong masks? bye, pottendo

PS: Pi4 doesn't build currently:

i2cmasterirq.cpp:169:41: error: 'ARM_IRQ_I2C' was not declared in this scope; did you mean 'ARM_IRQ_USB'?
  169 |         m_pInterruptSystem->ConnectIRQ (ARM_IRQ_I2C, InterruptStub, this);
      |                                         ^~~~~~~~~~~
rsta2 commented 7 months ago

Be careful with modifying the mode of GPIO pins 0-1 and 28-31. They have a special function in the system and shouldn't be changed. The RPi 4 build error has been fixed on the develop branch.

pottendo commented 7 months ago

Ok, fixed the tests now to run on all PIs (I've tested) - should be in my dev-branch to be updated on your side (if you like). I'll post the results in the discussion - probably better to be found be others.