I am using Keil, C51 Compiler with Infineon XC886 8-bit micro....
I have a simple application that acquires rising and falling edges at P3.0 and then calculates the Period and Pulse Width in ticks of T12.
Then the program "based on these values" stretches the pulse using a 2D lookup table and generates a PWM output on P3.7 (it is inverted).
The lookup table returns a value from 0 to 1000.... a value of 300 means add 30% to the actual pulse width (NOT duty cycle which is %).
Everything seems to work except the output pulse width is incorrect.
I have (by process of elimintation) worked out the portion of code that is causing problems, but I think that it is actually the compiler.
The name of the function is "modifyDutyCycle"..
Step 1: First I disabled all interrupts then cut and paste the contents of the function into main. Since the calculation was quite involved I created a number of temporary variables to see the step by step results....
for (periodTemp = 3500; periodTemp < 31000; periodTemp += 200) { for(pulseTemp = 150; pulseTemp < 4000; pulseTemp += 50) { //Checking the lookUpTable function here in the for loop.... works! //index1 = lookUpTable(periodTemp, pulseTemp); //delay(10); //Extended version of the calculation from the "modifyDutyCycle" function //adjustVal = (uword)(((ulong)dutyCycle[0])*((ulong)(lookUpTable(period[0], dutyCycle[0])))/1000); //index2 = (uword)(((ulong)pulseTemp)*((ulong)(lookUpTable(periodTemp, pulseTemp)))/1000); index2 = lookUpTable(periodTemp, pulseTemp); //index2 = uword index3 = (ulong)index2; //index3 = ulong index4 = (ulong)pulseTemp; //index4 = ulong index5 = index3*index4; //index5 = ulong index5 /= 1000; //Attempt #1 //index6 = (uword)index5; //index6 = uword //Attempt #2 //blah = index5; //blah = uword //Attempt #3 index6 = index5; } }
Inititally "Attempt #1 failed to give the correct value" Then I just added yet another variable "blah" - which generated the correct value. Then I tried with no type cast with success
Step 2: I returned to the original function and tried to get it to work - still using temporary variables. When I simulate I get the following results...
1. There is no green/grey block on the side of the window (where you normally blace a breakpoint) at the "adjustVal = index4;" line
2. When I put the variable in the "watch" window however it seems to update the value of adjustVal
void modifyDutyCycle(void) { //sam uword index1; ulong index2; ulong index3; ulong index4; uword adjustVal; //sam #ifdef debug programStatus = 0x40; #endif dutyCycleNew[3] = dutyCycleNew[2]; dutyCycleNew[2] = dutyCycleNew[1]; dutyCycleNew[1] = dutyCycleNew[0]; //Calculate the extra number of timer ticks to be added to the output pulse //Stretch based on pulse width (off-time) not on total period //adjustVal = (uword)(((ulong)dutyCycle[0])*((ulong)(lookUpTable(period[0], dutyCycle[0])))/1000); index1 = lookUpTable(period[0], dutyCycle[0]); index2 = (ulong)index1; index3 = (ulong)dutyCycle[0]; index4 = index2*index3; index4 /= 1000; //adjustVal = (uword)index4; //typecast.. automatic?? adjustVal = index4; //index1 = index4; //dutyCycleNew[0] = dutyCycle[0]; // //Check that the new duty cycle is <100% if ((dutyCycle[0] + adjustVal) < (period[0] - 10)) { //Return new updated duty cycle dutyCycleNew[0] = dutyCycle[0] + adjustVal; } else //Error has occurred.... { dutyCycleNew[0] = period[0] - 10; //Make the pulse width to approx. 100% } }
3. When I try it on my hardware, I have a pulse output but the width is incorrect - which looks very similar to the first time I tried the funtion in main "Attempt #1"
My problem is something to do with a type cast or a memory addressing issue I think. But my results are inconsistent.
Any help on this oune would be much appreciated!!
Thanks, bye!!
Back to the topic. I agree with Andrew's comment about code being optimized away. If you want to see intermediate calculation results, set the compiler optimization level to minimum or capture intermediate results in a way that does not depend on optimization level (printf?). Another point: apparently, your code is supposed to be fast. But the long multiplication and division (among other things) could take a while to execute. Are you sure you are not violating timing constraints that might be imposed by your application?
Sometimes, it can be good to scale numbers so the division instead will be 1024 or another two-potence. Division of numbers larger than the native register size is no fun thing. And depending on algorithm, the division may vary greatly in execution time depending on the specific values. This can create big problems for real-time-critical code.
Yeah, thats a good point...
I can change the values in the lookup table then the division just becomes a right shift operation.
At the current time, the processor isn't doing much. The program is entirely interrupt driven and the time between interrupts will be (minimum) about 2ms.
If I get the time I'll change it, but for now I am more concerned with getting it working.