4. Frequently Asked Questions

4.1. Is the CLA independent from the C28x CPU?

Yes. Once the CLA is configured by the main CPU it can execute algorithms independently. The CLA has its own bus structure, register set, pipeline and processing unit. In addition the CLA can access a host of peripheral registers directly. This makes it ideal for handling time-critical control loops and filtering or math algorithms.

4.2. Can the C28x and CLA be synchronized?

Synchronization is done by starting CLA execution either by a peripheral interrupt or by writing to a specific register. In addition the CLA can interrupt the main CPU.

4.3. Is the CLA programmable?

Yes. There are no algorithms built into the CLA hardware. The CLA is completely programmable in C or assembly.

4.4. Is there a C compiler for the CLA?

Yes. The TMS320C28x Code generation tools includes support for compiling CLA C code. Because of CLA architecture and programming environment constraints, the C language supported on the CLA has some restrictions. These are documented in the TMS320C28x Optimizing C/C++ Compiler User’s Guide, Chapter “CLA Compiler”.

4.5. How is data shared between the CLA and C28x?

The examples in C2000Ware demonstrate data exchange between the C28x and the CLA. This is done through RAM blocks that both of the CPUs can directly access. Since the CLA and the C28x code reside within same project, sharing data can be accomplished using these steps:

  1. Create a shared header file with common constants and variables. Include this file in both the C28x C and CLA code.
  2. Use data section pragma statements and the linker file to place the variables in the appropriate RAM.
  3. Define shared variables in your C28x .c code. C28x and CLA shared global variables must be defined in the C28x .c code, and not the CLA code. The way data pages work on each device does not match. It is more constrained on the C28x side. Thus, data defined on the C28x side can be accessed on the CLA side, but not the other way around.
  4. Initialize variables in the CPU to CLA message RAM with the main CPU.
  5. Initialize variables in the CLA to CPU message RAM with a CLA task. This initialization task can be started via the main C28x software.

4.6. How are data types different on C28x and CLA?

See also

C28x and CLA data types are documented in the version specific Compiler User’s Guide. (Compiler and Assembly Tools)

To avoid ambiguity when sharing data between CLA and C28x, it is strongly recommended that you use type declarations that include size information. For example, don’t use int. Use int32_t and uint16_t which are defined in stdint.h for both the C28x and CLA.

For example:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
//
// in the shared header file and main .c file
// Does not indicate the size of the variable
// An unsigned int on C28x is 16-bit and an unsigned int on CLA is 32-bits
//
unsigned int t0;
unsigned int t1;
//
// Instead use C99 data types with size information
//

#include <stdint.h>
uint16_t t0;
uint16_t t1;

Integers:

  • For CLA an int is 32-bits
  • For C28x an int is 16-bit

Pointers:

Pointers are interpreted differently on the C28x and the CLA. The C28x treats them as 32-bit data types (address bus size being 22-bits wide can only fit into a 32-bit data type) while the CLA only has an address bus size of 16 bits.

Assume the following structure is declared in a shared header file(i.e. common to the C28 and CLA) and defined and allocated to a memory section in a .c file:

Listing 4.1 Pointer Size Problem
      /********************************************************************
       shared.h
       C28x and CLA Shared Header File
      ********************************************************************/
      typedef struct{
        float a;
        float *b;
        float *c;
      }foo;


      /********************************************************************
       main.c
       Main C28x C-code Source File
      ********************************************************************/
      #pragma(X,"CpuToCla1MsgRam")        // Assign X to section CpuToCla1MsgRam
      foo X;


      /********************************************************************
       test.cla
       CLA C-code Source File
      ********************************************************************/
      __interrupt void Cla1Task1 ( void )
      {
        float f1,f2;
        f1 = *(X.b);
        f2 = *(X.c);    //Pointer incorrectly dereferenced
                        //Tries to access location 0x1503 instead
                        //of 0x1504
      }

Assume that the C28x compiler will allocate space for X at the top of the section CpuToCla1MsgRam as follows:

Element Description C28x Address
X.a a is a 32-bit float in address 0x1500-0x1501
X.b b is a 32-bit pointer in address 0x1502-0x1503
X.c b is a 32-bit pointer in address 0x1504-0x1505

The CLA will interpret this structure differently. The CLA treats pointers ‘’‘b’‘’ and ‘’‘c’‘’ as 16-bits wide and, therefore, incorrectly dereferences pointer c.

Element Description CLA Address
X.a a is a 32-bit float in address 0x1500-0x1501
X.b b is a 16-bit pointer in address 0x1502
X.c c is a 16-bit pointer in address 0x1503

The solution to this is to declare a new pointer as follows:

