Wednesday, 29 August 2018

How to make your own Olympus RM-1 compatible remote

Some history


Back in 2006, after a lot of research and experimenting I managed to crack the way Olympus controls the E-500 using the RM-1 IR remote control. This was my first digital camera related work and did it for fun. Recently I received some questions about it, so since it seems that the idea still interests some people I decided to post this article again. Olympus no longer makes any DSLR and I have no idea if this works with the more modern mirrorless cameras, so this is history. So whatever you make of this is up to you. I will not be able to provide any support, other than I know that the code worked very reliably and well with the remotes I made.

About the IR remote


The remote has five buttons but the picture shows a three button version. I managed to crack the function of all five. I don’t think any deep explanation is necessary, any person with a basic knowledge of microcontroller programming can implement the code in any type of microcontroller. The code is primarily written for the 12F629 PIC made by Microchip (which I believe is also out of production now) but it is easy to translate to other microcontrollers if you have enough programming knowledge and can read and understand assembly language.



Technical functional description


Modulation is 40 kHz symmetrical pulse modulation.
Each command starts with 3.8 ms 40kHz pulse train followed by 4ms Low state on GP5 and finished off with 550us 40kHz pulse train.

1 = 1500us GP5 Low state followed by 500us 40kHz pulse train.
0 = 500us GP5 Low state followed by 500us 40kHz pulse train.

After each button press there is a 500ms button repeat delay.

The Olympus button control codes are:

Fire button: 0110 0001 1101 1100 1000 0000 0111 1111
W button:    0110 0001 1101 1100 0100 0000 1011 1111
T button:    0110 0001 1101 1100 1100 0000 0011 1111
- button:    0110 0001 1101 1100 0010 0000 1101 1111
+ button:    0110 0001 1101 1100 1010 0000 0101 1111


The hardware


The hardware is very simple, it contains only of three resistors, one transistor driving the IR LED and a Microchip 12F629 PIC microcontroller and five buttons. The source code below is a fully working code example for the 12F629.

Click on the image to the right to see the schematics.





The picture shows a three button pocket version. With 4.5 V (3x1.5 hearing aid batteries) the range is about 12-15 meters outdoors. My remote has been working very well since May 2006, used it for as long as I used Olympus cameras.




 

 

The Source code


The source code is also very simple. It is written in assembly language, so just copy the code below and paste it into an assembler and compile it, or modify if you wish to modify it to your purpose.

;----------------------------------------------------------------
;
;    Emulation of Olympus RM-1 IR remote control using PIC 12F629.
;
;    The PIC GPIO 5 controls an IR-LED via one BC557 and a 2.7Ohm
;    resistor in series.
;
;    Olympus control codes are:
;

;    Button        GPIO    Code
;
;    Fire          0        0110 0001 1101 1100 1000 0000 0111 1111
;    W             1        0110 0001 1101 1100 0100 0000 1011 1111
;    T             2        0110 0001 1101 1100 1100 0000 0011 1111
;    -             3        0110 0001 1101 1100 0010 0000 1101 1111
;    +             4        0110 0001 1101 1100 1010 0000 0101 1111
;
;    Modulation is 40 kHz symetrical pulse modulation.
;
;    Each command starts with 3.8 ms 40kHz pulse train followed by
;    4ms Low state on GP5 and finished off with 550us 40kHz pulse train.
;
;    1 = 1500us GP5 Low state followed by 500us 40kHz pulse train.
;    0 = 500us GP5 Low state followed by 500us 40kHz pulse train.
;
;    After each button press there is a 500ms button repeat delay.
;
;
    title        "Olyremote-1"

    include     <p12f629.inc>
    __config    _MCLRE_OFF & _PWRTE_ON & _WDT_OFF & _INTRC_OSC_NOCLKOUT & _BODEN_OFF

    errorlevel    -302    ; No bank selection messages

;----------------------------------------------------------------
;
;            REGISTER DEFINITION
;
;----------------------------------------------------------------

DELAY_H        equ    0x20
DELAY_L        equ    0x21
IR_LENGTH    equ    0x22

