Community
cancel
Showing results for 
Search instead for 
Did you mean: 
MHill7
Beginner
1,008 Views

hrtimer.h und/oder timer interrupt

Jump to solution

Hallo liebe community,

für mein Projekt auf der Intel Edison Plattform benötige ich einen Timer/Timer-interrupt, welches alle 0,1ms (10kHz) ausgelöst wird. Soweit ich das sehe, ist der hrtimer in der aktuellen Poky-Distro nicht verfügbar, oder habe ich etwas übersehen? Mein Ziel ist, ein Signal mit 10 KHz über einen exteren Sensor (SPI) abzutasten und die Werte zu speichern. Besteht irgendeine Möglichkeit, das Problem auf Linuxebene zu lösen. Ich Arbeite mit Eclipse und C/C++ (kein Arduino)

Vielen Dank!

0 Kudos
1 Solution
KMill10
Valued Contributor II
66 Views

Pedro's answer is great and it runs in a tight loop.

Here are a couple of helper-functions that I use, to create timers which send a signal (similar to an interrupt) to the app at specified intervals. You can specify the interval in seconds or nano-seconds.

// When any timer fires it will call here.

// The ID of the timer is stored in the si_value.sival_ptr member.

static void handler(int sig, siginfo_t *si, void *uc)

{

UNUSED(uc); // The user-context is almost universally never used.

UNUSED(sig); // We could check SIG against TIMER_SIG but why bother since it's the only signal we registered for?

static uint64_t seconds = 0;

// off_t filesize;

uint32_t param;

// Get the timer ID.

param = (uint32_t)si->si_value.sival_ptr;

switch (param) {

case ONE_SECOND_TIMER:

seconds++;

//discovery_tick();

if((seconds % 120)==0)

{

if(mcp->opts.logfd)

{

// Tell world how many lines we have logged.

sprintf(g_buf, "Logged %d Lines",mcp->opts.loglines);

mc->sendMqttIDMessge(g_buf, (char*)"canlog");

}

}

break;

case TWENY_MILLISECOND_TIMER:

mcp->tick(); // Call the Microchip-Can-Controller tick.

break;

default:

break;

}

}

// Schedule and start a timer. Specify a uniuqe ID and time in seconds and nano-seconds.

void startTimer(uint32_t id, long sec, long nsec)

{

struct sigaction sa;

struct itimerspec ts;

struct sigevent sev;

timer_t tid;

// Configure the signal action.

sa.sa_flags = SA_SIGINFO;

sa.sa_sigaction = handler; // When the timer fires, it will call handler(...);

sigemptyset(&sa.sa_mask); // No masks.

// Establish a handler for our custom signal TIMER_SIG

if(sigaction(TIMER_SIG, &sa, NULL)==-1)

{

std::cerr << "Error in sigaction\n";

return;

}

// Configure the signal event structure

sev.sigev_notify = SIGEV_SIGNAL; // We wish to be notified using a SIGNAL

sev.sigev_signo = TIMER_SIG; // Use our custom signal number: TIMER_SIG

sev.sigev_value.sival_ptr = (void*)id;

// Configure the time-spec

ts.it_value.tv_sec = sec;

ts.it_value.tv_nsec = nsec;

ts.it_interval.tv_sec = sec;

ts.it_interval.tv_nsec = nsec;

// Create the timer

if(timer_create(CLOCK_REALTIME, &sev, &tid) == -1)

{

std::cerr << "Error in timer_create\n";

return;

}

// Start the timer.

if(timer_settime(tid,0,&ts, NULL)==-1)

{

std::cerr << "Error in settime\n";

}

}

I hope this helps too!

View solution in original post

3 Replies
idata
Community Manager
66 Views

Hello tuma84,

 

 

Thanks for reaching out!

 

 

As you mentioned, Edison's standard image doesn't have hrtimer installed, therefore it is not possible to create a timer with this library by default. However, I created this small script that might help you. The script creates a loop that, I believe, will get you as close to 100us as a non-RTOS OS will get you.

 

 

# include

 

