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.

TM4C123GH6PM: TM4C123GH6PM GPIO data register offset wrong in datasheet

Part Number: TM4C123GH6PM
Other Parts Discussed in Thread: EK-TM4C123GXL

Hello!

I've noticed that in the file

D S -T M 4C 123G H6 P M - 1 5 8 4 2 . 2 7 4 1
S P M S 376E

which is a datasheet for Tiva TM4C123GH6PM there's a wrong offset for the data register:

The datasheet says offset 0x0000 but the Code Composer Studio IDE has this register offset at 0x03FC. Writing to offset 0x00 does nothing, while I can confirm with an ek-tm4c123gxl board the pins toggle only if you write to offset 0x03FC. Am I correct or am I missing something?

Took me 1 day to figure it out :-D Now I know a lot about the Tiva's GPIO.

Regards,

L. B.

  • Hi,
    Which GPIO port and which pin are you trying to write to? Let's suppose you want to write to Port A pin 0. Normally, you would call the API as follows.

    GPIOPinWrite(GPIO_PORTA_BASE, GPIO_PIN_0, GPIO_PIN_0);

    Now look at the below API coding.

    In gpio.c you will see thatGPIOPinWrite(GPIO_PORTA_BASE, GPIO_PIN_0, GPIO_PIN_0 is writing to address ui32Port + (GPIO_O_DATA + (ui8Pins << 2)). The ui32Port is equal to 0x40004000 and the GPIO_O_DATA = 0x00000000 and the (ui8Piins<<2) is equal to 0x00000001<<2 or 0x0000004. The final address is equal to 0x40004004. Basically each bit in the data register is memory mapped to a word address to facilitate bit writing without performing read-modify-write. You can find some details in the datasheet under 10.2.1.2 Data Register Operation.



    //*****************************************************************************
    //
    //! Writes a value to the specified pin(s).
    //!
    //! \param ui32Port is the base address of the GPIO port.
    //! \param ui8Pins is the bit-packed representation of the pin(s).
    //! \param ui8Val is the value to write to the pin(s).
    //!
    //! Writes the corresponding bit values to the output pin(s) specified by
    //! \e ui8Pins. Writing to a pin configured as an input pin has no effect.
    //!
    //! The pin(s) are specified using a bit-packed byte, where each bit that is
    //! set identifies the pin to be accessed, and where bit 0 of the byte
    //! represents GPIO port pin 0, bit 1 represents GPIO port pin 1, and so on.
    //!
    //! \return None.
    //
    //*****************************************************************************
    void
    GPIOPinWrite(uint32_t ui32Port, uint8_t ui8Pins, uint8_t ui8Val)
    {
    //
    // Check the arguments.
    //
    ASSERT(_GPIOBaseValid(ui32Port));

    //
    // Write the pins.
    //
    HWREG(ui32Port + (GPIO_O_DATA + (ui8Pins << 2))) = ui8Val;
    }

    In hw_memmap.h
    //*****************************************************************************
    //
    // The following are defines for the base address of the memories and
    // peripherals.
    //
    //*****************************************************************************
    #define FLASH_BASE 0x00000000 // FLASH memory
    #define SRAM_BASE 0x20000000 // SRAM memory
    #define WATCHDOG0_BASE 0x40000000 // Watchdog0
    #define WATCHDOG1_BASE 0x40001000 // Watchdog1
    #define GPIO_PORTA_BASE 0x40004000 // GPIO Port A
    #define GPIO_PORTB_BASE 0x40005000 // GPIO Port B
    #define GPIO_PORTC_BASE 0x40006000 // GPIO Port C
    #define GPIO_PORTD_BASE 0x40007000 // GPIO Port D

    In hw_gpio.h
    //*****************************************************************************
    //
    // The following are defines for the GPIO register offsets.
    //
    //*****************************************************************************
    #define GPIO_O_DATA 0x00000000 // GPIO Data
    #define GPIO_O_DIR 0x00000400 // GPIO Direction


    In gpio.h
    //*****************************************************************************
    //
    // The following values define the bit field for the ui8Pins argument to
    // several of the APIs.
    //
    //*****************************************************************************
    #define GPIO_PIN_0 0x00000001 // GPIO pin 0
    #define GPIO_PIN_1 0x00000002 // GPIO pin 1
    #define GPIO_PIN_2 0x00000004 // GPIO pin 2
    #define GPIO_PIN_3 0x00000008 // GPIO pin 3
    #define GPIO_PIN_4 0x00000010 // GPIO pin 4
    #define GPIO_PIN_5 0x00000020 // GPIO pin 5
    #define GPIO_PIN_6 0x00000040 // GPIO pin 6
    #define GPIO_PIN_7 0x00000080 // GPIO pin 7
  • Hello,

    I understand your answer - you're talking about bit-banding.

    The project I'm working on is an open-source project and I have to write my own GPIOWrite function due to the copyright notice in the TivaWare library.

    Here is my code:

    // Define the registers we need to do a pin toggle ////////////////////////////
    #define ADDR(x)     (*((unsigned long*)(x)))
    #define SYSCTL_GPIO_ENABLE     *(volatile unsigned long *)0x400FE608
    #define SYSCTL_GPIO_READY      *(volatile unsigned long *)0x400FEA08

    #define SYSCTL_GPIOA_MASK      0x0001
    #define GPIO_PORTA_DIR         *(volatile unsigned long *)0x40004400 //GPIO Port A direction register base address
    #define GPIO_PORTA_DATA        *(volatile unsigned long *)0x400043FC //GPIO Port A data register base address
    #define GPIO_PORTA_DIG_PIN     *(volatile unsigned long *)0x4000451C //GPIO Port A digital pin enable register base address
    #define GPIO_PINMASK_7         0x80                                  //GPIO pin PA7 mask

    // Provide macros to do the pin toggling ////////////////////////////////////

    // Initialize the pin + clocks
    #define PIN_INIT(number)                                        \
        do {                                                        \
            switch(number){                                         \
            case 0:                                                 \            
                break;                                              \
             case 7:                                                \
                /* Turn on GPIO A Clock */                          \
                SYSCTL_GPIO_ENABLE |= SYSCTL_GPIOA_MASK;            \
                /* Wait for GPIO A ready */                         \
                while(!(SYSCTL_GPIO_READY & SYSCTL_GPIOA_MASK)){ }  \
                /* Set as output GPIO PA7 */                        \
                GPIO_PORTA_DIR |= GPIO_PINMASK_7;                   \
                GPIO_PORTA_DIG_PIN |= GPIO_PINMASK_7;               \
                /* Pull low GPIO PA7 */                             \
                GPIO_PORTA_DATA &= ~GPIO_PINMASK_7;                 \
                break;                                              \
            }                                                       \
        } while(0)

    // Set the pin to high
    #define PIN_SET(number)                         \
        do {                                        \
            switch(number){                         \
            case 0:                                 \           
                break;                              \
            case 7:                                 \
                /* Set PA7 */                       \
                GPIO_PORTA_DATA |= GPIO_PINMASK_7;  \
                break;                              \
            }                                       \
        } while(0)                                  \


    If I use

    #define GPIO_PORTA_DATA        *(volatile unsigned long *)0x40004000 //GPIO Port A data register base address

    it won't work.

    Regards,

    L. B.

  • You were on the right track to understand the bit banding. If you read the bit-banding concept again then you will understand how it works.

    Writing to 0x40004000 means you are not setting any pins high. No pins are writable.

    To set only pin 0 high you write to 0x40004004.
    To set only pin 1 high you write to 0x40004008.
    To set both pin 0 and pin 1 high you write to 0x4000400C.
    To set only pin 7 high yuo write to 0x40004200.
    To set all pins (pin0...pin7) high you write to 0x400043FC.

    What this means is that each one of the 256 combinations of pins is memory mapped to a unique word address that facilitate bit writing. When you write to 0x400043FC, this is the address where all pins are writable to high even though the value you wrote into it only set pin7.

    Try writing to 0x40004200 and you will find out that you can write to pin7 with a value of 0x80. If you were to write 0xFF to 0x0x40004200 only pin7 will set but no other pins. At this address only pin7 is writable.
  • In the datasheet indeed there's one important sentence at the beginning of the description, exactly the thing you're saying here, and this is:

    In order to write toGPIODATA, the corresponding bits in the mask, resulting from the address busbits [9:2], must be set. Otherwise, the bit values remain unchanged by the write.

    So I was mislead by thinking of the GPIODATA register as the OUT register in the MSP430.

    Thank you for your time!

    Regards,
    L. B.