MC9S08GT60 Port Setting Problems

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

MC9S08GT60 Port Setting Problems

7,228 Views
the_andie
Contributor I
Hi,

Processor: MC9S08GT60.
I am using the Port B as a Output (PTB0 .. PTB7).
The ATD Function is disabled.
Every 200ms i toggle each Pin of Port B in a Timer Overflow Interrupt with the commands PINxx ^= 1;
In the majority of cases it works.
But several times the whole Port B changes his Output value after a few µs i have set them.
When i try this with a other Port (for Example Port D) it works every time.
Maybe someone can help me.

Regards,
andie
Labels (1)
0 Kudos
14 Replies

900 Views
the_andie
Contributor I
thank you all for your help!

the solution is, that i disable the interrups, like rocco said.

__asm SEI;
PTBD_PTBD7 ^= 1;
__asm CLI;

cos in the ISR the value of the accumulator were changed.

regards,
andie.
0 Kudos

900 Views
peg
Senior Contributor IV

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

 

0 Kudos

900 Views
the_andie
Contributor I
Hi David,

now i understand it. You've right, again. That's exactly what i measure with my oscilloscope.
I also choose the IF construct and hope the compiler will translate it always in the same way :smileywink:

Thanks, andie.
0 Kudos

900 Views
the_andie
Contributor I
@ rocco:

i understand your explications. but in the main code and in the ISR i do not change the same pins of the port. the strange thing is, that i want to change a pin and then the whole port were changed.


@ bigmac:

when i use the command
PTBD_PTBD7 = PTBD_PTBD7 ^ 1;
i don't have the problem, cos the compiler (CW) translate it also to BRSET and then BSET, BCLR commands, like the if-else command.

when i use the comand
PTBD_PTBD7 ^= 1;
the compiler translate it to LDA, EOR and STA commands and then i have the problems...
0 Kudos

900 Views
peg
Senior Contributor IV

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

 

0 Kudos

900 Views
bigmac
Specialist III

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

 

 

0 Kudos

900 Views
the_andie
Contributor I
little corrections:

in the interrupt routine i only toggle 3 pins of port b.
in the main program i toggle another pin of port b with smaller pulses ( 200µs).
when i toggle this pin with the command

PTBD_PTBD7 ^= 1;

then it could happens, that all other pins of port b (which has changed not very long ago) also changed !!!
when i toggle this pin with the command

if (PTBD_PTBD7)
PTBD_PTBD7 = 0;
else
PTBD_PTBD7 = 1;

then everything works correctly.

can anyone tell me the reason of this?

regards,
andie
0 Kudos

900 Views
bigmac
Specialist III

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

 

0 Kudos

900 Views
peg
Senior Contributor IV


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


 

0 Kudos

900 Views
rhinoceroshead
Contributor I


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.

0 Kudos

900 Views
peg
Senior Contributor IV

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. :smileyhappy:

Regards David

 

Message Edited by peg on 2006-07-27 09:34 PM

0 Kudos

900 Views
rhinoceroshead
Contributor I

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.

0 Kudos

900 Views
rocco
Senior Contributor II
Are you treating Port B as a critical section? This is a very common problem.

When you toggle a bit with
PTBD_PTBD7 ^= 1;
you are doing a read/modify/write.

Since you are changing port B in both the main code (with interrupts enabled, I assume) and in an ISR, you have what is called a "critical section". What can happen is that the interrupt occurs after the read, but before the write. That make the read invalid, since the ISR has changed the port value subsequent to the read.

To treat port B as a critical section, you need to disable interrupts during any access to it (prior to the read, until after the write).
0 Kudos

900 Views
peg
Senior Contributor IV

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

 

0 Kudos