[S08SH] problem with data direction

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

[S08SH] problem with data direction

2,556 Views
utall
Contributor I

Hi all,

I'm driving a open collector device (I2C memory) using self made driver. I use PTB2 and PTB3 as SDA and SCL. On another pin of the same port (PTB4) I have a LED which blink at low frequency (25z). To drive SDA I switch the associated data direction bit (PTBDD3) to input, with external pullup resistor, if I want an high level, to output with value 0 if I want a low level.

In this situation, if I run the firmware it give to me write errors after a random time (2s, 9s, ...). I have the same problem if I remove physically the led but I keep unaltered the led driver (square wave at 25Hz).

I solve the problem if I remove the square wave on the led pin and/or change the port, from PTB to PTA.

 

This is a very annoying problem. Could anyone help me?

 

Thank you in advance

Labels (1)
0 Kudos
Reply
10 Replies

1,863 Views
bigmac
Specialist III

Hello,

 

The most likely cause of this problem is that, for the port pin you are using as SDA, you are not writing a low to the output bit after you have changed the direction from input to output.

 

If the LED pin, or any other  output pin on the same port, should have its state altered using a read-modify-write instruction (e.g. BSET or BCLR),  the SDA bit within the output register will not remain low if the data direction is currently input.  This is because an input pin with high state (due to pullup) will read as high, and this state will then be written back to the port output register.

 

Regards,

Mac

 

0 Kudos
Reply

1,863 Views
rocco
Senior Contributor II

+1 to what Mac said.

 

I was only half way through your post, when I tought of the same thing: The 25Hz routine is using read/modify/write, and it is changing the 0 on SDA to a 1.

 

You need to write a zero to the SDA data bit EVERY TIME you set the bit to output.

0 Kudos
Reply

1,863 Views
utall
Contributor I

 


rocco wrote:

You need to write a zero to the SDA data bit EVERY TIME you set the bit to output.


 

#define SetData           bitI2C_SDA = kINPUT
#define ClrData           ioI2C_SDA = 0; bitI2C_SDA = kOUTPUT

 

where:

 

#define ioI2C_SDA           PTBD_PTBD3
#define bitI2C_SDA          PTBDD_PTBDD3
#define kINPUT                     0
#define kOUTPUT                    1

:-)I always use these defines to drive the port...

 

Regards

Andrea

0 Kudos
Reply

1,863 Views
bigmac
Specialist III

Hello Andrea,

 

The problem is your ClrData macro!  Making some substitutions to clarify the operation, the macro becomes as follows -

#define ClrData  PTBD_PTBD3 = 0; PTBDD_PTBDD3 = 1

 

If the MTIM interrupt should occur after the first part of the macro has completed, but prior to the second part, the PTBD3 state will revert to a 1, for the reason previously mentioned.  This problem should be eliminated with either of the following variations -

 

#define ClrData  __asm sei; PTBD_PTBD3 = 0; PTBDD_PTBDD3 = 1; __asm cli

This is equivalent to Tony P's xuggestion, and will prevent the interrupt from occurring at the critical point.

 

#define ClrData  PTBDD_PTBDD3 = 1; PTBD_PTBD3 = 0

This may actively drive the pin high for a few cycles before the port pin is set low, but may be acceptable for the IIC case, provided the slave device is not driving low at this point.

 

You should also handle the SCL pin in a similar manner for the clock low state.

 

Regards,

Mac

 

0 Kudos
Reply

1,863 Views
utall
Contributor I

Hi all,

Thanks for replies.

The firmware as only a MTIM interrupt (80us) and the led routine run into this interrupt. All what it does is to switch a fixed output pin from 0 to 1 and viceversa. The IIC routine run in main and it's not atomic so the interrupt never stops. Ok, this could be a problem, but why when I change the port this problem disappear? Can I set the output value BEFORE changing the direction to "output"?

 

Andrea

 

0 Kudos
Reply

1,863 Views
tonyp
Senior Contributor II

In general, the recommended sequence to alter a pin state is to first change the data, and then the direction.  This avoids possible contention (however short that may be), and possible "spurious" edges.   However, in the presence of ISR which alter the same port (even if different pins on that port) these two actions must occur as one (atomically).  Not the whole IIC routine has to be atomic, just the pin change operation.  This is because if the ISR that toggles the LED, happens right after the data write (and before the direction change), the data will be changed to the current input of the pin (since you have not yet made it an output).  In assembly, it would be something like:

 

 sei

 bclr IIC_PIN,IIC_PORT

(interrupt could occur right here, if interrupts are not masked with SEI)

 bset IIC_PIN,IIC_PORT+DDR

 cli

 

(The ISR is already atomic, unless you re-enable interrupts within it for some reason.).  The LED toggle should look like:

 

 LDA LED_PORT   ;if previous code not atomic, the current input IIC state may be used

 EOR #LED_PIN_MASK

 STA LED_PORT

 

 

0 Kudos
Reply

1,863 Views
utall
Contributor I

Hi,

Ok I will try to apply your suggestions, but my question is: why if I change the led output port all problems disappear? If there is a firmware problem this modification shouldn't interfere. It can be a PCB problem, or a micro peculiarity that I did not consider. I often encounter this problem and I'd like to know how to solve it. When I programmed Microchip I never had this problem... many others, but not this.

Thanks again for your patience

 

Andrea

0 Kudos
Reply

1,863 Views
tonyp
Senior Contributor II

Apparently, you haven't understood what the real problem is, or you wouldn't be asking this.

 

The processor only deals with complete bytes at all times.  It can NOT change single bits (such as single pins).  Even with the BSET/BCLR instructions which are meant to change single bits (from a logical point of view), they do this by reading in a whole byte (the whole port), changing the specific bit (pin) using OR (for BSET) or AND (with inverted mask for BCLR), and finally writing the whole byte back out.

 

If you use different ports, then the two read-modify-write operations cannot possibly affect one another because they belong in different bytes.  The problem is only evident  when dealing with the same port (or same byte).

 

But, to be on the safe side, and given that over an application's life span a lot of changes may occur to the firmware, and sometimes new (formerly unused) pins become used in different ways than originally planned, it would be good to follow this method of updating pins regardless of how the current code affects the ports.  This will save you from future troubles debugging "ghosts" that appeared out of nowhere.

 

0 Kudos
Reply

1,863 Views
utall
Contributor I

Ok, I understand. Sorry but I misunderstand previous posts. Now it's more clear. I'll try and I post the results if this can help other users.

Best regards and thank you again

 

Andrea

0 Kudos
Reply

1,863 Views
tonyp
Senior Contributor II

It might help if you posted the LED blinking and I2C Send routines.

 

This sounds like a concurrency problem.  If these two actions might happen concurrently (at random points in time), you need to make sure the port updates are atomic (ie. with interrupts disabled.)

0 Kudos
Reply