Adapt bootloader for 12F1840 devices
[bootloader] / mybootload.X / main.asm
1     radix dec
2
3     errorlevel -302
4
5 #include "cpuselect.inc"
6
7 ; 16F1455 errata says self-program only works <= 4MHz clock
8 xtal    EQU 4000000
9 baud    EQU 19200
10
11 #include "spbrgselect.inc"
12
13 ; This is the smallest multiple of 32 that the bootloader
14 ; code fits into (minus the 4 for the remapped section)
15 loader_size     set 224
16
17 ; fit remap section in end of previous page
18 ; so we dont need to rewrite the bootloader page
19 remap_addr      set max_flash - loader_size - 4
20
21 ; Variables
22     cblock 0x20
23         buffer:80
24     endc
25
26     ; common ram section
27     cblock 0x70
28         cmd
29         crc
30         i
31         tmp
32     endc
33
34 ; ############ RESET ############
35 ; This is the normal reset vector
36 ; when a program is loaded, its version of these 4 will be moved
37 ; and replaced with our code to jump to the bootloader
38
39 Start CODE 0x0000
40     MOVLP   high(StartBoot)
41     GOTO    StartBoot
42     NOP
43     NOP
44 ; after this is the normal reset vector and rest of the loaded program
45
46
47 ; simple test program
48 Main
49 ;    banksel ANSELA
50 ;    CLRF    ANSELA
51 ;    banksel TRISA
52 ;    CLRF    TRISA
53 ;    CLRF    TRISC
54 ;    banksel PORTA
55 ;    BSF     PORTA,5     ; green on
56 ;    BCF     PORTA,4     ; red off
57 ;    SLEEP
58
59
60 ; At the far end of memory...
61 ; this is the relocated boot sector
62     ORG remap_addr
63 AppVector
64 ;    NOP
65     MOVLP   high(Main)
66     GOTO    Main    ; pretend program loaded
67     NOP
68     NOP
69
70 ; immediately followed by out bootloader
71     ORG     remap_addr+4
72 StartBoot
73
74     ; First configure the pin
75     ; 16f1455  RX=RC5 TX=RC4
76 ;    banksel TRISC
77 ;    BSF     TRISC,5   ; RC5 as input
78 ;    BCF     TRISC,4   ; RC4 as output
79     banksel SERIAL_PORT
80     CLRF    SERIAL_PORT
81     
82 #ifdef SERIAL_ANSEL
83     banksel SERIAL_ANSEL
84     CLRF    SERIAL_ANSEL
85 #endif
86
87     BTFSC   SERIAL_PORT,SERIAL_RXPIN   ; RC5 is Clear (break state) carry on
88     BRA     AppVector   ; Was not clear, launch app instead
89
90     ; Lets start the bootloader properly
91     banksel OSCCON
92     MOVLW   OSC_4MHZ
93     MOVWF   OSCCON      ; 4Mhz clock mode
94     BTFSS   OSCSTAT,HFIOFR
95     BRA     $-1         ; wait until oscillator is ready
96     MOVLW   b'00011001' ; Activate watchdog, 4 seconds
97     MOVWF   WDTCON
98
99 SetBaud
100     ; Set the baud rate and enable uart
101     banksel TXSTA
102     MOVLW   b'00100100' ; TXEN=1 SYNC=0 BRGH=1
103     MOVWF   TXSTA
104     banksel SPBRGL
105     MOVLW   spbrg_value
106     MOVWF   SPBRGL
107     CLRF    SPBRGH
108     banksel RCSTA
109     MOVLW   b'10010000' ; SPEN CREN
110     MOVWF   RCSTA
111
112 ; debug lights
113 ; debug RA5 green, RA4 red
114 ;    banksel ANSELA
115 ;    CLRF    ANSELA
116 ;    banksel TRISA
117 ;    CLRF    TRISA
118 ;    banksel PORTA
119 ;    BCF     PORTA,5     ; green off
120 ;    BSF     PORTA,4     ; red on
121     
122     ; Send the 'we heard you' ACK symbol
123     CLRF    crc
124     MOVLW   0x06
125     CALL    SendByte
126     MOVLW   'B'
127     CALL    SendByte
128     MOVLW   'L'
129     CALL    SendByte
130     
131     ; Wait for PC to drop the break condition
132     banksel SERIAL_PORT
133     BTFSS   SERIAL_PORT,SERIAL_RXPIN
134     BRA     $-1
135
136     ; Transmit device ID
137     banksel PMADRL
138     MOVLW   0x06  ; 0x8006 Device ID
139     MOVWF   PMADRL
140     CLRF    PMADRH
141     BSF     PMCON1,CFGS
142     BSF     PMCON1,RD
143     NOP
144     NOP
145     MOVF    PMDATH,W
146     CALL    SendByte
147     banksel PMDATL
148     MOVF    PMDATL,W
149     CALL    SendByte
150
151     ; Transmit location of bootloader, and thus top of flash
152     MOVLW   high(remap_addr)
153     CALL    SendByte
154
155     MOVLW   low(remap_addr)
156     CALL    SendByte
157
158     ; transmit csum to complete the welcome message
159     CALL    SendCRC
160
161     ; Wait here for instructions
162 CmdLoop
163     CLRWDT
164     CLRF    crc
165     CALL    ReadByte
166     MOVWF   cmd         ; keep it to re-examine
167
168     ; command 'R' read a row (32 words)
169     SUBLW   'R'
170     SKPNZ
171     BRA     ReadLine
172
173     ; command 'W' write a row (32 words)
174     MOVFW   cmd
175     SUBLW   'W'
176     SKPNZ
177     BRA     WriteLine
178
179     ; command 'B' reboot
180     MOVFW   cmd
181     SUBLW   'B'
182     SKPNZ
183     BRA     DoBoot
184
185     BRA     CmdLoop
186
187 ReadByte ; put it in W
188     banksel PIR1
189     BTFSS   PIR1, RCIF
190     BRA     $-1
191     banksel RCREG
192     MOVF    RCREG,W
193     ADDWF   crc,F
194     RETURN
195
196 ReadCRC
197     banksel PIR1
198     BTFSS   PIR1, RCIF
199     BRA     $-1
200     banksel RCREG
201     MOVF    RCREG,W
202     RETURN
203
204
205 SendCRC  ; copy the crc in as the thing to send
206     MOVF    crc,W
207 SendByte ; that is in W
208     ADDWF   crc,F
209     banksel PIR1
210     BTFSS   PIR1, TXIF
211     BRA     $-1
212     banksel TXREG
213     MOVWF   TXREG
214     RETURN
215
216 SendError ; Say there was an error (must be an in subr)
217     MOVLW   'E'
218     CALL    SendByte
219     BRA     CmdLoop
220
221 ReadLine ; read a row
222     CALL    ReadByte
223     banksel PMADRH
224     MOVWF   PMADRH  ; store the high byte
225     CALL    ReadByte
226     banksel PMADRL
227     ANDLW   0xE0    ; align to 32 word
228     MOVWF   PMADRL  ; store the low byte
229     CALL    ReadCRC ; read the checksum
230     SUBWF   crc,W
231     SKPZ             ; if crc-checksum !=0 goto Error
232     BRA     SendError
233 ; now lets send a record back to the host
234     MOVLW   row_size    ; 32 words
235     MOVWF   i
236     CLRF    crc         ; reset crc for outgoing message
237     MOVLW   'R'         ; warn that we are writing
238     CALL    SendByte
239     banksel PMADRH
240     MOVF    PMADRH,W    ; say what the start address is
241     ANDLW   0x7F        ; top bit is always set, duh
242     CALL    SendByte
243     banksel PMADRL
244     MOVF    PMADRL,W
245     CALL    SendByte
246
247 ReadLoop
248     banksel PMCON1
249     BCF     PMCON1,CFGS ; read program not config
250     BSF     PMCON1,RD
251     NOP
252     NOP
253     MOVF    PMDATH,W    ; send high byte
254     CALL    SendByte
255     banksel PMDATL
256     MOVF    PMDATL,W    ; send low byte
257     CALL    SendByte
258     banksel PMADRL
259     ; Assumption: this is 32 word aligned, will never cross boundary
260     INCF    PMADRL,F    ; increment address
261     DECFSZ  i,F         ; i--
262     BRA     ReadLoop    ; go around again
263     ; finished sending program words
264     CALL    SendCRC    ; send the crc
265     ; done, go back for next command
266     BRA     CmdLoop
267
268 WriteLine ; write a row
269     CALL    ReadByte
270     banksel PMADRH
271     MOVWF   PMADRH  ; store the high byte
272     CALL    ReadByte
273     banksel PMADRL
274     ANDLW   0xE0    ; align to 32 word
275     MOVWF   PMADRL  ; store the low byte
276     ; lets just store the bytes in buff until we are sure the checksum is good
277     banksel FSR0L
278     MOVLW   high(buffer)
279     MOVWF   FSR0H
280     MOVLW   low(buffer)
281     MOVWF   FSR0L
282     ; read row_size * 2 bytes
283     MOVLW   row_size * 2
284     MOVWF   i
285 WriteLineRead
286     CALL    ReadByte
287     MOVWI   FSR0++
288     DECFSZ  i,F
289     BRA     WriteLineRead
290     ; now read the crc and test
291     CALL    ReadCRC ; read the checksum
292     SUBWF   crc,W
293     SKPZ             ; if crc-checksum !=0 goto Error
294     BRA     SendError
295     ; everything is fine, commit to memory
296     ; first we have to erase the row
297     banksel PMCON1
298     BCF     PMCON1,CFGS ; program
299     BSF     PMCON1,FREE ; erase
300     BSF     PMCON1,WREN ; enable writes
301     MOVLW   0x55
302     MOVWF   PMCON2
303     MOVLW   0xAA
304     MOVWF   PMCON2
305     BSF     PMCON1,WR   ; commit
306     NOP
307     NOP     ; CPU goes to sleep for 2mS
308     BCF     PMCON1,WREN ; disable writes
309     ; now move the FSR back to the start
310     banksel FSR0L
311     MOVLW   high(buffer)
312     MOVWF   FSR0H
313     MOVLW   low(buffer)
314     MOVWF   FSR0L
315     MOVLW   row_size    ; need to do this once per word
316     MOVWF   i
317
318     ; setup for writing to latches
319     banksel PMCON1
320     BSF     PMCON1,WREN ; enable writes
321     BCF     PMCON1,CFGS ; program
322     BCF     PMCON1,FREE ; write not erase this time
323     BSF     PMCON1,LWLO ; into the latches
324
325 LatchWord
326     MOVIW   FSR0++
327     MOVWF   PMDATH
328     MOVIW   FSR0++
329     MOVWF   PMDATL
330     DECFSZ  i,F
331     BRA     LatchWrite
332     BRA     CommitWrite
333     ; just a latching write
334 LatchWrite
335     MOVLW   0x55
336     MOVWF   PMCON2
337     MOVLW   0xAA
338     MOVWF   PMCON2
339     BSF     PMCON1,WR   ; commit
340     NOP
341     NOP
342     INCF    PMADRL,F    ; move along
343     BRA     LatchWord
344 CommitWrite
345     BCF     PMCON1,LWLO ; real thing this time
346     MOVLW   0x55
347     MOVWF   PMCON2
348     MOVLW   0xAA
349     MOVWF   PMCON2
350     BSF     PMCON1,WR   ; commit
351     NOP
352     NOP             ; cpu stalls for 2mS
353     ; and we are finished
354     BCF     PMCON1,WREN ; disable writes
355     ; tell the other end we finished
356     CLRF    crc         ; reset crc for outgoing message
357     MOVLW   'W'         ; confirm the write command
358     CALL    SendByte
359     banksel PMADRH
360     MOVF    PMADRH,W    ; say what the start address is
361     ANDLW   0x7F        ; top bit is always set, duh
362     CALL    SendByte
363     banksel PMADRL
364     MOVF    PMADRL,W
365     ANDLW   0xE0        ; align to 32 word
366     CALL    SendByte
367     CALL    SendCRC
368     ; finished writing
369     BRA     CmdLoop
370
371 DoBoot
372     RESET
373
374 EndBoot
375     END
376