ATtiny85 TWI SDA/SCL Internal Pull-ups - TinyWireM Library

Go To Last Post
5 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

My question is the following:

Is it possible to enable the internal pull-up resistors on the PortB pins of an ATtiny85 when the direction of those pins is set as "output"?

 

The details of why I'm asking this question:

 

I've imported an Arduino sketch into Atmel Studio to get an understanding of how to use TWI to communicate with peripheral devices - the sketch is simple communication between an ATtiny85 and an MCP23008 I/O expander. I'm going through the code line-by-line and into the wire library (the TinyWireM variant) and the following does not make sense to me:

 

I have connected the SDA & SCL pins of the ATtiny85 directly to the MCP23008 SDA/SCL pins with no external pull-up resistors. Communication with the MCP23008 works just fine. I therefore assume that the internal pull-ups of the ATtiny85 SDA/SCL pins are doing the job, and indeed the initialization code that gets called in USI_TWI_Master.cpp suggests that it enables the internal pull-ups on the SDA & SCL lines:

 

/*---------------------------------------------------------------
 USI TWI single master initialization function
---------------------------------------------------------------*/
void TinyM_USI_TWI_Master_Initialise( void )
{
  PORT_USI |= (1<<PIN_USI_SDA);           // Enable pullup on SDA, to set high as released state.
  PORT_USI |= (1<<PIN_USI_SCL);           // Enable pullup on SCL, to set high as released state.
  
  DDR_USI  |= (1<<PIN_USI_SCL);           // Enable SCL as output.
  DDR_USI  |= (1<<PIN_USI_SDA);           // Enable SDA as output.

  USIDR    =  0xFF;                       // Preload dataregister with "released level" data.
  USICR    =  (0<<USISIE)|(0<<USIOIE)|                            // Disable Interrupts.
              (1<<USIWM1)|(0<<USIWM0)|                            // Set USI in Two-wire mode.
              (1<<USICS1)|(0<<USICS0)|(1<<USICLK)|                // Software stobe as counter clock source
              (0<<USITC);
  USISR   =   (1<<USISIF)|(1<<USIOIF)|(1<<USIPF)|(1<<USIDC)|      // Clear flags,
              (0x0<<USICNT0);                                     // and reset counter.
}

And the follwing macros are defined in USI_TWI_Master.h (I guess that the "__AVR_ATtiny85__" macro is defined, but I can't figure out where...):

#if defined(__AVR_ATtiny25__) | defined(__AVR_ATtiny45__) | defined(__AVR_ATtiny85__) | \
    defined(__AVR_AT90Tiny26__) | defined(__AVR_ATtiny26__)
    #define DDR_USI             DDRB
    #define PORT_USI            PORTB
    #define PIN_USI             PINB
    #define PORT_USI_SDA        PORTB0
    #define PORT_USI_SCL        PORTB2
    #define PIN_USI_SDA         PINB0
    #define PIN_USI_SCL         PINB2
#endif

 

However, from my reading of the ATtiny85 data sheet it seems to me that the internal pull-ups are disabled when a pin direction is set to output. This means that the above code enables the SDA/SCL pin internal pull-ups, then sets the SDA/SCL pins as outputs, which automatically disables the internal pull-ups.

Section 10.2.1 of the ATtiny85 data sheet states:

If PORTxn is written logic one when the pin is configured as an input pin, the pull-up resistor is activated. To switch the pull-up resistor off, PORTxn has to be written logic zero or the pin has to be configured as an output pin.

My understanding from the data sheet is that it could be possible to override the state of the internal pull-up resistors using the alternate pin functions, but I do not believe that this is being done in the code, nor is it even possible - if I am reading the following table correctly (from section 10.3.1 of the ATtiny data sheet), it shows that the pull-up override (PUOV) for the SCL (PB2) and SDA (PB3) pins is always 0 - i.e. you can override the pull-ups to always be disabled, but not to always be enabled.

 

The fact that the TWI communication is working correctly must mean that the internal pull-ups are enabled and that I'm drawing incorrect conclusions from the data sheet - specifically that paragraph from section 10.2.1.

 

Any enlightenment would be much appreciated.

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I2C comms use an open collector type of output with two states:

an Input with pullup resistor or

an output that is low only, so in this state no pull up is needed as the line will be pulled low by the output pin.

 

Hope that helps.

 

Jim

BTW, use of internal pull ups is recommended for generally, short,  slow speed buses (less then 100k bps)

 

 

 

 

Click Link: Get Free Stock: Retire early! PM for strategy

share.robinhood.com/jamesc3274
get $5 free gold/silver https://www.onegold.com/join/713...

 

 

 

 

Last Edited: Mon. Feb 18, 2019 - 08:50 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You must always use external pullups with I2C.

 

Internal pullups are the wrong value for I2C.   They are too weak for the I2C spec.

The TWI peripheral operates the output stage in "Open-Drain" mode independent of the internal pullups. 

 

You can not use internal pullups with USI because USI does not implement "Open-Drain" by itself.

 

Seriously,  two SMD resistors are not going to take up much pcb space.   Two resistors are not expensive.

 

David.

Last Edited: Mon. Feb 18, 2019 - 09:13 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks for the replies. They are helpful in so much that they illustrate how little I understand the electrical operation of the IO pins - more studying needed on my part.

 

Regarding the internal pullups: I'm looking through the Arduino Wire library as a "working" TWI implementation that I can study to understand how to roll my own implementation. I know the Arduino code does a "for dummies" enable of the internal pull-ups - I just couldn't reconcile what they do in their code with what I was reading in the ATtiny data sheet.

 

I interpret the following line in the data sheet:

To switch the pull-up resistor off ...  the pin has to be configured as an output pin

to mean that when the pin is configured as an output pin the internal pull-up is automatically disabled. Based on the Arduino code, that is clearly not the case.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You have misunderstood.   You should read the datasheet carefully.

 

Regular GPIO operation uses DDRB, PORTB, PINB registers.

 

Some peripherals take over the pins.   e.g. USART.    When enabled,   writing to DDR is ignored (on a Mega)

But with a Xmega you have to configure the USART pins.

You will have to check the datasheet for the ew Tiny0/1

 

I suggest that you invest $0.02 in two real life resistors.    It might hurt your pocket.

 

Yes the Wire.h library enables the pullups.    This is to support “Arduino: baby-talk programming for pothead” theory.

I am sure that the TinyWire.h library will work fine if you have external pullups.

 

David.