Main

 
X-10 Household Automation on AVRProject

X-10 Household Automation on AVRProject

In the early 1980s, I started dabbling with household automation. I purchased Plug-n-Power Controllers and consoles from Radio Shack. They also offered an interface that connected to the TRS-80 Model 1 Cassette Interface. This allowed me to delve into the Machine Language aspect of this technology (Z-80 machine language, though). The interface was primitive, but the code only needed written once. I had the Model 1 on a timer, it woke up in the morning. It loaded the time and date, looked up my schedule to see if it was a weekend, holiday, or day off (entered in a file). It either shut itself off, or woke me up using a variety of methods like flashing the lights and swearing at me through the voice synthesizer. That was 1984. I had a lot of time on my hands back then.

I'm amazed the technology didn't die. I'm sure some school with dozen young kids would've burnt down, get blamed on an X-10 malfunction, and spell liability doom for this technology forever more. It didn't happen. Radio Shack still sells the modules after 23 years. They're also available from many other sources.

X-10 communicates with RF pulses through the power line. These pulses occur on the trailing edges of the AC sine wave peaks within a small timing window (lowest power consumption on linear supplies). The code is not 'bullet proof' as appliances such as drills, circular saws, and washing machines can send errant codes through the line when mechanical switches bounce and arc. Early unfiltered switching power supplies were also a serious signal problem back in the early 90s. Furthermore, I have a whole pile of blown modules and control consoles evident from 23 years of constant use.

Recently I encountered an X-10 Powerhouse two way Power Line Interface (Model TW523) on Ebay. I purchased 2 (just in case my messing around fries one) . To my dismay, I found the technology almost unimproved. With only ancient knowledge and no documentation, I examined and reverse engineered, finding the pinout below.

1 - Yellow - pulled up with 10K ohm is 60 HZ

2 - Green is Common GND

3 - Red - pulled up with 10K ohm is Signal In

4 - Black - Jams controller when pulled up with 1K ohm à Signal Output

These signal-input pulses are 1.1mS to 1.2mS in width (1.146 to be exact). The pulses are roughly synchronized to the moment of change of the 60hz output signal. This TW523 module conveniently does the RF part and Opto-Isolates the inputs and outputs for us. Our AVRProject will be safe. We need 10K pull-ups to 5V on pins 1 and 3 to look at the data. I didn't believe the internal AVR pull-ups are strong enough to pull up the opto-isolators (50K ohm) so I didn't try it. Common GND is on pin 2.

A look at the logic analyzer of the 60hz clock and the Signal In lines shows the 60hz square wave. Hitting a button on a separate X-10 controller pad shows the pulses being pulled low for the 1.146mS length of time. I'm calling this pulse a '1'. Absence of a pulse would be called a '0'.

-The data pulse train, synchronized at 60hz (rising or falling) always starts with '1 1 1 0' pulse pattern. This is true for all commands, selects, and house codes.

-After this 'Start' signal, 8 bits of data is shifted out, MSB first, synchronized data bits are '1 0' pulse pattern for a logic 1, and '0 1' pulse pattern for a logic 0. The 8 bits is actually a 4 bit house encode (MSD), followed by 4 bits of either the unit select encode or command code (LSD).

-Finally, we get to the stop bit. If the last digit of the data was a unit select, it ends with a '0 1' pulse pattern. If it was a command, it ends with a '1 0' pulse pattern (OK, just a '1' will do).

-Above example shows 1110 01 01 01 01 01 10 10 01 01. It was captured when the '1' select button was pressed under house code 'M'.

House Codes and Unit Select codes are a mystery as to why they devised such an encrypted numbering system. I tried for weeks of idle time to figure a logical pattern -- failed. Here they are:

House Code Unit Select X-10 Encode Value
A 1 6
B 2 E
C 3 2
D 4 A
E 5 1
F 6 9
G 7 5
H 8 D
I 9 7
J 10 F
K 11 3
L 12 B
M 13 0
N 14 8
O 15 4
P 16 C
     
All Off   0
All On   1
On   2
Off   3
Dim   4
Brighten   5

I'll show a few pulse patterns to illustrate. These pulses are synchronized with either a rising or falling edge of the 60 hz signal (pulse output at 120hz rate), and are 1.146mS long for a '1' and absent for a '0':

1110101010101010101001 House Code J, Unit Select 10

1110010101010101010101 House Code M, Unit Select 13

1110101010100101010101 House Code J, Unit Select 13

1110011010010110100101 House Code A, Unit Select 1

1110010101010101010110 House Code M, Command All Units Off

1110010101010101011010 House Code M, Command All Lights On

Format:

1110 hh hh hh hh cc cc cc cc 10

or

1110 hh hh hh hh ss ss ss ss 01

Since these can be generated in an automated fashion, I found 236mS between the trailing bit of the first transmission and the leading bit of the following transmission (inter transmission spacing). That's about 420mS from start to start.

For my first project, I needed a display device to work on the many busted X-10 console controllers I had stashed in the garage. I had no way of knowing what they were transmitting or even IF they were transmitting.

The hardware is simple.

