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.

TMS320F280049: Illegal Fetch after startup on CLA

Part Number: TMS320F280049

Hi there,

I use CLA on F28004x to process some ADC data.
For migrating the code to CLA, I studied CLA Hands-on Workshop: https://training.ti.com/control-law-accelerator-cla-hands-workshop?context=1128629

As proposed in Tips & Tricks video, I implemented an access violation ISR to check if memory regions are correctly mapped to CLA.
Unfortunately, this ISR is called once right after initializing CLA, but I cannot figure out, why this happens..
In the following, I will provide the relevant code snippets:

1. CLA init Methods (configCLAMemory() is called before initCLA()) and accessViolationISR

void initCLA( void )
{
  EALLOW;
  Cla1Regs.MVECT1 = (uint16_t)(&Cla1Task1);
  Cla1Regs.MVECT8 = (uint16_t)(&Cla1Task8);

  DmaClaSrcSelRegs.CLA1TASKSRCSEL1.bit.TASK1  = CLA_TRIG_ADCBINT1;
  DmaClaSrcSelRegs.CLA1TASKSRCSEL2.bit.TASK8  = CLA_TRIG_NOPERPH;
  Cla1Regs.MIER.all                   = (M_INT1 | M_INT8);

  Cla1Regs.MCTL.bit.IACKE    = 1;
  EDIS;

  Cla1ForceTask8andWait();
}

void configCLAMemory(void)
{
    memcpy((uint32_t *)&Cla1ProgRunStart, (uint32_t *)&Cla1ProgLoadStart,
            (uint32_t)&Cla1ProgLoadSize );
    memcpy((uint32_t *)&Cla1ConstRunStart, (uint32_t *)&Cla1ConstLoadStart,
            (uint32_t)&Cla1ConstLoadSize );

    EALLOW;
    // Initialize and wait for CLA1ToCPUMsgRAM
    MemCfgRegs.MSGxINIT.bit.INIT_CLA1TOCPU = 1;
    while (MemCfgRegs.MSGxINITDONE.bit.INITDONE_CLA1TOCPU != 1)
    {
    };

    // Initialize and wait for CPUToCLA1MsgRAM
    MemCfgRegs.MSGxINIT.bit.INIT_CPUTOCLA1 = 1;
    while (MemCfgRegs.MSGxINITDONE.bit.INITDONE_CPUTOCLA1 != 1)
    {
    };

    // <Step 3> : Give CLA control over program and data RAM(s)
    //    - The MemCfgRegs register is described in TRM 2.14.17
    // Configure LS1RAM as program space for the CLA
    // First configure the CLA to be the master for LS1 and then
    // set the spaces to be program blocks
    MemCfgRegs.LSxMSEL.bit.MSEL_LS1 = 1;
    MemCfgRegs.LSxCLAPGM.bit.CLAPGM_LS1 = 1;

    //Next configure RAMLS0 as data space for the CLA
    // First configure the CLA to be the master the block and then
    // set the spaces to be data blocks
    MemCfgRegs.LSxMSEL.bit.MSEL_LS0 = 1;
    MemCfgRegs.LSxCLAPGM.bit.CLAPGM_LS0 = 0;

    // Detect any CLA fetch access violations, enable
    // interrupt for it
    AccessProtectionRegs.NMAVSET.bit.CLA1FETCH = 1;
    AccessProtectionRegs.NMAVINTEN.bit.CLA1FETCH = 1;
    // Set the ISR for access violation fault
    PieVectTable.RAM_ACCESS_VIOLATION_INT = &accessViolationISR;
    PieCtrlRegs.PIEIER12.bit.INTx12       = 1;
    IER                                  |= M_INT12;

    EDIS;

}

#pragma CODE_SECTION(accessViolationISR, ".TI.ramfunc")
__attribute__((interrupt))  void accessViolationISR(void)
{
    // Read the fetch address where the violation occurred
    fetchAddress = AccessProtectionRegs.NMCLA1FAVADDR;

    EALLOW;
    // clear the fault
    AccessProtectionRegs.NMAVCLR.bit.CLA1FETCH = 1;
    EDIS;
    __asm(" ESTOP0");

    // Acknowledge the RAM access violation interrupt
    PieCtrlRegs.PIEACK.all = M_INT12;
}

