I2C and Pull-up resistors on I/O ports

Hello all,

I’m trying to communicate an NXT with my VEX microcontroller by the I2C protocol. However, I had no success on getting the SDA and SCL lines low (the NXT is sending data).
I know I need pull-up resistors on those lines so the open-drain system works, but I’m not sure whether are there any internal ones on VEX digital ports. If yes, what are their resistance?
I have tried using 4k7 ohm resistors connecting the +5V line and both SDA and SCL lines, but I always get logical 1 as input.
Should I try connecting SDA and SCL directly to microcontroller, or maybe using different resistors?
I have also read somewhere in the forum that I could use Rx/Tx ports to get better speeds on bit-banging. Is this worth trying (and how?)?

Thanks.

Which controller? Pic or Cortex. Which development environment are you using?

Some info on the cortex here http://content.vexrobotics.com/docs/VEXnet_Cortex_UserGuide_081811.pdf

The clock line should be no problem as it’s output only, data line will be an issue, you will have to switch between output and input as I’m not sure open collector is supported.

I was able to get the SPI working on a VEX 0.5 Microcontroller using these pins although you will need pullups of 4.7K to 10K for I2C:

/*

// To set the direction (output) of the pins you use these aliases.
#define IO_PWM05 TRISEbits.TRISE0
#define IO_PWM06 TRISEbits.TRISE1
#define IO_PWM07 TRISEbits.TRISE2
#define IO_PWM08 TRISEbits.TRISE3

// When using them as outputs you drive a value with these aliases.
#define OUT_PWM01 OUT_CCP2
#define OUT_PWM02 OUT_CCP3
#define OUT_PWM03 OUT_CCP4
#define OUT_PWM04 OUT_CCP5
#define OUT_PWM05 LATEbits.LATE0
#define OUT_PWM06 LATEbits.LATE1
#define OUT_PWM07 LATEbits.LATE2
#define OUT_PWM08 LATEbits.LATE3
*/

#define SW_DIN_PIN PORTEbits.RE0 // Data in pin using VEX PWM05
#define TRIS_SW_DIN_PIN TRISEbits.TRISE0

#define SW_DOUT_PIN LATEbits.LATE1 // Data out pin using VEX PWM06
#define TRIS_SW_DOUT_PIN TRISEbits.TRISE1

#define SW_SCK_PIN LATEbits.LATE2 // Clock pin using VEX PWM07
#define TRIS_SW_SCK_PIN TRISEbits.TRISE2

#define CSEE PORTEbits.RE3 // select line for Serial EEPROM using VEX PWM08
#define TCSEE TRISEbits.TRISE3 // tris control for CSEE pin on PIC18F8720
#define SW_CS_PIN LATEbits.LATE3 // Chip Select on PIC18F8720
#define TRIS_SW_CS_PIN TRISEbits.TRISE3

I was already able to see the SDA/SCL lines changing their values on VEX 0.5 Digital ports, so it’s already a first step. Didn’t try the bit-banging yet, though.
Thanks for your response, but I’m not sure how to use these defines. Should I use them to read/write to PWM ports?
Also, in order to write back to the open collector, would I need to use transistors? I’m not sure whether just writing a logical 0/1 would do the job.

I was able to configure those PWM output bits from analog to digital and when I sent out a stream of 0xAA bytes using SPI, the SCK and SDO outputs changed state. I was also able to configure these bits as inputs and was able to read data from them using the SPI protocol.

