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.

TMS320F28384D: Can't use more than one IPC flag between CPU1 and CPU2

Part Number: TMS320F28384D

Hi!

I've been working with the IPC protocol for some time and I have been using the IPC Flag 0 for interrupting the CPU2 from the CPU1. However, for initial configurations of some parameters in the CPU1 process, I need to use another IPC flag with interrupting capabilities for CPU2, for which I'm trying using IpcCPU1toCPU2Regs.CPU1TOCPU2IPCFLG.IPC1.

My problem is when debugging, during the first initialization steps, I see that the function "IPC_setFlagLtoR" doesn't set the bit to 1, hence the "IPC_waitForAck" doesn't do anything. I have realized a couple of things when trying out different things:

  • Using Flag 1 in CPU1 and any other flag but flag 1 in CPU2, Flag1 goes to 1 and "IPC_waitForAck" waits = OK
  • Using the same flag in both CPUs, "IPC_setFlagLtoR" doesn't set flag X to 1 = Not OK

Note that I have also used the Flag 31 to synchronize both CPUs to let them both initialize their hardware and other things.

This is my code for the initialization part of the main routine for CPU1:

void main(void)
{
    // Initialize device clock and peripherals.
    Device_init();

//_______________________________________________________________________________________________________________________________________________
//                                                       BOOT DEL CORE 2 EN FLASH O RAM
//_______________________________________________________________________________________________________________________________________________
#ifdef triggersEnable
    #ifdef _FLASH
        Device_bootCPU2(BOOTMODE_BOOT_TO_FLASH_SECTOR0);
    #else
        Device_bootCPU2(BOOTMODE_BOOT_TO_M0RAM);
    #endif
#endif

    //
    // Disable all the interrupts.
    DINT;
    //
    // Setup GPIO by disabling pin locks and enabling pullups.
    Device_initGPIO();
    
#ifdef triggersEnable
    initSPI4SD();
#endif
    // 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();

//-----------------------------------------------------IMPORTANTE---------------------------------------------------------------
//--------------------------- (BOARD_INIT EJECUTA TODA LA CONFIGURACION DEFINIDA EN EL SYSCONFIG)-------------------------------
//-----------------------------------------------(FICHEROS board.c y board.h)---------------------------------------------------
    Board_init();

//_______________________________________________________________________________________________________________________________________________
//                                                INICIO IPC
//_______________________________________________________________________________________________________________________________________________
#ifdef triggersEnable
    IPC_clearFlagLtoR(IPC_CPU1_L_CPU2_R, IPC_FLAG_ALL); // Clear any IPC flags if set already
    IPC_sync(IPC_CPU1_L_CPU2_R, IPC_FLAG31);    // Synchronize both the cores. Borrar?
#endif

//_______________________________________________________________________________________________________________________________________________
//                                                DAR CONTROL DE RAMGS A CADA CORE
//_______________________________________________________________________________________________________________________________________________
#ifdef triggersEnable
    MemCfg_setGSRAMControllerSel((MEMCFG_SECT_GS10 | MEMCFG_SECT_GS11), MEMCFG_GSRAMCONTROLLER_CPU1); // Give memory access to GS10 and GS11 RAM to CPU1 and GS12, GS13 and GS14 to CPU2
    MemCfg_setGSRAMControllerSel((MEMCFG_SECT_GS12 | MEMCFG_SECT_GS13 | MEMCFG_SECT_GS14), MEMCFG_GSRAMCONTROLLER_CPU2);
#endif

//_______________________________________________________________________________________________________________________________________________
//                                                       CONFIGURACION DEL DAC
//_______________________________________________________________________________________________________________________________________________
    myDACA_init(); //DACA
    myDACB_init(); //DACB
    myDACC_init(); //DACC

//__________________________________________________________________________________________________________________________________________________
//                                                       CONFIGURACION EQEP ENCODER MODULE
//__________________________________________________________________________________________________________________________________________________
    EQEP_config(EQEP_BASE_SELECT);

//____________________________________________________________________________________________________________________________________________________
//                                                      CONFIGURACION DEL EMIF
//____________________________________________________________________________________________________________________________________________________



    //Estructura para par�metros de tiempos de R/W del EMIF
    EMIF_AsyncTimingParams tparam;
    // Configure to run EMIF1 on full Rate. (EMIF1CLK = CPU1SYSCLK)
    SysCtl_setEMIF1ClockDivider(SYSCTL_EMIF1CLK_DIV_1);
    // Grab EMIF1 For CPU1.
    EMIF_selectController(EMIF1CONFIG_BASE, EMIF_CONTROLLER_CPU1_G);
    // Disable Access Protection. (CPU_FETCH/CPU_WR/DMA_WR)
    EMIF_setAccessProtection(EMIF1CONFIG_BASE, 0x0);
    // Commit the configuration related to protection. Till this bit remains
    // set, contents of EMIF1ACCPROT0 register can't be changed.
    EMIF_commitAccessConfig(EMIF1CONFIG_BASE);
    // Lock the configuration so that EMIF1COMMIT register can't be changed
    // any more.
    EMIF_lockAccessConfig(EMIF1CONFIG_BASE);
    // Configure GPIO pins for EMIF1.
    setupEMIF1PinmuxAsync16Bit();        //PINES USADOS POR EL EMIF -- IMPORTANTE FUNCION!!

    // Configures Normal Asynchronous Mode of Operation.
    EMIF_setAsyncMode(EMIF1_BASE, EMIF_ASYNC_CS4_OFFSET,  //CAMBIO V2 PARA USAR CS4 EN VEZ DE CS3
                      EMIF_ASYNC_NORMAL_MODE);

    // Disables Extended Wait Mode.
    EMIF_disableAsyncExtendedWait(EMIF1_BASE, EMIF_ASYNC_CS4_OFFSET);//CAMBIO V2 PARA USAR CS4 EN VEZ DE CS3

    // Configure EMIF1 Data Bus Width.
    EMIF_setAsyncDataBusWidth(EMIF1_BASE, EMIF_ASYNC_CS4_OFFSET, //CAMBIO V2 PARA USAR CS4 EN VEZ DE CS3
                              EMIF_ASYNC_DATA_WIDTH_8);   //O PONER A 8 AUNQUE LUEGO PONER A 16 PARA EVITAR EL TURN-AROUND TIME. CUANDO SE USE EL ADC REAL, CAMBIAR A 8 EL DATAWIDTH

    //
    // Configure the access timing for CS4 space.
    //
    tparam.rSetup = 3;//5; //3
    tparam.rStrobe = 11;//15; //11
    tparam.rHold = 7;//6; //5
    tparam.turnArnd = 5;//5; //3
    tparam.wSetup = 3;//5; //3
    tparam.wStrobe = 7;//15; //7
    tparam.wHold = 6;//6;  //4
    EMIF_setAsyncTimingParams(EMIF1_BASE, EMIF_ASYNC_CS4_OFFSET, &tparam); //CAMBIO V2 PARA USAR CS4 EN VEZ DE CS3
    //                                                                          FUNCION DE CONFIGURACION DE GPIOS PARA EL ADC-EMIF
    setupGPIOcomEMIF_ADC();

//________________________________________________________________________________________________________________________________________________
//                                                   AJUSTE TRAMAS Y CONFIGURACION ADC
//_________________________________________________________________________________________________________________________________________________

    ajustetodastramasADC();

    configurarADC(tramaConfADC_SEQEN_BURST, 10, tramaFiltroPasoBajo376, 8);

    lect_ConfADC=0x0004; // LEE CONF ADC
    lect_RangoADC_0_3_A=0x0008; //LEE EL RANGO DEL ADCA CANAL 0-3
    lect_RangoADC_0_3_B=0x000C; //LEE EL RANGO DEL ADCB CANAL 0-3
    lect_RangoADC_4_7_A=0x000A; //LEE EL RANGO DEL ADCA CANAL 4-7
    lect_RangoADC_4_7_B=0x000E; //LEE EL RANGO DEL ADCB CANAL 4-7
    lect_FPBADC=0x001A; //LEE FILTRO PB
    //lect_CHADC=0x0006;

    res_lectConfADC=leerRegADC(lect_ConfADC,tamanobusdatos);
    res_lectRango_03A_ADC=leerRegADC(lect_RangoADC_0_3_A,tamanobusdatos);
    res_lectRango_03B_ADC=leerRegADC(lect_RangoADC_0_3_B,tamanobusdatos);
    res_lectRango_47A_ADC=leerRegADC(lect_RangoADC_4_7_A,tamanobusdatos);
    res_lectRango_47B_ADC=leerRegADC(lect_RangoADC_4_7_B,tamanobusdatos);
    res_lectFPBADC=leerRegADC(lect_FPBADC,tamanobusdatos);
    //res_lectCHADC=leerRegADC(lect_CHADC,tamanobusdatos);

    res_lectConfADC=ajustetramaADC(res_lectConfADC);
    res_lectRango_03A_ADC=ajustetramaADC(res_lectRango_03A_ADC);
    res_lectRango_03B_ADC=ajustetramaADC(res_lectRango_03B_ADC);
    res_lectRango_47A_ADC=ajustetramaADC(res_lectRango_47A_ADC);
    res_lectRango_47B_ADC=ajustetramaADC(res_lectRango_47B_ADC);
    res_lectFPBADC=ajustetramaADC(res_lectFPBADC);
   // res_lectCHADC=ajustetramaADC(res_lectCHADC);

    if(SEQEN==1){
        lectSTACK0=0x0040;
        lectSTACK1=0x0042;
        lectSTACK2=0x0044;
        lectSTACK3=0x0046;
        lectSTACK4=0x0048;
        lectSTACK5=0x004A;
        lectSTACK6=0x004C;
        lectSTACK7=0x004E;

        reslectSTACK0=leerRegADC(lectSTACK0,tamanobusdatos);
        reslectSTACK1=leerRegADC(lectSTACK1,tamanobusdatos);
        reslectSTACK2=leerRegADC(lectSTACK2,tamanobusdatos);
        reslectSTACK3=leerRegADC(lectSTACK3,tamanobusdatos);
        reslectSTACK4=leerRegADC(lectSTACK4,tamanobusdatos);
        reslectSTACK5=leerRegADC(lectSTACK5,tamanobusdatos);
        reslectSTACK6=leerRegADC(lectSTACK6,tamanobusdatos);
        reslectSTACK7=leerRegADC(lectSTACK7,tamanobusdatos);

        reslectSTACK0=ajustetramaADC(reslectSTACK0);
        reslectSTACK1=ajustetramaADC(reslectSTACK1);
        reslectSTACK2=ajustetramaADC(reslectSTACK2);
        reslectSTACK3=ajustetramaADC(reslectSTACK3);
        reslectSTACK4=ajustetramaADC(reslectSTACK4);
        reslectSTACK5=ajustetramaADC(reslectSTACK5);
        reslectSTACK6=ajustetramaADC(reslectSTACK6);
        reslectSTACK7=ajustetramaADC(reslectSTACK7);
    }


//____________________________________________________________________________________________________________________________________________
//                                                       AJUSTE TIMERS INTERRUPCION
//_____________________________________________________________________________________________________________________________________________

    if(SEQEN==1){
        if(BURSTMODE==1){
            Interrupt_register(INT_TIMER0, &cpuTimer0ISR_SEQEN_BURST);
        }
    }

    initCPUTimer0();

    if(SEQEN==0){
            configCPUTimer(CPUTIMER0_BASE, DEVICE_SYSCLK_FREQ, 1000);
    }
    else if(SEQEN==1){
       if(BURSTMODE==1){
           configCPUTimer(CPUTIMER0_BASE, DEVICE_SYSCLK_FREQ, Ts_us);           //TIEMPO EN MICROSEGUNDOS 200us
       }
       else
           configCPUTimer(CPUTIMER0_BASE, DEVICE_SYSCLK_FREQ, Ts_us);
    }

    CPUTimer_enableInterrupt(CPUTIMER0_BASE);
    Interrupt_enable(INT_TIMER0);


//_____________________________________________________________________________________________________________________________________________
//                                                       CONFIGURACION MODULO PWM
//______________________________________________________________________________________________________________________________________________
//      SE DESACTIVA LA SENAL DE RELOJ DEL TIME-BASE DEL MODULO PWM
        SysCtl_disablePeripheral(SYSCTL_PERIPH_CLK_TBCLKSYNC);

        configPWM_module_outputsignals(faseR_recv_BASE, TBPRD_recv);
        configPWM_module_outputsignals(faseS_recv_BASE, TBPRD_recv);
        configPWM_module_outputsignals(faseT_recv_BASE, TBPRD_recv);

        configPWM_module_outputsignals(faseR_rotor_BASE, TBPRD_rotor);
        configPWM_module_outputsignals(faseS_rotor_BASE, TBPRD_rotor);
        configPWM_module_outputsignals(faseT_rotor_BASE, TBPRD_rotor);

//      Se desactivan los relojes de los modulos PWM utilizados
        SysCtl_disablePeripheral(SYSCTL_PERIPH_CLK_EPWM1);
        SysCtl_disablePeripheral(SYSCTL_PERIPH_CLK_EPWM2);
        SysCtl_disablePeripheral(SYSCTL_PERIPH_CLK_EPWM3);
        SysCtl_disablePeripheral(SYSCTL_PERIPH_CLK_EPWM4);
        SysCtl_disablePeripheral(SYSCTL_PERIPH_CLK_EPWM5);
        SysCtl_disablePeripheral(SYSCTL_PERIPH_CLK_EPWM6);

// Enable Global Interrupt (INTM) and realtime interrupt (DBGM)

        //EDIS;
        EINT;
        ERTM;

        SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_TBCLKSYNC);
        CPUTimer_startTimer(CPUTIMER0_BASE);

        GPIO_writePin(enableControlOutputPin,0);

