Author Topic: Implementing an additional, high-priority thread for monitoring serial data  (Read 5527 times)

Offline staylo

  • Jr. Member
  • **
  • Posts: 51
I'm looking once again at implementing RS232 into CHDK, but I lack the knowledge to do it:

In order to successfully read an RS232 packet at 4800 baud (my minimum target), the usb power level must be read at intervals of exactly 208.33us +/- 2us (this is the timing required to ensure no errors). Unfortunately, I have no idea how to add a thread of such high-priority [To be reliable, I think it would have to be given priority over almost all other functions] into the CHDK architecture. Can anyone point me in the right direction?

This page has more basic information on RS232, and the code below shows the simple C required to read an RS232 packet at 9600 baud into a PIC microprocessor - I am hoping to implement something similar.

Code: [Select]
/*--------------------------------------------------------------------------*/
void RxSerial (void) {
/*--------------------------------------------------------------------------*/

/*
 ;---------------------------------------------------------------------------*
 ; Receives 1 start bit Lo, 9 data bits and 1 stop bit Hi at 9600 bps
 ; Byte time = 1.144 mS
 ; Bit  time = 104 uS (0.16% erro w/10 Mhz)
 ;
 ; False start bit check
 ;
 ; Start bit hunting timeout = 4*1.283ms
 ;
 ; Input  : none
 ; Output : Carry = 1 => success
 ;     rxBuf[0,1] = input byte +9th bit
 ;     Carry = 0 => error (timeout or stop bit=0)
 ;---------------------------------------------------------------------------*
*/

char idx;

rxBuf[0] = 4; // 5.135 ms timeout
idx      = 0;

while (1)
{
while (RxD_pin) // input "high"
{
if ((-- idx)==0)
{
rxBuf[0]--;
if (rxBuf[0]==0)
{
Carry = 0;
return;
}
}
}

Delay_uSeg(40); // 1/2 bit delay (40*3+7)*0.4us=50.8us
if (RxD_pin)
continue; // false start bit detection

rxBuf[0] = 0x01; // 9 bits counter and reception buffer
rxBuf[1] = 0x00;

do
{
Delay_uSeg(81); // (81*3+7)*0.4us=100us
nop(); // 0.4us
nop(); // 0.4us
Carry = RxD_pin; // 1.2us bit read
rxBuf[0] = rr(rxBuf[0]); // 0.4us store and count
rxBuf[1] = rr(rxBuf[1]); // 0.4us
} // 1.2us
while (Carry==0);
Delay_uSeg(81); // (81*3+7)*0.4us=100us
nop(); // 0.4us
Carry = RxD_pin; // stop bit read
return; // 100 us availiable
}
}

Offline staylo

  • Jr. Member
  • **
  • Posts: 51
I understand now (or think I do!) that there's no native threading support in the C language, so the approach I was suggesting would be - at best - very difficult to implement. A fallback solution, then:

When my_kbd_read_keys() is called, enter a loop that continuously checks the USB power level.
-If it goes high, the code interprets it as a start bit and attempts to parse the following logic levels as a data packet.
-If the USB power level stays low, the loop exits after a timeout duration (5ms?).

This should give the precise time resolution required without tying up the CPU for too long. Since the camera will only be listening for data for a short period of time it will be necessary to transmit a packet several times to ensure it is received, but this is not a big problem.

I have a few questions still though:

How long is a tick in CHDK? (eg from get_tick_count) Should it be consistent across all cameras? (DIGIC II/DIGIC III?)

What is the purpose of _kbd_pwr_on(),     _kbd_pwr_off()?

Offline GrAnd

  • Developers
  • Hero Member
  • ****
  • Posts: 916
  • [A610, S3IS]
    • CHDK
How long is a tick in CHDK? (eg from get_tick_count) Should it be consistent across all cameras? (DIGIC II/DIGIC III?)

