X-10 CM17A Interface by Mike Naberezny

Introduction

The FireCracker CM17A is a home automation control device sold in the United States by a company called X-10.

X-10 sells a variety of plug-in modules for controlling lights and power outlets. The devices communicate by injecting a signal onto the home's power lines, so X-10 modules can be distributed throughout the house and controlled without any additional wiring. A common X-10 device is usually something like an addressable switch called an "appliance module". Each X-10 device is identified by a unique house code and unit code. A command code instructs the devices to perform operations such as "on", "off", or "dim".

X-10 offers RF handheld remotes for controlling X-10 devices. The remotes transmit a signal to a transceiver module which in turn transmits the control signals over the power line to the modules. X-10 also sells a device called the FireCracker CM17A. The FireCracker is an X-10 RF remote for PCs that allows a PC to control any X-10 device wirelessly. The FireCracker looks like a small dongle that plugs into the serial port. With some simple wiring and software, the FireCracker can be controlled by any 6502-based machine.

Interface

The FireCracker is intended to plug into a PC serial port with its female DB9 connector. It uses only three lines on this port: GND (pin 5), DTR (pin 4), and RTS (pin 7). These lines may be directly connected to a VIA or similar I/O device by connecting a mating DB9 male and wiring up the ground and two signal lines like this:

FireCracker DB9 6522 VIA
RTS (pin 4) PB0 (pin 10)
DTR (pin 7) PB1 (pin 11)
GND (pin 5) Vss (pin 1)

Programming

Controlling the FireCracker requires a program that takes the X-10 House Code, Unit Address, and Command Code and translates them into a five-byte FireCracker command string. More details about the FireCracker protocol can be found on the web. The FireCracker uses a two-wire connection and each bit of the command string must be "bit-banged" into it. The program below is used to assemble and transmit the FireCracker command string. The FireCracker will broadcast the RF signal to its transceiver upon receiving a correct command string.

BYTE_TO_SEND	= $01
HOUSE_CODE	= $02
UNIT_CODE	= $03
COMMAND		= $04

		*=$700

RESET_CM17A:    JSR CM17INIT            ;Initialize I/O
                JSR RTS_LO
                JSR DTR_LO              ;Remove power from CM17A
                JSR PAUSE_50            ;Pause for 50ms
                JSR RTS_HI
                JSR DTR_HI              ;Restore power to CM17A
                RTS

SEND_COMMAND:   LDA #$D5
                STA BYTE_TO_SEND
                JSR SEND_BYTE           ;Send first header byte

                LDA #$AA
                STA BYTE_TO_SEND
                JSR SEND_BYTE           ;Send second header byte

                LDX HOUSE_CODE
                LDA HOUSE_TABLE,X
                STA BYTE_TO_SEND        ;BYTE_TO_SEND = HOUSE_TABLE,HOUSE_CODE

                LDA #$09
                CMP UNIT_CODE
                BCS LOW_UNIT            ;If UNIT_CODE < 9 Then Goto LOW_UNIT

                LDA #$04
                CLC
                ADC BYTE_TO_SEND
                STA BYTE_TO_SEND        ;BYTE_TO_SEND = BYTE_TO_SEND + 4

LOW_UNIT:       JSR SEND_BYTE           ;Transmit data first byte
                LDA #$20
                STA BYTE_TO_SEND        ;BYTE_TO_SEND = #$20
                LDA COMMAND
                BEQ ADD_UNIT            ;If COMMAND = 0 Then Goto ADD_UNIT
                LDA #$00
                STA BYTE_TO_SEND        ;BYTE_TO_SEND = #$00
                LDA COMMAND
                CMP #$01
                BEQ ADD_UNIT            ;If COMMAND = 1 Then Goto ADD_UNIT
                LDA #$88
                STA BYTE_TO_SEND        ;BYTE_TO_SEND = #$88
		LDA COMMAND
		CMP #$02
		BEQ NO_UNIT		;If COMMAND = 2 Then Goto NO_UNIT
		LDA #$98
		STA BYTE_TO_SEND	;BYTE_TO_SEND = #$98
		JMP NO_UNIT		;Goto NO_UNIT

