Using timing functions - page 5 - General Discussion and Assistance - CHDK Forum  

Using timing functions

  • 66 Replies
  • 10539 Views
*

Offline philmoz

  • *****
  • 3123
    • Photos
Re: Using timing functions
« Reply #40 on: 12 / April / 2014, 19:12:27 »
Advertisements
Code: [Select]
void __attribute__((optimize("O0"))) LED_flasher()
{
    ...
}

This should eliminate the need for dummy variables, or other tricks to stop the compiler optimising the function away.

Phil.
CHDK ports:
  sx30is (1.00c, 1.00h, 1.00l, 1.00n & 1.00p)
  g12 (1.00c, 1.00e, 1.00f & 1.00g)
  sx130is (1.01d & 1.01f)
  ixus310hs (1.00a & 1.01a)
  sx40hs (1.00d, 1.00g & 1.00i)
  g1x (1.00e, 1.00f & 1.00g)
  g5x (1.00c, 1.01a, 1.01b)

*

Offline reyalp

  • ******
  • 12066
Re: Using timing functions
« Reply #41 on: 13 / April / 2014, 02:13:05 »
Quote
What is getm and how should it be used? I couldn't find anything on google about it, is it a CHDK only thing?
You need to study the code & docs for chdkptp.  It seems that reyalp no longer posts plain script code - just commands that run from the chdkptp command line  ;)
A tangent, but maybe someone will find it useful...

I use chdkptp for testing stuff like this a lot, because I can try things quickly and see the result on my PC without having to upload a script or rebuild CHDK. Stuff like the snippet I posted is usually the result of a few iterations of testing and build progressively longer scripts. I post the code for future reference, and so anyone who case can see how I got the result or point out errors.

Breaking the earlier code down:
Code: [Select]
set_yield(-1,-1) -- disable script / keyboard task yield
-- wait for the timer to wrap, so we know we are starting near zero
local t0=peek(0xc0242014) while peek(0xc0242014) > t0 do end
local tick0=get_tick_count() -- get the start time in ms
-- wait for the counter to wrap ten more times to get a reasonable sample
for i=1 ,10 do
  t0=peek(0xc0242014)
  while peek(0xc0242014) > t0 do end
end
return get_tick_count() - tick0 -- return the elapsed time in ms
. executes the above without waiting for it to return. I discovered this was required because with yielding disabled and script in a tight loop, PTP isn't able to respond, and 10 seconds is longer than something is willing to wait. The return value is a "message" in the PTP extension, so running getm after about 10 seconds gets it.

10490 agrees very well with a counter that wraps every 1.048575 seconds. There's some room for error, but nowhere near half a seconds worth.
Don't forget what the H stands for.

Re: Using timing functions
« Reply #42 on: 13 / April / 2014, 04:05:58 »
Quote
Until it's interrupted or yields,  the current task gets all of the CPU.  I think that's what you were asking?
Yeah that's what I meant thanks.

I just looked at the output on the scope, and unfortunately it seems that it is getting interrupted every now and then with glitches. Then I realised I had been only testing it in playback mode. Shooting mode turned out to be so terrible that the LED was visibly flickering.

Is there any way to prevent other tasks from interrupting the process? Maybe some command to make the CPU ignore interrupts?


Quote
This should eliminate the need for dummy variables, or other tricks to stop the compiler optimising the function away.
Thanks, I'll try that. Now I know what all those __attribute__ tags in the code are for.


Re: Using timing functions
« Reply #43 on: 13 / April / 2014, 10:16:57 »
Is there any way to prevent other tasks from interrupting the process? Maybe some command to make the CPU ignore interrupts?
Bad coding practice at best.  Dangerous to your camera at worst.

AFAIK, the goal here is fast enough inter-camera communications to make coordinating a stereo rig viable?  With a little careful design, small bit packets with no timing requirement between packets, and duplicate messages using final error checking of the whole message (checksum or CRC) would seems to be adequate for the task.
Ported :   A1200    SD940   G10    Powershot N    G16


*

Offline reyalp

  • ******
  • 12066
Re: Using timing functions
« Reply #44 on: 13 / April / 2014, 15:19:56 »
Is there any way to prevent other tasks from interrupting the process? Maybe some command to make the CPU ignore interrupts?
Bad coding practice at best.  Dangerous to your camera at worst.
FWIW, you can disable interrupts using the ARM program status register. See "ARM Architecture Reference Manual" A2.5 Program status registers. The firmware has functions which do this, and they are used quite frequently. But as Waterwingz it's a bad idea unless you know exactly what you are doing.
Don't forget what the H stands for.

Re: Using timing functions
« Reply #45 on: 13 / April / 2014, 17:26:01 »
adequate for the task.

This is the point, define the task.
High-speed comms may be personally satisfying or a software challenge but what do you really need ?
If the aim is to ensure both cameras are in exactly the same mode, that is understandable but plenty of SDM and CHDK users manage without it (including me).
It does not take long to compare the settings and then leave them set.

I know someone who was developing an MTP solution for this but gave-up for unspecified reasons.

Nevertheless, good luck !

Re: Using timing functions
« Reply #46 on: 13 / April / 2014, 17:50:39 »
If the aim is to ensure both cameras are in exactly the same mode, that is understandable but plenty of SDM and CHDK users manage without it (including me). It does not take long to compare the settings and then leave them set.
IIRC,  the OP's original intent was to be able to do this while shooting stereo underwater.  Somewhat more difficult than normal,  even if the weather in the UK frequently makes one think of underwater photography.
Ported :   A1200    SD940   G10    Powershot N    G16

Re: Using timing functions
« Reply #47 on: 13 / April / 2014, 19:59:44 »
the OP's original intent was to be able to do this while shooting stereo underwater. 

Seems a legitimate application.

Comms speed required is another matter.


Re: Using timing functions
« Reply #48 on: 14 / April / 2014, 14:29:59 »
the OP's original intent was to be able to do this while shooting stereo underwater. 

Seems a legitimate application.

Comms speed required is another matter.

That was sort of the original intent, I had hoped to maybe do some underwater stereo-photography with the D20 rig. But I never got around to building a waterproof remote system, and now that summer's over, I probably won't be working on that until it starts to get warm again in November (that may sound confusing for those not in the southern hemisphere)

TBH the only reason I really bought a second D20 was because I got it cheap and I already had one anyway (as a camping camera that can get wet). Same with the SX40 (not the getting wet part though)


Quote
High-speed comms may be personally satisfying or a software challenge but what do you really need ?
If the aim is to ensure both cameras are in exactly the same mode, that is understandable but plenty of SDM and CHDK users manage without it (including me).
It does not take long to compare the settings and then leave them set.
Yeah I guess they don't really need to be that fast. Probably the largest ammount of data would be 64 bits for the SX40 (which has 32 bits of focus) and maybe 48 for the S110. Maybe 32, or maybe even less if I don't send focus.

With the S110's ring dial and also the thumb-dial on the back, it makes sense to keep it in manual mode all the time. And even with the D20 rig, I usually find myself changing the ISO settings and EV compensation alot. So having these values synchronised between the cameras will make shooting much more efficient. These settings are probably more important than the focus, which I might not send to the slave if I can't get the speed fast enough.





Anyway, I tried the following code:

Code: [Select]
void set_led_on()
{
    *((volatile int *) AF_LED_ADDRESS) = LED_ON;
    _SetHPTimerAfterTimeout(0,wait_until_this_time,set_led_off,set_led_off,0);
    wait_until_this_time += 512;
}

void set_led_off()
{
    *((volatile int *) AF_LED_ADDRESS) = LED_OFF;
    if (wait_until_this_time < 1000000)
    {
        _SetHPTimerAfterTimeout(0,wait_until_this_time,set_led_on,set_led_on,0);
        wait_until_this_time += 512;
    }
    else
    {
        wait_until_this_time = 256;
        start_LED_flasher = 1;
    }
}

void __attribute__((optimize("O0"))) LED_flasher()
{
    while (*(int*)0xc0242014 > 16)// wait till it's at the start
    { }
        _SetHPTimerAfterNow(wait_until_this_time,set_led_on,set_led_on,0);
        wait_until_this_time += 256;
}

And that gives a very clean 1kHz output from the LED (shooting mode):

But the only problem is that if wait_until_this_time is incremented any less than 512 each time, the camera will only flash the LED briefly then crash. Regardless of whether it's in playback or shooting mode. Any idea of why it would be doing this?

Also, if I can't get the precision faster than 512 us is there any chance I could call my own interrupts (maybe with a native call or even an assembly command with a pointer to the function or something)? And there wouldn't be much chance of it harming the camera would there?

Re: Using timing functions
« Reply #49 on: 15 / April / 2014, 13:09:30 »
More progress. I realised that, with the timing accuracy of the last test, there's really no need to use pulse-widths to transmit the data, it can just be bit-banged directly, as long as the start bit is synchronised beforehand (the slave will sample in the middle of each bit). So at 1kHz, a 64 bit transmission will only take 64ms. Haven't tested 2kHz but it should work aswell. Maybe even faster, more tests tomorrow. With this speed, error correction shouldn't take too much extra time.


sending a 16 bit packet. Should be able to handle a 48 or 64 bit packet without pauses hopefully.

Code: [Select]
int master_current_bit = 0;
int master_wait_untill = 2048;
void master_send_bit();

unsigned short master_message_buffer = 54321; //Just a random number at the moment


void __attribute__((optimize("O0"))) LED_flasher()
{
    while (*(int*)0xc0242014 > 1024) //wait till it's at the start, wrap will coded later
    {
       
    }
    _SetHPTimerAfterTimeout(0,master_wait_untill,master_send_bit,master_send_bit,0);
}



void master_send_bit()
{
    if (master_message_buffer & (1 << master_current_bit)) //get the current bit
    {
        *((volatile int *) AF_LED_ADDRESS) = LED_ON;
    }
    else
    {
        *((volatile int *) AF_LED_ADDRESS) = LED_OFF;
    }
    if (master_current_bit < 16) //16 bits for now
    {
        master_current_bit++;
        master_wait_untill+=1024;
        _SetHPTimerAfterTimeout(0,master_wait_untill,master_send_bit,master_send_bit,0);
    }
    else
    {
        master_wait_untill = 2048;
        start_LED_flasher = 1; //allow it to run again
    }
}


Tomorrow I'll hopefully get the transmitting/receiving part done (to a workable level, error correction later).
No questions at the moment, but suggestions/warnings welcome ;)

Thanks for all the help and advice received so far

 

Related Topics