This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

TMS320F28062: Reading GPADAT seems to read output latch and not pin state

Part Number: TMS320F28062

App uses TMS320F28062 in an application driving a 3 phase brushless DC motor.
App has been working great for a long time.
GPIO0 to GPIO5 are used as EPWM1 to EPWM3 to drive the motor FETs.
During boot, GPIO0-5 are set high and low and each state checked to verify they all are working.
This is performed by the following function, MotorTest().

Here is the problem.

During software validation must prove that if any of GPIO0-5 are shorted low or high that the MotorTest() will fail.

To do this, each of GPIO0-5 are loaded one at a time by a 100 ohm resistor to either GND or +3.3V.  This makes a high on the GPIO only reach 0.3V or the low only reach 3.1V.  So when any one of GPIO0-5 are set high and loaded by 100 ohms to GND the pin only reaches 0.3V but reading GPADAT returns a 1.  And when any one of GPIO0-5 are set low and loaded by 100 ohms to +3.3V the pin only reaches 3.1V but reading GPADAT returns a 0.

The MotorTest() always passes.

So, it appears that the read of GPADAT is not reading the pin state, but instead reading the output latch.  All documentation for this part clearly states that reading GPADAT will always return pin states, not the latch.


Can anyone tell me why this is happening?


Here is the function:

// This function tests that all of GPIO0 to GPIO5 can be set high and low
// GPIO0 to GPIO5 are tested one at a time by setting high, reading to verify,
// then setting low and reading to verify.
uint16_t MotorTest(void)
{
uint16_t error = 0;
uint32_t val32;
uint32_t mask32;

volatile uint16_t i;

EALLOW;                             // Enable EALLOW protected register access
GpioDataRegs.GPACLEAR.all = 0x3F;   // output latch for GPIO0-5 all set to 0
GpioCtrlRegs.GPAMUX1.all  = 0x0000; // GPIO functionality on GPIO0-GPIO15
GpioCtrlRegs.GPADIR.all   = 0x003F; // GPIO0-5 are outputs, GPIO6-GPIO31 are inputs
GpioCtrlRegs.GPAQSEL1.all = 0x0000; // GPIO0-GPIO15 Synch to SYSCLKOUT
GpioCtrlRegs.GPAPUD.all   = 0x003F; // Pullups disabled on GPIO0-5 and enabled on
                                    //   GPIO6-GPIO31
EDIS;                               // Disable EALLOW protected register access

for (i=0; i<10; i++);   // short delay

// walks a bit through GPIO0 to GPIO5
for(mask32=1UL; mask32<0x040UL; mask32<<=1)
{
    // set one of GPIO0-5 high, verify only it is high
    GpioDataRegs.GPASET.all = mask32;           // set one of GPIO0-5 high as specified by mask32
    for (i=0; i<10; i++);                       // short delay
    val32= GpioDataRegs.GPADAT.all & MOTOR_IO;  // read GPADAT
    if(val32 != mask32)                         // test that only the one bit set by mask32 is high
    {
        error= 1;
        break;
    }

    // clear all of GPIO0-5, verify all are low
    GpioDataRegs.GPACLEAR.all = mask32;         // clear one of GPIO0-5 as specified by mask32
    for (i=0; i<10; i++);                       // short delay
    val32= GpioDataRegs.GPADAT.all & MOTOR_IO;  // read GPADAT
    if(val32 != 0)                              // test that all bits are low
    {
        error= 1;
        break;
    }
}

return error;
}

  • Here is a simpler statement of the problem.

    NOTE: I am using GPASET and GPACLEAR and not using the "bit" construct so this has nothing to do with the well known GPADAT read-modify-write problem.  Also I am using a scope so I can see exactly what is happening.

    All T.I. documentation for this part indicates that reading GPADAT, regardless of GPADIR setting of input or output, should always read the state of the pin.

    If I configure GPIO0-5 as input, I can pull them up or down and see the correct pin state in reading GPADAT.

    If I configure GPIO0-5 as output, I can toggle them high and low and read back the correct pin state via GPADAT.

    If I load one of them with a 100 ohm pulldown resistor, and set to logic high, I can see the voltage on the pin go from 0.0V to 0.3V.  Reading GPADAT still returns the logic high I wrote to the latch and not the logic low on the actual pin.

    Exactly the opposite occurs if I use a 100 ohm pullup to +3.3V and set the pin low.  Voltage on pin goes from 3.3V to 3.1V but read of GPADAT is the logic low I wrote to the output latch.

    So it appears that reading GPADAT for an input reads the pin state but reading GPADAT for an output reads the output latch value.

    Can anyone confirm or explain this anomolous behavior?

  • Your thinking and the documentation are correct; the GPxDAT register should reflect the state of the pin, not the state of the output buffer.

    Have you tested this code previously?

    Have you made any recent modifications? For example maybe you changed the declaration GPxDAT, this needs to be declared as volatile. 

    How many units have you seen this issue on?

    If only one, How long have you been using this unit? Is it possible that you have caused damage through EOS or ESD?

    Regards,
    Cody 

  • Hi Cody,

    Have tested extensively.

    No modifications have been made to GPxDAT or any other registers.  All are from the CCS libraries.

    Two separate units show the same behavior.

    Since I can read pin state when configured as input and not when configured as output, I doubt there is EOS or ESD damage.

    Also, it works the same on multiple GPIOs.

    Seems pretty clear to me that unless there is some undocumented setting, reading GPxDAT when configured as output reads the latch.

    Mark

  • Mark,

    I wish I were hiding some undocumented setting that would make this whole post make sense. But, unfortunately, that is not the case here.

    Could you try reading the value of GPxDAT from the memory browser? This could help rule out unforeseen software bugs.

    I too think that ESD and EOS are likely not the cause, but its tough to immediately rule out EOS. If you're connecting a 100 ohm shunt to ground you are pulling too much current out of the pin and violating the datasheet limits.

    Could you describe the order of the test? for example run code, connect shunt, test low, test high. disconnect shunt, test low, test high. 

    Have you tried adding any delay in your code between writing and reading the GPIO?

    Alternatively, what are you trying to accomplish in this experiment? Is this just a validation of your test software to say "yes, this software can catch a short."? Are you planning on shorting the GPIOs of every device you produce?(I think that would be a bad idea)

    Regards,
    Cody 

  • Cody,

    Code being run is given in the original post.  Function is named MotorTest().  It is part of power-on-self-tests.

    Yes we are examing register contents from CCS and they match what the SW reads.

    Using the 100 ohm resistors is part of validation that the SW can actually catch a short.

    No we do not plan to do this in production, only to validate SW.

    Since only 0.3V is developed across the 100 ohms when set high then only 3mA is drawn so should be safe and within datasheet limits of 4mA.

    Note that there is delay prior to reading in the test using a volatile variable.  Have tried making it very long with no change in results.

    This is not an experiment!!!  This is production code and for a commercial product for a large company.

    Can you please fire up a dev board and verify this operation?

    Mark

  • Mark,

    I connected to an F28069M LaunchPad and ran the following tests.

    GPIO0 in input mode", using a 100Ohm shunt to connect it to 3.3V and GND.

    1. Without a shunt the GPADAT register indicates "0", the pin voltage was verified by oscilloscope to be 0V.
    2. When connecting the shunt GPADAT reflected the voltage forced on the pin.

    GPIO0 in output mode, using a 100Ohm shunt to connect it to 3.3V and GND. 

    1. GPIO output mode confirmed, setting GPASET register results in 3.3V on pin and using the GPACLEAR register results in 0V on pin.
    2. GPIO0 set to "0" in GPADAT.
      1. Connecting the shunt to Ground: Oscilloscope shows 0V and GPADAT indicates 0.
      2. Connecting the shunt to 3.3V: Oscilloscope shows ~0.9V and GPADAT indicates 0.
    3. GPIO0 set to "1" in GPADAT:
      1. Connecting the shunt to Ground: Oscilloscope shows 2.25V and GPADAT indicates 1.
      2. Connecting the shunt to 3.3V: Oscilloscope shows 3.3V and GPADAT indicates 1.

    The input mode tests make sense. The correct value is indicated.

    The output mode tests also make sense to me if you take into account the resistance of the output buffer. Using a 100 ohm shunt and seeing .9V indicates that the low side of the input buffer is ~39 ohms. Looking at the high side of the driver: again 100 ohm shunt, and 2.25V would indicate the pull-high portion of the buffer is ~49 ohms. 

    Takeaways:

    • We cannot ignore the output buffers resistance.
    • Output buffer resistance varies from device to device.
    • If you do actually short your pin to ground/VDD it should validate your code, but it will damage the device.
      • FYI I did connect a device pin directly to 3.3V while the output buffer was driving 0V and I was able to see a '1' appear in GPADAT

    Regards,
    Cody