ucl 1.0 # Copyright (c) 2000-2004 by Wayne C. Gramlich # All rights reserved. # This program contains the firmware for the Switch8 (revision E) # module. library $pic16f630 library clock4mhz library bit_bang package pdip pin 1 = power_supply pin 2 = ra5_in, name = sw2 pin 3 = ra4_in, name = sw3 pin 4 = ra3_in, name = sw4 pin 5 = rc5_unused pin 6 = rc4_out, name = debug_out pin 7 = rc3_in, name = serial_in pin 8 = rc2_out, name = serial_out pin 9 = rc1_in, name = sw0 pin 10 = rc0_in, name = sw1 pin 11 = ra2_in, name = sw5 pin 12 = ra1_in, name = sw6 pin 13 = ra0_in, name = sw7 pin 14 = ground configure wdte=off, fosc=int_no_clk # Some globals: byte constant state_size = 11 constant state_size2 = state_size << 1 global state[state_size] array[byte] bind command_previous = state[0] bind command_last = state[1] bind sent_last = state[2] bind sent_previous = state[3] bind raw = state[4] bind complement_mask = state[5] bind flags = state[6] bind low_mask = state[7] bind high_mask = state[8] bind rising_mask = state[9] bind falling_mask = state[10] bind interrupt_enable = flags@0 bind interrupt_pending = flags@1 global direction byte global glitch byte global index byte global debug_character byte global debug_counter byte global debug_index byte procedure main arguments_none returns_nothing local command byte local temp byte local do_send bit # Initalize all of the globals: call reset() # Process commands: loop_forever # Wait for command: command := byte_get() # Dispatch on command switch command >> 6 case 0 # 00xx xxxx: switch (command >> 3) & 7 case_maximum 7 case 0 # 0000 0xxx: do_send := 1 switch command case 0 # 0000 0000 (Read Inputs): temp := raw ^ complement_mask case 1 # 0000 0001 (Read Complement): temp := complement_mask case 2 # 0000 0010 (Read Raw): temp := raw case 4 # 0000 0100 (Read Read Low Mask): temp := low_mask case 5 # 0000 0101 (Read High Mask): temp := high_mask case 6 # 0000 0110 (Read Rising Mask): temp := rising_mask case 7 # 0000 0111 (Read Falling Mask): temp := falling_mask default do_send := 0 if do_send call byte_put(temp) case 1 # 0000 1xxx: switch (command >> 3) & 7 case 0 # 0001 0000 (Reset): call reset() case 1 # 0001 0010 (Set Complement Mask): complement_mask := byte_get() case 4 # 0001 0100 (Set Low Mask): low_mask := byte_get() case 5 # 0001 0101 (Set High Mask): high_mask := byte_get() case 6 # 0001 0110 (Set Rising Mask): rising_mask := byte_get() case 7 # 0001 0111 (Set Falling Mask): falling_mask := byte_get() default do_nothing default do_nothing case 3 # 11xx xxxx: switch (command >> 3) & 7 case 5 # 1110 1xxx: if command = 0xef # 1110 1111 (Read Interrupt Bits): temp := 0 if interrupt_pending temp@0 := 1 if interrupt_enable temp@1 := 1 call byte_put(temp) case 6 # 1111 0xxx: switch command & 7 case 0, 1, 2, 3 # 1111 00ep (Set Interrupt Bits): interrupt_enable := command@1 interrupt_pending := command@0 case 4, 5 # 1111 010p (Set Interrupt Pending): interrupt_pending := command@0 case 6, 7 # 1111 011e (Set Interrupt Enable): interrupt_enable := command@0 case 7 switch command & 7 case 0 # 1111 1000 (Clock Decrement): $osccal := $osccal - $osccal_lsb case 1 # 1111 1001 (Clock Increment): $osccal := $osccal + $osccal_lsb case 2 # 1111 1010 (Clock Read): call byte_put($osccal) case 3 # 1111 1011 (Clock Pulse): call byte_put(0) case 4 # 1111 1100 (ID Next): call byte_put(id(index)) index := index + 1 case 5 # 1111 1101 (ID Reset): index := 0 case 6 # 1111 1110 (Glitch Read): call byte_put(glitch) glitch := 0 case 7 # 1111 1111 (Glitch): if glitch != 0xff glitch := glitch + 1 default do_nothing procedure reset arguments_none returns_nothing # This procedure will initialize all global registers: $cmcon := 7 # Initialize global registers: index := 0 loop_exactly state_size state[index] := 0 index := index + 1 debug_counter := 0 debug_index := 0 debug_character := 0 # Initialize remaining registers: glitch := 0 index := 0 procedure delay arguments_none returns_nothing exact_delay delay_instructions # This procedure delays 1/3 of a bit. local temp byte local previous byte local current byte local not_current byte local changed byte # Kick the dog: watch_dog_reset # Read inputs: raw := 0 # We want "switch up" to be "one"; hence "if !sw?": # The labels on the board are backwards; hence, 0=>7, 1=>6,..., 7=>0: if !sw7 raw@0 := 1 if !sw6 raw@1 := 1 if !sw5 raw@2 := 1 if !sw4 raw@3 := 1 if !sw3 raw@4 := 1 if !sw2 raw@5 := 1 if !sw1 raw@6 := 1 if !sw0 raw@7 := 1 # Setup for interrupts: previous := current # Read the I/O port once: current := raw ^ complement_mask not_current := current ^ 0xf changed := current ^ previous # See about triggering the interrupt_pending flag: if (low_mask & not_current) | (high_mask & current) | (changed & current & rising_mask) | (changed & not_current & falling_mask) != 0 interrupt_pending := 1 # Send an interrupt if interrupts are enabled: if interrupt_pending if interrupt_enable # Shove serial out to low: interrupt_enable := 0 serial_out := 0 # Provide debug information: switch debug_counter case 0 # Send out start bit: debug_out := 0 case 3, 6, 9, 12, 15, 18, 21, 24, 27 # Send out data bit or stop bit: if debug_character@0 debug_out := 1 else debug_out := 0 case 4, 7, 10, 13, 16, 19, 22, 25 # Select next bit of debug_character: debug_character := debug_character >> 1 debug_character@7 := 1 case 28 debug_character := debug_index >> 1 case 30 debug_character := state[debug_character] #debug_character := 0x5a case 31 if !(debug_index@0) debug_character := debug_character >> 4 case 32 debug_character := (debug_character & 0xf) + '0' case 33 if debug_character > '9' debug_character := debug_character + 'A' - '0' - 10 case 34 if debug_index >= state_size2 debug_character := '\r\' case 35 if debug_index >= state_size2 + 1 # Turn off cursor and blink mode: debug_character := 0x88 case 36 debug_index := debug_index + 1 case 37 if debug_index >= state_size2 + 2 debug_index := 0 case 38 debug_counter := 0xff default do_nothing debug_counter := debug_counter + 1 procedure id argument index byte returns byte # This procedure will return the index'th byte of the id: if index <= 46 switch index case 0 return 1 case 1 return 0 case 2 return 32 case 3 return 1 case 4 return 3 case 5 return 1 case 6, 7 return 0 case 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23 return 0 case 24 return 8 case 25 return 'S' case 26 return 'w' case 27 return 'i' case 28 return 't' case 29 return 'c' case 30 return 'h' case 31 return '8' case 32 return 'E' case 33 return 13 case 34 return 'M' case 35 return 'o' case 36 return 'n' case 37 return 'd' case 38 return 'o' case 39 return '-' case 40 return 't' case 41 return 'r' case 42 return 'o' case 43 return 'n' case 44 return 'i' case 45 return 'c' case 46 return 's' return 0 origin 0x3ff procedure osccal arguments_none returns byte return 0xa0