# include

 

 

int main (int argc, char** argv) {

 

struct timeval tvalBefore;

 

struct timeval tvalAfter;

 

 

long time_elapsed = 0;

 

 

gettimeofday (&tvalBefore, NULL);

 

long time_b_sec = tvalBefore.tv_sec;

 

long time_b_usec = tvalBefore.tv_usec;

 

 

while (time_elapsed < 100)

 

{

 

gettimeofday (&tvalAfter, NULL);

 

long time_a_sec = tvalAfter.tv_sec;

 

long time_a_usec = tvalAfter.tv_usec;

 

time_elapsed = ((time_a_sec - time_b_sec) * 1000000L + time_a_usec) - time_b_usec;

 

}

 

printf("Time in microseconds: %ld microseconds\n", time_elapsed);

 

return 0;

 

}

 

 

I hope this information helps you, and if you have any doubts, please don't hesitate to ask.

 

Pedro M.
KMill10
Valued Contributor II
67 Views

Pedro's answer is great and it runs in a tight loop.

Here are a couple of helper-functions that I use, to create timers which send a signal (similar to an interrupt) to the app at specified intervals. You can specify the interval in seconds or nano-seconds.

// When any timer fires it will call here.

// The ID of the timer is stored in the si_value.sival_ptr member.

static void handler(int sig, siginfo_t *si, void *uc)

{

UNUSED(uc); // The user-context is almost universally never used.

UNUSED(sig); // We could check SIG against TIMER_SIG but why bother since it's the only signal we registered for?

static uint64_t seconds = 0;

// off_t filesize;

uint32_t param;

// Get the timer ID.

param = (uint32_t)si->si_value.sival_ptr;

switch (param) {

case ONE_SECOND_TIMER:

seconds++;

//discovery_tick();

if((seconds % 120)==0)

{

if(mcp->opts.logfd)

{

// Tell world how many lines we have logged.

sprintf(g_buf, "Logged %d Lines",mcp->opts.loglines);

mc->sendMqttIDMessge(g_buf, (char*)"canlog");

}

}

break;

case TWENY_MILLISECOND_TIMER:

mcp->tick(); // Call the Microchip-Can-Controller tick.

break;

default:

break;

}

}

// Schedule and start a timer. Specify a uniuqe ID and time in seconds and nano-seconds.

void startTimer(uint32_t id, long sec, long nsec)

{

struct sigaction sa;

struct itimerspec ts;

struct sigevent sev;

timer_t tid;

// Configure the signal action.

sa.sa_flags = SA_SIGINFO;

sa.sa_sigaction = handler; // When the timer fires, it will call handler(...);

sigemptyset(&sa.sa_mask); // No masks.

// Establish a handler for our custom signal TIMER_SIG

if(sigaction(TIMER_SIG, &sa, NULL)==-1)

{

std::cerr << "Error in sigaction\n";

return;

}

// Configure the signal event structure

sev.sigev_notify = SIGEV_SIGNAL; // We wish to be notified using a SIGNAL

sev.sigev_signo = TIMER_SIG; // Use our custom signal number: TIMER_SIG

sev.sigev_value.sival_ptr = (void*)id;

// Configure the time-spec

ts.it_value.tv_sec = sec;

ts.it_value.tv_nsec = nsec;

ts.it_interval.tv_sec = sec;

ts.it_interval.tv_nsec = nsec;

// Create the timer

if(timer_create(CLOCK_REALTIME, &sev, &tid) == -1)

{

std::cerr << "Error in timer_create\n";

return;

}

// Start the timer.

if(timer_settime(tid,0,&ts, NULL)==-1)

{

std::cerr << "Error in settime\n";

}

}

I hope this helps too!

View solution in original post

MHill7
Beginner
66 Views

Hi SpiderKenny,

thanks a lot! That is exactly what I was looking for. It's working so far. I will do some further tests but it's already more accurate than my thread-based solution. I also thought about putting an external clock on one input pin and using the edison's interrupt. Of course I don't want to change my PCB-layout again

Reply