;----------------------------------------------------------------
;
;            CODE
;
;----------------------------------------------------------------

    org     0x0000            ; RESET VECTOR
               
;----------------------------------------------------------------
;
;    Initialize PIC
;
initialize_pic

    bsf        STATUS,RP0        ; Sel Bank 1
    call    0x3ff            ; Get OSCAL value
    movwf    OSCCAL            ; write to OSCCAL register

    bcf        OPTION_REG,7    ; Enable weak pullups
    movlw    b'00010111'        ; on GPIO 0-4
    movwf    WPU

    movlw    b'00001000'        ; Enable port change interrupt
    movwf    INTCON

    bcf     STATUS,RP0        ; Select bank 0
    clrf    GPIO            ; Init GPIO
    movlw    0x07            ; set GP2 to digital
    movwf    CMCON
   
    bsf        STATUS,RP0
    movlw    b'00011111'           
    movwf    TRISIO            ; Set I/O 5 as outputs

    movlw    0x1f            ; Enable port change IRQ on GPIO 0-4
    movwf    IOC

    bcf     STATUS,RP0        ; Select bank 0
    bcf        GPIO,5            ; Set GPIO 5 Low

;----------------------------------------------------------------
;                                    
led_main_loop

    bcf        INTCON,GPIF        ; Clear interrupt flag
    bcf        GPIO,5            ; Set GPIO 5 Low

    sleep                    ; and go to sleep to save power
;
;    Wake up from sleep
;    Check which button generated wake-up
;
Test_W
    MOVF    GPIO,W            ; Read GPIO and test for W button
    ANDLW    b'00000001'        ; Mask for the W switch
    BTFSS    STATUS,Z        ; Check ZERO first
    goto    Test_F
    call    Exec_W
    goto    led_main_loop
   
Test_F
    MOVF    GPIO,W            ; Read GPIO and test for Fire button
    ANDLW    b'00000010'        ; Mask for the Fire switch
    BTFSS    STATUS,Z        ; Check ZERO
    goto    Test_T            ; Not Z
    call    Fire
    goto    led_main_loop

Test_T
    MOVF    GPIO,W            ; Read GPIO and test for Fire button
    ANDLW    b'00000100'        ; Mask for the Fire switch
    BTFSS    STATUS,Z        ; Check ZERO
    goto    Test_M            ; Not Z
    call    Exec_T
    goto    led_main_loop

Test_M
    MOVF    GPIO,W            ; Read GPIO and test for Fire button
    ANDLW    b'00001000'        ; Mask for the Fire switch
    BTFSS    STATUS,Z        ; Check ZERO
    goto    Test_P            ; Not Z
    call    Exec_M
    goto    led_main_loop

Test_P
    MOVF    GPIO,W            ; Read GPIO and test for Fire button
    ANDLW    b'00010000'        ; Mask for the Fire switch
    BTFSS    STATUS,Z        ; Check ZERO
    goto    led_main_loop    ; Not Z
    call    Exec_P
    goto    led_main_loop

;----------------------------------------------------------------
;
;        SUBROUTINES
;
;----------------------------------------------------------------

;----------------------------------------------------------------
;
;    The FIRE button was pressed, execute control sequence
;
;    Fire = 0110 0001 1101 1100 1000 0000 0111 1111
;
Fire
    call    Send_Header

    call    Send_One
    call    Send_Null
    call    Send_Null
    call    Send_Null

    call    Send_Null
    call    Send_Null
    call    Send_Null
    call    Send_Null

    call    Send_Null
    call    Send_One
    call    Send_One
    call    Send_One

    call    Send_One
    call    Send_One
    call    Send_One
    call    Send_One

    movlw    .250
    call    DELAY_X_msec        ; 250ms delay before return
    movlw    .250
    call    DELAY_X_msec        ; 250ms delay before return
    return

;----------------------------------------------------------------
;
;    The W button was pressed, execute control sequence
;
;    W = 0110 0001 1101 1100 0100 0000 1011 1111
;
Exec_W
    call    Send_Header

    call    Send_Null
    call    Send_One
    call    Send_Null
    call    Send_Null

    call    Send_Null
    call    Send_Null
    call    Send_Null
    call    Send_Null

    call    Send_One
    call    Send_Null
    call    Send_One
    call    Send_One

    call    Send_One
    call    Send_One
    call    Send_One
    call    Send_One

    movlw    .250
    call    DELAY_X_msec        ; 250ms delay before return
    movlw    .250
    call    DELAY_X_msec        ; 250ms delay before return
    return

;----------------------------------------------------------------
;
;    The T button was pressed, execute control sequence
;
;    T = 0110 0001 1101 1100 1100 0000 0011 1111
;
Exec_T
    call    Send_Header

    call    Send_One
    call    Send_One
    call    Send_Null
    call    Send_Null

    call    Send_Null
    call    Send_Null
    call    Send_Null
    call    Send_Null

    call    Send_Null
    call    Send_Null
    call    Send_One
    call    Send_One

    call    Send_One
    call    Send_One
    call    Send_One
    call    Send_One

    movlw    .250
    call    DELAY_X_msec        ; 250ms delay before return
    movlw    .250
    call    DELAY_X_msec        ; 250ms delay before return
    return

;----------------------------------------------------------------
;
;    The - button was pressed, execute control sequence
;
;    - = 0110 0001 1101 1100 0010 0000 1101 1111
;
Exec_M
    call    Send_Header

    call    Send_Null
    call    Send_Null
    call    Send_One
    call    Send_Null

    call    Send_Null
    call    Send_Null
    call    Send_Null
    call    Send_Null

    call    Send_One
    call    Send_One
    call    Send_Null
    call    Send_One

    call    Send_One
    call    Send_One
    call    Send_One
    call    Send_One

    movlw    .250
    call    DELAY_X_msec        ; 250ms delay before return
    movlw    .250
    call    DELAY_X_msec        ; 250ms delay before return
    return

;----------------------------------------------------------------
;
;    The + button was pressed, execute control sequence
;
;    + = 0110 0001 1101 1100 1010 0000 0101 1111
;
Exec_P
    call    Send_Header

    call    Send_One
    call    Send_Null
    call    Send_One
    call    Send_Null

    call    Send_Null
    call    Send_Null
    call    Send_Null
    call    Send_Null

    call    Send_Null
    call    Send_One
    call    Send_Null
    call    Send_One

    call    Send_One
    call    Send_One
    call    Send_One
    call    Send_One

    movlw    .250
    call    DELAY_X_msec        ; 250ms delay before return
    movlw    .250
    call    DELAY_X_msec        ; 250ms delay before return
    return

;----------------------------------------------------------------
;
;    Send_Header:    Remote codes must starts with this sequence.
;
Send_Header
    movlw    .120                ; Pulse 8ms
    call    Send_IR_Pulse
    movlw    .200
    call    Send_IR_Pulse
    movlw    .4                    ; Space 4ms
    call    DELAY_X_msec
    movlw    .22                    ; Pulse 550us
    call    Send_IR_Pulse

    call    Send_Null
    call    Send_One
    call    Send_One
    call    Send_Null

    call    Send_Null
    call    Send_Null
    call    Send_Null
    call    Send_One

    call    Send_One
    call    Send_One
    call    Send_Null
    call    Send_One

    call    Send_One
    call    Send_One
    call    Send_Null
    call    Send_Null

    return

;----------------------------------------------------------------
;
;    Send_One:   Sends 1677us low signal followed by pulse
;                modulated by 40kHz (25us) symetrical pulses sent
;                for 559us. Corresponds to Olympus IR code "1"
Send_One
    call    Delay_1500us        ; Space 1677us
    movlw    .22
    call    Send_IR_Pulse
    return

;----------------------------------------------------------------
;
;    Send_Null:    Sends 559us low signal followed by pulse
;                modulated by 40kHz (25us) symetrical pulses sent
;                for 559us. Corresponds Olympus IR code "0"
Send_Null
    call    Delay_500us            ; Space 559us
    movlw    .22                    ; Pulse
    call    Send_IR_Pulse
    return

