|
|
View previous topic :: View next topic |
Author |
Message |
johnh
Joined: 03 Jan 2004 Posts: 19 Location: UK - Brighton
|
Why does this happen?? |
Posted: Fri Apr 23, 2004 2:20 am |
|
|
Hello,
Here is a snippet of code that generates a pulse of a varying size dependant on the value of PosServo0.
I need a minimum pulse of around 900uS to drive a servo but i get some very strange readings.
If PosServo0 is = 0 then with the initial delay of 900 i would expect to see a pulse of around 900uS but i don't it is around 400uS higher. I have to set my initial pulse to around 516uS to get the required 900Us, can anybody explain why this happens. I don't mind living with this situation, but i wouldn't mind knowing why it does it. Here is the code.
Code: | x = 5;
output_high(PinServo0);
delay_us(516);
do {
delay_us(PosServo0);
} while(--x);
output_low(PinServo0); |
It goes round the do-while loop 5 times, but surely this can't add around 400uS if 1 instruction takes 1us (i'm using a 4MHz crystal)
Any thoughts greatly appreciated
John _________________ There are 10 kinds of people who understand binary, those who do and those who don't |
|
|
Haplo
Joined: 06 Sep 2003 Posts: 659 Location: Sydney, Australia
|
|
Posted: Fri Apr 23, 2004 2:32 am |
|
|
Quaoting from the manual:
Quote: |
The delay time may be longer than requested if an
interrupt is serviced during the delay. The time spent in
the ISR does not count toward the delay time.
|
This might be the case with your code. |
|
|
johnh
Joined: 03 Jan 2004 Posts: 19 Location: UK - Brighton
|
|
Posted: Fri Apr 23, 2004 2:40 am |
|
|
Hmmm,
I don't think so.. This delay is triggered by an interrupt every 16.5mS so each time this delay is triggered the ISR has just started and this delay is over well before the next ISR 16.5mS later _________________ There are 10 kinds of people who understand binary, those who do and those who don't |
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Fri Apr 23, 2004 2:51 am |
|
|
The fact that the delay looks like a constant 400us makes me suspicious.... Are you sure of your 'x=5' on entrance? If x=0, then you would loop for 255 times which would take about 400us... |
|
|
johnh
Joined: 03 Jan 2004 Posts: 19 Location: UK - Brighton
|
|
Posted: Fri Apr 23, 2004 2:56 am |
|
|
Yes certain of X=5 because if i have a value in PosServo0 then it moves the servo by the calculated amount. If X=0 then this would not happen, it would just generate a HUGE pulse.
Puzzling..! _________________ There are 10 kinds of people who understand binary, those who do and those who don't |
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Fri Apr 23, 2004 3:26 am |
|
|
The code generated for delay_us() is different when called with a contant than when called with a parameter.
Calling delay_us() with a constant value is accurate.
When calling delay_us() with a variable as parameter it has an overhead of about 20-25 instruction cycles. This means that with a 4MHz crystal the minimum delay time you can get is about 25us. You are calling it 5 times, that would explain 125us of your 400us delay.
I don't know what happened to the other 275us.... |
|
|
johnh
Joined: 03 Jan 2004 Posts: 19 Location: UK - Brighton
|
|
Posted: Fri Apr 23, 2004 3:29 am |
|
|
Yeah, that does account for some of the extra delay, but not all of it.
I suppose i will just have to say it is one of those things, but i hate to do that. It would be better to know. _________________ There are 10 kinds of people who understand binary, those who do and those who don't |
|
|
Ttelmah Guest
|
|
Posted: Fri Apr 23, 2004 4:24 am |
|
|
johnh wrote: | Yeah, that does account for some of the extra delay, but not all of it.
I suppose i will just have to say it is one of those things, but i hate to do that. It would be better to know. |
A lot depends also on the 'types' of the data. If 'x' is a long integer, it takes several times as long to do an addition/subtraction (the carry has to be dealt with). PosServo, should be an unsigned int.
I suspect you either have a different value in your registers than you think, or are using 'long' data types that add a lot more overhead.
For instance:
0026: NOP(FFFF)
0028: CLRF FEA
002A: MOVLW 19
002C: MOVWF FE9
002E: MOVLW FC
0030: ANDWF FEF,F
0032: RRCF FEF,F
0034: RRCF FEF,F
0036: MOVF FEF,W
0038: BTFSC FD8.2
003A: GOTO 0048
003E: GOTO 0044
0042: NOP
0044: DECFSZ FEF,F
0046: BRA 0042
0048: GOTO 01C4 (RETURN)
.................... delay_us(516);
01B0: MOVLW AB
01B2: MOVWF 00
01B4: DECFSZ 00,F
01B6: BRA 01B4
01B8: NOP
01BA: NOP
.................... do {
.................... delay_us(var);
01BA: MOVFF 18,19
01BE: CALL 0026
.................... } while(--x2);
01C2: DECFSZ 17,F
01C4: GOTO 01BA
Is the entire assembler sequence generated for your code, if int8 data types are chosen. Staring at the begining, the entry point is 1B0, the loop value used is 171, and the count takes 3uSec/loop, but only 2uSec on the last pass, then 4Sec are added for the loading, and the NOP's at the end. Total=516uSec.
If 'var' contains 10, and x2 contains 5, then the main loop will execute 5 times. The delay for each 'var', will be 3uSec (initial load and call), plus 14uSec if the count is zero (17uSec total overhead in this case), but for ten, the code takes the high six bits of the number (giving '2'), taking 15uSec to calculate this, and then executes a 4uSec loop for this many counts. It then takes 2uSec to return. So for the '10', the total delay will be 25uSec. The 'while' loop then adds another 4uSec/pass, so the total time becomes 145uSec.
There are a couple of uSec, then added by the time you 'clear' the pin. However the error _is not_ the scale that you are seeing. This suggests that there is something radically 'wrong' with either the numbers you are passing, or the data types (to make things worse...). The very 'suspicious' thing, is that the 'extra', is allmost exactly 256 instruction times.
However the possible errors are unfortunately large.
Consider using a timer for this. So loop with something like:
int16 delay;
delay=1000+((long)PosServo*4);
set_timer1(0);
output_high(PinServo0);
while (get_timer1()<delay) ;
output_low(PinServo0);
You will have to calculate the required multiplication factor, and offset value, to get the right time, depending on which timer you are using, but the delay then becomes a much more predictable value.
Ideally use the hardware PWM, or CCP (you can set the CCP to clear the pin when a particular count is reached).
Best Wishes |
|
|
Haplo
Joined: 06 Sep 2003 Posts: 659 Location: Sydney, Australia
|
|
Posted: Fri Apr 23, 2004 4:25 am |
|
|
Post the (relevant) generated code from the .LST file. This way we can see exactly how many instructions are being issued. |
|
|
johnh
Joined: 03 Jan 2004 Posts: 19 Location: UK - Brighton
|
|
Posted: Fri Apr 23, 2004 4:39 am |
|
|
I appreciate all the help you guys are giving.
Ttelmah, thanks for your suggestions. I will look at using a timer i think.
Here is the full list of the code, it pretty simple really..
Code: | // SEOS HMD servo development
// Include file that defines crystal speed (4Mhz) and that we are using PIC16F873
// and declares void genpulse(void) as a function
#include <Seosdev.h>
#define PinServo0 PIN_B7 //map PinServo0 to pin 28
// all variables used throughout code
int PosServo0 = 127;
int RawValue = 0;
int x = 0;
int i = 1;
// start of interrupt service routine occurs every 16.5ms
#int_TIMER0
TIMER0_isr()
{
genpulse();
}
void main()
{
// setting up interrupt routine
setup_timer_0(RTCC_INTERNAL | RTCC_DIV_64);
enable_interrupts(INT_TIMER0);
enable_interrupts(global);
// setting up the ADC
setup_adc(ADC_CLOCK_INTERNAL);
setup_adc_ports(A_ANALOG);
output_low(PinServo0);
PosServo0 = 127; // default servo pos
i = 1;
do {
set_adc_channel(0);
delay_ms(5);
RawValue = read_adc();
PosServo0 = RawValue;
} while (i = 1);
}
void genpulse(void)
{
x = 5;
output_high(PinServo0);
delay_us(516);
do {
delay_us(PosServo0);
} while(--x);
output_low(PinServo0);
} |
and this is the relevant LST file code
Code: | .................... void genpulse(void)
.................... {
.................... x = 5;
*
0054: MOVLW 05
0055: MOVWF 30
.................... output_high(PinServo0);
0056: BSF 03.5
0057: BCF 06.7
0058: BCF 03.5
0059: BSF 06.7
.................... delay_us(516);
005A: MOVLW AB
005B: MOVWF 20
005C: DECFSZ 20,F
005D: GOTO 05C
005E: NOP
005F: NOP
....................
.................... do {
.................... delay_us(PosServo0);
0060: MOVF 2E,W
0061: MOVWF 33
0062: GOTO 045
.................... } while(--x);
0063: DECFSZ 30,F
0064: GOTO 060
.................... output_low(PinServo0);
0065: BSF 03.5
0066: BCF 06.7
0067: BCF 03.5
0068: BCF 06.7
....................
....................
.................... } |
_________________ There are 10 kinds of people who understand binary, those who do and those who don't |
|
|
Haplo
Joined: 06 Sep 2003 Posts: 659 Location: Sydney, Australia
|
|
Posted: Fri Apr 23, 2004 4:42 am |
|
|
Also post the instructions from the address 0045 onwards. That's the code for the delay_us() function. |
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Fri Apr 23, 2004 4:51 am |
|
|
No offence, but just to make sure: What have you specified for "#use delay" ? |
|
|
Ttelmah Guest
|
|
Posted: Fri Apr 23, 2004 5:14 am |
|
|
ckielstra wrote: | No offence, but just to make sure: What have you specified for "#use delay" ? |
One obvious other comment. Change the variables to _unsigned_ integers (int8, or unsigned int). For signed, '127' is the maximum value that can properly be held....
Best Wishes |
|
|
johnh
Joined: 03 Jan 2004 Posts: 19 Location: UK - Brighton
|
|
Posted: Fri Apr 23, 2004 3:45 pm |
|
|
Sorry, left work at Lunch time.
As for the LST code from 0045, i won't be able to get that until monday, so i will post it then. (sorry didn't notice it jumped back up to 0045!)
Is an int signed then unless you specify unsigned int or int8? This could be a problem, i'll change this on monday and check the result.
Cheers for all your help guys, much appreciated. have a good weekend.
John _________________ There are 10 kinds of people who understand binary, those who do and those who don't |
|
|
johnh
Joined: 03 Jan 2004 Posts: 19 Location: UK - Brighton
|
|
Posted: Mon Apr 26, 2004 3:50 am |
|
|
Quote: | Is an int signed then unless you specify unsigned int or int8? This could be a problem, i'll change this on monday and check the result.
|
Haven't had chance to try this bit yet, but here is the code at 0045 as promised on Friday. Also ckielstra, #use delay is 4000000
Code: | .................... #use delay(clock=4000000)
0045: MOVLW 33
0046: MOVWF 04
0047: MOVLW FC
0048: ANDWF 00,F
0049: RRF 00,F
004A: RRF 00,F
004B: MOVF 00,W
004C: BTFSC 03.2
004D: GOTO 052
004E: GOTO 050
004F: NOP
0050: DECFSZ 00,F
0051: GOTO 04F
0052: BCF 0A.3
0053: GOTO 063 (RETURN) |
_________________ There are 10 kinds of people who understand binary, those who do and those who don't |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|