Skip to content

Xmodem Loader For The 1802 Olduino

September 3, 2017
img_9502

With this setup the AVR is reset by CTS but the serial signals are going direct to Q and /EF3 on the 1802

I have a more-or-less working xmodem bootloader for the 1802/1806. I want to run this without the AVR but for the moment it’s still in the circuit. The AVR is disconnected from the serial lines but it still has control of the 1802’s control lines to reset it.
As it stands, the xmodem sender on the host pulses RTS which resets the AVR. The AVR holds the 1802 in reset for a couple of seconds looking for data on its disconnected serial then starts the 1802.

The 1802 then sends a NAK on the serial line which starts the xmodem sequence. The fly in the ointment is that Q is low during the couple of seconds the AVR is waiting and the xmodem sender can interpret this as a 0. I have the same problem with the Olduino/Z’s loader and I always discard the first character received. It’s more intermittent with the 1802 and if i just discard the first character I often miss the NAK – because the loader doesn’t retry, it’s cooked.

Eventually I’ll get rid of the AVR but in the meantime maybe I get the loader to try a couple of NAKs with a shorter delay for response – 100ms instead of a second maybe.

I tried running without the AVR but i have a problem getting a clean reset of the 1802.
The details of the current reset are:
RTS goes low for 20ms but the AVR’s reset line goes low only for .4ms
4ms after RTS goes low, /CLEAR goes low, then /WAIT pulse low briefly – 7ns
2 seconds later /WAIT pulses low for 5 ms, 5ms later /CLEAR goes high
7ms later the 1802 sends the NAK
17ms later the xmodem sender responds and we’re off to the races.

The bootloader follows modified to NAK twice before timing out to the application. In combination with the sender throwing a way the first byte received this works pretty well.

;17-07-19 Standalone xmodem boot loader xmboot.asm
;	receives to fixed address APPADDR
	relaxed on
NAK:	EQU 0x15
SOH:	EQU 0x01
EOT:	EQU 0x04
ACK:	EQU 0x06
Rrcv:	EQU 8
Rsnd:	EQU 9
R14:	EQU 14
R12:	EQU 12
R11:	EQU 11
R3:	EQU 3
APPADDR: EQU 0x200
stkaddr: EQU 0x7FFF
blksize:	EQU 128
ldAD:	macro	reg1,directaddress	;load an absolute address or a constant into a register
	ldi	(directaddress)&255
	plo	reg1
	ldi	(directaddress)>>8; was/256
	phi	reg1
	endm

	seq			;prep Q for serial output
; XMODEM receiver based on xr.asm by Michael H Riley and serial routines by Josh Bensadon   
	ldaD	R12,APPADDR
	ldaD 	2,stkaddr
	sex	2
	ldaD	3,here
	sep	3
here:
	ldaD	Rsnd,serout
	ldaD    Rrcv,serinT
	ldi     NAK             ; need to send NAK to start
        sep     Rsnd
        sep     Rrcv          	; test for incoming character or timeout
        bnf     ckeot		;continue if no timeout
	ldaD    Rrcv,serinT	;reload address of serial routine with timeout
	ldi     NAK             ; retry NAK to start
        sep     Rsnd
        sep     Rrcv          	; test for incoming character or timeout
        bnf     ckeot		;continue if no timeout
	lbr launchapp		;timeout - launch already loaded application

filelp:    ;receive address is in R12, length goes in R11
;begining of block read. returns to filelp or exits to filedn   				
        sep     Rrcv          	; wait for incoming character
ckeot:	smi     EOT              ; check for EOT
        lbz     filedn           ; jump if so

	sep     Rrcv               ; read block number
	sep     Rrcv               ; read inverted block number

	ldi     blksize             ; 128 bytes to receive
	plo     r11

readlp: sep     Rrcv               ; read data byte
        str     r12                  ; store into output buffer
        inc     r12                  ; point to next position
        dec     r11                  ; decrement block count
        glo     r11                  ; see if done
        bnz     readlp              ; loop back if not
;end of block read
        sep     Rrcv               ; read checksum byte


        ldi     ACK                  ; send an ACK
        sep     Rsnd
       	lbr     filelp              ; loop back for more
filedn:    
        ldi     ACK                  ; acknowledge end of transmission
        sep     Rsnd

launchapp:				;dispatch code newly loaded or previously left 
	ldaD	0,APPADDR	;prepare to launch as if reset
	sex	0		;X=0
	sep	0		;PC=0 & go to loaded application


; *******************************************************************
; *** This software is copyright 2005 by Michael H Riley          ***
; *** You have permission to use, modify, copy, and distribute    ***
; *** this software so long as this copyright notice is retained. ***
; *** This software may not be used in commercial applications    ***
; *** without express written permission from the author.         ***
; *******************************************************************
	include "serwjrT1.inc"	
	
	org	0x200
;This is a standin for the program to be loaded
die:	
	seq
	req
	br	die

***File serwjrT1.inc follows
;bit-bang Serial routines adapted from Josh Bensadon's VELFbios-v3.1.asm
;https://groups.yahoo.com/neo/groups/cosmacelf/files/Member-JoshBensadon/
;Transmit Byte via Q connected to RS232 driver
;call via sep, returns via sep R3
;Byte to send in D
;Destroys r14
;17-09-02 this version times out on the first call only - approx 1.5 sec at 4MHz
;----------------------------------------------------------------------
 	IFNDEF 	LCC1802CPUSPEED
