HAL Co Gen of TI TMS470 high-end timer HET configures PWM output function

Recently, when I used the PWM function of TI’s TMS470, I found that the way it is implemented using HET is very special. And there is very little relevant information, so I deliberately recorded the relevant content, hoping to assist everyone’s learning.

What is HET? What is the difference from ordinary timer Timer?

Before using the PWM output function, you must first know what HET is.
HET, the name given by TI is high-end timer, that is, high-end timer. Note that it is a high-end timer, not an advanced timer. I didn’t react when I first saw it.
So how high-end is this so-called high-end timer?
In fact, the default functions of HET are very few. This can be seen from the application manual. This HET has few registers and no PWM related functions. But when you read in detail, you will find that TI has specially designated a RAM area (0xFF46 0000~0xFF47 FFFF) for the timer. This is the high end of the timer.
HET has a RAM area where users can place related instructions, and the timer has the ability to run these instructions.
For a simple understanding, HET can be regarded as a coprocessor. It has an instruction set independent of the CPU. Users can realize various functions by programming it (tool: HET IDE). Embedded systems typically have a range of timing and communication requirements. Typically, these requirements are unlocked at system design time. To support more complex timing functions or to protect communication flexibility, there may be a need to add an external ASIC or FPGA. These external devices add cost, power consumption, complexity, and board space. This HET can replace these additional components to a certain extent and reduce costs.

HET’s PWM function features

The number and functions of PWMs possessed by traditional MCUs are certain. The number of TI’s PWM generators is theoretically unlimited (of course, it is actually limited by the number of output pins and RAM space)
For example, taking STM32 as an example, timers are divided into advanced, general and basic. Among them, only advanced timers have all the functions of PWM, while basic timers do not have PWM functions. Although the timer has multiple output channels, the multi-channel PWM has the same cycle, but with different duty cycles. Every time you want to generate a PWM with a completely different duty cycle and period, you need to restart a timer. But HET is different. Since PWM is virtual, you can have 32 complete PWM functions (because TMS470 only has 32 HET output pins) and you can customize it to generate 3-phase complementary or higher number of collaborative PWM signals. . This cannot be done automatically by hardware in STM32.
And because the PWM is virtual, it can be connected to the Debug breakpoint during debugging. When the software executes to the breakpoint, the PWM can also be interrupted.
There is a 3-complementary PWM process in the TI forum:

Detailed explanation of the PWM generation process by HAL Co Gen

Next, I will generate a PWM process through HAL Co Gen and explain some of the mechanisms.
The relevant official content is in the 12.7 HET->Instruction Set chapter of the application manual, which can be read together.
Software PWM generation configuration
I configured the PWM as shown in the picture. After generating the project, you can find the following code in het.c, probably around line 1258

memcpy((void *)hetRAM, (const void *)hetPROGRAM, sizeof(hetPROGRAM));

The meaning of this line of code is to copy the hetPROGRAM data to the 0xFF46 0000 location of the MCU. As I said before, the HET exclusive space of TMS470 is here. Therefore, what we want to analyze is the hetPROGRAM array.

/* CNT: Timebase
*-Instruction = 0
* - Next instruction = 1
* - Conditional next instruction = na
* - Interrupt = na
* - Pin = na
* - Reg = T
*/
{
    /* Program */
    0x00001640U,
    /* Control */
    0x01FFFFFFU,
    /* Data */
    0xFFFFFF80U,
/* Reserved */
0x00000000U
},

Taking the above code as an example, I will first explain the general structure of hetPROGRAM. The above code is a command. The entire array of hetPROGRAM is composed of commands one by one. HET has a total of 21 commands, and most of the commands are only 3 A valid word, but one is reserved for TI alignment, so 4 are aligned.
Command type
From the comments, we can roughly know that the instruction number of this word is 0, the instruction number of the next command is 1, the conditional next instruction number is empty, there is no interrupt, and there is no corresponding pin.

CNT command

