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.

TMS320F28P650DK: Reading GPIO in CPU2

Part Number: TMS320F28P650DK
Other Parts Discussed in Thread: C2000WARE

Tool/software:

Hi TI Experts,

I'm working with the TMS320F28P650D dual-core device and looking to read GPIOs In CPU2 .

i am unable to read  the GPIOdata register in CPU2 but i can able to toggle the GPIO from CPU2

i have configured it for CPU2, but still I cant read,

similarly i am facing the issue with SCI, i am able to transmit from CPU2 but unable to receive the data ,but the data is present in the registers.  

Is there any thing to give access to CPU2 for Reading  

Any guidance, documentation links, or example projects would be greatly appreciated.

Thanks in advance!

  • Hello,

    You'll need to transfer GPIO control from CPU1 to CPU2 by using the GPIO_setControllerCore() function.

    GPIO_setControllerCore(x, GPIO_CORE_CPU2); // Transfer control of GPIOx to CPU2

    For sharing the GPIO configuration between cores, the other option is using IPC (Inter-Processor Communication).

    The C2000Ware has an example called "C:\ti\c2000\<version>\driverlib\f2837xd\examples\dual\ipcipc_ex1_gpio_toggle" that demonstrates this.

    Best Regards,

    Masoud

  • I've already done with the same procedure as you mentioned,But the problem still exists

  • If you initialize the GPIO by CPU1 and then transfer the control to CPU2, you should generally have access to data register. You can share the base code and we can debug it there.

    Best Regards,

    Masoud

  • #define M2_HALL_A 30
    void M2_HALL_A_init();
    #define M2_HALL_B 61
    void M2_HALL_B_init();
    #define M2_HALL_C 64
    void M2_HALL_C_init();
    
    
    void M2_HALL_A_init(){
    	GPIO_setPadConfig(M2_HALL_A, GPIO_PIN_TYPE_STD);
    	GPIO_setQualificationMode(M2_HALL_A, GPIO_QUAL_SYNC);
    	GPIO_setDirectionMode(M2_HALL_A, GPIO_DIR_MODE_IN);
    	GPIO_setControllerCore(M2_HALL_A, GPIO_CORE_CPU2);
    }
    void M2_HALL_B_init(){
    	GPIO_setPadConfig(M2_HALL_B, GPIO_PIN_TYPE_STD);
    	GPIO_setQualificationMode(M2_HALL_B, GPIO_QUAL_SYNC);
    	GPIO_setDirectionMode(M2_HALL_B, GPIO_DIR_MODE_IN);
    	GPIO_setControllerCore(M2_HALL_B, GPIO_CORE_CPU2);
    }
    void M2_HALL_C_init(){
    	GPIO_setPadConfig(M2_HALL_C, GPIO_PIN_TYPE_STD);
    	GPIO_setQualificationMode(M2_HALL_C, GPIO_QUAL_SYNC);
    	GPIO_setDirectionMode(M2_HALL_C, GPIO_DIR_MODE_IN);
    	GPIO_setControllerCore(M2_HALL_C, GPIO_CORE_CPU2);
    }

    this is in CPU1

            #define M2_HALL_A 30
            #define M2_HALL_B 61
            #define M2_HALL_C 64
            #define GPIOA_DATA_REG_ADDR   0x00007F00U
            
            
            
            hall_A1=GPIO_readPin(M2_HALL_A);
            hall_B1=GPIO_readPin(M2_HALL_B);
            hall_C1=GPIO_readPin(M2_HALL_C);
    
    
    
            volatile uint32_t *gpadat = (volatile uint32_t *)GPIOA_DATA_REG_ADDR;
            hall_A1=*gpadat;
            hall_A1 = ((*gpadat) >> 30) & 0x1;

    In CPU2

  • Hello,

    I have already sampled a P65 Launch Pad to run and debug the issue. I'll keep you posted soon.

    Thanks for the patience!

    Masoud

  • Hello,

    I just did a quick test on F28P65 Launch Pad and I was able to read the data on CPU2. 3. The point is that you should not directly read memory-mapped GPADAT from CPU1’s address map (your 0x00007F00 address is CPU1’s GPADAT in local view). You can just use "hall_A1=GPIO_readPin(M2_HALL_A);" for example.

    Here is my CPU1 code:

    //#############################################################################
    //
    // FILE:   led_ex1_c28x_dual_blinky_cpu1.c
    //
    // TITLE:  LED Blinky Example
    //
    //! \addtogroup driver_dual_example_list
    //! <h1> LED Blinky Example</h1>
    //!
    //! This example demonstrates how to blink a LED using CPU1 and blink another
    //! LED using CPU2 (led_ex1_blinky_cpu2.c).
    //!
    //! \note In the default CPU2 linker cmd file, GS4, FLASH_BANK3 and FLASH_BANK4
    //! are used for allocating various CPU2 sections. The CPU1 application
    //! assigns the ownership of these memory regions to CPU2. Please note that CPU2
    //! .out file can be loaded only after CPU1 completes this configuration
    //!
    //! The erase setting (CPU1/CPU2 On-Chip Flash -> erase setting) needs to be
    //! configured as selected banks only (Choose the corresponding BANKS allocated
    //! for CPUs) or necessary sectors only before loading CPU1/CPU2.out file
    //! (This is applicable only for FLASH configuration)
    //!
    //! \b External \b Connections \n
    //!  - None.
    //!
    //! \b Watch \b Variables \n
    //!  - None.
    //!
    //
    //#############################################################################
    //
    //
    // 
    // C2000Ware v5.05.00.00
    //
    // Copyright (C) 2024 Texas Instruments Incorporated - http://www.ti.com
    //
    // Redistribution and use in source and binary forms, with or without 
    // modification, are permitted provided that the following conditions 
    // are met:
    // 
    //   Redistributions of source code must retain the above copyright 
    //   notice, this list of conditions and the following disclaimer.
    // 
    //   Redistributions in binary form must reproduce the above copyright
    //   notice, this list of conditions and the following disclaimer in the 
    //   documentation and/or other materials provided with the   
    //   distribution.
    // 
    //   Neither the name of Texas Instruments Incorporated nor the names of
    //   its contributors may be used to endorse or promote products derived
    //   from this software without specific prior written permission.
    // 
    // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
    // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
    // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
    // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
    // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
    // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
    // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
    // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    // $
    //#############################################################################
    
    //
    // Included Files
    //
    #include "driverlib.h"
    #include "device.h"
    
    #define M2_HALL_A 0
    void M2_HALL_A_init();
    #define M2_HALL_B 1
    void M2_HALL_B_init();
    #define M2_HALL_C 2
    void M2_HALL_C_init();
    
    
    void M2_HALL_A_init(){
        GPIO_setPadConfig(M2_HALL_A, GPIO_PIN_TYPE_STD);
        GPIO_setQualificationMode(M2_HALL_A, GPIO_QUAL_SYNC);
        GPIO_setDirectionMode(M2_HALL_A, GPIO_DIR_MODE_IN);
        GPIO_setControllerCore(M2_HALL_A, GPIO_CORE_CPU2);
    }
    void M2_HALL_B_init(){
        GPIO_setPadConfig(M2_HALL_B, GPIO_PIN_TYPE_STD);
        GPIO_setQualificationMode(M2_HALL_B, GPIO_QUAL_SYNC);
        GPIO_setDirectionMode(M2_HALL_B, GPIO_DIR_MODE_IN);
        GPIO_setControllerCore(M2_HALL_B, GPIO_CORE_CPU2);
    }
    void M2_HALL_C_init(){
        GPIO_setPadConfig(M2_HALL_C, GPIO_PIN_TYPE_STD);
        GPIO_setQualificationMode(M2_HALL_C, GPIO_QUAL_SYNC);
        GPIO_setDirectionMode(M2_HALL_C, GPIO_DIR_MODE_IN);
        GPIO_setControllerCore(M2_HALL_C, GPIO_CORE_CPU2);
    }
    
    //
    // Main
    //
    void main(void)
    {
        //
        // Initialize device clock and peripherals
        //
        Device_init();
    
        //
        // Assign RAMs and Flash banks to CPU2.
        // In the default CPU2 linker cmd files, GS4, FLASH_BANK3 and FLASH_BANK4
        // are used for allocating various CPU2 sections.
        // In case CPU2 needs additional RAM or Flash regions, CPU1 needs to assign
        // its ownership to CPU2 using the following functions :
        //      - MemCfg_setGSRAMControllerSel for GSRAM
        //      - SysCtl_allocateDxRAM for DRAM
        //      - SysCtl_allocateFlashBank for Flash
        //
        MemCfg_setGSRAMControllerSel(MEMCFG_SECT_GS4, MEMCFG_GSRAMCONTROLLER_CPU2);
        SysCtl_allocateFlashBank(SYSCTL_FLASH_BANK3, SYSCTL_CPUSEL_CPU2);
        SysCtl_allocateFlashBank(SYSCTL_FLASH_BANK4, SYSCTL_CPUSEL_CPU2);
     
        //
        // Boot CPU2 core
        //
    #ifdef _FLASH
        Device_bootCPU2(BOOTMODE_BOOT_TO_FLASH_BANK3_SECTOR0);
    #else
        Device_bootCPU2(BOOTMODE_BOOT_TO_M0RAM);
    #endif
    
    
        //
        // Initialize GPIO and configure the GPIO pin as a push-pull output
        //
        Device_initGPIO();
        GPIO_setPadConfig(DEVICE_GPIO_PIN_LED1, GPIO_PIN_TYPE_STD);
        GPIO_setDirectionMode(DEVICE_GPIO_PIN_LED1, GPIO_DIR_MODE_OUT);
        GPIO_setPadConfig(DEVICE_GPIO_PIN_LED2, GPIO_PIN_TYPE_STD);
        GPIO_setDirectionMode(DEVICE_GPIO_PIN_LED2, GPIO_DIR_MODE_OUT);
    
        //
        // Configure CPU2 to control the LED GPIO
        //
        GPIO_setControllerCore(DEVICE_GPIO_PIN_LED2, GPIO_CORE_CPU2);
    
        //
        // Initialize PIE and clear PIE registers. Disables CPU interrupts.
        //
        Interrupt_initModule();
    
        //
        // Initialize the PIE vector table with pointers to the shell Interrupt
        // Service Routines (ISR).
        //
        Interrupt_initVectorTable();
    
        //
        // Enable Global Interrupt (INTM) and realtime interrupt (DBGM)
        //
        EINT;
        ERTM;
    
        //
        // Loop Forever
        //
        for(;;)
        {
            //
            // Turn on LED
            //
            GPIO_writePin(DEVICE_GPIO_PIN_LED1, 0);
    
            //
            // Delay for a bit.
            //
            DEVICE_DELAY_US(1000000);
    
            //
            // Turn off LED
            //
            GPIO_writePin(DEVICE_GPIO_PIN_LED1, 1);
    
            //
            // Delay for a bit.
            //
            DEVICE_DELAY_US(1000000);
        }
    }
    
    //
    // End of File
    //
    

    Here is my CPU2 code:

    //#############################################################################
    //
    // FILE:   led_ex1_c28x_dual_blinky_cpu2.c
    //
    // TITLE:  LED Blinky Example
    //
    //! <h1> LED Blinky Example (CPU2) </h1>
    //!
    //! This example demonstrates how to blink a LED using CPU2.
    //!
    //! \b External \b Connections \n
    //!  - None.
    //!
    //! \b Watch \b Variables \n
    //!  - None.
    //
    //
    //#############################################################################
    //
    //
    // 
    // C2000Ware v5.05.00.00
    //
    // Copyright (C) 2024 Texas Instruments Incorporated - http://www.ti.com
    //
    // Redistribution and use in source and binary forms, with or without 
    // modification, are permitted provided that the following conditions 
    // are met:
    // 
    //   Redistributions of source code must retain the above copyright 
    //   notice, this list of conditions and the following disclaimer.
    // 
    //   Redistributions in binary form must reproduce the above copyright
    //   notice, this list of conditions and the following disclaimer in the 
    //   documentation and/or other materials provided with the   
    //   distribution.
    // 
    //   Neither the name of Texas Instruments Incorporated nor the names of
    //   its contributors may be used to endorse or promote products derived
    //   from this software without specific prior written permission.
    // 
    // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
    // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
    // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
    // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
    // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
    // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
    // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
    // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    // $
    //#############################################################################
    
    //
    // Included Files
    //
    #include "driverlib.h"
    #include "device.h"
    
    #define M2_HALL_A 0
    #define M2_HALL_B 1
    #define M2_HALL_C 2
    #define GPIOA_DATA_REG_ADDR   0x00007F00U
    
    uint32_t hall_A1;
    uint32_t hall_B1;
    uint32_t hall_C1;
    
    //
    // Main
    //
    void main(void)
    {
        //
        // Initialize device clock and peripherals
        //
        Device_init();
    
        //
        // Initialize GPIO and configure the GPIO pin as a push-pull output
        //
        // This is configured by CPU1
    
        //
        // Initialize PIE and clear PIE registers. Disables CPU interrupts.
        //
        Interrupt_initModule();
    
        //
        // Initialize the PIE vector table with pointers to the shell Interrupt
        // Service Routines (ISR).
        //
        Interrupt_initVectorTable();
    
        //
        // Enable Global Interrupt (INTM) and realtime interrupt (DBGM)
        //
        EINT;
        ERTM;
    
    
    
        //
        // Loop Forever
        //
        for(;;)
        {
            //
            // Turn on LED
            //
            GPIO_writePin(DEVICE_GPIO_PIN_LED2, 0);
    
            //
            // Delay for a bit.
            //
            DEVICE_DELAY_US(1000000);
    
            //
            // Turn off LED
            //
            GPIO_writePin(DEVICE_GPIO_PIN_LED2, 1);
    
            //
            // Delay for a bit.
            //
            DEVICE_DELAY_US(1000000);
    
            hall_A1=GPIO_readPin(M2_HALL_A);
            hall_B1=GPIO_readPin(M2_HALL_B);
            hall_C1=GPIO_readPin(M2_HALL_C);
    
    
    
    //        volatile uint32_t *gpadat = (volatile uint32_t *)GPIOA_DATA_REG_ADDR;
    //        hall_A1=*gpadat;
    //        hall_A1 = ((*gpadat) >> 30) & 0x1;
        }
    }
    
    //
    // End of File
    //
    

    Best Regards,

    Masoud

  • Thanks for the reply!
    I've tried the above, but still it couldn't worked out.

    do i need to configure MemCfg_setGSRAMControllerSel(MEMCFG_SECT_GS4, MEMCFG_GSRAMCONTROLLER_CPU2);

  • Can you confirm how you read the data? In my test, I added "hall_A1", "hall_B1" and "hall_C1" to the watch window and jump wired the GPIO 0, 1 and 2 (select any GPIO) to the GND and 3.3V and watched the reading on watch window.

    Best Regards,

    Masoud

  • Thanks for the reply! 
    I have given hall sensor input to them and seen them in watch window as you did

    Thanks & Regards,

    Ranjith.

  • Glad to hear that issue has resolved!

  • No the issue has not resolved

  • In the shared code, I have defined the test GPIOs as:

    #define M2_HALL_A 0
    #define M2_HALL_B 1
    #define M2_HALL_C 2

    If you connect these pins to 0V or 3.3V, you read their logic on watch window. Here is there location:

    This has been tested and confirmed.

    Best Regards,

    Masoud

  • Thanks for the reply! 

    I can see the status of the gpio changing in the gpodat register 
    but i am not able to copy from that register and store in another variable
    Thanks & Regards,

    Ranjith.

  • Hi Ranjith,

    Two key points for CPU2 reads:

    1. Don’t dereference CPU1’s local GPADAT address from CPU2. The address you used (0x00007F00) is CPU1’s local view. From CPU2, that won’t give you a valid read in your application. Use the driverlib API instead:

    volatile uint32_t hall_A1, hall_B1, hall_C1;
    
    hall_A1 = GPIO_readPin(M2_HALL_A);
    hall_B1 = GPIO_readPin(M2_HALL_B);
    hall_C1 = GPIO_readPin(M2_HALL_C);

    Also mark your destination variables volatile so the compiler doesn’t optimize away the load. I tested this on an F28P65 LaunchPad with GPIOs tied to 0 V / 3.3 V and watched the values change in the watch window.

    2. Make sure CPU2 actually owns the pins. Configure on CPU1, then hand off ownership:

    // CPU1 side
    GPIO_setPadConfig(M2_HALL_A, GPIO_PIN_TYPE_STD);
    GPIO_setQualificationMode(M2_HALL_A, GPIO_QUAL_SYNC);
    GPIO_setDirectionMode(M2_HALL_A, GPIO_DIR_MODE_IN);
    GPIO_setControllerCore(M2_HALL_A, GPIO_CORE_CPU2);
    // repeat for B/C

    With this, CPU2 can read via GPIO_readPin() as above. This is the same flow I shared earlier and verified on hardware.

    “I can see GPADAT changing but can’t copy it into a variable”

    That symptom usually comes from (a) reading the wrong address map (see #1) or (b) the compiler optimizing away your read. Use GPIO_readPin() and store into a volatile variable; avoid direct pointer reads to GPADAT.

    If you try the GPIO_readPin() + volatile approach and still can’t capture the value into a variable on CPU2, please share a minimal CPU1/CPU2 pair (just the GPIO init/hand-off and the CPU2 read loop). I can run that exact pair on a LaunchPad and point to the line that’s blocking the read.

    Best regards,
    Masoud

  • Thanks for the reply! 

    I have find a issue regarding reading 
    if i declare the variables in local i can see the data  in the variables
    but if i declare the variables in global there is only 0 in it.


    Thanks & Regards,

    Ranjith.

  • Hello,

    This comes down to where the global variables lives (RAM block ownership / linker placement) and volatility/optimization. Locals land on the CPU’s stack (an LSx block owned by that CPU), so they “work”. Your globals are probably linked into a GSx RAM that CPU2 doesn’t own, or into a region you never enabled for CPU2 writes—so the write reads back as 0. You can put CPU2 globals in RAM that CPU2 owns.
    Say in your CPU2 linker cmd file:

    .text : > RAMGS4
    .bss : > RAMGS4
    .data : > RAMGS4
    .const : > RAMGS4
    .sysmem: > RAMGS4

    Give RAMGS4 to CPU2 before releasing CPU2 (Run on CPU1 during system init):

    EALLOW;
    MemCfgRegs.GSxMSEL.bit.MSEL_GS4 = 1;
    EDIS;

    Initialize the GS4 RAM you use

    EALLOW;
    MemCfgRegs.GSxINIT.bit.INIT_GS4 = 1;
    while(MemCfgRegs.GSxINITDONE.bit.INITDONE_GS4 == 0) { }
    EDIS;

    Note that, if a variable is written in an ISR or by another execution context (CLA/other CPU/DMAs) and read in main, declare it volatile so the compiler doesn’t cache it.

    Best Regards,

    Masoud

  • Thanks for the reply! 

    by adding this  MemCfg_setGSRAMControllerSel(MEMCFG_SECT_GS4, MEMCFG_GSRAMCONTROLLER_CPU2);
    in my code resolved the issue

    Thanks & Regards,

    Ranjith.