If you go to the download section in VEX you should be able to find my SPI_Example.zip application that reads and writes to a Microchip 25LC1024 SPI serial EEPROM using PIC18 C and MPLAB. It may be possible for you to modify it to use I2C so that it can read and write to a Microchip 24LC1024 I2C Serial EEPROM.

  1. This is how I confgured the PWM analog I/O bits as digital I/O:

    //***********************************************************************************************
    // Initialize the pins used for the I2C interface
    // configure port A for all digital inputs

    //OpenADC(ADC_FOSC_32 &
    // ADC_RIGHT_JUST & ADC_0ANA_0REF, ADC_CH0 & ADC_CH1 & ADC_CH2 & ADC_CH3 & ADC_CH4 & ADC_CH5 & ADC_CH6 & ADC_CH7 & ADC_INT_OFF);
    //OpenADC(ADC_0ANA_0REF, ADC_INT_OFF);
    OpenADC(ADC_0ANA, ADC_INT_OFF);

    // Configure PORTB interrupt with Interrupt on change off and pull-up resistors disabled

    OpenPORTB(PORTB_CHANGE_INT_OFF & PORTB_PULLUPS_OFF);

    // Configure PORT E for 8 Bits Digital I/O

    PSPCONbits.PSPMODE = 0;

    //The pullups on the interrupt pins are internal to the PIC micro. If that its the case, you can disable them by setting INTCON2.NOT_RBPU = 1.
    //Note: that this also disables the pullups for RB0 & RB1, which might effect the internal operation of the microcontroller. I’m not sure if
    // those lines are used for inter-processor communication. this is gleaned from the PIC18F8520 data sheet, and from examining ifi_aliases.h & ifi_picdefs.h

    //INTCON2.NOT_RBPU = 1;
    //***********************************************************************************************

    // Test the SPI interface by writing/reading to/from a Microchip 25LC512 SPI serial EEPROM

    // initialize the SPI2 port and CS to access the 25LC1024
    initSEE();
    .
    .
    .

  2. Here is the code to set/clear those reconfigured I/O bits:
    .
    .
    .

     SW_CS_PIN = 1;          // Make the CS pin high
     SW_DIN_PIN = 1;         // Make the DIN pin high
    

#if defined(MODE0) // Mode 0
SW_DOUT_PIN = 0; // Make the Dout and SCK pin low
SW_SCK_PIN = 0;
#endif

#if defined(MODE1) // Mode 1
SW_DOUT_PIN = 0; // Make the Dout pin low
SW_SCK_PIN = 1; // Make the SCK pin high
#endif

#if defined(MODE2) // Mode 2
SW_DOUT_PIN = 0; // Make the Dout and SCK pins low
SW_SCK_PIN = 0;
#endif

#if defined(MODE3) // Mode3
SW_DOUT_PIN = 0; // Make the Dout pin low
SW_SCK_PIN = 1; // Make the SCK pin high
#endif

    TRIS_SW_CS_PIN = 0;     // Make the CS pin an output
    TRIS_SW_DIN_PIN = 1;    // Make the DIN pin an input
    TRIS_SW_DOUT_PIN = 0;   // Make the DOUT pin an output
    TRIS_SW_SCK_PIN = 0;    // Make the SCK pin an output

Hi,

Thanks for your help!

I have seen that you manipulate port E fields to deal with PWM ports. Do you know which one is the equivalent to digital I/Os? (like PORTA, PORTB, etc.). I was hoping to test the bit-banging without the external pull-up resistors, and I think digital ports already have those (is this correct?)

Yes the digital I/O pins IO01 to IO16 have internal pull-up resistors, but in addition they also have resistors/diodes in series, which severely limits their bandwidth.

Which C compiler do you plan to use for you I2C project?

The PIC18F8520 port assignments are found in the ifi_aliases.h file. These PIC18 C files are part of the IFI Dynamic Tool Debugger application using PIC18C and MPLAB found as downloads on the VEX download code section.

.
.
.

/*
*-------------------------------------------------------------------------------
*---------- Aliases for DIGITAL IN/OUT - ANALOG IN connectors ------------------
*-------------------------------------------------------------------------------
*/
#define INPUT 1
#define OUTPUT 0

/* Used in User_Initialization routine in user_routines.c file. /
/
Used to set pins as INPUTS (analog or digital) or OUTPUTS (digital only). */
#define IO1 TRISAbits.TRISA0
#define IO2 TRISAbits.TRISA1
#define IO3 TRISAbits.TRISA2
#define IO4 TRISAbits.TRISA3
#define IO5 TRISAbits.TRISA5
#define IO6 TRISFbits.TRISF0
#define IO7 TRISFbits.TRISF1
#define IO8 TRISFbits.TRISF2
#define IO9 TRISFbits.TRISF3
#define IO10 TRISFbits.TRISF4
#define IO11 TRISFbits.TRISF5
#define IO12 TRISFbits.TRISF6
#define IO13 TRISHbits.TRISH4
#define IO14 TRISHbits.TRISH5
#define IO15 TRISHbits.TRISH6
#define IO16 TRISHbits.TRISH7