The CNT command is the first command in PWM generation.
CNT command
The analysis concluded:
BRK = 0, turns off software breakpoints during debugging. That is, software breakpoints during Debug will not affect the execution of the HET command.
Next Program address = 1, next execute the instruction in area 1 (hetPROGRAM[1]).
Opcode =6, look up Table 12-36 and find out that 6 represents the command code CNT.
Angle Count = 0, specifies when the counter is incremented. Only when the new angle flag is set (NAF_global=1), the value of ON will increment the counter value. Whenever the assembler encounters a CNT instruction, the OFF value increments the counter.
Register = 2, T type register (Details: 470 Application Manual Table 12-40)
Int ena = 0, interrupt is not enabled
Control = 1, determines whether to clear this field when reading the immediate data field [24:0].
Max count = 0xF FFFF = 1048575, specifies a 20-bit integer value used to define the maximum count value allowed in the data field. When the count in the data field equals max, the data field is reset to 0 and the Z system flag is set to 1
Data = FFFFC, specifies a 20-bit integer value used as a counter.

Using the code generated by HAL Co Gen, there is no significance in modifying this section.

PWCNT command

Immediately after CNT is the PWCNT command. There are two values in this command that need to be paid attention to, that is, the 2 in (2U << 7U) represents mapping to Pin2, and the 3 in (3U << 3U) represents the high and low pulse signals. .
PWCNT command

/* PWCNT: PWM 0 -> Duty Cycle
*-Instruction = 1
* - Next instruction = 2
* - Conditional next instruction = 2
* - Interrupt = 1
* - Pin = 2
*/
{
    /* Program */
    0x00002AE0U,
    /* Control */
    (0x00002006U | (2U << 7U) | (3U << 3U)),
    /* Data */
    0x00000000U,
/* Reserved */
0x00000000U
},

BRK = 0, turns off software breakpoints during debugging.
Next Program address = 2, then execute the instruction in area 2 (hetPROGRAM[2]).
Opcode = A, look up Table 12-36 and find out that A represents the instruction codes respectively DJZ, ECNT, PWCNT, SCNT.
hr_lr = 1, specifies high/low data resolution. If the hr_lr field is high, the instruction implements the hr_data field (when performing an operation on the hr pin). If the hr_lr field is low, the hr_data field is ignored.
Sub-Opcode = 3, analyze it together with Opcode to understand that the representative command is PWCNT.
Control = 0, determines whether to clear this field when reading the immediate data field [24:0].
En.Pin Action = 0, indicating that the output is not turned on during PWM initialization.
Conditional address = 2, execute area 2 if selected. This is consistent with the parameters of Next Program address, because PWM0 has not been initialized yet.
Pin Select = (2U << 7U), combined with the original HAL Co Gen, here sets the PWM0 output pin Pin2 we selected.
Action = (3U << 3U), combined with the initial HAL Co Gen, represents a high pulse.
Int ena = 0, interrupt is not enabled.
Data=0.

DJZ commands

DJZ command

/* DJZ: PWM 0 -> Period
*-Instruction = 2
* - Next instruction = 3
* - Conditional next instruction = 41
* - Interrupt = 2
* - Pin = na
*/
{
    /* Program */
    0x00003A40U,
    /* Control */
    0x00029006U,
    /* Data */
    0x00000000U,
/* Reserved */
0x00000000U
},

BRK = 0, turns off software breakpoints during debugging.
Next Program address = 3, then execute the instruction in area 3 (hetPROGRAM[3]).
Opcode = A, look up Table 12-36 and find out that A represents the instruction codes respectively DJZ, ECNT, PWCNT, SCNT.
Sub-Opcode = 2, analyze it together with Opcode to understand that the representative command is DJZ.
Control = 0, determines whether to clear this field when reading the immediate data field [24:0].
Conditional address = 41, execute area 41 if selected.
Register = 2, T type register (Details: 470 Application Manual Table 12-40)
Int ena = 0, interrupt is not enabled.
Data=0.

Next, the same structure is carried out from PWM0 to PWM7. As you can see inside, the PWCNT of PWM1 is initialized to pin 3, pulse high. But you will definitely find a problem, that is, we have clearly enabled PWM1, why is there still 0 in the PWCNT of PWM1? This is because the output configuration of the PWM is not controlled through here, but through a section of MOV64 at the back.

MOV64 command

The mov64 command is very important. Output control, duty cycle, and period are all adjusted here.
MOV64

/* MOV64: PWM 0 -> Duty Cycle Update
*-Instruction = 41
* - Next instruction = 42
* - Conditional next instruction = 2
* - Interrupt = 1
* - Pin = 2
*/
{
    /* Program */
    0x0002A101U,
    /* Control */
    (0x00002006U | (0x00000000U) | (0U << 20U) | (2U << 7U) | (3U << 3U)),
    /* Data */
    40032U,
/* Reserved */
0x00000000U
},

This is the first MOV64 command of PWM0
BRK = 0, turns off software breakpoints during debugging.
Next Program address = 42, then execute the instruction in area 42 (hetPROGRAM[42]).
Opcode = 1, look up table 12-36 to get the MOV command.
Remote Address = 1, remote address.
Control = 0, determines whether to clear this field when reading the immediate data field [24:0].
En.Pin Action = (0U << 20U), indicating that the output is not enabled by default in PWM.
Conditional address = 2, execute area 2 if selected.
Pin Select = (2U << 7U), combined with the original HAL Co Gen, here sets the PWM0 output pin Pin2 we selected.
Action = (3U << 3U), combined with the initial HAL Co Gen, represents a high pulse.
Register = 2, T type register (Details: 470 Application Manual Table 12-40)
Int ena = 0, interrupt is not enabled.
Data = 0x2001 = 8193. This is the duty cycle

/* MOV64: PWM 0 -> Period Update
*-Instruction = 42
* - Next instruction = 3
* - Conditional next instruction = 41
* - Interrupt = 2
* - Pin = na
*/
{
    /* Program */
    0x00003102U,
    /* Control */
    (0x00029006U | 0x00000000U),
    /* Data */
    79968U,
/* Reserved */
0x00000000U
},

This is the second MOV64 command of PWM0
BRK = 0, turns off software breakpoints during debugging.
Next Program address = 3, then execute the instruction in area 3 (hetPROGRAM[3]).
Opcode = 1, look up table 12-36 to get the MOV command.
Remote Address = 2, remote address.
Control = 0, determines whether to clear this field when reading the immediate data field [24:0].
En.Pin Action = (0U << 20U), indicating that the output is not enabled by default in PWM.
Conditional address = 41, execute area 41 if selected.
Pin Select = 0.
Action = 0.
Int ena = 0, interrupt is not enabled.
Register = 2, T type register (Details: 470 Application Manual Table 12-40)
Data=0x3CCB=15563. This is a cycle

HET command running logic

The running process of HET is a loop, similar to while, and the command sequence structure is a linked list structure.
Anyone who has studied the doubly linked list structure knows that the linked list has two pointers representing the previous data and the next data. The back pointer is the Next Program address, and the front pointer is the Remote Address. It’s just that HET has an additional Conditional address, which is somewhat similar to the goto command. After the PWM cycle is completed, it jumps to the MOV64 command to reload the duty cycle and cycle count values.
Run process
With this picture, the entire logic becomes clear. HET will run from the first instruction of hetPROGRAM, and the default first instruction is the CNT command. After the CNT command is completed, it will be commands such as PWCNT and DJZ. During normal operation, the MOV64 command will not be run, because after PCNT No. 40: Capture Period 7, it will jump to WCAP No. 57, and after WCAP No. 57, it will return to step 0 CNT.
Only after the PWM count ends, it will jump to MOV64 for reassignment and output configuration.

Okay, the above is the interpretation of HET’s configuration information and basic operating logic.