//_______________________________________________________________________________________________________________________________________________
//                                                      INICIALIZO VARIABLE TRIGGERS
//________________________________________________________________________________________________________________________________________________
#ifdef triggersEnable
      FlTrigg = 0;
#endif

//
// Activo Flag del IPC para pedir los datos del motor a la CPU2 guardados en SD. La CPU2 los guarda en
//
      IPC_setFlagLtoR(IPC_CPU1_L_CPU2_R, IPC_FLAG1);
      IPC_waitForAck(IPC_CPU1_L_CPU2_R, IPC_FLAG1);
      
[...]

Initialization code of CPU2:

void main(void)
{
    uint16_t i;
    FRESULT errorSD;
    FILINFO structInfo;
    uint8_t fileName[tamFileName], fileNameBorrar[tamFileName], *pBorrar;


    //
    // Initialize device clock and peripherals
    //
    Device_init();

    //
    // Disable pin locks and enable internal pullups.
    //
    Device_initGPIO();

    //
    // 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 CPU Timer 0 interrupt
    //
    Interrupt_enable(INT_TIMER0);

    //
    // Clear any IPC flags if set already
    //
    IPC_clearFlagLtoR(IPC_CPU2_L_CPU1_R, IPC_FLAG_ALL);

    //
    // Enable IPC interrupts
    //
    IPC_registerInterrupt(IPC_CPU2_L_CPU1_R, IPC_INT0, IPC_ISR0);           //Flag0 del IPC para recibir una medida cada triggSampleRate*200us
    IPC_registerInterrupt(IPC_CPU2_L_CPU1_R, IPC_INT3, IPC_motorParams);    //Flag1 del IPC para interrupcion para pedir parametros del motor de la SD

    //
    // Enable Global Interrupt (INTM) and realtime interrupt (DBGM)
    //
    EINT;
    ERTM;

    SDFatFS_init();

    SDFatFS_Handle sdFatFs_handle = SDFatFS_open(sdspiHandle, DRIVE_NUM);
    if (sdFatFs_handle == NULL)
    {
        while(1);
    }

    // Synchronize both the cores.
    //
    IPC_sync(IPC_CPU2_L_CPU1_R, IPC_FLAG31);

    contNewSamples = 0;
    aux = 0;

    //
    // Loop indefinitely
    //
    while(1)
    {
[...]

Interrupt function "IPC_motorParams" in CPU2:

__interrupt void IPC_motorParams(){

    motor1.fgrid = Pavlikfgrid;
    motor1.Pn_motor = PavlikPn_motor;
    motor1.p_motor = Pavlikp_motor;
    motor1.Vrot = PavlikVrot;
    motor1.Vg_ph_ph = PavlikVg_ph_ph;

    motor1.Jmotor = PavlikJmotor;
    motor1.gearbox = Pavlikgearbox;
    motor1.w_sincro = Pavlikw_sincro;
    motor1.TL_nominal = PavlikTL_nominal;
    motor1.TL_max = PavlikTL_max;
    motor1.overload_max = Pavlikoverload_max;
    motor1.w_grid = 2.0*pi*motor1.fgrid;
    motor1.m_motor = motor1.Vg_ph_ph/motor1.Vrot;     // Relacion de transformacion del motor
    motor1.m_motor_1 = motor1.Vrot/motor1.Vg_ph_ph;

    motor1.R1motor  = 0.03292              ;                     // Resistencia del estator
    motor1.L1motor  = (0.6221/(2*pi*motor1.fgrid));                       // Inductancia del estator
    motor1.R2motor  = 0.038                ;                     // Resistencia del rotor referida al estator
    motor1.L2motor  = (0.8476/(2*pi*motor1.fgrid));                       // Inductancia del rotor referida al estator
    motor1.Lm_motor = (22.80/(2*pi*motor1.fgrid)) ;                       // Inductancia mutua o magnetizante
    motor1.Ls       = (motor1.Lm_motor+motor1.L1motor);
    motor1.Lr       = (motor1.Lm_motor+motor1.L2motor);
    motor1.sigma = 1-((motor1.Lm_motor*motor1.Lm_motor)/(motor1.Ls*motor1.Lr));
    motor1.Flux_s = (motor1.Vg_ph_ph*raiz_2/raiz_3)/(2*pi*motor1.fgrid);      // Flujo magnetico del estator

    motor1.Leq_recv = 0.0005445567972672212;  //L_recv

    //
    // Acknowledge the flag
    //
    IPC_ackFlagRtoL(IPC_CPU2_L_CPU1_R, IPC_FLAG1);
    Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP1);
}

The interrupt in CPU2 doesn't execute in this case since the Flag 1 doesn't go to 1. And the CPU2 code just checks on loop other variables not related to this issue. What am I missing?

  • Hi,

    Where are you setting IPC flag 0? Setting flag 1 should be exactly the same. 

    You are watching the IPC registers and nothing happens? Could you try writing the registers manually ( just write to 1 in the CCS registers menu)? 

  • Hi Benjamin,

    I have used the IPC flag 0 inside a Timer 0 interrupt in CPU1. Every 200us, this interrupt sets the Flag 0 so, through and interrupt, the CPU2 can process some data.

    Btw, I have spotted an errata on the second code section included before "Initialization code of CPU2:" in line 44. I attached IPC_registerInterrupt(IPC_CPU2_L_CPU1_R, IPC_INT3, IPC_motorParams); but that was after countless trials an errors. What I have is IPC_registerInterrupt(IPC_CPU2_L_CPU1_R, IPC_INT1, IPC_motorParams);

    I have tried different things:

    • Swapping Flag 0 for Flag 1: now Flag 0 doesn't get set and Flag 1 works.
    • Setting Flag 1 in CPU1 with IPC_setFlagLtoR and registering a different interrupt in CPU2 (as stated in line 44, indicated above): Flag 1 gets set

    The latter finding is quite surprising to me to be honest...

    In response to your questions: yes, I have been watching the register IpcCPU1toCPU2Regs.CPU1TOCPU2IPCFLG.IPC1, and I'm able to see no changes. When trying to write the register manually, IpcCPU1toCPU2Regs.CPU1TOCPU2IPCSET.IPC1 doesn't change the register CPU1TOCPU2IPCFLG.IPC1 but CPU1TOCPU2IPCSET.IPC3 does change CPU1TOCPU2IPCFLG.IPC3.

  • Joaquin,

    In response to your questions: yes, I have been watching the register IpcCPU1toCPU2Regs.CPU1TOCPU2IPCFLG.IPC1, and I'm able to see no changes. When trying to write the register manually, IpcCPU1toCPU2Regs.CPU1TOCPU2IPCSET.IPC1 doesn't change the register CPU1TOCPU2IPCFLG.IPC1 but CPU1TOCPU2IPCSET.IPC3 does change CPU1TOCPU2IPCFLG.IPC3.

    Could you try using IPC Flag 3 for your interrupt then? Just wanted to point out that you must use Flag 1 for interrupt 1, Flag 2 for interrupt 2, flag 3 for interrupt 3, and flag 4 for interrupt 4. 

    So if you use a different flag, you will have to use a different IPC interrupt. 

    Best Regards,

    Ben Collier