User avatar
HermannSW
Posts: 1760
Joined: Fri Jul 22, 2016 9:09 pm
Location: Eberbach, Germany
Contact: Website Twitter YouTube

Raspberry Pi Zero 1ns "cycle counter register"

Sun Jul 31, 2016 8:14 pm

In a previous posting I asked how to (start and) read Raspberry Pi Zero "cycle counter register":
viewtopic.php?f=63&t=155498

Finally I found working code sample in that thread.

In this thread I want to show how to work with cycle counter, in kernel mode as well as in user mode, and show some results.

Find ccnt-1.tar archive attached, which you can unpack on your Pi Zero. You need to enable the Pi Zero to compile kernel modules as described in beginning of above mentioned thread:

Code: Select all

[email protected]:~ $ tar -tvf ccnt-1.tar 
drwxr-xr-x pi/pi             0 2016-07-31 04:48 ccnt-1/
-rw-r--r-- pi/pi           854 2016-07-29 20:02 ccnt-1/ccnt.c
-rw-r--r-- pi/pi           548 2016-07-29 19:57 ccnt-1/user-level-1.c
-rw-r--r-- pi/pi           328 2016-07-30 18:28 ccnt-1/Makefile
-rw-r--r-- pi/pi          1794 2016-07-30 13:31 ccnt-1/led-1.c
-rw-r--r-- pi/pi          1200 2016-07-30 13:37 ccnt-1/ccnt.rd.c
-rw-r--r-- pi/pi          1242 2016-07-29 19:49 ccnt-1/ccnt-1.c
[email protected]:~ $ 

Let's start first with ccnt-1.c ("make" creates three loaable modules and two user space executable). It does start cycle counter (with reset) and then measures the time needed for several statements:

Code: Select all

#include <linux/module.h>
#include <linux/delay.h>

#define E        (1<<0)  // enable all three counters
#define P        (1<<1)  // reset two count registers
#define C        (1<<2)  // reset cycle counter register
#define D        (1<<3)  // cycle count divider (64)
#define PMNC(v)  asm volatile("mcr p15, 0, %0, c15, c12, 0" :: "r"(v))
#define CCNT(v)  asm volatile("mrc p15, 0, %0, c15, c12, 1" : "=r"(v))

static int ccnt_1_init(void)
{
  unsigned int cyc1, cyc2, cyc3,cyc4, cyc5;

  printk(KERN_INFO "ccnt-1 enabling cycle counter (with reset)\n");
  PMNC(E|C);

  CCNT(cyc1); 
  CCNT(cyc2);
  asm volatile("nop");
  asm volatile("nop");
  asm volatile("nop");
  CCNT(cyc3);
  asm volatile("nop");
  asm volatile("nop");
  asm volatile("nop");
  asm volatile("nop");
  CCNT(cyc4);
  udelay(10);
  CCNT(cyc5);

  printk(KERN_INFO "ccnt-1 %u %u %u %u %u\n",cyc1,cyc2,cyc3,cyc4,cyc5);
  return 0;
}

static void ccnt_1_exit(void)
{
  unsigned int cycles1, cycles2;
  printk(KERN_INFO "ccnt-1 disabling cycle counter\n");

  PMNC(0); CCNT(cycles1); CCNT(cycles2);

  printk(KERN_INFO "ccnt-1 %u %u\n",cycles1,cycles2);
  printk(KERN_INFO "ccnt-1 stopping\n");
}

module_init(ccnt_1_init);
module_exit(ccnt_1_exit);
MODULE_LICENSE("GPL");
This is the result of running this code:

Code: Select all

[email protected]:~/ccnt-1 $ sudo insmod ccnt-1.ko 
[email protected]:~/ccnt-1 $ sudo rmmod ccnt-1.ko 
[email protected]:~/ccnt-1 $ dmesg | tail -5
[14091.259733] ccnt-1 enabling cycle counter (with reset)
[14091.259774] ccnt-1 3 11 19 162 10851
[14093.193035] ccnt-1 disabling cycle counter
[14093.193063] ccnt-1 136648403 136648403
[14093.193071] ccnt-1 stopping
[email protected]:~/ccnt-1 $ 
The overhead (clock counter difference of two consecutive reads) is 11-3=8.
3 "nop" assembler statements take 8ns as well (arm11 does instructon pipelining).
4 "nop" statements then take 162-19=143ns.
Finally udelay(10) delay for 10us takes 10851-162=10689ns (slightly more than 10us).


In order to be able to use cycle counter in user mode code this needs to be enabled.
I used the code from http://blog.regehr.org/archives/794 and added proper module cleanup code allowing to disable user mode access aswell:

Code: Select all

// cleanup additions to "http://blog.regehr.org/archives/794"

#include <linux/module.h>
#include <linux/kernel.h>
 
/*
 * works for ARM1176JZ-F
 */
 
int init_module(void)
{
  asm volatile ("mcr p15,  0, %0, c15,  c9, 0\n" : : "r" (1));
  printk (KERN_INFO "User-level access to CCR has been turned on.\n");
  return 0;
}
 
void cleanup_module(void)
{
  asm volatile ("mcr p15,  0, %0, c15,  c9, 0\n" : : "r" (0));
  printk (KERN_INFO "User-level access to CCR has been turned off.\n");
}

MODULE_LICENSE("GPL");  // avoid "taints kernel" message

And this is ccnt.c, user space program doing the same as ccnt-1.c loadable kernel mode module shown above:

Code: Select all

#include <stdio.h>
#include <unistd.h>

#define E        (1<<0)  // enable all three counters
#define P        (1<<1)  // reset two count registers
#define C        (1<<2)  // reset cycle counter register
#define D        (1<<3)  // cycle count divider (64)
#define PMNC(v)  asm volatile("mcr p15, 0, %0, c15, c12, 0" :: "r"(v))
#define CCNT(v)  asm volatile("mrc p15, 0, %0, c15, c12, 1" : "=r"(v))

int main(void)
{
  unsigned int cyc1, cyc2, cyc3,cyc4, cyc5;

  printf("ccnt enabling cycle counter (with reset)\n");
  PMNC(E|C);

  CCNT(cyc1); 
  CCNT(cyc2);
  asm volatile("nop");
  asm volatile("nop");
  asm volatile("nop");
  CCNT(cyc3);
  asm volatile("nop");
  asm volatile("nop");
  asm volatile("nop");
  asm volatile("nop");
  CCNT(cyc4);
  usleep(10);
  CCNT(cyc5);

  printf("ccnt %u %u %u %u %u\n",cyc1,cyc2,cyc3,cyc4,cyc5);
  return 0;
}
As you can see it even resets the cycle counter from user space.
Here is how to use it:

Code: Select all

[email protected]:~/ccnt-1 $ ./ccnt
ccnt enabling cycle counter (with reset)
Illegal instruction
[email protected]:~/ccnt-1 $ sudo ./ccnt
ccnt enabling cycle counter (with reset)
[email protected]:~/ccnt-1 $ sudo insmod user-level-1.ko 
[email protected]:~/ccnt-1 $ sudo ./ccnt
ccnt enabling cycle counter (with reset)
ccnt 3 11 107 116 275964
[email protected]:~/ccnt-1 $ 
You have to run as root, and user-level access has to be enabled.
The numbers are different to the numbers from loadable kernel module above:

Code: Select all

ccnt   3 11 107 116 275964
ccnt-1 3 11 19 162 10851
Since udelay(10) is not available in user space I used usleep(10) instead. As you can see that took 275us while udelay(10) took roughly 10us.
Attachments
ccnt-1.tar
(20 KiB) Downloaded 98 times
⇨https://stamm-wilbrandt.de/en/Raspberry_camera.html

https://github.com/Hermann-SW/Raspberry_v1_camera_global_external_shutter
https://stamm-wilbrandt.de/github_repo_i420toh264
https://github.com/Hermann-SW/fork-raspiraw
https://twitter.com/HermannSW

User avatar
HermannSW
Posts: 1760
Joined: Fri Jul 22, 2016 9:09 pm
Location: Eberbach, Germany
Contact: Website Twitter YouTube

Re: Raspberry Pi Zero 1ns "cycle counter register"

