null0bject
Posts: 4
Joined: Wed May 12, 2021 9:53 am

High frequency Generation on rpi 4b

Wed May 12, 2021 10:16 am

Hello,

There is a way to generate on a gpio (no matter the gpio) a square signal stable with a 50 kHz ?

At the moment, I try it using the bcm2835 lib on a raspberry pi 4B to control the gpios and timerfd to manage delays but the result is very bad, the frequency is not precise and unstable.

the delay function :

Code: Select all

void DelayMicrosecondsNoSleep (int delay_us)
{
	long int start_time;
	long int time_difference;
	struct timespec gettime_now;

	clock_gettime(CLOCK_REALTIME, &gettime_now);
	start_time = gettime_now.tv_nsec;		            // Get nS value
	while (1)
	{
		clock_gettime(CLOCK_REALTIME, &gettime_now);
		time_difference = gettime_now.tv_nsec - start_time;
		if (time_difference < 0)
			time_difference += 1000000000;				// (Rolls over every 1 second)
		if (time_difference > (delay_us * 1000))		// Delay for # nS
			break;
	}
}
the blink code (main loop) :

Code: Select all

int main()
{
    // gpio
    if(!bcm2835_init())
        return 1;

    bcm2835_gpio_fsel(PIN, BCM2835_GPIO_FSEL_OUTP);
    
    while(1)
    {
		bcm2835_gpio_write(PIN, 0);
		DelayMicrosecondsNoSleep(10);
		bcm2835_gpio_write(PIN, 1);
		DelayMicrosecondsNoSleep(10);
    }
    return 0;
}

Thanks,

null0bject
Attachments
stability.png
sometimes the frequency decreases
stability.png (12.88 KiB) Viewed 482 times
accuracy.png
the accuracy problem (10.8 us and not 10 us)
accuracy.png (12.61 KiB) Viewed 482 times

User avatar
joan
Posts: 15623
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK

Re: High frequency Generation on rpi 4b

Wed May 12, 2021 11:49 am

Yes, using a pigpio wave. You can switch one or more GPIO on or off with 1 microsecond resolution.

LTolledo
Posts: 5369
Joined: Sat Mar 17, 2018 7:29 am
Location: Anime Heartland

Re: High frequency Generation on rpi 4b

Wed May 12, 2021 1:15 pm

why do you want to generate that kind of square wave?
"Don't come to me with 'issues' for I don't know how to deal with those
Come to me with 'problems' and I'll help you find solutions"

Some people be like:
"Help me! Am drowning! But dont you dare touch me nor come near me!"

User avatar
RamaSpaceShip
Posts: 163
Joined: Sun Apr 26, 2020 12:19 pm

Re: High frequency Generation on rpi 4b

Wed May 12, 2021 5:08 pm

You need to reserve a core for the thread that generate the signal by using isolcpus in /boot/cmdline.txt
You need to run this thread at realtime priority, schedfifo with its affinity set to the reserved core.

I think there is uncertainty in your delay function.
For the same purpose, I use the following code (in Ada):

Code: Select all

         Period := To_Nanoseconds (Timer.Cycle) ;
         Result := Clock_Get_Time (CLOCK_MONOTONIC, Date) ;
         Cycles:
         loop
            Inc (Date, Period) ;
            while Clock_Nano_Sleep (CLOCK_MONOTONIC, TIMER_ABSTIME, Date, Remain) /= 0
            loop
               null ;
            end loop ;

            -- execute cyclic job, a false result indicates to end the cycles
            exit Cycles when not Timer.Expired ; -- Timer.Expired is the callback to execute at each cycle
         end loop Cycles ;
This gave me a square signal on the GPIO pins, with a deviation less than 100ns measured with a PicoScope 3500D sampling at 100Mhz.

User avatar
joan
Posts: 15623
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK

Re: High frequency Generation on rpi 4b

Wed May 12, 2021 5:23 pm

50 kHz square wave on GPIO X.

sudo pigpiod

X=23

pigs m $X w
pigs wvag $((1<<X)) 0 10 0 $((1<<X)) 10
pigs wvcre
pigs wvtxr 0

null0bject
Posts: 4
Joined: Wed May 12, 2021 9:53 am

Re: High frequency Generation on rpi 4b

Mon May 17, 2021 9:39 am

Hello, thanks for the answer.