Create a new pointer ‘’‘CLA_FPTR’‘’ which is a union of a 32-bit integer and a pointer to a float. The CLA compiler recognizes the size of the larger of the two elements (the 32 bit integer) and therefore aligns the pointer to the lower 16-bits. Now both the pointers ‘’‘b’‘’ and ‘’‘c’‘’ will occupy 32-bit memory spaces and any instruction that tries to de-reference pointer c will access the correct address 0x1504.

Listing 4.2 Pointer Size Solution
 /********************************************************************
   shared.h
   C28x and CLA Shared Header File
  ********************************************************************/
  typedef union{
    float *ptr; //Aligned to lower 16-bits
    Uint32 pad; //32-bits
  }CLA_FPTR;

  typedef struct{
    float a;
    CLA_FPTR b;
    CLA_FPTR c;
  }foo;


  /********************************************************************
   main.c
   Main C28x C-code Source File
  ********************************************************************/
  #pragma(X,"CpuToCla1MsgRam") //Assign X to section CpuToCla1MsgRam
  foo X;



  /********************************************************************
   test.cla
   CLA C-code Source File
  ********************************************************************/
  __interrupt void Cla1Task1 ( void )
  {
    float f1,f2;
    f1 = *(X.b.ptr);
    f2 = *(X.c.ptr); //Correct Access
  }

4.7. What can trigger a task (also referred to as an ISR)?

The following sources can start (trigger) a task:

  1. A peripheral interrupt
  2. Software trigger
  3. Another CLA task
  4. On some devices a specific task can be designated as a background task. Refer to Identifying Device-Specific CLA Features for details.

The C28x configures the CLA. Part of the configuration is specifying what silicon resource trigger which tasks. There are generally two registers used to configure the triggers for a task.

  • Older devices use the the MPISRCSEL1 register (i.e. 2803x, 2805x, 2806x).
  • More recent devices use a system register CLA1TASKSRCSELx (2837xD/S, F28004x…).

See also

The trigger can be an interrupt or it can be the C28x CPU through software. It is important to understand the trigger source is only the mechanism by which the task is started. The trigger source does not limit what the task can do or what registers it accesses.

  • The main C28x CPU

    Can start a task by using the IACK #16bit instruction. For example IACK 0x0003 would flag interrupt 1 and interrupt 2. This is the same as setting bits in the force register (MIFRC)

  • Another CLA task:

    On some devices, the CLA does not have access to directly force another task to be flagged. There are a couple of options:

    • Interrupt the C28x and force the task as part of the interrupt service routine.
    • Write to the ePWM register to force an interrupt which in-turn forces a task to be flagged.

4.8. Is there support for nesting tasks?

The CLA has its own fetch mechanism and can run and execute a task independently of the CPU. Only one task is serviced at a time - there is no nesting of tasks unless the background task in enabled. On devices with CLA Type 2 supporting background tasks, one level of nesting is possible. See CLA Types.

4.9. Is there a limitation on the code size for tasks?

Think of a task like an interrupt. It is a algorithm that is executed when the CLA receives an interrupt. The size of a task is only limited by the amount of program memory available and the CLA’s program counter.

The start address of a task is configurable. Each task has an associated interrupt vector (MVECT1 to MVECT8). For type 0 CLAs, (CLA Types) this vector holds the starting address (as an offset from the first program location) of the task. For all the other types, this vector holds the entire 16-bit address of the task.

  • CLA Type 0:

    The program space is limited to 12-bits or 4096 words. All CLA instructions are 32-bits, so within a 4k x 16 program space you can have ~2k CLA instructions.

  • CLA Type 1 and above:

    The program space is 16-bits wide, leaving the lower 64K words of space available as program space. Please refer to your device specific documentation for information on how to configure/allocate the memory spaces to the CLA.

The MSTOP instruction indicates the end of the task. After a task begins, the CLA will execute instructions until it encounters an “MSTOP” instruction.

4.10. Which peripheral registers can the CLA access directly?

Warning

Refer to the device-specific datasheet. If there is more than one CLA on a device, they may not all have the ability to connect to all of the same peripherals. (Device-Specific Features)

The answer is C2000 MCU family dependent. In general, more recently released device families support CLA access to more peripherals. The list below indicates where to look in the datasheet:

  1. The device block diagram: indicates which peripherals are connected to the CLA bus.
  2. The device level memory map: which memory blocks can be configured for CLA access
  3. The external interface (EMIF) memory map: indicates any memory regions the CLA can access
  4. The peripheral register memory maps: which specific peripheral registers the CLA has access to

Some examples:

  • 2803x: Direct access to the ADC result, ePWM+HRPWM, and comparator registers.
  • 2806x: Direct access to the ADC result, ePWM+HRPWM, eCAP, eQEP and comparator registers.
  • 2807x: Direct access to the the ADC module(s) (including results), ePWM+HRPWM, eCAP, eQEP, comparator subsytem, DAC subsystem, SPI, McBSP, uPP, EMIF, GPIO
  • 2837x: Direct access to the the ADC module(s) (including results), ePWM+HRPWM, eCAP, eQEP, comparator subsytem, DAC subsystem, SPI, McBSP, uPP, EMIF(s), GPIO