/* Aliases used to read the pins when used as INPUTS. */
#define rc_dig_in01 PORTAbits.RA0
#define rc_dig_in02 PORTAbits.RA1
#define rc_dig_in03 PORTAbits.RA2
#define rc_dig_in04 PORTAbits.RA3
#define rc_dig_in05 PORTAbits.RA5
#define rc_dig_in06 PORTFbits.RF0
#define rc_dig_in07 PORTFbits.RF1
#define rc_dig_in08 PORTFbits.RF2
#define rc_dig_in09 PORTFbits.RF3
#define rc_dig_in10 PORTFbits.RF4
#define rc_dig_in11 PORTFbits.RF5
#define rc_dig_in12 PORTFbits.RF6
#define rc_dig_in13 PORTHbits.RH4
#define rc_dig_in14 PORTHbits.RH5
#define rc_dig_in15 PORTHbits.RH6
#define rc_dig_in16 PORTHbits.RH7

/* Aliases used to drive the pins when used as OUTPUTS. */
#define rc_dig_out01 LATAbits.LATA0
#define rc_dig_out02 LATAbits.LATA1
#define rc_dig_out03 LATAbits.LATA2
#define rc_dig_out04 LATAbits.LATA3
#define rc_dig_out05 LATAbits.LATA5
#define rc_dig_out06 LATFbits.LATF0
#define rc_dig_out07 LATFbits.LATF1
#define rc_dig_out08 LATFbits.LATF2
#define rc_dig_out09 LATFbits.LATF3
#define rc_dig_out10 LATFbits.LATF4
#define rc_dig_out11 LATFbits.LATF5
#define rc_dig_out12 LATFbits.LATF6
#define rc_dig_out13 LATHbits.LATH4
#define rc_dig_out14 LATHbits.LATH5
#define rc_dig_out15 LATHbits.LATH6
#define rc_dig_out16 LATHbits.LATH7

/*
*-------------------------------------------------------------------------------
*---------- Aliases for INTERRUPTS connectors (inputs) -------------------------
*-------------------------------------------------------------------------------

  • Below are aliases for the input pins labelled INTERRUPTS on the VEX Robot Controller.
  • These pins are connected to PULL-UPS, meaning they are normally HIGH (1).
    */
    #define rc_dig_int1 PORTBbits.RB2
    #define rc_dig_int2 PORTBbits.RB3
    #define rc_dig_int3 PORTBbits.RB4
    #define rc_dig_int4 PORTBbits.RB5
    #define rc_dig_int5 PORTBbits.RB6
    #define rc_dig_int6 PORTBbits.RB7

/*
*-------------------------------------------------------------------------------
*---------- Aliases for each RC analog input -----------------------------------
*-------------------------------------------------------------------------------

  • Below are aliases for the analog input channels of the 18F8520.
  • They correspond to the DIGITAL IN/OUT - ANALOG IN pins on the Robot Controller.
    /
    /
    Used in Get_Analog_Value(…) routine. */
    #define rc_ana_in01 ADC_CH0
    #define rc_ana_in02 ADC_CH1
    #define rc_ana_in03 ADC_CH2
    #define rc_ana_in04 ADC_CH3
    #define rc_ana_in05 ADC_CH4
    #define rc_ana_in06 ADC_CH5
    #define rc_ana_in07 ADC_CH6
    #define rc_ana_in08 ADC_CH7
    #define rc_ana_in09 ADC_CH8
    #define rc_ana_in10 ADC_CH9
    #define rc_ana_in11 ADC_CH10
    #define rc_ana_in12 ADC_CH11
    #define rc_ana_in13 ADC_CH12
    #define rc_ana_in14 ADC_CH13
    #define rc_ana_in15 ADC_CH14
    #define rc_ana_in16 ADC_CH15

/* Used in Set_Number_of_Analog_Channels(…) routine in user_routines.c file. /
#define NO_ANALOG ADC_0ANA /
All digital /
#define ONE_ANALOG ADC_1ANA /
analog: AN0 digital: AN1->15 /
#define TWO_ANALOG ADC_2ANA /
analog: AN0->1 digital: AN2->15 /
#define THREE_ANALOG ADC_3ANA /
analog: AN0->2 digital: AN3->15 /
#define FOUR_ANALOG ADC_4ANA /
analog: AN0->3 digital: AN4->15 /
#define FIVE_ANALOG ADC_5ANA /
analog: AN0->4 digital: AN5->15 /
#define SIX_ANALOG ADC_6ANA /
analog: AN0->5 digital: AN6->15 /
#define SEVEN_ANALOG ADC_7ANA /
analog: AN0->6 digital: AN7->15 /
#define EIGHT_ANALOG ADC_8ANA /
analog: AN0->7 digital: AN8->15 /
#define NINE_ANALOG ADC_9ANA /
analog: AN0->8 digital: AN9->15 /
#define TEN_ANALOG ADC_10ANA /
analog: AN0->9 digital: AN10->15 /
#define ELEVEN_ANALOG ADC_11ANA /
analog: AN0->10 digital: AN11->15 /
#define TWELVE_ANALOG ADC_12ANA /
analog: AN0->11 digital: AN12->15 /
#define THIRTEEN_ANALOG ADC_13ANA /
analog: AN0->12 digital: AN13->15 /
#define FOURTEEN_ANALOG ADC_14ANA /
analog: AN0->13 digital: AN14->15 /
/
There is no FIFTEEN_ANALOG! /
#define SIXTEEN_ANALOG ADC_16ANA /
All analog */