ADD_UNIT:	LDA #$09
		CMP UNIT_CODE
		BCS ADU2		;If UNIT_CODE < 9 Then Goto ADU2
		LDA UNIT_CODE
		SEC
		SBC #$08
		TAX
		JMP AU3
  ADU2:		LDX UNIT_CODE		;X = UNIT_CODE
  ADD3:		LDA UNIT_TABLE,X
		CLC
		ADC BYTE_TO_SEND
		STA BYTE_TO_SEND	;BYTE_TO_SEND = BYTE_TO_SEND + (UNIT_TABLE Data)
NO_UNIT:	JSR SEND_BYTE		;Transmit second byte
		LDA #$AD
		STA BYTE_TO_SEND
		JSR SEND_BYTE		;Transmit footer byte
		RTS

SEND_BYTE:	LDA BYTE_TO_SEND
		LDX #$08
  SB1:		ROL
		BCS SB2
		JSR SEND_0
		JMP SB3
  SB2:		JSR SEND_1
  SB3:		DEX
		BNE SB1
		RTS

SEND_0:         JSR RTS_LO
                JSR PAUSE_1
                JSR RTS_HI
                RTS

SEND_1:         JSR DTR_LO
                JSR PAUSE_1
                JSR DTR_HI
                RTS

;Timing Routines
PAUSE_1:        RTS        ;Routine to pause 1ms
PAUSE_50:	RTS        ;Routine to pause 50ms

;I/O Routines
CM17INIT:       RTS        ;Initialize your I/O (data direction registers)
DTR_HI:         RTS        ;Set CM17A's DTR line (pin 4) to high.
DTR_LO:         RTS        ;Set CM17A's DTR line (pin 4) to low.
RTS_HI:         RTS        ;Set CM17A's RTS line (pin 7) to high.
RTS_LO:         RTS        ;Set CM17A's RTS line (pin 7) to low.

HOUSE_TABLE:	.BYTE $60, $70, $40, $50, $80, $90, $A0, $B0, $E0, $F0, $C0
		.BYTE $D0, $00, $10, $20, $30
UNIT_TABLE:	.BYTE $00, $10, $08, $18, $40, $50, $48, $58

To use the program presented above you must add a few routines that will be specific to your hardware. PAUSE_1 and PAUSE_50 will simply pause for one and fifty milliseconds, respectively. This allows the FireCracker to keep up with the transmission. CM17INIT will contain any initialization code required for the I/O, such as setting a VIA's data direction register. The remaining routines, such as DTR_HI and RTS_LO, will set the line states of your I/O lines as indicated by the comments in the code.

To use the code, first call RESETCM17A which will reset the FireCracker by temporarily removing power from it. This only needs to be done once in your program. Next, the HOUSE_CODE, UNIT_CODE, and COMMAND variables need to be set.

The HOUSE_CODE is a number from 0-x (decimal), corresponding House Codes A-x. The UNIT_CODE is a number from 0-x, corresponding to Unit Codes 1-x. The command codes are:

Description Command Code
Off 0
On 1
Bright 2
Dim 3

For example, to turn an appliance module ON whose address is B2 (House Code "B", Unit Code "2"), set HOUSE_CODE=1, UNIT_CODE=1, and COMMAND=1. Finally, calling SEND_COMMAND will construct the codes for the FireCracker and transmit them. Here is an example of how to call these routines, again setting B2 ON:

MAIN:		JSR RESETCM17A        ;Reset the FireCracker CM17A

                LDA #01
		STA HOUSE_CODE        ;Set the House Code (B)

		LDA #01
		STA UNIT_CODE         ;Set the Unit Code (2)

		LDA #01
		STA COMMAND           ;Set the Command Code (On)

		JSR SEND_COMMAND      ;Command FireCracker for B2 ON
		RTS 

Conclusion

With your I/O routines and timing routines added, after this code is executed the appliance module at address B2 should turn ON. Setting the COMMAND code to 0 (OFF) and calling SEND_COMMAND again will turn the module back OFF.

You now have all of the tools necessary to control almost any appliance or light with X-10 modules and your 6502-based project. Add some timer code and you can easily turn appliances on and off with a schedule program. Since the FireCracker is wireless, this will work with battery-operated projects like robots as well.

Last page update: November 28, 2002.