;; ;; spreadspace pic utils ;; ;; ;; Copyright (C) 2011 Christian Pointner ;; ;; This file is part of spreadspace pic utils. ;; ;; spreadspace pic utils is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; any later version. ;; ;; spreadspace pic utils is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with spreadspace pic utils. If not, see . ;; ;; ------------------------------------- ;; PREAMBLE LIST p=16F887 include "p16f887.inc" __config _CONFIG1, _DEBUG_OFF & _LVP_OFF & _FCMEN_OFF & _IESO_OFF & _BOR_OFF & _CPD_OFF & _CP_OFF & _MCLRE_OFF & _PWRTE_OFF & _WDT_OFF & _INTOSC __config _CONFIG2, _BOR21V & _WRT_256 ;; ------------------------------------- ;; DEFINES #define BOOTPIN PORTC,7 USERVECT EQU H'100' ISRVECT EQU USERVECT + H'4' VERSION_MAJ EQU .0 VERSION_MIN EQU .1 NAME_0 EQU 'n' NAME_1 EQU 'i' NAME_2 EQU 'l' DEVID_L EQU H'82' DEVID_H EQU H'20' FLASH_SIZE_L EQU H'00' FLASH_SIZE_H EQU H'20' ; 0x2000 -> 8192 Words of Flash FSS EQU .16 ; writing is done 8 words at a time but 16 words get erased EEPROM_SIZE_L EQU H'00' EEPROM_SIZE_H EQU H'01' ; 0x0100 -> 256 Bytes of EEPROM MESS EQU .64 ; this limit is because of to combuff size and single byte len field for messages SUPPORTED_H EQU .0 SUPPORTED_L EQU b'00000110' ; only read/write flash is supported by now ;; ERROR codes E_OK EQU .0 E_INV_CMD EQU .1 E_BAD_CSUM EQU .2 E_NOT_IMPL EQU .3 E_FLASH_WERR EQU .4 E_ADDR_INVALID EQU .5 E_ADDR_PROHIB EQU .6 E_VALUE_OOB EQU .7 ;; CMD codes CMD_INVALID EQU .0 CMD_IDENTIFY EQU .1 CMD_BOOT EQU .2 CMD_RESET EQU .3 CMD_R_FLASH EQU .4 CMD_W_FLASH EQU .5 CMD_R_EEPROM EQU .6 CMD_W_EEPROM EQU .7 CMD_R_CONFIG EQU .8 CMD_W_CONFIG EQU .9 CMD_MAX EQU .9 ;; Sanity Checks CMD_MIN_LEN EQU .3 FLASH_BOUNDARY EQU b'00001111' ; flash boundary is at 16 bytes boundaries ;; Variables combuff EQU H'0020' combuff_end EQU H'006F' current_cmdlen EQU H'0070' csum EQU H'0071' flags EQU H'007D' #define F_CMD_STARTED flags,0 cnt2 EQU H'007E' cnt1 EQU H'007F' ;; ------------------------------------- ;; Boot test org .0 ;; btfsc BOOTPIN ;; goto USERVECT goto boot ;; ------------------------------------- ;; goto user ISR org .4 isr goto ISRVECT ;; ------------------------------------- ;; Bootloader (Subroutines) uart_tx_byte ;send one byte and add it to csum btfss PIR1,TXIF goto uart_tx_byte movwf TXREG xorwf csum,f return ;; ------------------ send_answer ; generic answer message, leave len of data in W addlw .3 movwf combuff + .1 decf combuff + .1,w movwf cnt1 movlw combuff movwf FSR clrf csum send_answer_next movf INDF,w call uart_tx_byte incf FSR,f decfsz cnt1,f goto send_answer_next movf csum,w call uart_tx_byte return ;; ------------------ ack_cmd ; short answers which only contain return code movwf combuff + .2 movlw .1 call send_answer return ;; ------------------------------------- ;; Bootloader (init) boot ;; bank 3 bsf STATUS,RP0 bsf STATUS,RP1 movlw b'00001000' ; TX non-inverted, 16bit Baudrate, no auto baud detect ;; movlw b'00011000' ; TX inverted, 16bit Baudrate, no auto baud detect movwf BAUDCTL ;; bank 1 bcf STATUS,RP1 movlw b'01110000' ; set internal OSC to 8MHz movwf OSCCON movlw b'00100100' ; Baudrate = High Speed, async mode, transmit enabled, 8bit movwf TXSTA movlw .34 ; Baudrate = 57600 (@ 8MHz) -> -0,79 % Error ;; movlw .51 ; Baudrate = 38400 (@ 8MHz) -> -0,002 % Error ;; movlw .103 ; Baudrate = 19200 (@ 8MHz) -> 0,16 % Error movwf SPBRG clrf SPBRGH ;; bank 0 bcf STATUS,RP0 movlw b'10010000' ; enable Serial Port, 8bit, enable continues receive, disable address detection movwf RCSTA ;; --------- end of init wait_new_cmd movlw combuff movwf FSR clrf combuff clrf current_cmdlen clrf flags wait_cmd ; wait for new commands btfsc PIR1,RCIF goto uart_rx_byte btfsc RCSTA,OERR goto uart_rx_oe goto wait_cmd uart_rx_oe ; recover from overflow bcf RCSTA,CREN bsf RCSTA,CREN goto wait_new_cmd uart_rx_byte ; process received byte btfsc RCSTA,FERR goto uart_rx_fe movf RCREG,w movwf INDF incf FSR,f btfss F_CMD_STARTED goto wait_cmd_len movf current_cmdlen,f btfsc STATUS,Z goto new_cmd decfsz current_cmdlen,f goto wait_cmd goto exec_cmd uart_rx_fe ; recover from framing error movf RCREG,w goto wait_new_cmd wait_cmd_len ; command code received, now wait for length bsf F_CMD_STARTED goto wait_cmd new_cmd ; got new command code and length -> check it movf combuff,w sublw CMD_MAX btfss STATUS,C goto invalid_cmd movlw CMD_MIN_LEN ; check for minimum command len subwf combuff + .1,w btfss STATUS,C goto invalid_cmd movlw .2 ; 2 bytes already received subwf combuff + .1,w movwf current_cmdlen goto wait_cmd exec_cmd ; command is complete -> check csum movlw combuff movwf FSR movf combuff + .1,w movwf cnt1 clrf csum exec_cmd_check_csum movf INDF,w xorwf csum,f incf FSR,f decfsz cnt1,f goto exec_cmd_check_csum movf csum,f btfss STATUS,Z goto csum_error movf combuff,w ; command is correct and complete -> dispatch addwf PCL,f goto wait_new_cmd goto cmd_identify ; identify goto cmd_boot ; boot goto cmd_not_impl ; reset goto cmd_r_flash ; read flash segment goto cmd_w_flash ; write flash segment goto cmd_not_impl ; read eeprom goto cmd_not_impl ; write eeprom goto cmd_not_impl ; read config goto cmd_not_impl ; write config ;; ** error messages ******* invalid_cmd ; received command code is not known or len is bogus movlw E_INV_CMD call ack_cmd goto wait_new_cmd csum_error ; received command has an invalid check sum movlw E_BAD_CSUM call ack_cmd goto wait_new_cmd address_invalid ; received command uses invalid address (i.e. not aligned to 16bytes) movlw E_ADDR_INVALID call ack_cmd goto wait_new_cmd address_prohibited ; received command uses prohibited address (i.e. FLASH < 0x100) movlw E_ADDR_PROHIB call ack_cmd goto wait_new_cmd ;; ** Command Handlers ******************** ;; ** identify ******* cmd_identify clrf csum movf combuff,w call uart_tx_byte movlw .19 call uart_tx_byte movlw E_OK call uart_tx_byte movlw VERSION_MIN call uart_tx_byte movlw VERSION_MAJ call uart_tx_byte movlw NAME_0 call uart_tx_byte movlw NAME_1 call uart_tx_byte movlw NAME_2 call uart_tx_byte movlw DEVID_L call uart_tx_byte movlw DEVID_H call uart_tx_byte movlw FLASH_SIZE_L call uart_tx_byte movlw FLASH_SIZE_H call uart_tx_byte movlw FSS call uart_tx_byte movlw EEPROM_SIZE_L call uart_tx_byte movlw EEPROM_SIZE_H call uart_tx_byte movlw MESS call uart_tx_byte movlw SUPPORTED_L call uart_tx_byte movlw SUPPORTED_H call uart_tx_byte movf csum,w call uart_tx_byte goto wait_new_cmd ;; ** boot ******* cmd_boot movlw E_OK call ack_cmd goto USERVECT ;; ** read flash ******* cmd_r_flash call read_flash_segment call send_answer goto wait_new_cmd ;; ** write flash ******* cmd_w_flash call write_flash_segment call send_answer goto wait_new_cmd ;; ** not implemented commands ******* cmd_not_impl movlw E_NOT_IMPL call ack_cmd goto wait_new_cmd ;; ------------------------------------- ;; actual flash/eeprom functions ;; flash read -------- read_flash_segment movlw FSS ; initialize EEADR:EEADRH and FSR movwf cnt1 movlw b'01011000' movwf STATUS movlw combuff + .2 movwf FSR movf INDF,w movwf EEADR incf FSR,f movf INDF,w movwf EEADRH read_flash_segment_loop bsf STATUS,RP0 ; perform the actual read bsf EECON1,EEPGD bsf EECON1,RD nop nop bcf STATUS,RP0 movf EEDAT,w ; load code word from EEDAT:EEDATH to combuff movwf INDF incf FSR,f movf EEDATH,w movwf INDF incf FSR,f incfsz EEADR,f ; increment flash address goto read_flash_segment_next incf EEADRH,f read_flash_segment_next decfsz cnt1,f goto read_flash_segment_loop bcf STATUS,RP1 clrf combuff + .2 ; = E_OK retlw .1 + .2*FSS ; bytes to send ;; flash write -------- write_flash_segment movf combuff + .3,f ; if addr[15:8] == 0 -> boot loader section btfsc STATUS,Z goto address_prohibited movlw FLASH_BOUNDARY ; addr on boundary? andwf combuff + .2,w btfss STATUS,Z goto address_invalid movlw FSS ; initialize EEADR:EEADRH and FSR movwf cnt1 movlw b'01011000' movwf STATUS movlw combuff + .2 movwf FSR movf INDF,w movwf EEADR incf FSR,f movf INDF,w movwf EEADRH write_flash_segment_loop incf FSR,f ; load code word into EEDAT:EEDATH movf INDF,w movwf EEDAT incf FSR,f movf INDF,w movwf EEDATH bsf STATUS,RP0 ; now start the acutal write sequence bsf EECON1,EEPGD bsf EECON1,WREN movlw H'55' movwf EECON2 movlw H'AA' movwf EECON2 bsf EECON1,WR nop nop bcf EECON1,WREN bcf STATUS,RP0 incfsz EEADR,f ; increment flash address goto write_flash_segment_next incf EEADRH,f write_flash_segment_next decfsz cnt1,f goto write_flash_segment_loop bsf STATUS,RP0 clrw ; check if a write error occured btfsc EECON1,WRERR movlw E_FLASH_WERR bcf STATUS,RP1 bcf STATUS,RP0 movwf combuff + .2 ; = E_OK retlw .1 ; bytes to send ;; ------------------------------------- ;; ------------------------------------- ;; dummy user code org USERVECT ;; goto USERVECT bsf STATUS,RP0 bcf TRISD,0 bcf STATUS,RP0 userloop movlw b'00000001' xorwf PORTD,f movlw .255 movwf cnt1 usercnt1 movlw .255 movwf cnt2 usercnt2 decfsz cnt2,f goto usercnt2 decfsz cnt1,f goto usercnt1 goto userloop ;; ------------------------------------- ;; END end