All pastes #488284 Raw Edit

Stuff

public text v1 · immutable
·published 2007-05-14 22:35 UTC
rendered paste body
; ==================================================
; ==     Botload, el bootloader de EuskalBot      ==
; ==================================================

; Basado en tinybld

                RADIX           DEC
                LIST            P=18F2520
                include         "p18f2520.inc"

; ==================================================
; CONFIGURACIÓN
; ==================================================
; configuración de placa y rs232
xtal            EQU             10000000
baud            EQU             115200

; calcular SPBRG, redondeando correctamente
; settings: BRG16=1, BRGH=1
; cuando la PLL esta actica, BRGH=0 nos da un divisor de 4 adicional
spbrgval        EQU             ((xtal+(baud*2))/(baud*4))-1

; configuración del PIC
                __CONFIG        _CONFIG1H, _OSC_HSPLL_1H & _FCMEN_OFF_1H & _IESO_OFF_1H
                __CONFIG        _CONFIG2L, _PWRT_ON_2L & _BOREN_SBORDIS_2L & _BORV_2_2L
                __CONFIG        _CONFIG2H, _WDT_OFF_2H
                __CONFIG        _CONFIG3H, _MCLRE_ON_3H & _LPT1OSC_OFF_3H & _PBADEN_OFF_3H & _CCP2MX_PORTC_3H
                __CONFIG        _CONFIG4L, _STVREN_ON_4L & _LVP_OFF_4L & _XINST_OFF_4L & _DEBUG_OFF_4L
                __CONFIG        _CONFIG5L, _CP0_OFF_5L & _CP1_OFF_5L & _CP2_OFF_5L & _CP3_OFF_5L
                __CONFIG        _CONFIG5H, _CPB_OFF_5H & _CPD_OFF_5H
                __CONFIG        _CONFIG6L, _WRT0_OFF_6L & _WRT1_OFF_6L & _WRT2_OFF_6L & _WRT3_OFF_6L
                __CONFIG        _CONFIG6H, _WRTB_OFF_6H & _WRTC_OFF_6H & _WRTD_OFF_6H
                __CONFIG        _CONFIG7L, _EBTR0_OFF_7L & _EBTR1_OFF_7L & _EBTR2_OFF_7L & _EBTR3_OFF_7L
                __CONFIG        _CONFIG7H, _EBTRB_OFF_7H

; dirección de configuración que contiene el modo de oscilador (PLL o no)
CONFIG1H        EQU             0x300001
; dirección con el ID del PIC
DEVID1          EQU             0x3ffffe
; dirección con flags sobre el codigo de usuario
SW_FLAGS_ADDR   EQU             0x007FFE


; ==================================================
; VARIABLES
; ==================================================
BLVARS          UDATA_ACS
FLAGS           RES             1
SW_FLAGS        RES             1
RCV_CD_1        RES             1
RCV_CD_2        RES             1
RCV_CD_3        RES             1
CRC             RES             1
CMD             RES             1
CTR             RES             1
CTRO            RES             1

PROGBUF         UDATA           0x100
BUFFER          RES             64

#define         USING_PLL       FLAGS,0
#define         RECONFIG        FLAGS,1

; ==================================================
; VECTORES
; ==================================================

; vector de reset de usuario (saltar al bootloader)
CPU_RST_VECTOR  CODE            0x0
                goto            STARTBL

; vector de reset del bootloader (saltar al codigo)
BL_VECTORS      CODE            0x7E00
STARTBL         bra             START
BL_INTH_VECTOR  CODE            0x7E02
INTBL           bra             USERINT_HANDLER

; codigo principal del bootloader
LOADER          CODE

; ==================================================
; MACROS
; ==================================================

SENDCHAR        MACRO           CHR
                movlw           CHR
                rcall           UART_SEND
                ENDM