;----------------------------------------------------------------
;
;    Send_IR_Pulse will send a 50% duty cycle pulse until
;    IR_LENGTH is zero. Puls sent on GPIO 5
;
Send_IR_Pulse
    movwf    IR_LENGTH    ; Save number of IR cycles
IR_Pulse                ; loop
    movlw    .3            ; set this to 3 to get 40kHz modulation
    movwf    DELAY_L
    bsf        GPIO,5        ; Set GPIO 5 High
High_20
    decfsz    DELAY_L,F    ; This gives about 12 us High
    goto    High_20
    nop                    ; set this two nops to get 40kHz modulation
    nop
    movlw    .2            ; set this to 2 to get 40kHz modulation
    movwf    DELAY_L
    bcf        GPIO,5        ; Set GPIO 5 Low
Low_20
    decfsz    DELAY_L,F    ; This gives about 12 us Low
    goto    Low_20
    nop
    decfsz    IR_LENGTH,F    ; Decrement IR cycle counter
    goto    IR_Pulse    ; and loop if not zero
    nop
    return

;----------------------------------------------------------------
;
;     Delay routines for correct output pulse width
;
;    This delay is used for output pulse width control
;
DELAY_X_msec                ; Call here with W = X msec delay
    MOVWF    DELAY_H

DELAY_1msec
    MOVLW    .250            ; 1 msec delay loop counter
    MOVWF    DELAY_L
   
DELAY_1ms                    ; 1 msec delay loop
    NOP
    DECFSZ    DELAY_L, F
    GOTO    DELAY_1ms

    DECFSZ    DELAY_H, F        ; Loop counter 1 msec delay loop
    GOTO    DELAY_1msec        ; until counter is zero
    RETLW    0

;----------------------------------------------------------------
;
Delay_1500us

    call    Delay_500us
    call    Delay_500us

;----------------------------------------------------------------
;
Delay_500us
    movlw    .122
    MOVWF    DELAY_L
    call    DELAY_4us
    nop
    nop
    return

;----------------------------------------------------------------
;
DELAY_4us                    ; 4usec delay loop.
    NOP
    DECFSZ    DELAY_L, F
    GOTO    DELAY_4us
    return
   
    end


And finally...


For those of you who only are interested in the HEX code, here it is:
 
:020000040000FA
:100000008316FF23900081131730950008308B0072
:10001000831285010730990083161F3085001F3039
:100020009600831285120B108512630005080139B2
:10003000031D1C284A20132805080239031D222805
:100040003420132805080439031D282860201328AC
:1000500005080839031D2E287620132805081039B5
:10006000031D13288C201328A220BB20BF20BF20F3
:10007000BF20BF20BF20BF20BF20BF20BB20BB2090
:10008000BB20BB20BB20BB20BB20FA30D520FA30E0
:10009000D5200800A220BF20BB20BF20BF20BF204A
:1000A000BF20BF20BF20BB20BF20BB20BB20BB2068
:1000B000BB20BB20BB20FA30D520FA30D520080069
:1000C000A220BB20BB20BF20BF20BF20BF20BF205D
:1000D000BF20BF20BF20BB20BB20BB20BB20BB203C
:1000E000BB20FA30D520FA30D5200800A220BF204E
:1000F000BF20BB20BF20BF20BF20BF20BF20BB2010
:10010000BB20BF20BB20BB20BB20BB20BB20FA30C4
:10011000D520FA30D5200800A220BB20BF20BB206C
:10012000BF20BF20BF20BF20BF20BF20BB20BF20DB
:10013000BB20BB20BB20BB20BB20FA30D520FA302F
:10014000D52008007830C320C830C3200430D52023
:100150001630C320BF20BB20BB20BF20BF20BF2044
:10016000BF20BB20BB20BB20BF20BB20BB20BB20AF
:10017000BF20BF200800DE201630C3200800E0208A
:100180001630C3200800A2000330A1008516A10B81
:10019000C728000000000230A1008512A10BCE2864
:1001A0000000A20BC42800000800A000FA30A10043
:1001B0000000A10BD828A00BD6280034E020E020B6
:1001C0007A30A100E6200000000008000000A10B2A
:0401D000E628080015
:02400E00843FED:00000001FF