Sun Jul 31, 2016 8:41 pm

Now lets talk on the other two programs in the archive.

I am interested in reading digital GPIO pins very fast, and the 1ns clock precision of the Pi Zero made me try that. I need this to measure speed of light:
https://forum.arduino.cc/index.php?topic=406165.0

Since light travels 0.33m in 1ns "really fast" measurements are needed for 2*9=18m measuing distance in our house. Light travels 18m in 54ns!

So this is loadable kernel module led-1.c reading one GPIO pin by "gpio_get_value()":

Code: Select all

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/gpio.h>
#include <linux/delay.h>

#define E        (1<<0)  // enable all three counters
#define P        (1<<1)  // reset two count registers
#define C        (1<<2)  // reset cycle counter register
#define D        (1<<3)  // cycle count divider (64)
#define PMNC(v)  asm volatile("mcr p15, 0, %0, c15, c12, 0" :: "r"(v))
#define CCNT(v)  asm volatile("mrc p15, 0, %0, c15, c12, 1" : "=r"(v))

static struct gpio leds[] = {
  { 13, GPIOF_OUT_INIT_HIGH, "LED 1" },
  { 19, GPIOF_IN, "INP 1" },
};


static int led_1_init(void)
{
  unsigned int cyc1, cyc2, cyc3,cyc4, cyc5, inp1, inp2, inp3, inp4, inp5, inp6;
  int ret = 0;

  printk(KERN_INFO "%s\n", __func__);

  ret = gpio_request_array(leds, ARRAY_SIZE(leds));

  if (ret) {
    printk(KERN_ERR "Unable to request GPIOs: %d\n", ret);
    return ret;
  }

  printk(KERN_INFO "led-1 enabling cycle counter (with reset)\n");
  PMNC(E|C);

  CCNT(cyc1); 
  CCNT(cyc2);
  inp1 = gpio_get_value(19);
  CCNT(cyc3);
  inp2 = gpio_get_value(19);
  inp3 = gpio_get_value(19);
  CCNT(cyc4);
  inp4 = gpio_get_value(19);
  inp5 = gpio_get_value(19);
  inp6 = gpio_get_value(19);
  CCNT(cyc5);

  printk(KERN_INFO "led-1 %u %u %u %u %u\n",cyc1,cyc2,cyc3,cyc4,cyc5);
  return 0;
}

static void led_1_exit(void)
{
  unsigned int i, cycles1, cycles2;
  printk(KERN_INFO "led-1 disabling cycle counter\n");

  PMNC(0); CCNT(cycles1); CCNT(cycles2);

  printk(KERN_INFO "led-1 %u %u\n",cycles1,cycles2);
  printk(KERN_INFO "led-1 stopping\n");

  printk(KERN_INFO "%s\n", __func__);

  for(i = 0; i < ARRAY_SIZE(leds); i++) {
    gpio_set_value(leds[i].gpio, 0); 
  }
	
  gpio_free_array(leds, ARRAY_SIZE(leds));
}

module_init(led_1_init);
module_exit(led_1_exit);
MODULE_LICENSE("GPL");

Here are the reported runtimes for 1, 2 and 3 reads:

Code: Select all

[email protected]:~/ccnt-1 $ sudo insmod led-1.ko 
[email protected]:~/ccnt-1 $ sudo rmmod led-1.ko 
[email protected]:~/ccnt-1 $ dmesg | tail -7
[15812.796344] led_1_init
[15812.796400] led-1 enabling cycle counter (with reset)
[15812.796416] led-1 124 132 1701 2265 3090
[15814.827404] led-1 disabling cycle counter
[15814.827431] led-1 141033007 141033007
[15814.827439] led-1 stopping
[15814.827447] led_1_exit
[email protected]:~/ccnt-1 $ 

The 275ns needed per gpio_get_value() call show this approach is unusable (too much overhead for functions calling other functions, validation, checks, ...):

Code: Select all

[email protected]:~/ccnt-1 $ bc -lq
(1701-132)/1
1569.00000000000000000000
(2265-1701)/2
282.00000000000000000000
(3090-2265)/3
275.00000000000000000000

