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.

CCS/F28M35H22C: shared memory between two cores

Part Number: F28M35H22C
Other Parts Discussed in Thread: CONTROLSUITE

Tool/software: Code Composer Studio

Hi, 

Could you please help confirm the how the shared memory data exchange being controlled between two cores ?

I'm trying to writing and reading data on both M3 and C28 side, then exchange data through shared memory S0~S7. But I'm wondering do we need to pay special attention when to start writing on one side(eg. C28), then when to start reading on the other side(M3)? 

So far my understanding is that we can writing the data on C28 anytime, on the M3 side we can check if there's any available data that's been written to C28, then reading from M3 side. 

On C28 side, I plan to have buffer that constantly write or overwrite the data to the shared memory; M3 side also constantly monitoring data on M3 side.  

Will that work? Or what would be the typical design if we want use shared memory for the data exchange between two cores?

Thanks,

YZ

  • Hi,

    So far my understanding is that we can writing the data on C28 anytime, on the M3 side we can check if there's any available data that's been written to C28, then reading from M3 side. 

    Yes, you can write and read data simultaneously from both the cores. Accesses are arbitrated  between two masters and given memory block.

    On C28 side, I plan to have buffer that constantly write or overwrite the data to the shared memory; M3 side also constantly monitoring data on M3 side

    No issue with that. If M3 is reading to same address which is getting updated by C28x and based on arbitration, M3 may get old data or new updated data. You need to take care of that in your code.

    Regards,

    Vivek Singh

  • Hi Vivek,

    Thanks a lot for quick response. 

    About "M3 may get old data or new updated data. You need to take care of that in your code." , what would be typical design to take care of this part? Any suggestion?

    For now I think maybe write a buffer on M3 side to constantly overwrite old data with latest updated data; then maybe have some sort of data flow control to decide when to start read data or temporarily buffer latest data. 

    Thanks,

    YZ

  • Hi,

    Best thing would be to use the handshake between both the cores via IPC flag(interrupts). After updating the data C28x can set the IPC flag. M3 can read the data once it sees the IPC flag set and after completion of read, acknowledge the IPC flag.

    Regards,
    Vivek Singh
  • Hi Vivek, 

    Thanks a lot for the response. Could you please help me understand better with some example? Or a simple code skeleton to illustrate this IPC(interrupt) and acknowledge of IPC flag?

    If I look at controlsuite, there're 3 example about IPC in following ? what would be different between them? What would be best practice we should follow?

    controlSUITE\device_support\f28m35x\v220\F28M35x_examples_Dual:

    ctom_ipcdrivers

    ctom_ipcdrivers_lite

    ctom_ipcdrivers_wrprotect

    Thanks a lot in advance~!

    YZ

  • We provide two different kinds of IPC drivers--a basic "lite" version and a more advanced version that can handle some queuing of commands and multiple channels. The ctom_ipcdrivers_lite and ctom_ipcdrivers are demonstrating the features those two options. The wrprotect example just shows the functionality of some of the driver functions that write to MWRALLOW protected memory.

    The ctom_ipcdrivers_lite example is probably a good starting point. You can step through the code and get an idea of what the functions do. If the drivers are more than you need, you can still use them to get an idea of how to use the IPC flags to inform the other core that there's new data ready.

    Whitney
  • Hi Whitney, 

    Thanks a lot for the reply. Could you please help me understand a little bit more about this example F28M35x_examples_Dual\ctom_ipcdrivers_lite?

    I'm not quite sure about how this IPC mechanism has been implemented. Eg. The shared memory S0 has been allocated to M3 that has the ownership, and we allocate data writing on C28 to address of C28_MTOC_PASSMSG? Also could you please help explain a little on the following code ?

    on ctom_ipcdrivers_lite_m3.c, there're some lines of code like the following

     // Initialize M3toC28 message RAM and Sx SARAM and wait until initialized
        RAMMReqSharedMemAccess(S0_ACCESS, SX_M3MASTER); 
    
        HWREG(RAM_CONFIG_BASE + RAM_O_MSXRTESTINIT1) |= 0x1;
        while((HWREG(RAM_CONFIG_BASE + RAM_O_MSXRINITDONE1)&0x1) != 0x1)
        {
        }
        HWREG(RAM_CONFIG_BASE + RAM_O_MTOCCRTESTINIT1) |= 0x1;
        while((HWREG(RAM_CONFIG_BASE + RAM_O_MTOCRINITDONE)&0x1) != 0x1)
        {
        }

        On ctom_ipcdrivers_lite_c28.c, there's FLAG17 and FLAG1 use differently, also there's code lines like following 

        #define C28_MTOC_PASSMSG  0x0003FFF4            // Used by M3 to pass address of local variables to perform
    
        Uint32 *pulMsgRam = (void *)C28_MTOC_PASSMSG;
        // Spin here until M3 is ready
        while (!IPCMtoCFlagBusy(IPC_FLAG17)) ;
        IPCMtoCFlagAcknowledge(IPC_FLAG17);
       // 16 and 32-bit Data Writes
        // Write 16-bit word to M3 16-bit write word variable.
        IPCLiteCtoMDataWrite(IPC_FLAG1, pulMsgRam[0],(Uint32)usWWord16,
                             IPC_LENGTH_16_BITS,
                             IPC_FLAG32);

    2. It seems that IPC mechanism also used for booting up process from M3 to C28, like boot from FLASH or RAM etc. Could you please help me understand how we did that ? What does it mean in the header file description? 

    How could we enable boot from m3 to C28? One issue I have is that if I power cycle the processor, the M3 will still runs normally, but C28 won't boot up. It seems that I'm missing the IPC boot function from m3 to c28 core. Could you please help understand that ? 

    3. I saw one of the implementation from other TI example is that we also configure the m3 memory L0, L1, M0, M1 in the following. But I wasn't quite understand, could you please help me for the m3 core, what would be the best practice to allocate memory map, and how we design boot process from m3 to c28?

    /*Function Name:  master_ram_init_control_m1_msgram_memories
    * Description:-  Function called to Zero-Initialize control subsystem M1 and Message RAM memories 
    *  using MTOCIPC commands to C-Boot ROM
    * 
    */
    void master_ram_init_control_m0m1_msgram_memories()
    {
          unsigned int ii = 0;
    //RAM INIT for M1, and CTOM MsgRAM - M0 RAM INIT is done by C-BootROM
          //#define CCORE_M0M1_CTOM_MSG_RAM_INIT_REG_ADDR 0x4920
          //#define CCORE_M0_RAM_INIT_BIT     0x01
          //#define CCORE_M1_RAM_INIT_BIT 0x04
          //#define CCORE_CTOM_MSG_RAM_INIT_BIT 0x10
          IPCLiteMtoCSetBits_Protected(IPC_FLAG1, 0x4920, 0x14, IPC_LENGTH_32_BITS, IPC_FLAG32);
          
          //wait until C-BootROM acks
          
          while(HWREG(MTOCIPC_BASE + IPC_O_MTOCIPCFLG) & IPC_FLAG1);
          
          //CHECK IF pass or fail
          if(HWREG(MTOCIPC_BASE + IPC_O_MTOCIPCFLG) & IPC_FLAG32)
          {//still set - so command failed.
                //error - blink SLOOOOOOOOWWW
                    while(1)
                    {
                        //if you are here, this is bad
                    }
                
          }
          //WAIT for RAM_INIT done of above.
          //GIVE some cycles delay until CCORE performs RAM INIT
          for(ii =0 ; ii < 2048; ii++);
          
          //READ RAM_INIT_DONE register
          //#define CCORE_M0M1_CTOM_MSG_RAM_INIT_DONE_REG_ADDR  0x4930
          //#define CCORE_M0_RAM_INIT_DONE_BIT      0x01
          //#define CCORE_M1_RAM_INIT_DONE_BIT 0x04
          //#define CCORE_CTOM_MSG_RAM_INIT_DONE_BIT 0x10
          
          do
          {
                IPCLiteMtoCDataRead(IPC_FLAG1, 0x4930, IPC_LENGTH_32_BITS, IPC_FLAG32);
                
                //wait until C-BootROM acks
                while(HWREG(MTOCIPC_BASE + IPC_O_MTOCIPCFLG) & IPC_FLAG1);
                
                //CHECK IF pass or fail
                if(HWREG(MTOCIPC_BASE + IPC_O_MTOCIPCFLG) & IPC_FLAG32)
                {//still set - so command failed.
                          while(1)
                          {
                                  //if you are here, this is bad
                          }
                      
                }
                else
                {
                      if(HWREG(MTOCIPC_BASE + IPC_O_MTOCIPCDATAR) & 0x14)
                      {
                            //RAM_INIT completed - do nothing :-)
                            break;
                      }
                      else
                      {
                            //RAM_INIT not done yet, so wait for more time and read ram init done register.
                            //GIVE some cycles delay until CCORE performs RAM INIT
                            for(ii =0 ; ii < 2048; ii++);
                            continue;
                      }
                }
          }while(1);
    }
    void master_ram_init_control_L0_L4_memories()
    {
          unsigned int ii = 0;
     //RAM INIT for L0,L1,L2,L3 
          //#define CCORE_L0L4_RAM_INIT_REG_ADDR    0x4922
          //#define CCORE_L0_RAM_INIT_BIT     0x01
          //#define CCORE_L1_RAM_INIT_BIT 0x04
          //#define CCORE_L2_RAM_INIT_BIT 0x10
          //#define CCORE_L3_RAM_INIT_BIT 0x40
          IPCLiteMtoCSetBits_Protected(IPC_FLAG1, 0x4922, 0x55, IPC_LENGTH_32_BITS, IPC_FLAG32);
          
          //wait until C-BootROM acks
          while(HWREG(MTOCIPC_BASE + IPC_O_MTOCIPCFLG) & IPC_FLAG1);
          
          //CHECK IF pass or fail
          if(HWREG(MTOCIPC_BASE + IPC_O_MTOCIPCFLG) & IPC_FLAG32)
          {//still set - so command failed.
                    while(1)
                    {
                        //if you are here, this is bad;
                    }
                
          }
          //WAIT for RAM_INIT done of above.
          //GIVE some cycles delay until CCORE performs RAM INIT
          for(ii =0 ; ii < 2048; ii++);
          
          //READ RAM_INIT_DONE register
          //#define CCORE_L0_L4_RAM_INIT_DONE_REG_ADDR    0x4932
          //#define CCORE_L0_RAM_INIT_DONE_BIT      0x01
          //#define CCORE_L1_RAM_INIT_DONE_BIT 0x04
          //#define CCORE_L2_RAM_INIT_DONE_BIT 0x10
          //#define CCORE_L3_RAM_INIT_DONE_BIT 0x40
          
          do
          {
                IPCLiteMtoCDataRead(IPC_FLAG1, 0x4932, IPC_LENGTH_32_BITS, IPC_FLAG32);
                
                //wait until C-BootROM acks
                while(HWREG(MTOCIPC_BASE + IPC_O_MTOCIPCFLG) & IPC_FLAG1);
                
                //CHECK IF pass or fail
                if(HWREG(MTOCIPC_BASE + IPC_O_MTOCIPCFLG) & IPC_FLAG32)
                {//still set - so command failed.
                          while(1)
                          {
                              //if you are here, this is bad
                          }
                      
                }
                else
                {
                      if(HWREG(MTOCIPC_BASE + IPC_O_MTOCIPCDATAR) & 0x55)
                      {
                            //RAM_INIT completed - do nothing :-)
                            break;
                      }
                      else
                      {
                            //RAM_INIT not done yet, so wait for more time and read ram init done register.
                            //GIVE some cycles delay until CCORE performs RAM INIT
                            for(ii =0 ; ii < 2048; ii++);
                            continue;
                      }
                }
          }while(1);
    
    }

  • The MTOC message RAM is being used to tell the C28 the addresses of the variables, registers, and functions it will be interacting with through the IPC functions. Since it's MTOC RAM you don't need to change the permissions like the example does for S0. Also, it doesn't look like the example is actually writing anything to S0--it's just using it to demonstrate the access request process.

    This example is using IPC_FLAG17 as a way to make sure the C28 doesn't begin the test until the M3 has completed all of its initialization. IPC_FLAG1 is being used as an indication that a command is being sent--note that the functions on the M3 side are waiting to see it get set before proceeding. It's also being used to generate an interrupt. IPC_FLAG32 is being used for return status.

    For details on the operation of the boot ROM, please read that section of the technical reference manual. As for the issue you're seeing, are you using the Flash-standalone build configuration of the project? You need to make sure that call to IPCMtoCBootControlSystem() is getting compiled into your project.

    Whitney