I need to generate a signal at maximum 50 Khz but in reality it can be lower than 50 Khz and also it can just be a simple pulse.
I tried the nanopulse.c viewtopic.php?t=270197 (I put the good base addresses) but doesn't work for me.

Currently, I'm trying this but seems to not work :

Code: Select all

#include <stdio.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>

/* others definitions */
#define BLOCK_SIZE 		         (4*1024)

/* PWM0 registers */
#define PWM0_BASE_ADDRESS        0x7E20C000

#define PWM0_CTL                 (PWM0_BASE_ADDRESS + 0x00)
#define PWM0_STA                 (PWM0_BASE_ADDRESS + 0x04)
#define PWM0_DMAC                (PWM0_BASE_ADDRESS + 0x08)
#define PWM0_RNG1                (PWM0_BASE_ADDRESS + 0x10)
#define PWM0_DAT1                (PWM0_BASE_ADDRESS + 0x14)
#define PWM0_FIF1                (PWM0_BASE_ADDRESS + 0x18)
#define PWM0_RNG2                (PWM0_BASE_ADDRESS + 0x20)
#define PWM0_DAT2                (PWM0_BASE_ADDRESS + 0x24)

/* gpio registers */
#define GPIO_PULSE               12                               // broche physique 32
#define ALT_FUNC0                0x04                             // b0100

#define GPIO_BASE_ADDRESS        0x7E200000
#define GPFSEL1                  (GPIO_BASE_ADDRESS + 0x04)
#define GPFSEL1_GPIO_PULSE_MASK  (0x000001C0)                     // b0000 0000 0000 0000 0000 0001 1100 0000 
#define GPSET0                   (GPIO_BASE_ADDRESS + 0x1C)
#define GPCLR0                   (GPIO_BASE_ADDRESS + 0x28)

struct bcm2711_peripheral 
{
    unsigned long addr_p;
    int mem_fd;
    void *map;
    volatile unsigned int *addr;
};
 
struct bcm2711_peripheral gpio = {GPIO_BASE_ADDRESS};

/* macros definitions */
#define INP_GPIO(g)   *(gpio.addr + ((g)/10)) &= ~(7<<(((g)%10)*3))
#define OUT_GPIO(g)   *(gpio.addr + ((g)/10)) |=  (1<<(((g)%10)*3))
#define SET_GPIO_ALT(g,a) *(gpio.addr + (((g)/10))) |= (((a)<=3?(a) + 4:(a)==4?3:2)<<(((g)%10)*3))
#define GPIO_SET  *(gpio.addr + 7)
#define GPIO_CLR  *(gpio.addr + 10)
#define GPIO_READ(g)  *(gpio.addr + 13) &= (1<<(g))

// Exposes the physical address defined in the passed structure using mmap on /dev/mem
int map_peripheral(struct bcm2711_peripheral *p)
{
   // Open /dev/mem
   if ((p->mem_fd = open("/dev/mem", O_RDWR|O_SYNC) ) < 0) 
   {
      printf("Failed to open /dev/mem, try using sudo.\n");
      return -1;
   }
 
   p->map = mmap(
      NULL,
      BLOCK_SIZE,
      PROT_READ|PROT_WRITE,
      MAP_SHARED,
      p->mem_fd,      // File descriptor to physical memory virtual file '/dev/mem'
      p->addr_p       // Address in physical map that we want this memory block to expose
   );
 
   if (p->map == MAP_FAILED) 
   {
        perror("mmap");
        return -1;
   }
 
   p->addr = (volatile unsigned int *) p->map;
 
   return 0;
}
 
void unmap_peripheral(struct bcm2711_peripheral *p) 
{
    munmap(p->map, BLOCK_SIZE);
    close(p->mem_fd);
}

int main()
{
   /* initialisations */
   // check if gpio are usable
   if(map_peripheral(&gpio) == -1) 
   {
      printf("Failed to map the physical GPIO registers into the virtual memory space.\n");
      return -1;
   }

   // define PULSE_PIN as output
   INP_GPIO(GPIO_PULSE);
   OUT_GPIO(GPIO_PULSE);

   while(1)
   {
    GPIO_SET = 1 << GPIO_PULSE;
    sleep(1);
 
    GPIO_CLR = 1 << GPIO_PULSE;
    sleep(1);
   }

   return 0;
}
I will try your proposals.

Return to “Advanced users”