So finally ccnt.rd.c will measure reading of 32(!) GPIO port values by a single pointer read:

Code: Select all

#include <stdio.h>
#include <wiringPi.h>

#define E        (1<<0)  // enable all three counters
#define P        (1<<1)  // reset two count registers
#define C        (1<<2)  // reset cycle counter register
#define D        (1<<3)  // cycle count divider (64)
#define PMNC(v)  asm volatile("mcr p15, 0, %0, c15, c12, 0" :: "r"(v))
#define CCNT(v)  asm volatile("mrc p15, 0, %0, c15, c12, 1" : "=r"(v))


// only for Raspberry Pi Zero, and only for GPIOxy, 00<=xy<=31
//
volatile unsigned int *GPSET=NULL, *GPCLR=NULL, *GPINP=NULL;
unsigned int GPIO27 = 1<<27;

// INP Pin - wiringPi pin 2 is BCM_GPIO 27.

#define	INP	2

int main(void)
{
  unsigned int cyc1, cyc2, cyc3,cyc4, cyc5;
  unsigned int inp1, inp2, inp3, inp4, inp5, inp6, inp7;

  wiringPiSetup () ;
  GPSET = getGpio()+7;
  GPCLR = getGpio()+10;
  GPINP = getGpio()+13;

  pinMode (INP, INPUT) ;

  printf("ccnt.rd enabling cycle counter (with reset)\n");
  PMNC(E|C);

  CCNT(cyc1); 
  CCNT(cyc2);
  inp1 = *GPINP;
  CCNT(cyc3);
  inp2 = *GPINP;
  inp3 = *GPINP;
  CCNT(cyc4);
  inp4 = *GPINP;
  inp5 = *GPINP;
  inp6 = *GPINP;
  inp7 = *GPINP;
  CCNT(cyc5);

  printf("ccnt.rd %u %u %u %u %u\n",cyc1,cyc2,cyc3,cyc4,cyc5);
  return 0;
}
For ccnt.rd.c to compile you need a slightly enhanced wiringPi library described in this posting:
https://forum.arduino.cc/index.php?topi ... msg2852141


And here are the results, userlevel access needs to be enabled again:

Code: Select all

[email protected]:~/ccnt-1 $ sudo insmod user-level-1.ko 
[email protected]:~/ccnt-1 $ sudo ./ccnt.rd
ccnt.rd enabling cycle counter (with reset)
ccnt.rd 3 11 600 700 988
[email protected]:~/ccnt-1 $ 

Doing the math again:

Code: Select all

[email protected]:~/ccnt-1 $ bc -lq
(600-11)/1
589.00000000000000000000
(700-600)/2
50.00000000000000000000
(988-700)/4
72.00000000000000000000

Even the best (50ns per GPIO read) is bad.

In the arduino forum thread linked to above I have demonstrated how to read 32 (Arduino) digital inputs of one port (Arduino Due has 4 ports) with only 3 clock cycles per read. Although Arduino Due CPU clock is only 84MHz compared to Pi Zero 1GHz that does give me 3*(1000/84)=35.7ns per read, quite less than the 50ns on Pi Zero in best case, and much more reliable.


So for measuring speed of light I will go back to my (4) Arduino Dues (12$), but I liked what I learned with my (3) Pi Zero (5$) in the last weeks.

Hermann.
⇨https://stamm-wilbrandt.de/en/Raspberry_camera.html

https://github.com/Hermann-SW/Raspberry_v1_camera_global_external_shutter
https://stamm-wilbrandt.de/github_repo_i420toh264
https://github.com/Hermann-SW/fork-raspiraw
https://twitter.com/HermannSW

jdb
Raspberry Pi Engineer & Forum Moderator
Raspberry Pi Engineer & Forum Moderator
Posts: 2199
Joined: Thu Jul 11, 2013 2:37 pm

Re: Raspberry Pi Zero 1ns "cycle counter register"

Mon Aug 01, 2016 6:53 pm

You will never get deterministic or nanosecond-precise timing on a system as complex as the Pi SoC.

