Peripheral clock control

I have found information that suggest that Linux on these boards (or Libgpiod) can/might disable the GPIO clock except when actually changing a pin. That is to say it enables the clock, writes to the pin and then disables it.

Is this the kind of stuff going on under the hood here?

Why is this question relevant? I am asking because we work hard so the endpoint user doesn’t need to know anything about Linux.

1 Like

I was interested in accessing and manipulating peripheral register directly and I stumbled upon this question at ST.

An ST engineer wrote:

The Linux kernel manages the clock enable of all the peripherals in order to minimize the power consumption.

The GPIO driver enables the clock only when it needs to change or read one of the GPIO registers, then turns the clock off immediately.

I was curious as to whether this kind of thing goes on on the Domino board.

Some peripherals are disable until user enable (like lcd), some are always enabled.

On Domino, GPIO from port A to Z are always enabled.

Thanks, well clearly I’m missing something fundamental here, in principle this code should cause the boards red LED to pulse on and off, every second but alas nothing!

This is experimental code just to let me get a proof of concept, the solution builds and runs fine but the LED doesn’t pulse (a similar test with the various IoT libraries does work fine).

We have Register class that does the job.

use this class to read and compare values with your class. If they are different mean something with your class (software).

So far I don’t see you set Alt pin. Default should be Alt0 but not sure during boot if they were changed.

Many thanks Dat. I did explore that register class and some of my code is based on that. It would be great if someone were able to create a small sample that pulses the red LED using just Register methods, that would be most instructive and could serve as a baseline for some of the stuff I’m looking at, prove that if done correctly, it all works.

In this code, I’d expect the last statement to turn the Led on, the preceding statements turn it on then off, but the final register write has no effect:

            var port = EPM815.Gpio.Pin.PC0 / 16;
            var pin = EPM815.Gpio.Pin.PC0 % 16;
            var gpioDriver = new LibGpiodDriver((int)port);

            var gpioController = new GpioController(PinNumberingScheme.Logical, gpioDriver);

            gpioController.OpenPin(pin);
            gpioController.SetPinMode(pin, PinMode.Output);
            gpioController.Write(pin, PinValue.High);
            gpioController.Write(pin, PinValue.Low);

            Register.Write(GPIOC_ADR + GPIO_ODR_OFX, 0x_00_00_00_01);

Clearly Libgpiod polices access to the pin, forces a particular usage pattern (i.e. must open before using etc) but the register write should bypass all that, I don’t see how Libgpiod can “get in the way” here.

Admittedly that code is poor, I set all outputs to zero except pin 0, but this is just hacking, to get insight into stuff. This seems to suggest too that Libgpiod does more than simply update bit 0 of that register.

Very puzzling…

Oh, by the way these are in a simple static class:

        public const UInt32 GPIOC_ADR = 0x50004000;
        public const UInt16 GPIO_ODR_OFX = 0x14;

Below works on pin PA0 as tested, but pin PC0 doesn’t. Not sure what it is, but enough to say the register class works.

And yes, you need to enable the clock.

var id = EPM815.Gpio.Pin.PA0;
var port = id / 16;
var pin = id % 16;

var GPIO_PORT = 0x50002000 + port * 0x1000;
var GPIO_PORT_MODER = GPIO_PORT + 0;

var GPIO_PORT_OTYPER = GPIO_PORT + 0x4;
var GPIO_PORT_BSRR = GPIO_PORT + 0x18;

Register.Write(0x50000A28, (uint)(1 << (int)port));

var value = Register.Read((uint)GPIO_PORT_MODER);

var clear = 3 << (pin * 2);

value &= (uint)~clear;

var set = (uint)1 << (pin * 2);

value |= set;

Register.Write((uint)GPIO_PORT_MODER, value);

while (true)
{
    Register.Write((uint)GPIO_PORT_BSRR, 1 << 0);
    Thread.Sleep(100);
    Register.Write((uint)GPIO_PORT_BSRR, 1 << 16);
    Thread.Sleep(100);
}

Thank you s much for this Dat, I ran it and of course it works (I never really doubted that the Register class worked, I was just puzzled about PC0 and by the way PD0 is the same, for some reason direct register access doesn’t work for that either).

This is enough for me to do the exploration I wanted to do.

Thanks

Thanks for let us know. We will investigate why some pins don’t work.

Thanks, much appreciated.

By the way, while running some performance tests I discovered a possible bug, it seems that repeated use of Register for register updates, eventually exhausts something in the OS.

I can write this up in GitHub issue if you like or detail it here. I doubt anyone will use Register much (I’m using it to help me develop something else), but if it exposes a deeper issue it might be worth looking into.

yes, add to github issue we will look into it, more detail will be easier for us.

Dat,

I want to thank you again for your valuable assistance, it’s been very helpful to me.

I’m fleshing out some ideas that I’ve had for a couple years, now that we can use C# 12 to write code for these devices the sky’s the limit.

I’m personally interested in both powerful abstractions and very high performance, and C# 12 is enabling me to do stuff that is tedious and cumbersome in C and C++, so much baggage.

I’ll be sharing the fruits of this with the community here in due course, but wanted to thank you for your time and patience with what might sometimes seem like rather dumb questions!

2 Likes