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 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
: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.