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!!
The whole point of having type definitions like this is to make the size & signed-ness certain.
The Bad Thing is that the meaning of "word" is ambiguous and, therefore, the meaning of uword is ambiguous.
the meaning of 'horse' is ambigous if you do not speak english, if you do, it is not.
the meaning of 'word' is ambigous if you do not work with the group that uses it, if you do, it is not.
I personally prefer US or U16, but last place I worked used 'u_word', and where I am now they use 'WORD', neither is ambigous to me, after seeing the dfinitions/standard sheet.
Erik
It's just that some define "word" as 16-bit whatever architecture you use.
And some define "word" as the natural register size for the architecture.
If "word" sometimes is the name of a fixed-size entity, and sometimes for a "most efficient" entity, then lots of confusions are likely to happen.
Totally agree with Erik Malund.
My team has used types like word since 1990 and their use has long been second nature. Code has been ported from 8 bit to 16 bit and now to 32 bit and the transitions has been reassuringly straightforward. Back then they we didn't use so many typedefs, they were defines and apart from the latter not being understood by the compiler/debugger, I can see no problem with their use either.
Coincidentally, when we look at other code that contains "word", we realise it might be platform specific and, rather than considering it ambiguous, it acts as a catalyst for the typedef of it to be examined.
ambiguous: Open to more than one interpretation; having a double meaning.
But for the compiler, at the time of compilation, it can only have one meaning, which must have been given by a typedef or a define.
So the meaning is both well defined and precise. The person maintaining the project must of course refer to the "dictionary" to make sure they understand the meaning of any word (pun intended) they are unsure of.
If "word" sometimes is the name of a fixed-size entity, and sometimes for a "most efficient" entity, then lots of confusions are likely to happen. which it (hopefully) is not within an organization
If you want "word" to be "bad" then you need to declare everything but the K&R names "bad" as well. For all I care a byte can be named 'fido' after the smallest dog a short can be shorthanded to 'Ralph' after the mediun sized dog and an int named 'bozo' after the largest dog without any ill effect as long as everyone in the organization agree to it (I am exaggerating a bit here to make the point) I agree that it would be wonderful if K&R had used short names for variable types (do you know anyone that faithfully types "unsigned char") however each place decides what shorthand they use. I have learned that adaptng to an organizations standard is far better than 'improving it' by not following it. A bad standard is far better than none.
But the point of source code is as much - if not more - to convey the programmer's meaning to other human readers as it is to the compiler.
Otherwise, why bother to have "meaningful" names at all?
IF you want a type that is, specifically a signed 16-bit integral value, why not give it a name which says that explicitly?
"which it (hopefully) is not within an organization"
That depends a lot on what projects that organisation is busy with.
Would you rename all data types used by the Windows API just to normalize them with the data type names used by the own organisation for own projects?
So what do you do when you have one set of projects where WORD is a 16-bit integer, and another set of projects where WORD is the size of the target platforms registers? What happens when developers from one set of projects jumps to the other set of projects?
Microsoft themselves have had huge problems with their own code because of their data type uses. What should they do when all developers declared the variables as WORD - according to the API documentation - and the 16-bit API moved to a 32-bit and later a 64-bit target where the parameter in question needed to change accordingly? While other uses of the same WORD did not relate to the int size or the size needed to span the memory system.
Many, many real-world examples can be shown, where the use of "word" have resulted in large costs in rework or because of bugs because of the ambiguous meaning of the term. It's just that lots of projects survives far longer than originally planned, and gets moved to new platforms in a way not intended.
Code really should separate data types used when size is important and where it isn't important. stdint.h have data types like uint16_t, uint_fast16_t and uint_least16_t just to give developers the tools to tell other developers and the compilers what is important. And if we need to store an address as an integer data type instead of a pointer data type, we have intptr_t or uintptr_t.
If we have the tools, we should make use of them.
If we have seen common and well-documented problems with a specific data type naming, we should try to avoid that type of naming.
"IF you want a type that is, specifically a signed 16-bit integral value, why not give it a name which says that explicitly?"
So, following that suggestion, we'd better from now on refer to margerine as "hydrogenated plant material" ;)
To me, it is not a case of a type with a name of word as being ambiguous. It may be better (and I think more accurate) to describe a type with than name as being non-intuitive.
If variables, types, functions, modules (or whatever) have intuitive names, then the code has a far better chance of being understood by a 'human'.
As said before, 'word' is not my preference, as a lousy typist, I prefer U16. However, once again, if all developers in a group fully understand the meaning of "Ralph", "Ralph" will work.
I do believe that outlawing "WORD" after it has been used by an organization for a long time will lead to more problems that keeping it.
I have not, for a long time had the luxury of starting an organizations embedded software from scratch, but when doing so have never used 'word' or 'WORD'.
Yes, using 'word' is not the best choice, but it is, in my opinion, not as disastrous as some think.
"However, once again, if all developers in a group fully understand the meaning of "Ralph", "Ralph" will work."
Exactly. But even if all developers in a groupo fully understand the maning of "Ralph", it would still not be a good idea to create a variable "Ralph" or a data type "Ralph" to store the mains voltages read from an ADC.
And "Ralph" would not be a good name of a function that computes the RMS of the same mains voltage measurements.
And "Ralph" would not be a good name for a signal pin used to latch data onto a LCD to display the results of such a mains measurement.
The bad thing here, is that "Ralph" - just as "word" - requires the user to memorize the meaning of a token that does not in itself carry any real descriptive meaning. A real program does not contain one symbol. It contains hundreds or thousands or maybe much, much more. But our memories are limited. So once now and then, one of these developers will forget the true, original, meaning of that symbol. And it will suddenly be used for something else that is not compatible with the original meaning.
That a program can work, if a data type 'word' is used, doesn't say much. The question isn't if a program will work. The question is the total probability of introducing errors, because of the additional needs to make sure that everyone involved understands the exact meaning of every symbol, without the symbol name giving any meaningful hint.
And the even bigger problem - what do you do with a program that uses the datatype 'word', if you need to move the source code to a different platform? Is 'word' still a 16-bit data type? Or is 'word' still a register-size data type? With a data type named after the properties it promises to supply the developer with, you will have a greater probability that all developers will remember that every single use of the datatype is based on these promised properties. And not potential extra properties for that specific platform.
The ultimate question here is: What do you promise the developer, when you give them access to a variable of the data type 'word'? What is the text of your contract? And are you sure that you can keep that contract if porting the source code? Microsoft failed badly, when they promised a meaning of 'WORD'. They run like an express train straight into a very massive wall. Option 1: Break the contract on the meaning of 'WORD'. Option 2: Break the contract of the meaning of their different function calls and structures.
Microsoft isn't the only company that have hit that very massive wall because they have reached a situation where they have to make a promise - all caused by the use of 'word', 'WORD', 'Word', 'QWORD', or similar.
The smart thing to do, is to avoid taking routes where it is already know that a skillfull trap-layer have set out a number of well-camouflaged traps. The likelyhood of getting caught is just too high. And the rework costs can be quite high to try to back-track.