4

I trying to toggle one of my GPIO pins at a specific frequency, at the kHz range.

I set up the wiringPi Library, the blinking example seems to work just fine.So I modified the code, so it will oscillat at 35 Khz, but the output frequency is about 5.5 kHz. However when I ran the code with no delay at all the output frequency was 0.5 Mhz. Note that I don't output anything to the screen.

I guess that that this related to the definition of sleeping function "suspends the execution of the calling thread", so returning the thread to the foreground might take some time.

How can I define the precise sleeping time?

  • I tired to use usleep as well an nanosleep, but same problem.
  • All the above was done done via an SSH, as I mentioned, no output was sent during execution
  • The pi is running an Apache server, but I guess it doesn't have a big affect on it

Here is the code I used

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

int main (void){
  int pin = 7;

  struct timespec time;
  time.tv_sec = 0;
  time.tv_nsec = 14000L;

  if (wiringPiSetup() == -1)
    exit (1);

  pinMode(pin, OUTPUT);

  while(1){
    digitalWrite(pin, 1);
    nanosleep(&time,&time);
    digitalWrite(pin, 0);
    nanosleep(&time,&time);
  }

  return 0;
}
Kirill Kulakov
  • 139
  • 1
  • 4

3 Answers3

5

What you are trying to achieve is almost impossible using operating system. It's really hard to have some hard real time user space mechanism inside operating system. You can try with some RT systems (I don't know if there are some RPi ports) or real time application interface (RTAI, Xenomai, RT Linux) and write some RT module.

nanosleep() suspends the execution of the calling thread until either at least the time specified in *req has elapsed

this means that your timer will least at least time specified, but it could take longer to invoke the timer signal.

codewarrior
  • 501
  • 2
  • 7
  • As I suspected :/ , What do you think about a blocking function for a specific time? for instance: while( currentTime() - startTime < delay ); Or should I consider external controlled square wave generator such as 555? – Kirill Kulakov Dec 08 '12 at 15:34
  • I would consider writing kernel module and if that will not give what you want then try external generator. Some usefull info could be found here: http://www.mjmwired.net/kernel/Documentation/timers/timers-howto.txt. Take a look especially at usleep_range function. – codewarrior Dec 08 '12 at 15:44
  • Since I'm not familiar with writing kernel modules, I'd go with an external oscillator, I'll try the usleep_range() method – Kirill Kulakov Dec 08 '12 at 21:34
2

It appears as if you are trying to achieve PWM. For your desired duty cycle you're probably better going after a hardware PWM solution rather than toggle GPIO with user-space delays. The reason for this is that nanosleep reduces to a wait for an interrupt on a hardware timer, which takes a non-negligible about of time to be serviced at user-space.

Here's a good starting point: Can I use the GPIO for pulse width modulation (PWM)?

-1

As @codewarrior said that the nanosleep() will suspend the thread for at least the specified time, so I decided to block the thread rather than return the CPU time to the OS.

Here is my implantation of a precise delay function:

#include <sys/time.h>

void udelay(long us){
    struct timeval current;
    struct timeval start;

    gettimeofday(&start, NULL);
    do {
        gettimeofday(&current, NULL);
    } while( ( current.tv_usec*1000000 + current.tv_sec ) - ( start.tv_usec*1000000 + start.tv_sec ) < us );
}
no id
  • 169
  • 1
  • 9
Kirill Kulakov
  • 139
  • 1
  • 4
  • This is not "best" solution in case of performance. If you will try to controll more than one pin you could encounter serious limitations. – codewarrior Dec 08 '12 at 18:18
  • Yes, I know, but I'm using it just one pin for a few millisecond to transmit (modulated IR) a signal.So performance should be an issue here – Kirill Kulakov Dec 08 '12 at 21:30
  • 2
    No. What you have is not a precise delay function. The issue is that even though you don't actively yield to the scheduler by calling a sleep function, you will still get interrupts into the kernel, and the scheduler will still perform context switches to other userspace processes for system housekeeping, which will cause hiccups in your timing. If you used code like this to make an audio tone, and hooked it up to a piezo transducer, you would likely hear periodic gaps when the system is lightly loaded, and grunge when a lot is going on. – Chris Stratton Nov 14 '15 at 02:39