1/1000 for all cameras (it's a timer).
CHDK Developer.

Offline fingalo

  • Developers
  • Jr. Member
  • ****
  • Posts: 92
This is about the same approach I started out to investigate. Problem I found is that the USB signal is delayed -about- 50 ms after it is set on the port. Only solution would be to find a way to read the USB signal directly from a variable or port. It seem that the USB power signal is filtered via some procedure in the camera.

Offline staylo

  • Jr. Member
  • **
  • Posts: 51
Gradually closing in on this. With modified code (continuously loops until it detects the rising edge or a 5ms timeout is reached) I'm now able to detect signals of 10ms duration even without an interrupt pulse, so if there is any power filtering it seems to be less severe on the A640 than fingalo's S3IS.

Interestingly, although get_tick_count returns values in ms, its resolution only seems to be 10ms.

Offline staylo

  • Jr. Member
  • **
  • Posts: 51
Couldn't resist having a crack at this at lunchtime. The A640 can correctly detect a 208.33us bit (4800 baud). It's just down to the timing now.  :xmas

Offline staylo

  • Jr. Member
  • **
  • Posts: 51
Success! I can now talk to my A640 (one byte at a time) at 4800 baud (faster speeds should be perfectly possible) with moderate reliability (because I'm only able to monitor the USB power levels for a limited time, errors are fairly inevitable - I'll have to fine tune the timing and add parity etc to deal with this) . This is a lot more usable than the serial demo I showed. With a little bit of work this makes an awful lot of applications feasible.  8)

Code to follow later tonight, I'll see if I can get it to behave in a more stable manner first.

Offline Divalent

  • Rookie
  • *
  • Posts: 9
check out this section from the wiki scrip tutorial discussion page on script timing.  I think any serial port monitoring for anything other than simple control codes would have to be done at a lower level than a uBasic script.

http://chdk.wikia.com/wiki/Talk:UBASIC/TutorialScratchpad#uBasic_timing.__One_line_.28only.21.29_executed_every_10_msec.3F


Offline staylo

  • Jr. Member
  • **
  • Posts: 51
Thanks, Divalent, and you're right - the monitoring takes place in the CHDK source and updates a variable with the most recently decoded byte, which is then polled by the uBASIC routine. It's not going to be practical to monitor a constant stream of data - eg NMEA position data from a GPS - or indeed reliably capture a single packet, but it does make it extremely simple to send instructions to the camera from any serial equipped device that supports 4800 baud. I've still got a couple of timing issues to sort out.

CHDK Forum


Offline mx3

  • Developers
  • Sr. Member
  • ****
  • Posts: 372
firmware dumper?
« Reply #9 on: 04 / December / 2007, 14:16:05 »
  • Publish
  • staylo:
    is it possible to make firmware dumper using this?
    or it is one-way  transfer only?
    skype: max_dtc. ICQ: 125985663, email: win.drivers(at)gmail, eVB decompiler

    Offline staylo

    • Jr. Member
    • **
    • Posts: 51
    Currently the code is receive only - I read on dpreview that someone has found how to manipulate the TX bit, which could allow for serial output from the camera. I haven't looked at this in any detail yet, but it seems feasible at least.

    Offline fingalo

    • Developers
    • Jr. Member
    • ****
    • Posts: 92
    This is very interesting! I found a difference in the reading the USB signal. In s3 the reading take place after _kbd_read_keys_r2 routine in others before this routine. That could explain why I get this big delay. I will check tonight. Very promising, nice work!

    Offline crunchy_3d

    • Rookie
    • *
    • Posts: 24
    Success! I can now talk to my A640 (one byte at a time) at 4800 baud (faster speeds should be perfectly possible) with moderate reliability ... With a little bit of work this makes an awful lot of applications feasible.  8)

    ... including multi-camera shooting!  :)

    Offline Microfunguy

    • Developers
    • Guru Member
    • ****
    • Posts: 3205
      • StereoData Maker
    > When my_kbd_read_keys() is called, enter a loop that continuously checks the USB power level.


    I thought that function was only called every 10 msec ?


    Do you know if any routines call 'gui_kbd_process' , I cannot find any ?



    David

    Offline staylo

    • Jr. Member
    • **
    • Posts: 51
    It's only called every 10ms, but you can tie it up for longer. (I've just realised I must be tying it up for 10ms as I'm using a timeout based around get_tick_count, which only seems to have a 10ms resolution).

    Quote
    Do you know if any routines call 'gui_kbd_process' , I cannot find any ?


    gui_kbd_process is called core/kbd.c, under kbd_process:

    Code: [Select]
    if (kbd_is_key_pressed(KEY_SHOOT_FULL)){
        key_pressed = 100;
        if (!state_kbd_script_run){
                    script_console_clear();
                    script_console_add_line(lang_str(LANG_CONSOLE_TEXT_STARTED));
    script_start();
        } else {
                    script_console_add_line(lang_str(LANG_CONSOLE_TEXT_INTERRUPTED));
    script_end();
        }
    }

    if (state_kbd_script_run)
        process_script();
    else {
        gui_kbd_process();
    }


    Try this useful and fast utility; it searches through text files for a string and shows you the number of matches:
    Simple Search/Replace

     


    SimplePortal 2.3.3 © 2008-2010, SimplePortal