Good luck. I hope some of you will still find this old code useful.

Wednesday, 10 January 2018

Improving my Scheppach SD 1600v scroll saw


Please click on the images for larger view if you would like to see more details.

As many of you know, I bought a Scheppach SD1600v scroll saw.


I find it very useful for some work, for instance sawing PCB and other thin material, as well as where other type of saw is not possible to use. It can manage quite well not only thin and soft material, but also aluminium up to 10mm (tested). Probably it could also be used on steel with the right blade, but I have had no reason to try that.

Of course, for this price one should not expect miracles. The machine seems to work well, but it would be surprising if I could not find some weak points.

The LED light


It is a very useful feature to have a LED light on a long arm, but...

I don't like is that the LED light is pretty weak and it is not possible to turn it on without starting the motor also. This is definitely something I will fix at a later stage.

The dust blower


Again, a very good idea and a useful feature, but the pump pumping the air is not very efficient at low speeds, and the flexible pipe is not intended for this purpose and it takes too much space as well as it gets in the way all the time. I will replace the whole thing with a simple fan later on which will blow more efficiently at a constant power independent of the sawing speed. In the meantime I replaced the tube with a soft silicon tube which is much better than the one delivered with the machine.

A fence


There is no fence delivered, so sawing in straight line is practically impossible. Maybe it is not the proper machine for straight sawing, but I intend to use it for that as well, so in my opinion a fence is necessary. Again, this is going to be done later, but for now I use some temporary solution.

The throat plate


The delivered one may works for general wood work or large pieces, but when small items are sawed the plate is not really a good design, mainly because of the huge gaps in it. I don't know how the designers were thinking at all. Even if the table is tilting, the huge gaps are not necessary.

 Regardless which way I rotate the plate the gaps are there and they are making the actual sawing more difficult, even for larger items. I regarded this as the higher priority of all the possible improvements and decided to fix it immediately. As many of you know, I built a CNC which could easily be used for making a new plate out of any material, wood, aluminium or plastic, but because I fairly recently bought a 3D printer kit I decided that this is a perfect exercise in 3D printing so I designed an printed a new plate.

The actual design is fairly simple and straight forward using FreeCAD software. All that was needed was to use a caliper and measure the original one for the dimensions and measure the position of the saw blade when inserted in the saw arms.





On the left is the original, on the right is the 3D printed one. The hole for the saw blade is 6mm in diameter and the gap to slide the throat plate into place is 1.5mm wide. Quite a huge difference compared with the original.





Printing time was about two hours on my printer with my settings, but the results are good, the plate fits perfectly. OK, this is actually the third version, the whole was misplaced a little bit in the first version and after printing the second one and testing, I realized that a small gap was indeed very good to have, so I added the 1.5mm wide gap to be able to change blade without the need of having the plate inserted at the same time.

Now the plate is as good as it gets, the saw blade is perfectly centred and is easy to change blade if necessary. Of course, I can not tilt the table with this plate, if I want to do that I need to change to the original plate for now.





I need to design and make a new one if I want one for tilted table operation with very small gap, but the advantage of a 3D printer is the very short lead time between design and product, and especially for single item, or prototype manufacturing it is very nice to have the possibility of quickly printing readily usable items. Of course, using the CNC would be even faster since it would only take a few minutes to mill out such a plate on my DIY CNC, so perhaps for the next one I will use the CNC, but for now, the 3D printer is the latest toy and is great fun to use it.

Download the STL file


If you want to print one for your own scroll saw then you can download the STL file through this link:

Scroll saw throat plate STL file.

The plate may even other scroll saw machines, there seems to be plenty with similar circular plate.

A quick Google search shows hundreds with similar plates.

The plate whole diameter is 80 mm and with the normal PLA shrinkage the printed item is just perfect. The plate is 3mm thick. Measure your machine before printing because it is pointless to print if you can't use it.