/*
*-------------------------------------------------------------------------------
*---------- Aliases for CCP pins (PWM OUT 1-4 connectors) ----------------------
*-------------------------------------------------------------------------------

  • Below are aliases for the four PWM OUT pins which can be configured for use
  • as digital inputs or outputs. They are CCP pins with special features as
  • detailed in the PIC18FXX20 Data Sheet on page 149.
  • The pin mapping is as follows:
  • PWM OUT 1 -> CCP2
  • PWM OUT 2 -> CCP3
  • PWM OUT 3 -> CCP4
  • PWM OUT 4 -> CCP5
    /
    /
    To set the direction (input or output) of the pins you use these aliases. */
    #define IO_CCP2 TRISEbits.TRISE7
    #define IO_CCP3 TRISGbits.TRISG0
    #define IO_CCP4 TRISGbits.TRISG3
    #define IO_CCP5 TRISGbits.TRISG4

/* When using them as inputs you read the values with these aliases. */
#define IN_CCP2 PORTEbits.RE7
#define IN_CCP3 PORTGbits.RG0
#define IN_CCP4 PORTGbits.RG3
#define IN_CCP5 PORTGbits.RG4

/* When using them as outputs you drive a value with these aliases. */
#define OUT_CCP2 LATEbits.LATE7
#define OUT_CCP3 LATGbits.LATG0
#define OUT_CCP4 LATGbits.LATG3
#define OUT_CCP5 LATGbits.LATG4

/*
*-------------------------------------------------------------------------------
*---------- Aliases for PWM pins (PWM OUT 5-8 connectors) ----------------------
*-------------------------------------------------------------------------------

  • Below are aliases for the four PWM OUT pins which can be configured for use
  • as digital inputs or outputs.
  • The pin mapping is as follows:
  • PWM OUT 5 -> OUT_PWM05
  • PWM OUT 6 -> OUT_PWM06
  • PWM OUT 7 -> OUT_PWM07
  • PWM OUT 8 -> OUT_PWM08
    /
    /
    To set the direction (output) of the pins you use these aliases. */
    #define IO_PWM05 TRISEbits.TRISE0
    #define IO_PWM06 TRISEbits.TRISE1
    #define IO_PWM07 TRISEbits.TRISE2
    #define IO_PWM08 TRISEbits.TRISE3

/* When using them as outputs you drive a value with these aliases. */
#define OUT_PWM01 OUT_CCP2
#define OUT_PWM02 OUT_CCP3
#define OUT_PWM03 OUT_CCP4
#define OUT_PWM04 OUT_CCP5
#define OUT_PWM05 LATEbits.LATE0
#define OUT_PWM06 LATEbits.LATE1
#define OUT_PWM07 LATEbits.LATE2
#define OUT_PWM08 LATEbits.LATE3

/*
*-------------------------------------------------------------------------------
*---------- Aliases for TTL connectors (serial port 2) -------------------------
*-------------------------------------------------------------------------------

  • Below are aliases for the second serial port (USART2) pins labeled TTL.
    */
    #define usart2_TX LATGbits.LATG1
    #define usart2_RX PORTGbits.RG2

/*
*-------------------------------------------------------------------------------
*---------- Aliases for User Modes --------------------------------------------
*-------------------------------------------------------------------------------
*/
#define user_display_mode rxdata.rc_mode_byte.mode.user_display
#define autonomous_mode rxdata.rc_mode_byte.mode.autonomous

I am using the C18 compiler.
Ok, if I use pull-up resistors and PWM ports, would there be any difference on how to treat them other than issuing this:
PSPCONbits.PSPMODE = 0;
line? If I understood, this sets port E to digital I/O, then I can use TRIS, LAT and PORT for them?

You are really helping me, thanks =)

Hmm, I have started trying to use PWM ports as Inputs. My code is basically:

PSPCONbits.PSPMODE = 0;
TRISEbits.TRISE7 = 1;
//watch for changes in PORTEbits.RE7