Programming took the better part of a day - includes writing this web page. It works very reliably although it does miss codes when the 'Bright' or 'Dim' buttons are pressed. It serves my purpose of troubleshooting keyboard controllers since my majority of failures turned out to be the cheap 'House Code' thumb wheel selectors on the bottom. They were putting out the right unit codes, but to the wrong house codes. A couple had no output at all, even though the light flashed.

The transmit side will wait for another day. There's enough code space left inside the AT90S2313 for some output command functions, but this project is a good start on understanding the technology.
Bascom AVR includes methods of transmitting X-10 codes (but not receiving them as shown here)

Robert J Reeder
AVRProject.com
03/14/04

Download Bascom AVR and Doc files

 

'X-10 Code Display for Powerhouse two-way Power Line Interface TW523

'by Robert J Reeder, AVRProject 03/13/04

'This program only displays codes.

Dim H As Byte , S As Byte , C As Byte , X As Byte

Dim Shift1 As Byte , Shift2 As Byte , Shift3 As Byte

Dim Tbl(16) As Byte , Func As String * 7

Tbl(1) = 13

Tbl(2) = 5

Tbl(3) = 3

Tbl(4) = 11

Tbl(5) = 15

Tbl(6) = 7

Tbl(7) = 1

Tbl(8) = 9

Tbl(9) = 14

Tbl(10) = 6

Tbl(11) = 4

Tbl(12) = 12

Tbl(13) = 16

Tbl(14) = 8

Tbl(15) = 2

Tbl(16) = 10

'shift 1, 2, and 3 are the main in shift register.

'

Config Pind.2 = Input

Config Pind.3 = Input

Config Pinb.1 = Input

Config Pinb.0 = Output

Config Pind.5 = Output

Portb.0 = 0

C = 0

Shift1 = 0

Shift2 = 0

Shift3 = 0

'We will interrupt every rise or fall of pin 1 (actually 120hz)

Config Int0 = Falling

Config Int1 = Rising

On Int0 Sixtyhertz Nosave

On Int1 Sixtyhertz Nosave

Enable Int0

Enable Int1

Enable Interrupts

Home

Home

Cls

Cursor Off

'Display the codes:

'Upper line = "House x Sel nn" (Select)

'Lower Line = "House x ccccccc" (Command)

'Output to 9600 baud RS232 for permanent log of activity

'Main Program Loop (hard work done in machine code)

Loop1:

If C = 0 Then Goto Loop1

X = Tbl(h) + 64

Print "House " ; Chr(x) ; " ";

If C = 64 Then

Upperline

Lcd "House " ; Chr(x) ; " Sel " ; Tbl(s) ; " ";

Print "Sel " ; Tbl(s)

End If

If C = 128 Then

Lowerline

Lcd "House " ; Chr(x) ; " " ;

If S = 1 Then Func = "All Off"

If S = 2 Then Func = "All On "

If S = 3 Then Func = "On "

If S = 4 Then Func = "Off "

If S = 5 Then Func = "Dim "

If S = 6 Then Func = "Brightn"

Lcd Func;

Print Func

End If

C = 0

Goto Loop1

 

'Interrupt routine - most work is done here

'Sets C=128 or C=64 if an input is received

Sixtyhertz:

$asm

push r31

push r30

push r29

push r28

in r31,sreg

push r31

'give some delay time 400uS (10Mhz dependant, but forgiving)

ldi r30,6

clr r31

Sh1:

dec r31

brne sh1 ;3 cycles

dec r30

brne sh1 ;(3 * 256 + 3)=771 *6=463uS

'Now we shift the <shift> bytes through carry

'leaving R31=MsB, R30=CsB, R29=LsB

lds r29,{Shift3}

'Set the carry flag if the input line is pulled low

clc

sbis pinb,1

sec

rol r29

sts {Shift3},r29

lds r30,{Shift2}

rol r30

sts {Shift2},r30

lds r31,{Shift1}

rol r31

sts {Shift1},r31

'now we check for the 3 high bits of [shift1] for set with a 4th clear

andi r31,240 ;F0

cpi r31,224 ;E0

brne Sh2

'goes to Sh2 if pattern not found

'shift r31-r29 4 more times

lds r31,{Shift1}

ldi r28,4 ;loop counter

Sh3:

lsl r29

rol r30

rol r31

dec r28

brne Sh3

'store results

sts {h},r31 ;house code

sts {s},r30 ;select or command

sts {c},r29 ;top two bits = 01 for sel, = 10 for cmd

 

'compress bits

ldi r28,4

clr r29

clr r30

Sh4:

lsl r31

rol r29

lsl r31

rol r30

dec r28

brne Sh4

inc r29

sts {h},r29 ;house code 1-16

dec r29

'At this point, R29 and R30 should be opposites

'xor one with the other should yeild all 1's

eor r30,r29

cpi r30,15

brne BitError

'now lets do the same for the select or cmd

lds r31,{s}

ldi r28,4

clr r29

clr r30

Sh5:

lsl r31

rol r29

lsl r31

rol r30

dec r28

brne Sh5

inc r29

sts {s},r29 ;unit code 1-16

dec r29

eor r30,r29

cpi r30,15

breq Sh2

Biterror:

clr r31

sts {c},r31 ;clears C to void corrupt data

Sh2:

pop r31

Out Sreg , R31

pop r28

pop r29

pop r30

pop r31

$end Asm

Return

End