In my project i try to creat function implements easy average filter
unsigned int uint_average_filter (unsigned int *buffer, unsigned char order, unsigned char order_devider);
First parameter it's pointer to buffer with sampled values, Second parameter it's number of sample in buffer, Third parameter it's "divider" for shift operation after sum of sampled value. Function code:
unsigned int uint_average_filter (unsigned int *buffer, unsigned char order, unsigned char order_devider){ unsigned char counter = 0; unsigned long acc = 0; for(counter = 0; counter<order; counter++){ acc += buffer[counter]; } acc >>=order_devider; // wrong result here!!!!! return acc; }
When i try to use my function i get wrong result, and i see Disassembly code for this function:
... C:0x074B AF30 MOV R7,0x30 C:0x074D AE2F MOV R6,0x2F C:0x074F AD2E MOV R5,0x2E C:0x0751 AC2D MOV R4,0x2D C:0x0753 A92B MOV R1,0x2B C:0x0755 A801 MOV R0,0x01 C:0x0757 120B02 LCALL C?ULSHR(C:0B02) C:0x075A 8F30 MOV 0x30,R7 C:0x075C 8E2F MOV 0x2F,R6 C:0x075E 8D2E MOV 0x2E,R5 C:0x0760 8C2D MOV 0x2D,R4 C:0x0762 22 RET
From C:0x074B to C074D i see load acc value to R4 to R7 register, next two instruction must load order_devider(value placed to D:0x2B in data memory) to R0 (for function C?ULSHR) but D:0x2B placed ro R1 and to R0 loaded value located in data memory by address 0x01?? Where i wrong??
If parameter order_divider replace by constant value(example 0x04) i have correct code:
C:0x074B AF30 MOV R7,0x30 C:0x074D AE2F MOV R6,0x2F C:0x074F AD2E MOV R5,0x2E C:0x0751 AC2D MOV R4,0x2D C:0x0755 A801 MOV R0,#0x04 C:0x0757 120B02 LCALL C?ULSHR(C:0B02) C:0x075A 8F30 MOV 0x30,R7 C:0x075C 8E2F MOV 0x2F,R6 C:0x075E 8D2E MOV 0x2E,R5 C:0x0760 8C2D MOV 0x2D,R4 C:0x0762 22 RET
and this works fine.
Thaks for help!
D:0x2B placed ro R1 and to R0 loaded value located in data memory by address 0x01??
You'll want to look up what is at address 0x01.
Where i wrong??
In assuming that you've found the source of whatever the actual problem is. Because this here isn't.
You did not mention the value of order_devider. FWIW, if it is >=32, then the shift operation's behavior is undefined.
I've checked the code of lib function ULSHR. It's quite ordinary. No plain bug found.
R4~R7 contains the unsigned long digit and R0 contains how many rotations.
If unwanted result committed, it should be resulted from an improper order_devider.
You should check order_devider between 0~31 before doing your rotation. Otherwise you'll get ZERO for sure.
Thanks for answer! order_devider of course in range 0~31.
Ejack Zhang sayd:
Problem this: Why unsigned char order_devider (located by D:0x2B addres in data memory) placed to R1 instead R0, and R0 loaded with data memory by addres D:0x01 (no variable references to this address!) ?
If i try to place function code directly to main code all works perfectly, and R0 loaded with corect value(with value of variable located in data or xdata memory and declareted as global variable in main.h, example). But when i use my function I get that: order_devider located by 0x2B addres in data memory placed to R1 (why? variable declarated as unsigned char!).
If register bank 0 is active (see two bank select bits in PSW) then D:0x01 is of course the location of R1 in the data segment. The generated code is not 'nice/perfect' but fully correct.
James Wilson You try to tell me that my variable located by 0x2B addres in data memory loaded first to R1 register and after loaded from R1 to R0??
If i call this function by Timer ISR which declarated with
using 3
Should I also declarated with "using 3" my function? maybe you can tell where you can read about this? Thank you!
Yes, declarate my function with "using 3" correct this issue. But if I need use this function in different ISR with diffirent "using"'s i need to write different function for this??
Thaks all for help! http://www.keil.com/support/docs/598.htm http://www.keil.com/support/man/docs/c51/c51_noaregs.htm This two link to resolve this issue. Thread closed!