Mon petit boot loader

Regarde s'il y a une connexion RS232 de branché, si oui part dans un petit interprèteur de commandes, si non démarre l'application principale.

;**********************************************************************************
;* Title		: zBLOADER
;* Version		: 1.1a
;* Last updated	: zf 070808.2307
;* Target		: Atmel AVR ATtiny45
;*
;* Support		: www.zufferey.com
;*
;* si connexion RS232 présente part en mode commandes
;* si non exécute l'application principale
;**********************************************************************************

.include "tn45def.inc"

;***** Pin definitions

.equ	RxD	=3			;Receive pin is PB3
.equ	TxD	=4			;Transmit pin is PB4

;***** Global register variables

.def	bitcnt	=R16			;bit counter
.def	temp	=R17			;temporary storage register

.def	TxByte	=R18			;Data to be transmitted
.def	RxByte	=R19			;Received data

.def	adr	=R20			;Adresse pour l'EEPROM

;***** Constantes

.equ		sb	=1		;Number of stop bits (1, 2, ...)

; constante b pour 1 MHz RC oscillator:
;   9600 bps - b=14
;   4800 bps - b=31
;  19200 bps - b=5
;  28800 bps - b=2

.equ	b	=30			; baud rate: 4800 bps



.cseg
.org 0

	rjmp Reset


.org 30






	rjmp Reset







;***** Divers strings
VersionSTR:
.DB	"zBLOADER 1.1a 070808.2307",13,10,10,0

HelloWorldSTR:
.DB	"Hello World",13,10,0

HelpSTR:
.DB	"a: test BCD, b: test ADC, c: test multi/div, C:cls, G:go app, h:help, H:HelloWorld, v:version",13,10,0,0


;***** RS232init
RS232init:
;	sbi	PORTB,TxD			;Init port pins en RS232 mode
	cbi	PORTB,TxD			;Init port pins en TTL mode
	sbi	DDRB,TxD

	sbi	PORTB,RxD			;met la pull up
	cbi	DDRB,RxD
	ret


;***** putchar