LCC1802CPUSPEED EQU 4000000
 	ENDIF
 	MACEXP ON
bitdelay: MACRO baudrate,cpuspeed,baseline,xreg
	rept ((cpuspeed/(baudrate*8)-baseline))/3
	NOP
	endm
	rept (((cpuspeed/(baudrate*8)-baseline)#3))>=1
	sex xreg
	endm
	ENDM
__BAUDRATE EQU 	9600
	align 64
serout:			;entry from assembly with char in D
	phi R14		;save char in R14.1
	ldi 9		;9 bits to transmit (1 start + 8 data)
	plo r14
	ghi R14
	shl		;set start bit
	rshr		;DF=0

.txcloop:
	bdf $+5		;10.5   jump to seq to send a 1 bit
	req		;11.5   send a 0 bit
	br $+5		;1      jump +5 to next shift
	seq		;11.5   send a 1 bit
	br $+2		;1      jump +2 to next shift (NOP for timing)
	rshr		;2      shift next bit to DF flag
	phi r14		;3      save D in r14.1
	DEC r14		;4      dec bit count
	glo r14		;5      get bit count
	bz .txcret	;6      if 0 then all 9 bits (start and data) sent
	ghi r14		;7      restore D
	bitdelay __BAUDRATE,LCC1802CPUSPEED,20,2,{EXPAND}
	br .txcloop	;9.5    loop back to send next bit
.txcret: ghi r14		;7
	bitdelay __BAUDRATE,LCC1802CPUSPEED,16,2
	seq		;11.5 stop bit
	bitdelay __BAUDRATE,LCC1802CPUSPEED,4,2
	sep R3		;return 
	br serout	;reset for next time
;**********************************************************************
;serinT
;Receive Byte via EF3 connected to RS232 receiver
;Receives 8 bits
;call via sep
;Returns with Byte received in D, DF is set if the start bit is never seen
;Destroys r14
;----------------------------------------------------------------------
	align 64
serinT:			;serial input with timeout of 65535*6*16 machine cycles - approx 1.5 sec at 4MHZ
	ldaD R14,0x4000	;R14 is timeout loop counter
.rxcw:	b3 .okgo	;check for start bit after each instruction
	dec 14
	b3 .okgo	;check for start bit after each instruction
	ghi 14
	b3 .okgo	;check for start bit after each instruction
	bnz .rxcw
;here we've had a timeout - set DF and return
	ldi 1
	shr
	sep R3		;return
	br  serinT	;for next time
.serinN:	bn3 .serinN	;serial input without timeout	
.okgo:			;here we know the start bit is present
 	ldi 8		;start bit +7 bits from loop, last bit on returning
	plo r14
	ldi 0
	NOP		;delay to center samples

.rxcloop:
	bitdelay __BAUDRATE,LCC1802CPUSPEED,20,2
	b3 $+6		;11.5 sample rx input bit
	ori 80h		;1
	br $+4		;2
	phi r14		;1
	phi r14		;2
	shr		;3
	phi r14		;4
	DEC r14		;5
	glo r14		;6
	bz .rxcret	;7
	ghi r14		;8
	br  .rxcloop	;9
.rxcret: ghi r14	;8
	ghi r14		;9
	bitdelay __BAUDRATE,LCC1802CPUSPEED,20,2
	b3 $+4		;11.5 sample last rx input bit
	ori 80h		; for a 1 bit
	adi 0		;clear the DF flag because no timeout
	sep R3		;return
	br  .serinN	;for next time - only timeout on first call
	
from __future__ import print_function
import sys
import logging
logging.basicConfig()
import serial
try:
    from cStringIO import StringIO
except:
    from StringIO import StringIO
from xmodem import XMODEM, CRC
from time import sleep
import os
if len(sys.argv)>1:
    filename=sys.argv[1]
else:
    filename="a_code.bin"
fileSize=os.path.getsize(filename)
print ("File Size is",fileSize)
xpect=(fileSize/128)

def getc(size, timeout=1):
    return port.read(size)
xcount=0
xprog=0
def putc(data, timeout=1):
    global xcount,xprog
    port.write(data)
    if (len(data)==128): # if it's a block
    	xcount=xcount+1
    	newprog=(xcount*50)/xpect
    	for x in range(newprog-xprog):
            sys.stdout.write("#")
        sys.stdout.flush()
        xprog=newprog
    sleep(0.001) # give device time to send ACK

#Main program starts here - define the serial port, set RTS off, then open it
port = serial.Serial(parity=serial.PARITY_NONE,
                     bytesize=serial.EIGHTBITS,
                     stopbits=serial.STOPBITS_ONE,timeout=5,xonxoff=0,
                     rtscts=0,dsrdtr=0,baudrate=9600)
port.rts=False
port.port='COM3'
port.open()
port.rts=True
sleep(0.001)
port.rts=False
#open the file to be loaded
stream = open(filename,'rb')
sleep(0.1)
port.read(1) #ditch the 1st char - always seems to be 0

#transfer the file
result=XMODEM(getc, putc).send(stream, quiet = 1)

stream.close()
port.close()

if result:
    print ("\ntransfer successful")
    sleep(.25)
else:
    print ("\ntransfer unsuccessful")
    x=raw_input("press enter to continue...");
Advertisements

From → Uncategorized

Leave a Comment

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: