Hi Andie,
I would have thought the more elegant solution was to use the IF construct. It looks more like the BRSET that it generates and doesn't require the interrupts to be disabled. A comment should be made in the code here in case someone decides to "optimise" it later.
But "each to his own"
Also your "cos" explaination (or understanding) is not quite correct.
The value of the accumulator changing in the ISR is irrelevant as the accumulator value from the main routine is stacked before the ISR and unstacked after it. The problem is that this stacked value is supposed to be the current port value but after the ISR it won't (might not) be.
Regards David
OK, so CW compiles these two versions of the same thing differently.
The LDA, EOR, STA can fail because if the ISR interrupts in between these three commands then the main code will continue with a stale value for the port. This will set any bits that where changed in the ISR back to what they were before the ISR did its thing.
In the bit testing case, no value for the whole port is retained only the branch address which is determined in one opcode.
David
Hello all,
It actually surprises me that the compiler ever does a BSET/BCLR construct to represent the exclusive-OR case, simply because there is no single instruction to "flip a single bit", and the bit mask construct would be simpler.
This seems to demonstrate a very significant "trap" that is not obvious when using C, and whether or not a problem occurs could well be compiler dependent.
The situation is much more obvious with assembly programming where it is clearly evident whether single BSET or BCLR instructions are used, or multiple instructions using a bit mask is used.
The problem could apply with the manipulation of any bit within a port, where other bits can change under interrupt control (and where the evidence that other bits may alter may be in a totally different file). This would seem to imply that the only safe way to manipulate an I/O port bit in C code is to disable interrupts, and to re-enable them after the manipulation, just in case an interrupt might affect another bit in the same port, now or in a future upgrade of the firmware.
Regards,
Mac
Hello Andie,
As a matter of curiosity, do you still get the same problem if you use the following -
PTBD_PTBD7 = PTBD_PTBD7 ^ 1;
Regards,
Mac
bigmac wrote:Hello Andie,
As a matter of curiosity, do you still get the same problem if you use the following -
PTBD_PTBD7 = PTBD_PTBD7 ^ 1;
Regards,
Mac
Not sure what you're thinking here Mac...
The above is equivalent in C to PTBD_PTBD7 ^= 1;
so surely it compiles to the same thing???
The if else structure probably compiles to BRSET and then BSET, BCLR and thus avoids the problem as there is no bytes held between opcodes and therefore the ISR can break in anywhere.
Another example of C being inappropriate for this kind of stuff.
Regards David
peg wrote:Another example of C being inappropriate for this kind of stuff.
With all due respect, Peg, I have never found an example of C being inappropriate for this kind of stuff. Nowadays, the vast majority of embedded applications are written in C. Everything is possible - albeit open to debate about being less efficient during runtime and more efficient in programming time.
Also, it is erroneous to assume that a single assembly instruction is atomic. The HC12, for example, has a handful of non-atomic assembly instructions that can be interrupted. As processors become more pipelined this becomes even more evident, but for the HC08 I believe all instructions are atomic.
It is standard practice to force code segments into being atomic when multiple threads access the same variables. It is the first zinger that appears in any textbook when discussing threaded programming.
Hi,
My point is that if you have to concern yourself with what the code will compile into (or how different compilers will generate the output) then what is the purpose of using the higher level language?
With a proper hardware abstraction layer it is fine (or where you are not dealing directly with the hardware). Because then you just code away making it do what you want.
My "this kind of stuff" wasn't meant to refer to embedded processors in general, but more specifically bit level hardware manipulation.
As the question relates to a specific 9S08 processor, I take it that the last two paragraphs are just general comment.
Hmm.. took a while to get a bite, I thought the bait had rotted away.
Regards David
Message Edited by peg on 2006-07-27 09:34 PM
Appropriate or inappropriate, I've never been surprised by the way CW does bit-level hardware manipulation and I've used C exclusively for years. That's why I'm surprised to find someone claiming that it is, perhaps, unreliable.
You know, I see a lot of people doing bit setting/clearing in C like this:
PTBD_PTBD7 = 1;
which is fine, but I was taught to do it with the whole byte and a bitmask like this:
PTBD |= 0x80;
In the case of the exclusive or, with a single bit, does the bitwise XOR even make sense when applied to a single bit? The_andie originally stated that the entire port was sometimes flipping its state.
My question is, how did the other bits get flipped if CW was using BRSET, BSET, and BCLR?
It seems like CW must be doing something like:
PTB ^= 1;
instead of applying the XOR to just 1 bit like:
PTBD_PTBD7 ^=1;
I've never looked into how the bit structures are laid out in the really long header file where they are defined... Maybe the answer lies in there somewhere.
I've always toggled bits like this:
if (PTB & 0x80) {
PTB &= ~0x80;
} else {
PTB |= 0x80;
}
This compiles to BRCLR, BRSET and BCLR - which should never mess with other bits in the port. But still I would disable interrupts before starting this segment.
Hi Andie,
If you have the ADC function disabled and you have port B set up as all outputs then the pins will only change state on a write to PTBD or PTBDD. I would suggest you check your code or cut it down to a minimal program that can be posted here.
Regards David