Effects such as cache eviction and bus arbitration in the multi-master bus fabric mean that the time taken to execute a peripheral bus read or execute a given set of instructions will be variable.

At best, you can have a kernel-level non-preemptible section that handles the inner loop. I'd imagine the tightest time resolution you can reliably stick to would be 100ns or so.

Arduinos are microcontrollers - single CPU, simple pipeline, near-cycle-accurate deterministic IO performance.
Rockets are loud.
https://astro-pi.org

User avatar
HermannSW
Posts: 1760
Joined: Fri Jul 22, 2016 9:09 pm
Location: Eberbach, Germany
Contact: Website Twitter YouTube

Re: Raspberry Pi Zero 1ns "cycle counter register"

Tue Aug 02, 2016 2:32 pm

Hi gdb,

> You will never get deterministic or nanosecond-precise timing on a system as complex as the Pi SoC.
>
I agree with that statement for a longer period of code execution.

My appliaction runs for a very short timeframe, and I need the super fast readings only in a short time from that:
https://forum.arduino.cc/index.php?topi ... msg2799723

Code: Select all

...
FDFFFFFF FDFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF 87 30 
FDFFFFFF FDFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF 87 30 
...
Above you see 8 consecutive Arduino Due "port b" readings retrieved by this code:

Code: Select all

...
  t1=SysTick->VAL;
  
  // capture port B every 3 clock cycles
  //
  a1 = p->PIO_PDSR;
  a2 = p->PIO_PDSR;
  a3 = p->PIO_PDSR;
  a4 = p->PIO_PDSR;
  a5 = p->PIO_PDSR;
  a6 = p->PIO_PDSR;
  a7 = p->PIO_PDSR;
  a8 = p->PIO_PDSR;
  t2=SysTick->VAL;
...
"87 30" at the end of the lines means that the 8 readings start 87 clock cycles after laser LED has been turned "on" and then "off". "FD..." has photo cell not received laser light, "FF..." is when laser beam has been detected:

Code: Select all

  q->PIO_SODR = b7;  // turn laser on ...
  q->PIO_CODR = b7;  // ... and directly off again
  t0=SysTick->VAL;
And the the 8 reading statements together with the t2 timer read take 30 clock cycles (adding a read statement increases count by 3).

So we speak of a very short timeframe of 87+30=117 Arduino clock cycles (84MHz) with in total 117*11.9 = 1392.3ns = 1.4us in total. And the difference t2-t1 printed each time clarifies whether things were done in time or not.

I hoped that this would be replicable for Pi Zero, but I don't know how to do GPIO reads by simple pointer read as I did in ccnt.rd.c in kernel space. That probably can be quite better than the 50ns per read in user mode ccnt.rd.c and might work in my 1.4us in total timeframe.

Hermann.
⇨https://stamm-wilbrandt.de/en/Raspberry_camera.html

https://github.com/Hermann-SW/Raspberry_v1_camera_global_external_shutter
https://stamm-wilbrandt.de/github_repo_i420toh264
https://github.com/Hermann-SW/fork-raspiraw
https://twitter.com/HermannSW

User avatar
HermannSW
Posts: 1760
Joined: Fri Jul 22, 2016 9:09 pm
Location: Eberbach, Germany
Contact: Website Twitter YouTube

Re: Raspberry Pi Zero 1ns "cycle counter register"

Sat Aug 06, 2016 9:13 am

In this posting
viewtopic.php?p=1017550#p1017550
further above I showed how to reduce the 275ns time per "gpio_get_value()" call to 50ns with hacky "*GPINP" in program "ccnt.rd.c". Because I was not able to do direct GPIO access in kernel space I had to do "*GPINP" in user space program "ccnt.rd.c".

To make this thread complete for people needing to do most efficient (hacky) GPIO reads find below loadable kernel module "led-3.c" that does efficient (hacky) GPIO reads from kernel space.

It was a long journey, and I had to look up many functions and data structures in Raspbian kernel, and the whole work was like peeling a big onion. I started with 275ns "gpio_get_value()", arrived at 160ns "chip->get(chip, offset)", further to "readl(GPINP)" and finally reaching at 55ns "*GPINP".

