All pastes #488275 Raw Edit

Anonymous

public text v1 · immutable
·published 2007-05-14 22:29 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		RECONFIG
		bra		MAINLOOP

		; esperar al PC
		rcall		RECEIVE_RESET_TO
WAITLOOP	rcall		RECEIVE_NO_RESET
		sublw		'B'
		; si no es 'B', seguir esperando
		bnz		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

; --------------------------------------------------
; esperar a que se hayan enviado todos los caracteres, y resetear
; --------------------------------------------------
SEND_AND_RESET
		rcall		UART_SEND
		btfss		TXSTA,TRMT
		bra		$-2
		reset

; --------------------------------------------------
; 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