; File: GW60_ext.asm ; Target: PIC16F690 ; Author: DIRB ; Date: 2021-01-15 ; Compiler: pic-as (v2.31) ; IDE: MPLABX v5.45 ; =========================================================================== ; ### Extension code for GW60 firmware to support serial TRÅDFRI protocol ### ; =========================================================================== ; Free code area in original F/W: ; BLOCK0 0x0600 to 0x07FF ; --------------------------------------------------------------------------- ; Free RAM area in original F/W: ; BANK0 0x40-42, 0x44, 0x7C, 0x7D ; BANK1 0xB6, 0xCA, 0xE2-E8, (E9), 0xEA-ED, 0x7C, 0xFD ; --------------------------------------------------------------------------- ; Used RAM in extention: ; ; BANK0: ; RAM_ext_stat (0x7C) ; bit 0: 1 = UP command ; bit 1: 1 = DOWN command ; ... ; bit 5: 0 = DOWN, 1 = UP direction of new position ; bit 6: 1 = new position to go to ; bit 7: 1 = new byte received ; RAM_rxd_byte (0x7D) stores received byte ; RAM_frm_cnt (0x44) counts received byte of frame ; RAM_cmd1 (0x40) individual command byte 1 ; RAM_cmd2 (0x41) individual command byte 2 ; RAM_cmd3 (0x42) individual command byte 3 (check sum) ; ; BANK1: ; RAM_newpos (0xB6) new position in percent ; RAM_div16_lp (0xCA) DIV16 loop count ; RAM_p_stat (0xE4) actual position in percent ; RAM_chksum (0xE5) checksum of status frame ; RAM_div16_rem0 (0xE6) DIV16 REMB0 ; RAM_div16_tmp1_mm (0xE7) DIV16 TEMP1 (MMSB) ; RAM_div16_tmp2_mm (0xE8) DIV16 TEMP2 (MMSB) ; RAM_div16_rem1 (0xE9) DIV16 REMB1 ; RAM_div16_tmp1_l (0xEA) DIV16 TEMP1 (LSB) ; RAM_div16_tmp1_m (0xEB) DIV16 TEMP1 (MSB) ; RAM_div16_tmp2_l (0xEC) DIV16 TEMP2 (LSB) ; RAM_div16_tmp2_m (0xED) DIV16 TEMP2 (MSB) ; ; RAM used by original F/W: ; byte_DATA_2C RxD from UART ; byte_DATA_30 button counter flags (short touch) ; 0x01 = DOWN ; 0x02 = UP ; 0x04 = SUN ; 0x08 = CLOCK ; 0x10 = SET ; 0x20 = REED ; byte_DATA_53 actual current ; byte_DATA_B1 upper limit (LSB) ; byte_DATA_B2 upper limit (MSB) ; byte_DATA_B3 lower limit (LSB) ; byte_DATA_B4 lower limit (MSB) ; byte_DATA_B8 actual position (LSB) ; byte_DATA_B9 actual position (MSB) ; --------------------------------------------------------------------------- PROCESSOR 16F690 #include #include "RAM_def.INC" ; --------------------------------------------------------------------------- ; Globals GLOBAL isr_ext, init_ext, loop_ext, panel_ext EXTRN sub_send_byte ; --------------------------------------------------------------------------- PSECT ext,class=CODE,abs,reloc=2,delta=2 ORG 0x0600 IF EXTEND=1 ; =========================================================================== ; called by F/W at each button read out from panel ; --------------------------------------------------------------------------- panel_ext: btfsc RAM_ext_stat, 0 ; UP command received ? bsf byte_DATA_30, 0 ; then simulate UP button pressed bcf RAM_ext_stat, 0 btfsc RAM_ext_stat, 1 ; DOWN command received ? bsf byte_DATA_30, 1 ; then simiulate DOWN button pressed bcf RAM_ext_stat, 1 btfsc RAM_ext_stat, 6 ; new position to reach ? call on_pos ; check if position reached ; --------------------------------------------------------------------------- return ; (replaced instruction) ; --------------------------------------------------------------------------- ; =========================================================================== ; called from interrupt service routine ; --------------------------------------------------------------------------- isr_ext: ; --------------------------------------------------------------------------- movwf byte_DATA_2C ; save received byte in 0x2C (replaced instr) ; --------------------------------------------------------------------------- bsf RAM_ext_stat, 7 ; set flag for new byte received return ; =========================================================================== ; called by firmware once at the end of init phase ; --------------------------------------------------------------------------- init_ext: clrf RAM_ext_stat ; clear extension STATUS clrf RAM_frm_cnt ; clear frame counter bsf RP0 clrf RAM_p_stat ; status pos = 0 movlw 0x9B ; status check sum movwf RAM_chksum ;movlw 0x0f ; ====== just for devopment version ====== ;movwf OSCTUNE ; ====== just for devopment version ====== movlw 0x65 ; setup serial I/F movwf TXSTA ; TX9+TXEN+BRGH+TX9D = 1 movlw 0x08 movwf BAUDCTL ; BRG16 = 1 movlw 0x40 ; Baudrate 0x340 = 832 -> 2401 Baud movwf SPBRG movlw 0x03 ; Baudrate High movwf SPBRGH ;movlw 0xA5 ; send test byte ;call sub_send_byte ; transmit byte bcf RP0 init_exit: ; --------------------------------------------------------------------------- bsf byte_DATA_35, 7 ; replaced instruction from original code ; --------------------------------------------------------------------------- return ; =========================================================================== ; called from main loop ; --------------------------------------------------------------------------- loop_ext: bcf RP0 bcf RP1 ; new byte received ? btfss RAM_ext_stat, 7 ; new byte received ? goto loop_exit ; NO! bcf RAM_ext_stat, 7 call receive_frame ; decode frame byte by byte ;##### 6-byte RAM monitor ;call monitor loop_exit: ; --------------------------------------------------------------------------- clrwdt ; replaced instruction from original code ; --------------------------------------------------------------------------- return ; =========================================================================== ; Subroutines ; =========================================================================== ; -------------------------------------------------------------------- ; check if on position on_pos: call calcpos bsf RP0 movf RAM_newpos,w subwf RAM_p_stat btfss ZERO ; already on position ? goto notpos reached: bcf RP0 bcf RAM_ext_stat, 6 ; clear positioning bit bsf RAM_ext_stat, 1 ; press button to stop return notpos: bcf RP0 btfsc RAM_ext_stat, 5 ; UP direction ? goto its_up btfsc CARRY goto reached posdone: bcf RP0 return its_up: btfsc CARRY goto posdone goto reached ; -------------------------------------------------------------------- ; debug output only ; monitor: movlw 0x20 ; wait for SPACE key xorwf byte_DATA_2C,w btfss STATUS,2 return bsf RP0 movf byte_DATA_B1,w bcf RP0 call sub_send_byte ; transmit byte bsf RP0 movf byte_DATA_B2,w bcf RP0 call sub_send_byte ; transmit byte bsf RP0 movf byte_DATA_B3,w bcf RP0 call sub_send_byte ; transmit byte bsf RP0 movf byte_DATA_B4,w bcf RP0 call sub_send_byte ; transmit byte bsf RP0 movf byte_DATA_B8,w bcf RP0 call sub_send_byte ; transmit byte bsf RP0 movf byte_DATA_B9,w bcf RP0 call sub_send_byte ; transmit byte return ; -------------------------------------------------------------------- ; calc position in % ; calcpos: ; upper limit - actual position bsf RP0 movf byte_DATA_B1,w ; copy upper limit to temp1 movwf RAM_div16_tmp1_l movf byte_DATA_B2,w movwf RAM_div16_tmp1_m MOVF byte_DATA_B8,W ; substraction SUBWF RAM_div16_tmp1_l,F BTFSS CARRY DECF RAM_div16_tmp1_m,F MOVF byte_DATA_B9,W SUBWF RAM_div16_tmp1_m,F ; check if actual position was higher then the upper limit movlw 0xFF xorwf RAM_div16_tmp1_m,w btfss ZERO goto noff clrf RAM_div16_tmp1_l clrf RAM_div16_tmp1_m ; upper limit - lower limit = range noff: clrf RAM_div16_tmp1_mm ; temp 1 MMSB ; multiply with 100 call mul100 movf byte_DATA_B1,w ; copy upper limit to temp2 movwf RAM_div16_tmp2_l movf byte_DATA_B2,w movwf RAM_div16_tmp2_m MOVF byte_DATA_B3,W ; substraction SUBWF RAM_div16_tmp2_l,F BTFSS CARRY DECF RAM_div16_tmp2_m,F MOVF byte_DATA_B4,W SUBWF RAM_div16_tmp2_m,F ;devide by range call div16bit movf RAM_div16_tmp1_l,w movwf RAM_p_stat bcf RP0 return ; -------------------------------------------------------------------- ; send STATUS: ; 00 FF D8 64 FF 00 00 9B ; +--------------> Voltage ; +-----------> Current ; +--------> Position 0-100% (0x00 - 0x64) ; +-----> Checksum send_status: movlw 0x00 ; send test byte call sub_send_byte ; transmit byte movlw 0xFF ; send test byte call sub_send_byte ; transmit byte movlw 0xD8 ; send test byte call sub_send_byte ; transmit byte movlw 0x64 ; send test byte call sub_send_byte ; transmit byte bsf RP0 movlw 0xFF ; max voltage level bcf RP0 call sub_send_byte ; transmit byte bsf RP0 movf byte_DATA_53,w ; get actual current bcf RP0 call sub_send_byte ; transmit byte bsf RP0 movf RAM_p_stat,w bcf RP0 call sub_send_byte ; transmit byte bsf RP0 movf RAM_chksum,w bcf RP0 call sub_send_byte ; transmit byte bcf RP0 return ; -------------------------------------------------------------------- ; IKEA Tradfri commands: ; UP 0x00 0xFF 0x9A 0x0A 0xDD 0xD7 00FF9A0ADDD7 ; DOWN 0x00 0xFF 0x9A 0x0A 0xEE 0xE4 00FF9A0AEEE4 ; STOP 0x00 0xFF 0x9A 0x0A 0xCC 0xC6 00FF9A0ACCC6 ; GOTO 0x00 0xFF 0x9A 0XDD (POS) (CS) 00FF9ADD32EF ; Status reqest 0x00 0xFF 0x9A 0xCC 0xCC 0x00 00FF9ACCCC00 receive_frame: ; if (RAM_frm_cnt == 0) movf RAM_frm_cnt,w btfss STATUS,2 goto loc_1650 ; if (RAM_rxd_byte == 0x00) movf byte_DATA_2C,w btfss STATUS,2 goto loc_142 loc_1648: ; RAM_frm_cnt++ incf RAM_frm_cnt goto loc_142 ; else if (RAM_frm_cnt == 1) loc_1650: decf RAM_frm_cnt,w btfss STATUS,2 goto loc_1658 ; if (RAM_rxd_byte == 0xFF) incf byte_DATA_2C,w btfss STATUS,2 goto loc_1682 goto loc_1648 loc_1656: ; else;main.c: 43: RAM_frm_cnt = 0 clrf RAM_frm_cnt goto loc_142 loc_1658: ; else if (RAM_frm_cnt == 2) movlw 2 xorwf RAM_frm_cnt,w btfss STATUS,2 goto loc_1666 ; if (RAM_rxd_byte == 0x9A) movlw 0x9A xorwf byte_DATA_2C,w btfss STATUS,2 goto loc_1682 goto loc_1648 loc_1666: ; else if (RAM_frm_cnt < 6) movlw 6 subwf RAM_frm_cnt,w BTFSC CARRY goto loc_1672 loc_1668: ; if (RAM_frm_cnt == 3) movlw 3 xorwf RAM_frm_cnt,w btfss STATUS,2 goto loc_1672 ; RAM_cmd1 = RAM_rxd_byte movf byte_DATA_2C,w movwf RAM_cmd1 goto loc_1648 loc_1672: ; if (RAM_frm_cnt == 4) movlw 4 xorwf RAM_frm_cnt,w btfss STATUS,2 goto loc_1676 ; RAM_cmd2 = RAM_rxd_byte; movf byte_DATA_2C,w movwf RAM_cmd2 goto loc_1648 loc_1676: ; if (RAM_frm_cnt == 5) movlw 5 xorwf RAM_frm_cnt,w btfss STATUS,2 goto loc_1682 ; RAM_cmd3 = RAM_rxd_byte; movf byte_DATA_2C,w movwf RAM_cmd3 ; decode_frame(); call decode_frame goto loc_142 loc_1682: ; else RAM_frm_cnt = 0; clrf RAM_frm_cnt loc_142: return ; -------------------------------------------------------------------- decode_frame: ; RAM_frm_cnt = 0; clrf RAM_frm_cnt ; if (RAM_cmd1 == 0x0A) { movlw 0x0A xorwf RAM_cmd1,w btfss STATUS,2 goto loc_1767 ; if (RAM_cmd2 == 0xDD && RAM_cmd3 == 0xD7) UP(); movlw 0xDD xorwf RAM_cmd2,w btfss STATUS,2 goto loc_1755 movlw 0xD7 xorwf RAM_cmd3,w btfss STATUS,2 goto loc_1755 call cmd_up return loc_1755: ; if (RAM_cmd2 == 0xEE && RAM_cmd3 == 0xE4) DOWN(); movlw 0xEE xorwf RAM_cmd2,w btfss STATUS,2 goto loc_1761 movlw 0xE4 xorwf RAM_cmd3,w btfss STATUS,2 goto loc_1761 call cmd_down return loc_1761: ; if (RAM_cmd2 == 0xCC && RAM_cmd3 == 0xC6) STOP(); movlw 0xCC xorwf RAM_cmd2,w btfss STATUS,2 goto loc_1767 movlw 0xC6 xorwf RAM_cmd3,w btfss STATUS,2 goto loc_1767 call cmd_stop return loc_1767: ; } if (RAM_cmd1 == 0xCC) { movlw 0xCC xorwf RAM_cmd1,w btfss STATUS,2 goto loc_1775 ; if (RAM_cmd2 == 0xCC && RAM_cmd3 == 0x00) STAT(); movlw 0xCC xorwf RAM_cmd2,w btfss STATUS,2 goto loc_1775 movf RAM_cmd3,w btfss STATUS,2 goto loc_1775 call cmd_stat return loc_1775: ; } if (RAM_cmd1 == 0xDD) { movlw 0xDD xorwf RAM_cmd1,w btfss STATUS,2 goto loc_1781 ; if ((RAM_cmd2 ^ 221) == RAM_cmd3) GOTO(); movlw 0xDD xorwf RAM_cmd2,w xorwf RAM_cmd3,w btfss STATUS,2 goto loc_1781 call cmd_goto loc_1781: return ; -------------------------------------------------------------------- ; Command: UP cmd_up: bsf RAM_ext_stat, 0 bcf RAM_ext_stat, 6 ; clear new position move ;movlw 'U' ; send test byte ;call sub_send_byte ; transmit byte return ; -------------------------------------------------------------------- ; Command: DOWN cmd_down: bsf RAM_ext_stat, 1 bcf RAM_ext_stat, 6 ; clear new position move ;movlw 'D' ; send test byte ;call sub_send_byte ; transmit byte return ; -------------------------------------------------------------------- ; Command: STOP cmd_stop: bsf RAM_ext_stat, 1 bcf RAM_ext_stat, 6 ; clear new position move ;movlw 'S' ; send test byte ;call sub_send_byte ; transmit byte return ; -------------------------------------------------------------------- ; Command: STATUS cmd_stat: call calcpos call send_status return ; -------------------------------------------------------------------- ; Command: GOTO position ; new position in RAM_cmd2 cmd_goto: ;movlw 'P' ; send test byte ;call sub_send_byte ; transmit byte ;movf RAM_cmd2,w ; send test byte ;call sub_send_byte ; transmit byte movlw 0x64 xorwf RAM_cmd2,w btfsc STATUS,2 goto cmd_down ; new pos = 100% -~ DOWN movf RAM_cmd2,w btfsc STATUS,2 goto cmd_up ; new pos = 0% -~ UP movf RAM_cmd2,w ; copy new position bsf RP0 movwf RAM_newpos bcf RP0 call calcpos bsf RP0 movf RAM_newpos,w subwf RAM_p_stat btfsc ZERO ; already on position return bsf RAM_ext_stat, 6 ; set new position move btfss CARRY goto go_dn go_up: bcf RP0 bsf RAM_ext_stat, 5 ; direction is up bsf RAM_ext_stat, 0 return go_dn: bcf RP0 bcf RAM_ext_stat, 5 ; direction is down bsf RAM_ext_stat, 1 return ; -------------------------------------------------------------------- ; Multiplication * 100 ; Author: Generator ; From: http://www.piclist.com/techref/piclist/codegen/constdivmul.htm ; ; ALGORITHM: ; Clear accumulator ; Add input * 64 to accumulator ; Add input * 32 to accumulator ; Add input * 4 to accumulator ; Move accumulator to result ; Approximated constant: 100, Error: 0 % ; Input: RAM_div16_tmp1_l/EB, 16 bits ; Output: RAM_div16_tmp1_l/EB + RAM_div16_tmp1_mm, 23 bits ; Code size: 48 instructions mul100: ;shift accumulator left 2 times bcf CARRY rlf RAM_div16_tmp1_l, f rlf RAM_div16_tmp1_m, f clrf RAM_div16_tmp1_mm rlf RAM_div16_tmp1_mm, f rlf RAM_div16_tmp1_l, f rlf RAM_div16_tmp1_m, f rlf RAM_div16_tmp1_mm, f ;copy accumulator to temporary movf RAM_div16_tmp1_mm, w movwf RAM_div16_tmp2_mm movf RAM_div16_tmp1_m, w movwf RAM_div16_tmp2_m movf RAM_div16_tmp1_l, w movwf RAM_div16_tmp2_l ;shift temporary left 3 times bcf CARRY rlf RAM_div16_tmp2_l, f rlf RAM_div16_tmp2_m, f rlf RAM_div16_tmp2_mm, f rlf RAM_div16_tmp2_l, f rlf RAM_div16_tmp2_m, f rlf RAM_div16_tmp2_mm, f rlf RAM_div16_tmp2_l, f rlf RAM_div16_tmp2_m, f rlf RAM_div16_tmp2_mm, f ;add temporary to accumulator movf RAM_div16_tmp2_l, w addwf RAM_div16_tmp1_l, f movf RAM_div16_tmp2_m, w BTFSC CARRY incfsz RAM_div16_tmp2_m, w addwf RAM_div16_tmp1_m, f movf RAM_div16_tmp2_mm, w BTFSC CARRY incfsz RAM_div16_tmp2_mm, w addwf RAM_div16_tmp1_mm, f ;shift temporary left 1 times bcf CARRY rlf RAM_div16_tmp2_l, f rlf RAM_div16_tmp2_m, f rlf RAM_div16_tmp2_mm, f ;add temporary to accumulator movf RAM_div16_tmp2_l, w addwf RAM_div16_tmp1_l, f movf RAM_div16_tmp2_m, w BTFSC CARRY incfsz RAM_div16_tmp2_m, w addwf RAM_div16_tmp1_m, f movf RAM_div16_tmp2_mm, w BTFSC CARRY incfsz RAM_div16_tmp2_mm, w addwf RAM_div16_tmp1_mm, f return ; -------------------------------------------------------------------- ; Division 24bit by 16bit ; Author: Nikolai Golovchenko ; From: http://www.piclist.com/techref/microchip/math/div/24by16.htm ; ;Inputs: ; Dividend - RAM_div16_tmp1_mm:RAM_div16_tmp1_m:RAM_div16_tmp1_l ; Divisor - RAM_div16_tmp2_m:RAM_div16_tmp2_l ;Temporary: ; Counter - RAM_div16_lp ; Remainder- RAM_div16_rem0:RAM_div16_rem1 ;Output: ; Quotient - RAM_div16_tmp1_mm:RAM_div16_tmp1_m:RAM_div16_tmp1_l div16bit: CLRF RAM_div16_rem0 CLRF RAM_div16_rem1 MOVLW 24 MOVWF RAM_div16_lp LOOPU2416: RLF RAM_div16_tmp1_l, W ;shift dividend left to move next bit to remainder RLF RAM_div16_tmp1_m, F ; RLF RAM_div16_tmp1_mm, F ; RLF RAM_div16_rem1, F ;shift carry (next dividend bit) into remainder RLF RAM_div16_rem0, F RLF RAM_div16_tmp1_l, F ;finish shifting the dividend and save carry in RAM_div16_tmp1_l.0, ;since remainder can be 17 bit long in some cases ;(e.g. 0x800000/0xFFFF). This bit will also serve ;as the next result bit. MOVF RAM_div16_tmp2_l, W ;substract divisor from 16-bit remainder SUBWF RAM_div16_rem1, F ; MOVF RAM_div16_tmp2_m, W ; BTFSS CARRY ; INCFSZ RAM_div16_tmp2_m, W ; SUBWF RAM_div16_rem0, F ; ;here we also need to take into account the 17th bit of remainder, which ;is in RAM_div16_tmp1_l.0. If we don't have a borrow after subtracting from lower ;16 bits of remainder, then there is no borrow regardless of 17th bit ;value. But, if we have the borrow, then that will depend on 17th bit ;value. If it is 1, then no final borrow will occur. If it is 0, borrow ;will occur. These values match the borrow flag polarity. BTFSC CARRY ;if no borrow after 16 bit subtraction BSF RAM_div16_tmp1_l, 0 ;then there is no borrow in result. Overwrite ;RAM_div16_tmp1_l.0 with 1 to indicate no ;borrow. ;if borrow did occur, RAM_div16_tmp1_l.0 already ;holds the final borrow value (0-borrow, ;1-no borrow) BTFSC RAM_div16_tmp1_l, 0 ;if no borrow after 17-bit subtraction GOTO UOK46LL ;skip remainder restoration. ADDWF RAM_div16_rem0, F ;restore higher byte of remainder. (w ;contains the value subtracted from it ;previously) MOVF RAM_div16_tmp2_l, W ;restore lower byte of remainder ADDWF RAM_div16_rem1, F ; UOK46LL: DECFSZ RAM_div16_lp, f ;decrement counter GOTO LOOPU2416 ;and repeat the loop if not zero. RETURN ; =========================================================================== ENDIF END