|
From: Arkadi S. <ar...@me...> - 2008-08-07 20:30:02
|
Hello.
I'm having troubles with a custom delay functions that never returns. Same code
compiled with PICC Lite compiler perform as expected.
This code works fine:
void delay_ms(unsigned int ms)
{
int i;
while (ms--) for (i = 0; i < 440; ++i);
}
But the delay_ms() below never returns and prints endless line of 'd'-s.
#define TMR0_PER_MS 20 // TMR0_PER_MS/(20MHz/4 clocks per cycle/256 prescaler) =
0.001s (1ms)
void tx(char c) {
while (!TXIF); // wait for transmitter to become free
TXREG = c;
}
unsigned char start_timer(void)
{
unsigned char tmr;
T0IF = 0;
// here is a short window of TMR0 overflow
tmr = TMR0;
if (tmr != 255)
T0IF = 0;
return tmr;
}
int time_since(unsigned char tmr_start)
{
int tm;
if (T0IF) { // if timer overflow
tm = 255 - tmr_start + TMR0;
} else {
tm = TMR0 - tmr_start;
if (tm < 0) // overflow happened just after T0IF is read
tm = 255 - tmr_start;
}
return tm;
}
void delay_ms(unsigned int ms)
{
unsigned char tmr_start, debug_skip_i = 0;
while (ms--) {
tmr_start = start_timer();
if (!debug_skip_i++)
tx('d');
while (time_since(tmr_start) < TMR0_PER_MS);
}
}
It doesn't matter how big is the delay_ms() argument: 5000 or 50 - it loops
endlessly in while(ms--).
Changing delay_ms() argument to unsigned char make it exit while() loop, but the
resulting delay is wrong and much less than required. Ie.
int i;
for (i = 0; i < 100; ++i) delay_ms(100);
produces almost no delay.
The start_timer()/time_since() might look like an overkill but I use them in
other parts of the code.
Here are the assembler listings generated by the compiler:
---------------------------------------
1. simple but good
_delay_ms ;Function start
; 2 exit points
; .line 96; "pic-fire.c" void delay_ms(unsigned int ms)
BANKSEL r0x1012
MOVWF r0x1012
MOVF STK00,W
MOVWF r0x1013
_00137_DS_
; .line 108; "pic-fire.c" while (ms--) for (i = 0; i < 440; ++i);
BANKSEL r0x1013
MOVF r0x1013,W
MOVWF r0x1014
MOVF r0x1012,W
MOVWF r0x1015
MOVLW 0xff
ADDWF r0x1013,F
BTFSS STATUS,0
DECF r0x1012,F
MOVF r0x1014,W
IORWF r0x1015,W
BTFSC STATUS,2
GOTO _00143_DS_
MOVLW 0xb8
MOVWF r0x1014
MOVLW 0x01
MOVWF r0x1015
_00142_DS_
MOVLW 0xff
BANKSEL r0x1014
ADDWF r0x1014,F
BTFSS STATUS,0
DECF r0x1015,F
MOVF r0x1014,W
IORWF r0x1015,W
BTFSS STATUS,2
GOTO _00142_DS_
GOTO _00137_DS_
_00143_DS_
RETURN
; exit point of _delay_ms
---------------------------------------
2. using timer, wrong
_delay_ms ;Function start
; 2 exit points
; .line 85; "pic-fire.c" void delay_ms(unsigned int ms)
BANKSEL r0x1012
MOVWF r0x1012
MOVF STK00,W
MOVWF r0x1013
; .line 88; "pic-fire.c" while (ms--) {
CLRF r0x1014
_00142_DS_
BANKSEL r0x1013
MOVF r0x1013,W
MOVWF r0x1015
MOVF r0x1012,W
MOVWF r0x1016
MOVLW 0xff
ADDWF r0x1013,F
BTFSS STATUS,0
DECF r0x1012,F
MOVF r0x1015,W
IORWF r0x1016,W
BTFSC STATUS,2
GOTO _00145_DS_
; .line 89; "pic-fire.c" tmr_start = start_timer();
CALL _start_timer
BANKSEL r0x1015
MOVWF r0x1015
; .line 90; "pic-fire.c" if (!debug_skip_i++)
MOVF r0x1014,W
MOVWF r0x1016
INCF r0x1014,F
MOVF r0x1016,W
BTFSS STATUS,2
GOTO _00139_DS_
; .line 91; "pic-fire.c" tx('d');
MOVLW 0x64
CALL _tx
_00139_DS_
; .line 92; "pic-fire.c" while (time_since(tmr_start) < TMR0_PER_MS);
BANKSEL r0x1015
MOVF r0x1015,W
CALL _time_since
BANKSEL r0x1017
MOVWF r0x1017
MOVF STK00,W
MOVWF r0x1016
;signed compare: left < lit(0x14=20), size=2, mask=ffff
MOVF r0x1017,W
ADDLW 0x80
ADDLW 0x80
BTFSS STATUS,2
GOTO _00153_DS_
MOVLW 0x14
SUBWF r0x1016,W
_00153_DS_
BTFSC STATUS,0
GOTO _00142_DS_
;genSkipc:3225: created from rifx:0xbfb4db30
GOTO _00139_DS_
_00145_DS_
RETURN
; exit point of _delay_ms
|