Welcome, Guest

Author Topic: A10: Slow toggling of GPIO by writing directly to registers from kernel-module  (Read 2948 times)

Felipito

  • Newbie
  • *
  • Posts: 2
  • Karma: +0/-0
Hi all,

I am trying to toggle an output-GPIO (PI0) as fast as possible by using a kernel-module (see below code) that directly writes to the corresponding GPIO-register (physical address: 0x01c20800 + 0x130). But due some unknown reason, the toggle only works reliable if I use a delay greater 20 microseconds between setting and resetting the line. I expected to achieve some nano-seconds as minimal delay. For this reason, I think there is something wrong with my GPIO-configuration.

Now, have somebody tried to speed up the GPIO-toggling on that way? or give me a hint for solving this issue? Thanks in advance.

BR,

Luis

Code: [Select]
#include <linux/module.h>
#include <linux/gpio.h>
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/platform_device.h>

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Luis");

#define MY_GPIO_CLK           (49)
#define SW_PA_PORTC_IO_BASE      0x01c20800
#define CSP_PIN_PHY_ADDR_SIZE    0x1000

static int write_delay = 0;
static void __iomem *my_io = NULL;

static struct gpio my_gpios[] = {
    { MY_GPIO_CLK, GPIOF_OUT_INIT_LOW, "clock" },
};

static void sunxi_gpio_write_raw(u32 value)
{
        u32 val;

        if (write_delay) {
            ndelay(write_delay);
        }

        iowrite32(value, my_io + 0x130);

        val = ioread32(my_io + 0x130);
        if (value != val) {
            printk(KERN_ERR "Failed iowrite32() | %i %i\n", value, val);
        }
}

static int wago_write_byte(u8 data)
{
    uint pos;

    write_delay = 200;

    for (pos = 0; pos < 2; pos++) {
        //gpio_set_value(MY_GPIO_CLK, 1);
        sunxi_gpio_write_raw(1);

        //gpio_set_value(MY_GPIO_CLK, 0);
        sunxi_gpio_write_raw(0);
    }

    return 0;
}

static __init int wago_init(void)
{
    int err;

    my_io = ioremap_nocache(SW_PA_PORTC_IO_BASE, CSP_PIN_PHY_ADDR_SIZE);
    if (NULL == my_io) {
        printk(KERN_ERR "Failed to ioremap()\n");
        return -EIO;
    }

    err = gpio_request_array(my_gpios, ARRAY_SIZE(my_gpios));
    if (err) {
        iounmap(my_io);
        printk(KERN_ERR "Couldn't request GPIOs, %i\n", err);
        return err;
    }

    wago_write_byte(0xaa);
    printk(KERN_INFO "WAGO module loaded " __TIME__ "\n");
    return 0;
}

static __exit void wago_exit(void)
{
    gpio_free_array(my_gpios, ARRAY_SIZE(my_gpios));
    iounmap(my_io);
}

module_init(wago_init);
module_exit(wago_exit);

JohnS

  • Hero Member
  • *****
  • Posts: 1718
  • Karma: +33/-47
Don't expect more than about 4MHz as there appear to be weird internal interlocks in the chip itself.

John

Felipito

  • Newbie
  • *
  • Posts: 2
  • Karma: +0/-0
Don't expect more than about 4MHz as there appear to be weird internal interlocks in the chip itself.

Thanks for the info, but at this moment I have about 50kHz. I would be happy to see 2MHz as I need it for generating a bus clock.

I haven't tested with another GPIO than PI0. Could be a problem of this specific line? I will test it at this evening.

Luis
« Last Edit: July 27, 2015, 06:24:21 PM by Felipito »

JohnS

  • Hero Member
  • *****
  • Posts: 1718
  • Karma: +33/-47
It seems to me it will never be a sensible way to create a clock, let alone quite a fast one.  I'd use an existing peripheral type.

John