; no contar con que W tenga el valor correcto, porque a veces no se usa
MOVLWF          MACRO           FILE,LITERAL
        if LITERAL==0xFF
                setf            FILE
        else
        if LITERAL==0x00
                clrf            FILE
        else
                movlw           LITERAL
                movwf           FILE
        endif
        endif
                ENDM

; ==================================================
; CÓDIGO
; ==================================================

START
                ; resetear flags
                clrf            FLAGS

RECONFIGURE

                bcf             USING_PLL

                ; leer byte de config CONFIG1H
                MOVLWF          TBLPTRU, upper CONFIG1H
                MOVLWF          TBLPTRH, high CONFIG1H
                MOVLWF          TBLPTRL, low CONFIG1H
                tblrd*
                ; comprobar modo PLL
                movf            TABLAT,W
                andlw           b'00001111'
                xorlw           _OSC_HSPLL_1H & b'00001111'
                ; si la PLL esta activa, apuntarlo
                skpnz
                bsf             USING_PLL

                ; leer byte de flags del software
                MOVLWF          TBLPTRU, upper SW_FLAGS_ADDR
                MOVLWF          TBLPTRH, high SW_FLAGS_ADDR
                MOVLWF          TBLPTRL, low SW_FLAGS_ADDR
                tblrd*
                movff           TABLAT, SW_FLAGS


                ; configurar TX UART, modo rapido (divisor BRG /4)
                MOVLWF          TXSTA, (0<<TX9)|(1<<TXEN)|(0<<SYNC)|(1<<BRGH)

                ; si la PLL esta activa, configurar divisor BRG /16
                btfsc           USING_PLL
                bcf             TXSTA,BRGH

                ; configurar TMR0
                MOVLWF          T0CON,(1<<TMR0ON)|(1<<T08BIT)|(0<<T0CS)|(0<<PSA)|(7<<T0PS0)

                ; configurar baudrate
                MOVLWF          SPBRGH, high spbrgval
                MOVLWF          SPBRG, low spbrgval
                MOVLWF          BAUDCON, (1<<BRG16)

                ; activar UART y RX
                MOVLWF          RCSTA, (1<<SPEN)|(0<<RX9)|(1<<CREN)

                btfsc           REC     WAITLOOP
                rcall           RECEIVE_NO_RESET
                sublw           'L'
                ; si no es 'L', seguir esperando
                bnz             WAITLOOP

                ; 'BL' recibido
                ; enviar ID del PIC
                MOVLWF          TBLPTRU, upper DEVID1
                MOVLWF          TBLPTRH, high DEVID1
                MOVLWF          TBLPTRL, low DEVID1
                tblrd*+
                movf            TABLAT,W
                rcall           UART_SEND
                tblrd*
                movf            TABLAT,W
                rcall           UART_SEND

                ; cuando saltemos a RECONFIGURE, nos saltaremos el dialogo inicial con el PC
                bsf             RECONFIG

MAINLOOP
                ; esperar a que finalice la escritura anterior
                btfsc           EECON1,WR
                bra             $-2
                ; desactivar escritura
                clrf            EECON1

                ; esperando comandos
                SENDCHAR        'K'
                ; recibir comando
                rcall           RECEIVE
                movwf           CMD

                ; escribir EEPROM
                movlw           'E'
                cpfseq          CMD
                bra             CMD_NO_E

                ; recibir dirección y datos
                clrf            CRC
                rcall           RECEIVE
                movwf           EEADR
                rcall           RECEIVE
                movwf           EEDATA
                ; recibir y comprobar CRC
                rcall           RECEIVE
                movf            CRC,F
                bnz             BAD_CRC

                ; configurar escritura
                movlw           (0<<EEPGD)|(0<<CFGS)|(1<<WREN)
                ; escribir
                rcall           WRITE

                bra             MAINLOOP