Is this supposed to get PWM 1 as a digital input? I am only getting many 0s and 1s sequentially. Tried attaching a bumper, but it’s still unresponsive.

You are correct, setting PSPCONbits.PSPMODE to 0 changes the Port E bits to work as digital I/O. It could be that you are getting 0’s and 1’s when you press the bumper switch because it is not de-bounced enough. Try connecting the input to +5Volts using a 10K pull-up resistor and a jumper wire and see if the state changes to a 1. Also try connecting the input to ground and see if it reads 0.

  1. Did it work as an output when you set TRISEbits.TRISE7 = 0 and work as an input when you set TRISEbits.TRISE7 = 1 ?

  2. Are you using the LATE bits for digital output ?
    LATEbits.LATE7 = 1 // Set the bit to 1 - high
    LATEbits.LATE7 = 0 // Set the bit to 0 - low

  3. Are you using the PORTEbits.RE7 bit for input?

Well, I got the input working. Now I can’t work with the output on PWM port 1. This is my main code:

PSPCONbits.PSPMODE = 0;
Wait(100);

TRISEbits.TRISE7 = 0;
Wait(100);

LATEbits.LATE7 = 1;
Wait(100);

while (1);

Shouldn’t this give me 5V on PWM port 1?

Also, does the PSPCONbits.PSPMODE change only PWM port 1 or does it also set other PWMs as digital I/O?

Sorry for the confusion, I made a mistake in the previous post. The Port E assignments that are changed correspond to PWM05…PWM08 on the Motor block.

In order to write to PWM07 you use LATEbits.LATE2 as shown in the IFI define below:

// To set the direction (output) of the pins you use these aliases.
#define IO_PWM05 TRISEbits.TRISE0
#define IO_PWM06 TRISEbits.TRISE1
#define IO_PWM07 TRISEbits.TRISE2
#define IO_PWM08 TRISEbits.TRISE3

// When using them as outputs you drive a value with these aliases.
#define OUT_PWM01 OUT_CCP2
#define OUT_PWM02 OUT_CCP3
#define OUT_PWM03 OUT_CCP4
#define OUT_PWM04 OUT_CCP5
#define OUT_PWM05 LATEbits.LATE0
#define OUT_PWM06 LATEbits.LATE1
#define OUT_PWM07 LATEbits.LATE2
#define OUT_PWM08 LATEbits.LATE3
*/

Try using PWM05 with this code and also test the input:

PSPCONbits.PSPMODE = 0;
Wait(100);

TRISEbits.TRISE0 = 0;
Wait(100);

LATEbits.LATE0 = 1;
Wait(100);

while (1);

The PSPCONbits.PSPMODE changes only PWM05…PWM08 ports. I don’t know how to reconfigure the PWM01…PWM04 ports at this time. I only needed four I/O pins to implement SPI (SDI, SDO, SCK and CS). You should be able to work only two I/O pins (SCL, SDA)

Hi,
Thanks for the clarification! So I was probably just lucky enough to be able to read PWM01 as a digital port, even though I hadn’t actually configured it… Will test it tomorrow with your suggestion and post results.

It may be that you can read/write to PWM01…PWM04 without configuring them. You might want to try that experiment also.

Well, I couldn’t get PWM output to work. Even though I set the output to High, it still acts as Low.
Anyway, the output isn’t exactly what I would use: in order to simulate the open collector, I would manipulate the TRIS state (input -> high impedance, output -> ground). However, this didn’t seem to work on the PWM ports either (although it’s just fine on the digital ports).
And, as you said, the digital ports turned out to be just too slow for I2C: in my tests, it always missed ~3 pulses in a total of ~40.

How about trying to use the second UART pins for serial port 2 that are TTL levels?

/*
*-------------------------------------------------------------------------------
*---------- Aliases for TTL connectors (serial port 2) -------------------------
*-------------------------------------------------------------------------------

  • Below are aliases for the second serial port (USART2) pins labeled TTL.
    */
    #define usart2_TX LATGbits.LATG1
    #define usart2_RX PORTGbits.RG2

I got it working using RG1/TX for the SCL line and RG2/RX for the SDA line. The connections are made on the VEX Digital Input/Output block using the TX and RX for serial port 2. In order to do this you must disable the USART2 peripheral using the following logic:

// Disable serial port 2
RCSTA2bits.SPEN = 0; // Serial Port Disable [249]
// 0: serial port is disabled
// 1: serial port is enabled