putchar:
	ldi	bitcnt,9+sb	;1+8+sb (sb is # of stop bits)
	com	Txbyte		;Inverte everything
	sec			;Start bit

putchar0:
	brcc	putchar1	;If carry set
;	cbi	PORTB,TxD	;    send a '0' en RS232 mode
	sbi	PORTB,TxD	;    send a '0' en TTL mode
	rjmp	putchar2	;else	

putchar1:
;	sbi	PORTB,TxD	;    send a '1' en RS232 mode
	cbi	PORTB,TxD	;    send a '1' en TTL mode
	nop

putchar2:
	rcall UART_delay	;One bit delay
	rcall UART_delay

	lsr	Txbyte		;Get next bit
	dec	bitcnt		;If not all bit sent
	brne	putchar0	;   send next
					;else
	ret			;   return


;***** putstring
putstring:
	lpm	Txbyte,Z+
	cpi	Txbyte,0
	brne	putstring1
	ret

putstring1:
	rcall	putchar			;And transmit the data
	rjmp	putstring


;***** putbin
putbin:
	rcall	bin2BCD16		;result: tBCD2:tBCD1:tBCD0 = $054321
	mov 	TxByte,tBCD2
	rcall	putbin1
	mov 	TxByte,tBCD1
	rcall	putbin2
	mov 	TxByte,tBCD0
	rcall	putbin2
	ret


putbin2:
	swap	TxByte
	rcall	putbin1
	swap	TxByte
	rcall	putbin1
	ret


putbin1:
	push	TxByte
	andi	TxByte,15
	ldi	r17,'0'
	add	TxByte,r17
	rcall	putchar
	pop	TxByte
	ret


;***** getchar

getchar:	ldi 	bitcnt,8+sb	;8 data bit + 1 stop bit

getchar1:
;		sbic 	PINB,RxD	;Wait for start bit en RS232 mode
		sbis 	PINB,RxD	;Wait for start bit en TTL mode
		rjmp 	getchar1

		rcall UART_delay	;0.5 bit delay

getchar2:	rcall UART_delay	;1 bit delay
		rcall UART_delay		

		clc			;clear carry
;		sbic 	PINB,RxD	;if RX pin high en RS232 mode
		sbis 	PINB,RxD	;if RX pin high en TTL mode
		sec			;

		dec 	bitcnt		;If bit is stop bit
		breq 	getchar3	;   return
					;else
		ror 	Rxbyte		;   shift bit into Rxbyte
		rjmp 	getchar2	;   go get next
getchar3:	ret


;****** UART_delay

UART_delay:	ldi	temp,b
UART_delay1:	dec	temp
		brne	UART_delay1
		ret


;***************************************************************************
;*
;* "bin2BCD16" - 16-bit Binary to BCD conversion
;*
;* This subroutine converts a 16-bit number (fbinH:fbinL) to a 5-digit
;* packed BCD number represented by 3 bytes (tBCD2:tBCD1:tBCD0).
;* MSD of the 5-digit number is placed in the lowermost nibble of tBCD2.
;*
;* Number of words	:25
;* Number of cycles	:751/768 (Min/Max)
;* Low registers used	:3 (tBCD0,tBCD1,tBCD2)
;* High registers used  :4(fbinL,fbinH,cnt16a,tmp16a)	
;* Pointers used	:Z
;*
;***************************************************************************

.equ	AtBCD0	=13		;address of tBCD0
.equ	AtBCD2	=15		;address of tBCD1

.def	tBCD0	=r13		;BCD value digits 1 and 0
.def	tBCD1	=r14		;BCD value digits 3 and 2
.def	tBCD2	=r15		;BCD value digit 4
.def	fbinL	=r16		;binary value Low byte
.def	fbinH	=r17		;binary value High byte
.def	cnt16a	=r18		;loop counter
.def	tmp16a	=r19		;temporary value

bin2BCD16:
	ldi	cnt16a,16	;Init loop counter	
	clr	tBCD2		;clear result (3 bytes)
	clr	tBCD1		
	clr	tBCD0		
	clr	ZH		;clear ZH (not needed for AT90Sxx0x)
bBCDx_1:lsl	fbinL		;shift input value
	rol	fbinH		;through all bytes
	rol	tBCD0		;
	rol	tBCD1
	rol	tBCD2
	dec	cnt16a		;decrement loop counter
	brne	bBCDx_2		;if counter not zero
	ret			;   return

bBCDx_2:ldi	r30,AtBCD2+1	;Z points to result MSB + 1
bBCDx_3:
	ld	tmp16a,-Z	;get (Z) with pre-decrement
	subi	tmp16a,-$03	;add 0x03
	sbrc	tmp16a,3	;if bit 3 not clear
	st	Z,tmp16a	;	store back
	ld	tmp16a,Z	;get (Z)
	subi	tmp16a,-$30	;add 0x30
	sbrc	tmp16a,7	;if bit 7 not clear
	st	Z,tmp16a	;	store back
	cpi	ZL,AtBCD0	;done all three?
	brne	bBCDx_3		;loop again if not
	rjmp	bBCDx_1		


;***************************************************************************
;*
;* "mpy16u" - 16x16 Bit Unsigned Multiplication
;*
;* This subroutine multiplies the two 16-bit register variables 
;* mp16uH:mp16uL and mc16uH:mc16uL.
;* The result is placed in m16u3:m16u2:m16u1:m16u0.
;*  
;* Number of words	:14 + return
;* Number of cycles	:153 + return
;* Low registers used	:None
;* High registers used  :7 (mp16uL,mp16uH,mc16uL/m16u0,mc16uH/m16u1,m16u2,
;*                          m16u3,mcnt16u)	
;*
;***************************************************************************

;***** Subroutine Register Variables

.def	mc16uL	=r16		;multiplicand low byte
.def	mc16uH	=r17		;multiplicand high byte
.def	mp16uL	=r18		;multiplier low byte
.def	mp16uH	=r19		;multiplier high byte
.def	m16u0	=r18		;result byte 0 (LSB)
.def	m16u1	=r19		;result byte 1
.def	m16u2	=r20		;result byte 2
.def	m16u3	=r21		;result byte 3 (MSB)
.def	mcnt16u	=r22		;loop counter

;***** Code

mpy16u:	clr	m16u3		;clear 2 highest bytes of result
	clr	m16u2
	ldi	mcnt16u,16	;init loop counter
	lsr	mp16uH
	ror	mp16uL

m16u_1:	brcc	noad8		;if bit 0 of multiplier set
	add	m16u2,mc16uL	;add multiplicand Low to byte 2 of res
	adc	m16u3,mc16uH	;add multiplicand high to byte 3 of res
noad8:	ror	m16u3		;shift right result byte 3
	ror	m16u2		;rotate right result byte 2
	ror	m16u1		;rotate result byte 1 and multiplier High
	ror	m16u0		;rotate result byte 0 and multiplier Low
	dec	mcnt16u		;decrement loop counter
	brne	m16u_1		;if not done, loop more
	ret


;***************************************************************************
;*
;* "div16u" - 16/16 Bit Unsigned Division
;*
;* This subroutine divides the two 16-bit numbers 
;* "dd8uH:dd8uL" (dividend) and "dv16uH:dv16uL" (divisor). 
;* The result is placed in "dres16uH:dres16uL" and the remainder in
;* "drem16uH:drem16uL".
;*  
;* Number of words	:19
;* Number of cycles	:235/251 (Min/Max)
;* Low registers used	:2 (drem16uL,drem16uH)
;* High registers used  :5 (dres16uL/dd16uL,dres16uH/dd16uH,dv16uL,dv16uH,
;*			    dcnt16u)
;*
;***************************************************************************

;***** Subroutine Register Variables

.def	drem16uL=r14
.def	drem16uH=r15
.def	dres16uL=r16
.def	dres16uH=r17
.def	dd16uL	=r16
.def	dd16uH	=r17
.def	dv16uL	=r18
.def	dv16uH	=r19
.def	dcnt16u	=r20

;***** Code

div16u:	clr	drem16uL	;clear remainder Low byte
	sub	drem16uH,drem16uH;clear remainder High byte and carry
	ldi	dcnt16u,17	;init loop counter
d16u_1:	rol	dd16uL		;shift left dividend
	rol	dd16uH
	dec	dcnt16u		;decrement counter
	brne	d16u_2		;if done
	ret			;    return
d16u_2:	rol	drem16uL	;shift dividend into remainder
	rol	drem16uH
	sub	drem16uL,dv16uL	;remainder = remainder - divisor
	sbc	drem16uH,dv16uH	;
	brcc	d16u_3		;if result negative
	add	drem16uL,dv16uL	;    restore remainder
	adc	drem16uH,dv16uH
	clc			;    clear carry to be shifted into result
	rjmp	d16u_1		;else
d16u_3:	sec			;    set carry to be shifted into result
	rjmp	d16u_1
	
	

































;***** RESET

reset:
	ldi r16, LOW(RAMEND)        	;Setup of stack pointer
	ldi r17, HIGH(RAMEND)
	out SPL, r16
	out SPH, r17

	rcall	RS232init

	sbic 	PINB,RxD			;Test si une prise RS232 est connectée
	rjmp	Application

	ldi	Txbyte,12			
	rcall	putchar
	rjmp	VersionDISP

CommandLoop:
	ldi	Txbyte,'>'			
	rcall	putchar
	rcall	getchar

	cpi	Rxbyte,'a'
	breq	ApplicationA

	cpi	Rxbyte,'b'
	breq	ApplicationB

	cpi	Rxbyte,'c'
	breq	ApplicationC

	cpi	Rxbyte,'C'
	breq	ClearScr

	cpi	Rxbyte,'G'
	breq	Application

	cpi	Rxbyte,'h'
	breq	HelpDISP

	cpi	Rxbyte,'H'
	breq	HelloWorldDISP

	cpi	Rxbyte,'v'
	breq	VersionDISP

	ldi	Txbyte,7 			;fait un beep si pas reconnu
	rcall	putchar

	rjmp CommandLoop


;Clear terminal (FromFeed)
ClearScr:
	ldi	Txbyte,12			
	rcall	putchar
	rjmp CommandLoop

;Envoie une virgule puis un espace sur le port RS232
CommaSpaceDISP:
	ldi	Txbyte,','			
	rcall	putchar
	ldi	Txbyte,' '			
	rcall	putchar
	ret

;Envoie le Help sur le port RS232
HelpDISP:
	ldi	Zl,low(HelpSTR*2)
	ldi	Zh,high(HelpSTR*2)
	rcall	putstring
	rjmp	CommandLoop


;Envoie Hello Word sur le port RS232
HelloWorldDISP:
	ldi	Zl,low(HelloWorldSTR*2)
	ldi	Zh,high(HelloWorldSTR*2)
	rcall	putstring
	rjmp	CommandLoop


;Affiche la version du système
VersionDISP:
	ldi	Zl,low(VersionSTR*2)
	ldi	Zh,high(VersionSTR*2)
	rcall	putstring
	rjmp	CommandLoop







;Fait clignoter le portB2
Application:

.def Delay =r17 ; Delay variable 1
.def Delay2 =r18 ; Delay variable 2

	sbi	DDRB,2				; met le PORTB2 en sortie

Application1:
	sbi	PORTB,2			; Set PORTB2
	rcall 	DLY1
	cbi 	PORTB,2			; Clear PORTB2
	rcall 	DLY1
	rjmp	Application1				; Repeat loop forever


DLY1:
	ldi Delay2, 0
DLY2:
	dec	Delay
	brne	DLY2
	dec	Delay2
	brne	DLY2
	ret






;Application A pour les tests
ApplicationA:
	ldi	fbinL,low(54300)
	ldi	fbinH,high(54300)
	rcall	putbin
	rjmp 	CommandLoop







;Application B pour les tests
ApplicationB:

	;init the ADC 
	ldi	r16,0b10001111		;internal 1.1V ref, ADC4 is input (Thermal)
	out	ADMUX,r16
	ldi	r16,0b11000111		;adc on, start adc, no interrupt, CLK = sysclk / 128)
	out	ADCSRA,r16

	;wait for conversion complete
W4ADC:
	sbic	ADCSRA,ADSC
	rjmp	W4ADC

	in	fbinL,ADCL
	in 	fbinH,ADCH
	rcall	putbin
	rjmp 	CommandLoop









ApplicationC:

;***** Multiply Two Unsigned 16-Bit Numbers (11 * 37)
	ldi	mc16uL,low(11)
	ldi	mc16uH,high(11)
	ldi	mp16uL,low(37)
	ldi	mp16uH,high(37)
	rcall	mpy16u	
	
	mov	fbinL,m16u0
	mov	fbinH,m16u1
	rcall	putbin
	rcall	CommaSpaceDISP

;***** Divide Two Unsigned 16-Bit Numbers (407/11)
	ldi	dd16uL,low(407)
	ldi	dd16uH,high(407)
	ldi	dv16uL,low(11)
	ldi	dv16uH,high(11)
	rcall	div16u	

	mov	fbinL,dres16uL
	mov	fbinH,dres16uH
	rcall	putbin

	rjmp 	CommandLoop

 

 

(c) www.zufferey.com