2. Relevant regions of Linker cmd file:

   /* CLA Program Memory */
   Cla1Prog         : LOAD = FLASH_BANK0,
   					  RUN = RAMLS1,
   					  LOAD_START(_Cla1ProgLoadStart),
   					  LOAD_SIZE(_Cla1ProgLoadSize),
   					  LOAD_END(_Cla1ProgLoadEnd),
   					  RUN_START(_Cla1ProgRunStart),
   					  RUN_SIZE(_Cla1ProgRunSize),
   					  RUN_END(_Cla1ProgRunEnd),
   					  PAGE = 0, ALIGN(4)
   /* CLA DATA */
   Cla1DataRam      : > RAMLS0,      PAGE = 1
   Cla1ToCpuMsgRAM  : > CLA1_MSGRAMLOW,   PAGE = 1
   CpuToCla1MsgRAM  : > CLA1_MSGRAMHIGH,  PAGE = 1

   /* CLA Compiler Sections */
   .scratchpad		: > RAMLS0,		 PAGE = 1
   .bss_cla		    : > RAMLS0,      PAGE = 1
   .const_cla       : LOAD = FLASH_BANK0,
   					  RUN = RAMLS0,
   					  LOAD_START(_Cla1ConstLoadStart),
   					  LOAD_SIZE(_Cla1ConstLoadSize),
   					  LOAD_END(_Cla1ConstLoadEnd),
   					  RUN_START(_Cla1ConstRunStart),
   					  RUN_SIZE(_Cla1ConstRunSize),
   					  RUN_END(_Cla1ConstRunEnd),
   					  PAGE = 1


3. CLA - Code:
__attribute__((interrupt)) void Cla1Task1(void)
{

}

__attribute__((interrupt))  void Cla1Task8 ( void )
{

}


Even if i Leave the CLA Tasks completely empty, I run into accessViolationISR some lines after I called initCLA() and I cannot figure out why.
The CLA Task Vectors MVECT1 and MVECT8 point to the correct Ram Addresses, I already verified this by studying the generated Mapfile.
The fetch Address is always 0. I run into accessViolationISR definitely only once!
Can you find any error in my init Code mapping the RAM Regions to CLA? I think, I did it correctly, like it was shown in Hand-On Workshop.

Thank you in advance! Best regards,

Chris

  • Hi Christian,

    I don't see anything wrong with the programming either.

    Can you check that LS0 and LS1 are only being allocated to the CLA and are not allocated to any other section on the C28 side?

    In the accessViolationISR what is the fetchAddress that is failing?

    Thanks,

    Ashwini

  • Hi Ashwini,

    thank you for your reply. I ensured that LS0 and LS1 are only allocated to CLA, they are definitely not used on C28 side.

    The fetchAddress is 0. I have set the fetchAddress variable to some value other than 0 manually on program start and after halting in the Access Violation ISR, it is always set to 0.

    Best regards,

    Chris

  • Hi Christian,

    If the CLA fetch violation occurred then fetchAddress cannot be 0.

    Can you set a breakpoint at the start of the accessViolationISR and then read back the NMAVFLG and MAVFLG to check which bit is set and has triggered the access violation ISR?

    Thanks,
    Ashwini

  • Hi Ashwini,

    I have set multiple Breakpoints in accessViolationISR, but Debugger only halts at the ESTOP Line. Then this address is definitely set to 0. I am not sure, if the register contents are displayed correctly then, but they all seem to be 0.

  • Hi Christian,

    Can you update the accessViolationISR to read and save to variable the NMAVFLG  and MAVFLG so we can review the status at ESTOP0. It would help confirm is indeed CLA1FETCH has been set since it is getting cleared before ESTOP0.

    Thanks,
    Ashwini

  • Hi Ashwini,

    I´ve adapted accessViolationISR as proposed by you:

    #pragma CODE_SECTION(accessViolationISR, ".TI.ramfunc") 
    __attribute__((interrupt))  void accessViolationISR(void)
    {
        // Read the fetch address where the violation occurred
        fetchAddress = AccessProtectionRegs.NMCLA1FAVADDR;
        loc_nmavflg = AccessProtectionRegs.NMAVFLG.all;
        loc_mavflg = AccessProtectionRegs.MAVFLG.all;
    
        EALLOW;
        // clear the fault
        AccessProtectionRegs.NMAVCLR.bit.CLA1FETCH = 1;
        EDIS;
    
        __asm(" ESTOP0");
    
        // Acknowledge the RAM access violation interrupt
        PieCtrlRegs.PIEACK.all = M_INT12;
    }

    This results in the following:

    Best regards,
    Chris

  • Hi Christian,

    I just noticed that in your code you have the following lines which is forcing the violation and hence generating the interrupt. Please remove this line.

    "AccessProtectionRegs.NMAVSET.bit.CLA1FETCH = 1;"

    The only line you need is to the one where the interrupt is enabled in NMAVINTEN.

    Thanks,

    Ashwini

  • Hi Ashwini,

    yeah, that´s it!
    I did not deeply think about this line, because I copied it directly from the proposed solution from CLA Hands-on-Lab chapter 5 where this was presented as solution for catching Acess violations on CLA. For whatever reason, this line was included in the Hands-on-lab example as well. Anyway - good to know that this line is obsolete ;)

    Thank you a lot!
    Chris