I had to copy in several data structures and constants from "gpiolib", see three sections framed with "/////////" in code below. This is sample execution:

Code: Select all

[email protected]:~ $ sudo insmod ccnt-1/led-3.ko 
[email protected]:~ $ sudo rmmod ccnt-1/led-3.ko 
[email protected]:~ $ dmesg | tail -6
[   38.047122] random: nonblocking pool is initialized
[  191.494918] led_3_init
[  191.494987] led-3 3000c1ff 3802c1ff pinctrl-bcm2835
[  191.494998] led-3 enabling cycle counter (with reset)
[  191.495009] led-3 3 11 152 534 1851
[  196.019873] led_3_exit
[email protected]:~ $ 
The "chip" label reported is "pinctrl-bcm2835" as expected. Time per one of the 24 "*GPINP" calls is (1851-534)/24=54.9ns. Different to "gpio_get_value()" not only the value of one pin gets read, but the value of GPIO00-GPIO31. In order to be sure the code works it contains a little test. I connected GPIO17 and GPIO27 with a cable, then did "gpio_set_value(17, 1)" between two reads for the 32 GPIOs (*GPINP), and the program reports both values in hex: "3000c1ff 3802c1ff". As you can see the two bits 17 and 27 changed (in bold 3802c1ff).

While this did not help me to get consecutive GPIO reads (in kernel space) below 50ns per read, this work is a nice completion of previous high precision timing work.

Hermann.

P.S:
In a seperate kernel module I determined time for accessing a non-IO "volatile unsigned int *", that only needs 14.875ns per read ...


This is "ccnt-1/led-3.c":

Code: Select all

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/gpio.h>
#include <linux/delay.h>


/////////////////////////////////////////////////////////////////////////////////////
#include <linux/device.h>

struct gpio_desc {
        struct gpio_chip        *chip;
        unsigned long           flags;
/* flag symbols are bit numbers */
#define FLAG_REQUESTED  0
#define FLAG_IS_OUT     1
#define FLAG_EXPORT     2       /* protected by sysfs_lock */
#define FLAG_SYSFS      3       /* exported via /sys/class/gpio/control */
#define FLAG_ACTIVE_LOW 6       /* value has active low */
#define FLAG_OPEN_DRAIN 7       /* Gpio is open drain type */
#define FLAG_OPEN_SOURCE 8      /* Gpio is open source type */
#define FLAG_USED_AS_IRQ 9      /* GPIO is connected to an IRQ */
#define FLAG_IS_HOGGED  11      /* GPIO is hogged */

        /* Connection label */
        const char              *label;
        /* Name of the GPIO */
        const char              *name;
};

#define BCM2835_NUM_GPIOS 54
#define BCM2835_NUM_BANKS 2
#define BCM2835_NUM_IRQS  3

#define GPLEV0		0x34	/* Pin Level */

struct bcm2835_gpio_irqdata {
	struct bcm2835_pinctrl *pc;
	int irqgroup;
};

struct bcm2835_pinctrl {
	struct device *dev;
	void __iomem *base;
	int irq[BCM2835_NUM_IRQS];

	/* note: locking assumes each bank will have its own unsigned long */
	unsigned long enabled_irq_map[BCM2835_NUM_BANKS];
	unsigned int irq_type[BCM2835_NUM_GPIOS];

	struct pinctrl_dev *pctl_dev;
	struct irq_domain *irq_domain;
	struct gpio_chip gpio_chip;
	struct pinctrl_gpio_range gpio_range;

	struct bcm2835_gpio_irqdata irq_data[BCM2835_NUM_IRQS];
	spinlock_t irq_lock[BCM2835_NUM_BANKS];
};
/////////////////////////////////////////////////////////////////////////////////////


#define E        (1<<0)  // enable all three counters
#define P        (1<<1)  // reset two count registers
#define C        (1<<2)  // reset cycle counter register
#define D        (1<<3)  // cycle count divider (64)
#define PMNC(v)  asm volatile("mcr p15, 0, %0, c15, c12, 0" :: "r"(v))
#define CCNT(v)  asm volatile("mrc p15, 0, %0, c15, c12, 1" : "=r"(v))