CMD_NO_E        ; escribir FLASH
                movlw           'F'
                cpfseq          CMD
                bra             CMD_NO_F

                clrf            CRC
                ; recibir dirección
                rcall           GET_TBLPTR

                ; recibir 64 bytes
                movlw           64
                movwf           CTR
                ; cargar dirección del buffer en FSR0
                lfsr            FSR0,BUFFER
FLASH_READ_LOOP ; recibir byte
                rcall           RECEIVE
                ; poner en el buffer
                movwf           POSTINC0
                ; decrementar CTR hasta 0
                decfsz          CTR,F
                bra             FLASH_READ_LOOP

                ; recibir y comprobar CRC
                rcall           RECEIVE
                movf            CRC,F
                bnz             BAD_CRC

                ; configurar borrado
                movlw           (1<<EEPGD)|(0<<CFGS)|(1<<FREE)|(1<<WREN)
                ; borrar sector
                rcall           WRITE

                ; decrementar TBLPTR
                tblrd*-

                ; escribir 64 bytes (32*2)
                movlw           2
                movwf           CTRO
FLASH_PROG_OLOOP
                ; escribir 32 bytes
                movlw           32
                movwf           CTR
                ; resetear dirección del buffer en FSR0
                clrf            FSR0L
FLASH_PROG_LOOP ; leer byte desde el buffer
                movf            POSTINC0,W
                ; poner en los latches de escritura
                movwf           TABLAT
                tblwt+*
                ; decrementar CTR hasta 0
                decfsz          CTR,F
                bra             FLASH_PROG_LOOP

                ; configurar escritura
                movlw           (1<<EEPGD)|(0<<CFGS)|(0<<FREE)|(1<<WREN)
                ; escribir sector
                rcall           WRITE

                ; decrementar CTRO hasta 0
                decfsz          CTRO,F
                bra             FLASH_PROG_OLOOP

                bra             MAINLOOP

                ; escribir CONFIG
CMD_NO_F        movlw           'C'
                cpfseq          CMD
                bra             CMD_NO_C

                clrf            CRC
                ; leer dirección
                rcall           GET_TBLPTR
                ; leer datos
                rcall           RECEIVE
                movwf           TABLAT
                ; leer y comprobar CRC
                rcall           RECEIVE
                movf            CRC,F
                bnz             BAD_CRC

                ; guardar config en el latch
                tblwt*

                ; configurar escritura
                movlw           (1<<EEPGD)|(1<<CFGS)|(1<<WREN)
                ; escribir configuración
                rcall           WRITE

                ; delay de 3,2ms para dejar que la PLL se estabilice, si la hemos activado
                clrf            TMR0L
                btfss           TMR0L,7
                bra             $-2

                bra             RECONFIGURE

                ; ejecutar programa
CMD_NO_C        movlw           'R'
                cpfseq          CMD
                bra             CMD_NO_R
                bra             RUN_USER_PROGRAM

                ; keepalive (no-op)
CMD_NO_R        movlw           'N'
                cpfseq          CMD
                bra             CMD_NO_N
                bra             MAINLOOP

CMD_NO_N        ; comando incorrecto
                movlw           '?'
                bra             SEND_AND_RESET

BAD_CRC
                movlw           '!'
                bra             SEND_AND_RESET

; ==================================================
; FUNCIONES
; ==================================================

; --------------------------------------------------
; leer TBLPTR
; --------------------------------------------------
GET_TBLPTR
                rcall           RECEIVE
                movwf           TBLPTRU
                rcall           RECEIVE
                movwf           TBLPTRH
                rcall           RECEIVE
                movwf           TBLPTRL
                return

; --------------------------------------------------
; procedimiento de escritura
; --------------------------------------------------
WRITE
                movwf           EECON1
                movlw           0x55    ; procedimiento de control
                movwf           EECON2
                movlw           0xAA
                movwf           EECON2
                bsf             EECON1,WR       ; escritura
                return

; --------------------------------------------------
; enviar caracter via uart
; --------------------------------------------------
UART_SEND
                btfss           TXSTA,TRMT
                bra             $-2
                movwf           TXREG
                return

