Mirror with some correction

Dependencies:   mbed FastIO FastPWM USBDevice

Revision:
76:7f5912b6340e
Parent:
60:f38da020aa13
Child:
77:0b96f6867312
--- a/FreescaleIAP/IAP.s	Sun Jan 29 19:04:47 2017 +0000
+++ b/FreescaleIAP/IAP.s	Fri Feb 03 20:50:02 2017 +0000
@@ -1,76 +1,192 @@
-; Put this in READWRITE memory, to ensure that it goes in RAM 
+; FreescaleIAP assembly functions
+;
+; Put all code here in READWRITE memory, to ensure that it goes in RAM 
 ; rather than flash.  
     AREA iapexec_asm_code, CODE, READWRITE
+    
+;---------------------------------------------------------------------------
+; iapEraseSector(FTFA_Type *FTFA, uint32_t address)
+;   R0 = FTFA pointer
+;   R1 = starting address
 
-; iapExecAsm(FSTAT)
-;   FSTAT = address of ftfa->FSTAT register
-;
-; Note: arguments passed in R0, R1...
-    EXPORT iapExecAsm
-iapExecAsm
-    ; Do a layered call to our main handler routine.  Advice on ARM
-    ; forums suggests that before we carry out the Flash write, we should
-    ; do an extra call layer from one RAM-resident code block to another 
-    ; RAM-resident code block, with the inner block firing off the actual
-    ; FTFA execution.  This supposedly will reduce the chances of core
-    ; lockup during the write.  This strikes me as probably superstitious
-    ; in origin ("it was crashing and then I made some random changes to
-    ; the code that I can't remember and also knocked three times on the 
-    ; desk and then it worked, so always knock three times on a desk").
-    ; But I have indeed seen random crashes, and this is only a few bytes
-    ; of extra code, so what the heck.
-    ;
-    ; If there's a real justification for this, it's probably that the
-    ; extra call fills up the CPU instruction fetch/pre-fetch mechanism 
-    ; with RAM addresses, flushing out any remaining Flash addresses that 
-    ; might trigger an asynchronous Flash read from the CPU instruction 
-    ; fetch mechanism.  The big hazard with programming Flash through the 
-    ; FTFA is that any read access to the Flash will fail while a write
-    ; operation is in progress.  This will cause a CPU lockup if such a
-    ; read comes from the instruction fetcher.
-    ;
-    ; Simply push the link register, call our main routine, and return.
-    ; Arguments are in registers (R0, R1, ...), so they'll just pass
-    ; through to the callee.
-    STMFD   R13!, {LR}
-    BL      iapExecMain
-    LDMFD   R13!, {PC}  
-
-;
-; Main routine
-;
-iapExecMain
-    ; push R1, R2, link
-    STMFD   R13!, {R1,R2,LR}
+    EXPORT iapEraseSector
+iapEraseSector
+    ; save registers
+    STMFD   R13!,{R1,R4,LR}
+    
+    ; Ensure that no interrupts occur while we're erasing.  This is
+    ; vitally important, because the flash controller doesn't allow
+    ; anyone to read from flash while an erase is in progress.  Most
+    ; of the program code is in flash, which means that any interrupt
+    ; would invoke flash code, causing the CPU to fetch from flash,
+    ; violating the no-read-during-erase rule.  The CPU instruction
+    ; fetch would fail, causing the CPU to lock up.
+    CPSID I              ; interrupts off
+    DMB                  ; data memory barrier
+    ISB                  ; instruction synchronization barrier
+    
+    ; wait for any previous command to complete
+    BL      iapWait
     
-    ; Advice on ARM forums suggests that we should add a little artificial
-    ; delay here to avoid core lockup.  The point seems to be to reduce the
-    ; chances that a bus operation related to instruction fetching will hit 
-    ; the Flash while the write operation is executing.  This seems as
-    ; superstitious as the extra layered call (see above), but just in case...
-    MOVS    R1, #100    ; loop counter
-L0
-    SUBS    R1, R1, #1  ; R1 = R1 - 1
-    BNE     L0          ; loop until we reach 0    
-        
-    ; NB - caller is responsible for doing this
-    ; clear old errors from status bits 
-    ;MOVS    R1, #0x70   ; FPVIOL (0x10) | ACCERR (0x20) | RDCOLOERR (0x40)
-    ;STRB    R1, [R0]
+    ; clear any errors
+    BL      iapClearErrors
+    
+    ; set up the command parameters
+    MOVS    R4,#0
+    STRB    R4,[R0,#1]   ; FTFA->FCNFG <- 0
+    MOVS    R4,#9        ; command = erase sector (9)
+    STRB    R4,[R0,#7]   ; FTFA->FCCOB0 <- command
+    
+    STRB    R1,[R0,#4]   ; FTFA->FCCOB3 <- address bits 16-23
     
-    ; start command
-    MOVS    R1, #0x80   ; CCIF (0x80)
-    STRB    R1, [R0]
+    MOVS    R1,R1,LSR #8 ; address >>= 8
+    STRB    R1,[R0,#5]   ; FTFA->FCCOB2 <- address bits 8-15
+    
+    MOVS    R1,R1,LSR #8 ; address >>= 8
+    STRB    R1,[R0,#6]   ; FTFA->FCCOB1 <- address bits 0-7
     
-    ; wait until command completed - the CCIF bit is SET when the command completes
-    MOVS    R2, #0x80   ; CCIF (0x80)
-L1
-    LDRB    R1, [R0]
-    TSTS    R1, R2      ; CCIF (0x80)
-    BEQ     L1
+    ; execute and wait for completion
+    BL      iapExec
+    BL      iapWait
+    
+    ; restore interrupts
+    CPSIE I
 
     ; pop registers and return
+    LDMFD   R13!,{R1,R4,PC}    
+
+;---------------------------------------------------------------------------
+; iapProgramBlock(TFA_Type *ftfa, uint32_t address, const void *src, uint32_t length)
+;   R0 = FTFA pointer
+;   R1 = flash address
+;   R2 = source data pointer
+;   R3 = data length in bytes
+
+    EXPORT iapProgramBlock
+iapProgramBlock
+    ; save registers
+    STMFD   R13!, {R1,R2,R3,R4,LR}
+    
+    ; Turn off interrupts while we're working.  Flash reading
+    ; while writing doesn't seem to be forbidden the way it is
+    ; while erasing (see above), but even so, each longword
+    ; transfer requires writing to 10 separate registers, so
+    ; there's a lot of static state involved - we don't want
+    ; any other code sneaking in and changing anything on us.
+    CPSID I              ; interrupts off
+    DMB                  ; data memory barrier
+    ISB                  ; instruction synchronization barrier
+    
+    ; wait for any previous command to complete
+    BL      iapWait
+    
+    ; iterate over the data
+LpLoop
+    CMPS    R3,#3        ; at least one longword left (>= 4 bytes)?
+    BLS     LpDone       ; no, done
+    
+    ; clear any errors from the previous command
+    BL      iapClearErrors
+    
+    ; set up the command parameters
+    MOVS    R4,#0
+    STRB    R4,[R0,#1]   ; FTFA->FCNFG <- 0
+    MOVS    R4,#6        ; command = program longword (6)
+    STRB    R4,[R0,#7]   ; FTFA->FCCOB0 <- command
+    
+    MOVS    R4,R1        ; R4 <- current address
+    STRB    R4,[R0,#4]   ; FTFA->FCCOB3 <- address bits 16-23
+    
+    MOVS    R4,R4,LSR #8 ; address >>= 8
+    STRB    R4,[R0,#5]   ; FTFA->FCCOB2 <- address bits 8-15
+
+    MOVS    R4,R4,LSR #8 ; address >>= 8    
+    STRB    R4,[R0,#6]   ; FTFA->FCCOB1 <- address bits 0-7
+    
+    LDRB    R4,[R2]      ; R4 <- data[0]
+    STRB    R4,[R0,#8]   ; FTFA->FCCOB7 <- data[0]
+    
+    LDRB    R4,[R2,#1]   ; R4 <- data[1]
+    STRB    R4,[R0,#9]   ; FTFA->FCCOB6 <- data[1]
+    
+    LDRB    R4,[R2,#2]   ; R4 <- data[2]
+    STRB    R4,[R0,#0xA] ; FTFA->FCCOB5 <- data[2]
+    
+    LDRB    R4,[R2,#3]   ; R4 <- data[3]
+    STRB    R4,[R0,#0xB] ; FTBA->FCCOB4 <- data[3]
+    
+    ; execute the command
+    BL      iapExec
+    
+    ; advance to the next longword
+    ADDS    R1,R1,#4     ; flash address += 4
+    ADDS    R2,R2,#4     ; source data pointer += 4
+    SUBS    R3,R3,#4     ; data length -= 4
+    B       LpLoop       ; back for the next iteration
+    
+LpDone    
+    ; restore interrupts
+    CPSIE I
+    
+    ; pop registers and return
+    LDMFD   R13!, {R1,R2,R3,R4,PC}    
+
+    
+;---------------------------------------------------------------------------
+; iapClearErrors(FTFA_Type *FTFA) - clear errors from previous command
+;   R0 = FTFA pointer
+
+iapClearErrors
+    ; save registers
+    STMFD   R13!, {R2,R3,LR}
+
+    LDRB    R2, [R0]    ; R2 <- FTFA->FSTAT
+    MOVS    R3, #0x30   ; FPVIOL (0x10) | ACCERR (0x20)
+    ANDS    R2, R2, R3  ; R2 &= error bits
+    BEQ     Lc0         ; if all zeros, no need to reset anything
+    STRB    R2, [R0]    ; write the 1 bits back to clear the error status
+Lc0
+    ; restore registers and return
+    LDMFD   R13!, {R2,R3,PC}    
+
+
+;---------------------------------------------------------------------------
+; iapWait(FTFA_Type *FTFA) - wait for command to complete
+;   R0 = FTFA pointer
+
+iapWait
+    ; save registers
+    STMFD   R13!, {R1,R2,LR}
+
+    ; the CCIF bit is SET when the command completes
+Lw0
+    LDRB    R1, [R0]     ; R1 <- FTFA->FSTAT
+    MOVS    R2, #0x80    ; CCIF (0x80)
+    TSTS    R1, R2       ; test R1 & CCIF
+    BEQ     Lw0          ; if zero, the command is still running
+
+LwDone
+    ; pop registers and return
     LDMFD   R13!, {R1,R2,PC}    
+
+
+;---------------------------------------------------------------------------
+; iapExec(FTFA_Type *FTFA)
+;   R0 = FTFA pointer
+
+iapExec
+    ; save registers
+    STMFD   R13!, {R1,LR}
+        
+    ; write the CCIF bit to launch the command
+    MOVS    R1, #0x80    ; CCIF (0x80)
+    STRB    R1, [R0]     ; FTFA->FSTAT = CCIF
+    
+    ; wait until command completed
+    BL      iapWait
+
+    ; pop registers and return
+    LDMFD   R13!, {R1,PC}    
     
     END
     
\ No newline at end of file