The first problem is that the compiler does not accept ".REPT 31" as inline ASM (code for procedure towards the end). This can be worked around by repeating the NOP instruction 31 times (not very elegant!), however then I get the error:
"0:0 E-0 Linker error: Routine exceeds page boundaries 16320 Sleeptest.dpas"
If I remove two of the NOPS or shift the address of the routine accordingly, I can get it to compile. However then the that part of the ASM code end with:
Code: Select all
$3FF8 $000000 NOP
;Sleeptest.dpas,110 :: PWRSAV #0
$3FFA $FE4000 PWRSAV #0
;Sleeptest.dpas,111 :: end;
$3FFC $ Sleeptest_L_6:
;Sleeptest.dpas,112 :: end;
$3FFC $ L_end__gotosleep:
$3FFC $060000 RETURN
So it is obvious that the two NOPs had to be deleted because, not surprising, there is an instruction to return from the procedure that take up space. This is not what the workaround asked for, the PWRSAV #0 has to be placed at the very end. I see no way of doing this without some modification of the compiler.
Out of curiosity, I checked the manual of the CCS compiler, and there it appears that a the PWRSAV instruction is by default inserted at the very end if this feature is not deactivated, the sleep errata could be the reason.
Could we get some help from ME on this?
My initial attempt (for dsPIC30F3013):
Code: Select all
Procedure GotoSleep; org $3FC0;
// GotoSleep calls PwrSav #0
begin
asm
//; fill remainder of the last row of prog mem with NOP instructions
.rept 31
NOP
.endr
//;Place SLEEP instruction in the last word of program memory
PWRSAV #0
end;
end;
Microchip's ASM example:Ensure that the PWRSAV #0 instruction is located
at the end of the last row of Program Flash
Memory available on the target device and fill the
remainder of the row with NOP instructions.
This can be accomplished by replacing all
occurrences of the PWRSAV #0 instruction with a
function call to a suitably aligned subroutine. The
address( ) attribute provided by the MPLAB
ASM30 assembler can be utilized to correctly align
the instructions in the subroutine. For an
application written in C, the function call would be
GotoSleep( ), while for an assembly language
application, the function call would be
CALL _GotoSleep.
The Address Error Trap Service Routine software
can then replace the invalid return address saved
on the stack with the address of the instruction
immediately following the _GotoSleep or
GotoSleep( ) function call. This ensures that
the device continues executing the correct code
sequence after waking up from Sleep mode.
Example 8 demonstrates the work around
described above, as it would apply to a
dsPIC30F3012 device.
Code: Select all
; ----------------------------------------------------------------------------------------------
.global __reset
.global _main
.global _GotoSleep
.global __AddressError
.global __INT1Interrupt
; ----------------------------------------------------------------------------------------------
.section *, code
_main:
BSET INTCON2, #INT1EP ; Set up INT pins to detect falling edge
BCLR IFS1, #INT1IF ; Clear interrupt pin interrupt flag bits
BSET IEC1, #INT1IE ; Enable ISR processing for INT pins
CALL _GotoSleep ; Call function to enter SLEEP mode
_continue:
BRA _continue
; ----------------------------------------------------------------------------------------------
; Address Error Trap
__AddressError:
BCLR INTCON1, #ADDRERR
; Set program memory return address to _continue
POP.D W0
MOV.B #tblpage (_continue), W1
MOV #tbloffset (_continue), W0
PUSH.D W0
RETFIE
; ----------------------------------------------------------------------------------------------
__INT1Interrupt:
BCLR IFS1, #INT1IF ; Ensure flag is reset
RETFIE ; Return from Interrupt Service Routine
; ----------------------------------------------------------------------------------------------
.section *, code, address (0x3FC0)
_GotoSleep:
; fill remainder of the last row with NOP instructions
.rept 31
NOP
.endr
; Place SLEEP instruction in the last word of program memory
PWRSAV #0