; --------------------------------------t

; --------------------------------------------------
; resetear timeout de recepción
; --------------------------------------------------

receive_cycles  EQU             ((6*256+3)*256+3)

RECEIVE_RESET_TO
                movlw           xtal/4/receive_cycles
                btfsc           USING_PLL
                movlw           xtal/receive_cycles
                movwf           RCV_CD_1
                clrf            RCV_CD_2
                clrf            RCV_CD_3
                return
; --------------------------------------------------
; recibir caracter
; --------------------------------------------------
RECEIVE
                rcall           RECEIVE_RESET_TO
RECEIVE_CL2
                clrf            RCV_CD_2
RECEIVE_CL3
                clrf            RCV_CD_3
; recibir caracter sin reset del timeout
RECEIVE_NO_RESET
                ; comprobar
                btfss           PIR1,RCIF
                bra             RECEIVE_NO
                movf            RCREG,W
                ; actualizar CRC
                addwf           CRC,F
                return
RECEIVE_NO
                decfsz          RCV_CD_3,F
                bra             RECEIVE_NO_RESET
                decfsz          RCV_CD_2,F
                bra             RECEIVE_CL3
                decfsz          RCV_CD_1,F
                bra             RECEIVE_CL2
                ; timeout!
                bra             RUN_USER_PROGRAM
; --------------------------------------------------
; ejecutar codigo de usuario
; --------------------------------------------------
RUN_USER_PROGRAM

                ; comprobar modo de interrupción
                btfss           SW_FLAGS,0
                bra             NO_INTERRUPT_SETUP

                ; configurar interrupción de recepción
                bcf             PIR1,RCIF
                bsf             PIE1,RCIE
                bsf             INTCON,PEIE
                bsf             INTCON,GIE

NO_INTERRUPT_SETUP
                ; comprobar modo UART
                btfsc           SW_FLAGS,1
                bra             NO_UART_RESET
                ; resetear UART
                clrf            RCSTA
                clrf            TXSTA
                clrf            BAUDCON
                clrf            SPBRGH
                clrf            SPBRG

NO_UART_RESET
                ; resetear registros
                clrf            STKPTR
                clrf            TBLPTRU
                clrf            TBLPTRH
                clrf            TBLPTRL
                clrf            TABLAT
                clrf            FSR0H
                setf            T0CON
                clrf            TMR0H
                clrf            EECON1
                clrf            EEDATA
                clrf            EEADR

                ; saltar a codigo de usuario
                bra             USER_RST

; --------------------------------------------------
; interrupción de usuario, comprobar recepción UART
; --------------------------------------------------
USERINT_HANDLER
                ; comprobar si es una interrupción de UART
                btfss           PIR1,RCIF
                bra             RETURN_TO_USER
                ; leer byte recibido
                movf            RCREG,W
                sublw           'B'
                ; si no es 'B', continuar comprobando RCIF hasta que se ponga a 0
                bnz             USERINT_HANDLER
                ; 'B' recibido, resetear al bootloader
                reset

RETURN_TO_USER  ; hacer sitio en la pila
                PUSH
                ; guardar la dirección de el vector de interrupción de usuario
                MOVLWF          TOSU,upper USER_INTH
                MOVLWF          TOSH,high USER_INTH
                MOVLWF          TOSL,low USER_INTH
                ; saltar al codigo de usuario, restaurando los valores de STATUS,W,BSR de camino
                return          FAST

; ==================================================
; DATOS BOOTLOADER
; ==================================================
BOOTLOADER_DATA CODE            0x7FC0
USER_RST        reset
                nop
                nop
                nop
USER_INTH
                reset
                nop
                nop
                nop
                nop
                nop
                nop
                nop
SOFTWARE_FLAGS  CODE            SW_FLAGS_ADDR
                dw              0x0000

            END