static struct gpio pins[] = {
  { 17, GPIOF_OUT_INIT_LOW, "OUT 1" },
  { 27, GPIOF_IN, "INP 1" },
};

static int led_3_init(void)
{
  unsigned int cyc1, cyc2, cyc3,cyc4, cyc5, inp1, inp2, inp3, inp4, inp5, inp6, inp7;
  int ret = 0;


///////////////////////////////////////////
  const struct gpio_desc *desc;
  struct gpio_chip        *chip;
  int offset;
  struct bcm2835_pinctrl *pc;
  //void __iomem *GPINP;
  volatile unsigned int *GPINP;
///////////////////////////////////////////


  printk(KERN_INFO "%s\n", __func__);

  ret = gpio_request_array(pins, ARRAY_SIZE(pins));

  if (ret) {
    printk(KERN_ERR "Unable to request GPIOs: %d\n", ret);
    return ret;
  }


///////////////////////////////////////////
  desc=gpio_to_desc(27);
  chip = desc->chip;
//  offset = gpio_chip_hwgpio(desc);
  offset = desc - &desc->chip->desc[0];
//  value = chip->get ? chip->get(chip, offset) : -EIO;

//  inp1 = bcm2835_gpio_get(chip, offset);
  pc = dev_get_drvdata(chip->dev);

  GPINP = (volatile int *)(pc->base + GPLEV0);
//  inp1 = readl(GPINP);
  inp1 = *GPINP;
  gpio_set_value(17, 1);
  udelay(10);
//  inp2 = chip->get(chip, offset);
//  inp2 = readl(GPINP);
  inp2 = *GPINP;

  printk(KERN_INFO "led-3 %x %x %s\n",inp1,inp2,chip->label);
///////////////////////////////////////////


  printk(KERN_INFO "led-3 enabling cycle counter (with reset)\n");
  PMNC(E|C);

  CCNT(cyc1); 
  CCNT(cyc2);
  inp1 = *GPINP;
  CCNT(cyc3);
  inp2 = *GPINP;
  inp3 = *GPINP;
  inp4 = *GPINP;
  inp5 = *GPINP;
  inp6 = *GPINP;
  inp7 = *GPINP;
  CCNT(cyc4);
  inp2 = *GPINP;
  inp3 = *GPINP;
  inp4 = *GPINP;
  inp5 = *GPINP;
  inp6 = *GPINP;
  inp7 = *GPINP;
  inp2 = *GPINP;
  inp3 = *GPINP;
  inp4 = *GPINP;
  inp5 = *GPINP;
  inp6 = *GPINP;
  inp7 = *GPINP;
  inp2 = *GPINP;
  inp3 = *GPINP;
  inp4 = *GPINP;
  inp5 = *GPINP;
  inp6 = *GPINP;
  inp7 = *GPINP;
  inp2 = *GPINP;
  inp3 = *GPINP;
  inp4 = *GPINP;
  inp5 = *GPINP;
  inp6 = *GPINP;
  inp7 = *GPINP;
  CCNT(cyc5);

  printk(KERN_INFO "led-3 %u %u %u %u %u\n",cyc1,cyc2,cyc3,cyc4,cyc5);
  return 0;
}

static void led_3_exit(void)
{
  printk(KERN_INFO "%s\n", __func__);

  gpio_free_array(pins, ARRAY_SIZE(pins));
}

module_init(led_3_init);
module_exit(led_3_exit);
MODULE_LICENSE("GPL");
⇨https://stamm-wilbrandt.de/en/Raspberry_camera.html

https://github.com/Hermann-SW/Raspberry_v1_camera_global_external_shutter
https://stamm-wilbrandt.de/github_repo_i420toh264
https://github.com/Hermann-SW/fork-raspiraw
https://twitter.com/HermannSW

daslolo
Posts: 4
Joined: Sun May 13, 2018 4:59 am

Re: Raspberry Pi Zero 1ns "cycle counter register"

Wed May 16, 2018 7:40 am

I read that switch mode to kernel takes time on Pi. have you tried programming one of the bare metal things like Ultubo? maybe you'd get faster GPIO read

Return to “General discussion”