4.11. Can the CLA send an interrupt to the C28x?

Todo

check if there are new mechanisms on F28004x

Yes. The CLA can send an interrupt to the C28x as follows:

  • End of Task:

    The CLA will send an interrupt to the PIE (peripheral interrupt expansion block) to let the main CPU (C28x) know a task has completed. Each task has an associated vector in the PIE. This interrupt is automatically fired when the associated task completes. For example when task 1 completes, CLA1_INT1 in the PIE will be flagged. If this interrupt is not enabled, then the C28x will ignore it.

  • Forced Interrupt:

    This applies to CLA type 1 and later. (Note: when this option is enabled it automatically disables the end of task interrupt). The CLA has a Software Interrupt Capability, where a task can enable and force an interrupt to the main CPU. For example Task 1 can enable a software interrupt for task 2, by writing to the TASK2 bit of the CLA1SOFTINTEN register, and then forcing that interrupt by writing to the TASK2 bit of the CLA1SOFTINTFRC register.

  • Overflow and Underflow:

    There are dedicated interrupts in the C28x PIE for CLA floating-point overflow and underflow conditions.

4.12. Does the CLA have access to all memory blocks?

No, the memory blocks that are available for use by the CLA is device family dependent.

See also

The memory map in the device-specific datasheet indicates which blocks the CLA can access. (Device-Specific Features)

  • The main CPU can allocate specific memory blocks to the CLA
  • The memory map indicates which memory blocks can be configured for CLA usage.
  • In some devices the memory usage (program or data) is fixed. In other devices some memory blocks accessible by the CLA can be configured as program memory or data memory.

In addition, there are dedicated message RAMs with a fixed configuration. Look for these in the memory map as well. Two examples are given below. Some devices have additional message RAMs.

  • CLA to CPU Message RAM: CLA can read/write, main CPU can only read
  • CPU to CLA Message RAM: CPU can read/write, CLA can only read

4.13. If C28x and CLA can access the same device resource, which has priority?

The device automatically arbitrates the access to the resource. That is, there is a defined order of priority.

See also

Search for the word “arbitration” in the device-specific Technical Reference Manual (TRM) for more information. (Device-Specific Features).

Keep in mind if the main CPU performs a read-modify-write operation on a peripheral register and between the read and the write the CLA modifies the same register, the changes made by the CLA can be lost. In general it is best to not have both processors writing to the same registers.

If the CLA is configured to respond to a peripheral interrupt, then the interrupt will still go to the C28x PIE. This enables both CPUs to respond if needed.

4.14. How can I measure the duration of a task?

  • Option 1: Use a timer:

    One method is to use a free running timer to capture the number of cycles the task execution took. The CLA has access to the PWM timers. As an example you could capture the number of cycles in C as follows:

    1. At the start of the task, CLA reads the timer
    2. Execute the task
    3. At the end of the task, CLA reads the timer again
    4. Calculate the number of cycles between (1) and (3)
    ct1 = EPwm1Regs.TBCTR;
    //
    //..... code to be measured here .....
    //
    ct2 = EPwm1Regs.TBCTR;
    delta_ct = ct2 - ct1;
    
  • Option 2: Use a GPIO pin:

    On some devices, the CLA has direct access to GPIO pins. In this case, instead of reading a timer, the CLA could toggle a pin before and after the code to be measured. Monitor the pin using an oscilloscope to measure the delta in time.

  • Accounting for Overhead

    There will be some overhead due to triggering the CLA task and notifying the C28x that it has completed. In order to test this overhead, you could use a timer on the C28x to time the start and stop of the CLA task.

    1. Read the timer using the C28x
    2. Start the CLA task via the C28x Software
    3. Wait for the MIRUN bit to clear
    4. Read the timer using the C28x
    5. Calculate the delta between (1) and (4)
    6. Also refer to this post: https://e2e.ti.com/support/microcontrollers/c2000/f/171/t/738758

4.15. Can the C28x terminate a CLA task?

Yes. If a interrupt has been flagged, but the task has not yet run, the main CPU can clear the flag using the MICLR register.

If the task is already running then a soft reset (in MCTL) will terminate the task and clear the MIER register. If you want to clear all of the CLA registers you can use the hard reset option in the MCTL register.

4.16. What does the “Symbol, X, referenced in a.obj, assumes that data is blocked but is accessing non-blocked data in b.obj. Runtime failures may result” warning from the Linker mean?

This is a diagnostic added in C2000 code generation tools v20.2.x.LTS to detect when data accesses that assume data is blocked are made to non-blocked definitions.

The common case for this is a global CLA definition that is used in C28 code. For more background refer to 20.2.x LTS README entry for the new diagnostic.