element14 Community
element14 Community
    Register Log In
  • Site
  • Search
  • Log In Register
  • Community Hub
    Community Hub
    • What's New on element14
    • Feedback and Support
    • Benefits of Membership
    • Personal Blogs
    • Members Area
    • Achievement Levels
  • Learn
    Learn
    • Ask an Expert
    • eBooks
    • element14 presents
    • Learning Center
    • Tech Spotlight
    • STEM Academy
    • Webinars, Training and Events
    • Learning Groups
  • Technologies
    Technologies
    • 3D Printing
    • FPGA
    • Industrial Automation
    • Internet of Things
    • Power & Energy
    • Sensors
    • Technology Groups
  • Challenges & Projects
    Challenges & Projects
    • Design Challenges
    • element14 presents Projects
    • Project14
    • Arduino Projects
    • Raspberry Pi Projects
    • Project Groups
  • Products
    Products
    • Arduino
    • Avnet Boards Community
    • Dev Tools
    • Manufacturers
    • Multicomp Pro
    • Product Groups
    • Raspberry Pi
    • RoadTests & Reviews
  • Store
    Store
    • Visit Your Store
    • Choose another store...
      • Europe
      •  Austria (German)
      •  Belgium (Dutch, French)
      •  Bulgaria (Bulgarian)
      •  Czech Republic (Czech)
      •  Denmark (Danish)
      •  Estonia (Estonian)
      •  Finland (Finnish)
      •  France (French)
      •  Germany (German)
      •  Hungary (Hungarian)
      •  Ireland
      •  Israel
      •  Italy (Italian)
      •  Latvia (Latvian)
      •  
      •  Lithuania (Lithuanian)
      •  Netherlands (Dutch)
      •  Norway (Norwegian)
      •  Poland (Polish)
      •  Portugal (Portuguese)
      •  Romania (Romanian)
      •  Russia (Russian)
      •  Slovakia (Slovak)
      •  Slovenia (Slovenian)
      •  Spain (Spanish)
      •  Sweden (Swedish)
      •  Switzerland(German, French)
      •  Turkey (Turkish)
      •  United Kingdom
      • Asia Pacific
      •  Australia
      •  China
      •  Hong Kong
      •  India
      •  Korea (Korean)
      •  Malaysia
      •  New Zealand
      •  Philippines
      •  Singapore
      •  Taiwan
      •  Thailand (Thai)
      • Americas
      •  Brazil (Portuguese)
      •  Canada
      •  Mexico (Spanish)
      •  United States
      Can't find the country/region you're looking for? Visit our export site or find a local distributor.
  • Translate
  • Profile
  • Settings
Transportation & Automotive
  • Technologies
  • More
Transportation & Automotive
Blog Create and Measure signals with Hercules High End Timer (HET) - 2: Generate Dynamic Duty Cycle
  • Blog
  • Forum
  • Documents
  • Quiz
  • Polls
  • Members
  • Mentions
  • Sub-Groups
  • Tags
  • More
  • Cancel
  • New
Transportation & Automotive requires membership for participation - click to join
  • Share
  • More
  • Cancel
Group Actions
  • Group RSS
  • More
  • Cancel
Engagement
  • Author Author: Jan Cumps
  • Date Created: 7 Jan 2020 6:00 PM Date Created
  • Views 3485 views
  • Likes 7 likes
  • Comments 10 comments
  • nhet
  • automotive
  • hercules
Related
Recommended

Create and Measure signals with Hercules High End Timer (HET) - 2: Generate Dynamic Duty Cycle

Jan Cumps
Jan Cumps
7 Jan 2020

This project uses the timers of a TI Hercules microcontroller to generate complex digital signals and to measure digital signals.

 

In this post: create a triangle wave by modulating the duty cycle of a fixed frequency pulse wave.

 

image

 

This project is based on TI's application note spna178: Monitoring PWM Using N2HET.

That note explains the functionality and has a link to a Code Composer Studio project .

I'm using these as the source for the blog series.

 

Triangle signal from a pulse wave

 

Creating a triangle wave by playing with the duty cycle of a pulse wave is a nice simple case.

We're trying to generate an analog signal purely by controlling the amount of energy in each cycle of the pulse wave.

This is different than ladder DACs that generate a level based on a digital value. Our example creates a level by controlling how long a pulse stays high vs low.

When a 3.3 V pulse has 100% duty cycle, the average delivered is 3.3 V.

When that same signal has a duty cycle of 50%, average = 1.65 V, and so forth down to 0 V at 0% duty cycle.

The output signal doesn't look like a triangle when you probe it, because it's a pulse train. When you run it through a low-pass filter, it's integrated into its analog representation: a triangle wave.

I didn't find a good picture with a triangle wave. The below one shows the very same concept but with a sinus signal generated with duty cycle modulation.

On popular demand I'll probe the actual pulse train together with the triangle wave on my launchpad.

 

image

source: part of a diagram from TI application note SPNA217: Sine Wave Generation Using PWM With HerculesTm N2HET

 

TI has application notes solely focused on generating different wave types (trapezoid, triangle in one and in another note sine wave) by playing with the duty cycle of the HET modules.

They do a much better attempt to explain it than I do here. Check the app notes if the above doesn't make sense.

 

The HET Code

 

The flow that generates the pulse train is shown in the chart below:

image

source: TI's application note spna178: Monitoring PWM Using N2HET, showing the triangle waveform logic

 

Now the HET code that implements this. I believe this is among the most difficult code to read (together with TI' PRU instructions).

I need the comments to recognise the flowchart parts above.

 

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; This example code is to be loaded to N2HET1 to generate a triangle waveform using varying
; duty cycle ramping from 0% duty to a programmable maximum duty cycle and then ramp down 
; to 0% again.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

; PWM frequency to be generated
PWM_PERIOD             .equ 3

; The pin number that will output the PWM signal
PWM_PIN_NUM            .equ 9

; The initial maximum duty cycle (compare value) to be generated.
INIT_COMPARE           .equ 1

; delay amount to increment from one duty cycle to the next duty cycle.
INCREMEMT_DELAY        .equ 0

; delay amount to decrement from one duty cycle to the next duty cycle.
DECREMEMT_DELAY        .equ 0

; amount of increment 
DUTY_INCREMEMT         .equ 0

; amount of decrement
DUTY_DECREMEMT         .equ 0

; amount of increment 
DUTY_INCREMEMT_HR      .equ 1

; amount of decrement
DUTY_DECREMEMT_HR      .equ 1

; key to unlock N2HET 
UNLOCK_KEY             .equ 0xA

; The data field of the MOV32 instruction contains an initial value (0x5) that 
; is not equal to the key to unlock the N2HET program. First the MOV32 
; instruction moves the initial value toa temporaray register T
L00   MOV32 { remote=DUMMY,type=IMTOREG,reg=T,data=0x5};

; Compare the register T value with the key to unlock N2HET. The key to unlock 
; is 0xA. If the key is not matched then go back to L00. The CPU is supposed 
; to write the proper key (0xA) to unlock the N2HET
L01   ECMP { next=L00,hr_lr=LOW,cond_addr=L02,pin=0,reg=T,data=UNLOCK_KEY};

; Creating a virtual counter using CNT which will determines the period of 
; the PWM to be generated. The initial small max count allows for quick
; simulation which can later be changed by the host CPU. 
L02   CNT { reg=A,irq=ON,max=PWM_PERIOD};

; Use ECMP to determine the duty cycle of the PWM on the specified pin. The
; pin field and the duty cycle are changeable by the CPU.
L03   ECMP { hr_lr=HIGH,en_pin_action=ON,cond_addr=L04,pin=PWM_PIN_NUM,action=PULSELO,
             reg=A,irq=OFF,data=0,hr_data=0};

; Only when the CNT reaches the max count will the program go to the 
; conditional address. We want to wait for one complete PWM waveform to be 
; generated before changing the duty cycle. When CNT reaches the max
; value it will set the Z flag.
L04   BR { next=L00,cond_addr=L05,event=Z};

; the data field in this ADD acts as a up/down flag. We want to create a 
; triangle waveform. The PWM will first increase the duty cycle until it 
; reaches the specified maximum duty cycle before it starts to decrease the 
; duty. The up/down flag is used to create two different paths in the flow
; to alternate before increasing duty cycle vs decreasing duty cycle. 
L05   ADD { src1=ZERO,src2=ZERO,dest=NONE,data=0};

; Move the up/down flag to a temp register T.
L06   MOV32 { remote=L05,type=REMTOREG,reg=T};

; Compare this up/down flag to 0. 0 means to increase the duty cycle and 1 
; means to decrease the duty cycle. 
L07   ECMP { next=L16,cond_addr=L08,pin=0,reg=T,data=0};

; move the ECMP DF which contains the compare value for duty cycle creation
; to register R 
L08   MOV32 { remote=L03,type=REMTOREG,reg=R};

; Subtract the current compare value from the max duty cycle stored in 
; REM_DUTY. The result will be stored in register S.
L09   SUB { src1=REM,src2=R,dest=S,remote=REM_DUTY,data=0};

; If the substraction result is more than 0 then it means it has not 
; reached the max duty cycle we will increase the duty cycle. If it is 
; zero then we have reached the max duty cycle and we will change to 
; up/down flag to down position.
L10   BR { next=L14,cond_addr=L11,event=GT};

; Insert delay before changing to the next duty cycle
L11   DJZ { next=L00,cond_addr=L12,reg=NONE,data=INCREMEMT_DELAY};

; Add specified amount to the existing compare value (duty cycle). This 
; value is also changeable by CPU
L12   ADD { src1=R,src2=IMM,dest=S,rdest=REM,remote=L03,data=DUTY_INCREMEMT,
            hr_data=DUTY_INCREMEMT_HR};

; Reset the increment delay to the specified amount.
L13   MOV32 { next=L15,remote=L11,type=IMTOREG&REM,reg=NONE,data=INCREMEMT_DELAY};

; Now change the up/down flag to down by moving a 1 to the up/down flag
L14   MOV32 { remote=L05,type=IMTOREG&REM,reg=NONE,data=1};

; Branch to the beginning
L15   BR { next=L00,cond_addr=L00,event=NOCOND};

; move the ECMP DF to register R which contains the current compare value
; (duty cycle)
L16   MOV32 { remote=L03,type=REMTOREG,reg=R}; 

; Subtract the current duty cycle by the specified amount. This value is 
; also changeable by CPU.
L17   SUB { src1=R,src2=IMM,dest=S,rdest=NONE,data=DUTY_DECREMEMT,
            hr_data=DUTY_DECREMEMT_HR};

; As long as the subtraction result is greater than zero, we will keep 
; decreasing the duty cyle or otherwise we will again change the up/down 
; flag to up position. The destination register is A which contains the 
; subtraction result.
L18   BR { next=L19,cond_addr=L22,event=N};

; Insert the delay before decreasing to the next duty cycle.
L19   DJZ { next=L00,cond_addr=L20,reg=NONE,data=DECREMEMT_DELAY};

; Move the subtraction result to the ECMP DF as the new duty cycle
L20   MOV32 { next=L21,remote=L03,type=REGTOREM,reg=S};

; Reset the decrement delay to the specified amount
L21   MOV32 { next=L00,remote=L19,type=IMTOREG&REM,reg=NONE,data=DECREMEMT_DELAY};

; Move the value 0 to the up/down flag so in the next LRP the program 
; flow will execute the path to increase duty cycle.
L22   MOV32 { remote=L05,type=IMTOREG&REM,reg=NONE,data=0};

; Branch to beginning
L23   BR { next=L00,cond_addr=L00,event=NOCOND};

; REM_DUTY data field stores the maximum duty cycle the PWM to be generated. 
; The host CPU can change this value.
REM_DUTY   ECMP { next=REM_DUTY,cond_addr=REM_DUTY,pin=0,reg=A,data=INIT_COMPARE,hr_data=0};
DUMMY   BR { next=DUMMY,cond_addr=DUMMY,event=NOCOND,irq=OFF};

 

Format is label-command-attributes. All instructions are documented in the TMS reference manual, section 17.5.

The defines in the code are placeholders in this example. All of these can be set from the firmware before the timer is kicked off ...

 

image

 

Give data to the HET controller at runtime from Firmware

 

Here's an example on how these values are overruled at runtime:

 

/* Change to desired PWM Period in terms of (uS)
 * the default 45.52uS will generate a 12-bit resolution on the PWM
 * with each resolution equal to HR=VCLK2=11.11nS.
 * 45.52uS / 11.11ns = 4096.
 */
#define PWM_PERIOD    45.52F

/* Change to desired maximum duty in terms of (%)
 * N2HET1 will generate a varying PWM from 0% duty to
 * the maximum duty specified by PWM_DUTY */
#define PWM_DUTY      100.0

/* allowable LR Prescaler values are 5, 6 and 7. Anything less will
 * will not have enough time slots for the N2HET program. HR prescaler
 * is always divide by 1 from VCLK2.
 * 7 -> one LR = 128 HR
 * 6 -> one LR = 64 HR
 * 5 -> one LR = 32 HR
 */
#define LRPFC 7

/* The NH2ET1 program will automatically increase the PWM
 * modulation from 0% duty cycle to maximum duty cycle
 * specified in PWM_DUTY. When PWM_DUTY is reached it starts
 * to decrease the duty cycle from PWM_DUTY to 0%.
 * DUTY_INCREMENT specifies the delta amount of duty cycle to
 * change from one duty cycle to the next duty cycle while
 * the duty cycle is increasing. This is expressed in terms
 * of (%). For example specifying DUTY_INCREMENT equal to
 * 2 will mean the duty cycle will start at 0% and the next
 * duty cycle will be 2% at a 2% increment. If 0 is
 * specified, then the N2HET1 will increment the duty cycle
 * at 1 HR (High Resolution) clock  */
#define DUTY_INCREMENT   0.0F

/* DUTY_INCREMEMT specifies the delta amount of duty cycle to
 * change from one duty cycle to the next duty cycle while
 * the duty cycle is decreasing. This is expressed in terms
 * of (%). */
#define DUTY_DECREMENT   0.0F

/* The increment delay is the delay at which the PWM modulation
 * will increase the duty cycle from one duty cycle to the
 * next duty cycle. This is expressed in terms
 * of (uS).  For example, if INCREMENT_DELAY is specified for
 * 10.0F (equal to 10uS) then the N2HET1 will wait for 10uS
 * before changing to the new duty cycle */
#define INCREMENT_DELAY  0.0F

/* Decrement delay. The Decrement delay is the delay at
 * which the PWM will decrease the duty cycle. This is expressed
 * in terms of (uS).  */
#define DECREMENT_DELAY  0.0F

/* Pin number in N2HET1 to generate the PWM. */
#define NHET1_PIN_PWM PIN_HET_9

// ...

  /* Set N2HET1[9] to output */
  hetREG1->DIR = 1 << NHET1_PIN_PWM;

  /* Change the LRPFC according to user input */
  hetREG1->PFR = (LRPFC << 8) ;

  /* Initiailize the PWM period and duty cycle based on the defined parameters */
  hetRAM1->Instruction[pHET_L02_0].Control = (uint32)CNT_MAX_PERIOD | (hetRAM1->Instruction[pHET_L02_0].Control & 0xFD0000);
  hetRAM1->Instruction[pHET_REM_DUTY_0].Data = ecmp_compare_value;

  /* Configure the N2HET1 pin to output the PWM */
  hetRAM1->Instruction[pHET_L03_0].Control = (hetRAM1->Instruction[pHET_L03_0].Control & 0xFFFFE0FF) |
                                    (NHET1_PIN_PWM << 8);
  hetRAM1->Instruction[pHET_L12_0].Control = (hetRAM1->Instruction[pHET_L12_0].Control & 0xFFFFE0FF) |
                                    (NHET1_PIN_PWM << 8);

  /* Configure the amount of delay before increasing to the next duty cycle */
  hetRAM1->Instruction[pHET_L11_0].Data = ((uint32)RAMPUP_WAIT << 7);
  hetRAM1->Instruction[pHET_L13_0].Data = ((uint32)RAMPUP_WAIT << 7);

  /* Configure the amount of delay before decreasing to the next duty cycle */
  hetRAM1->Instruction[pHET_L19_0].Data = ((uint32)RAMPDOWN_WAIT << 7);
  hetRAM1->Instruction[pHET_L21_0].Data = ((uint32)RAMPDOWN_WAIT << 7);

  /* Duty cycle increment amount */
  if ( (uint32)DELTA_INCREMENT == 0){
    hetRAM1->Instruction[pHET_L12_0].Data = (1 << (7 - LRPFC));
  } else {
    hetRAM1->Instruction[pHET_L12_0].Data = (((uint32)DELTA_INCREMENT) << (7 - LRPFC));
  }

  /* Duty cycle decrement amount */
  if ((uint32)DELTA_DECREMENT == 0) {
    hetRAM1->Instruction[pHET_L17_0].Data = (1 << (7 - LRPFC));
  } else {
    hetRAM1->Instruction[pHET_L17_0].Data = (((uint32)DELTA_DECREMENT) << (7 - LRPFC));
  }

  /* Unlock the N2HET program. Initially after reset the N2HET program is locked */
  hetRAM1->Instruction[pHET_L00_0].Data = UNLOCK_KEY << 7;

 

The way of working is basic. The HET assembler translates your HET program in an array with binary data. One entry per instruction.

But it helps you a little with a custom  that fits your code and allows you to see where the parameters are for each instruction, so that you don't have to perform magic logic.

 

The assembler instruction (as discussed in the previous post , this command is entered in the project pre-build steps:

${HET_COMPILER} -v2 -n0  -hc32 "..\HET_code\Async_PWM_Triangle_Wave.het"

 

The easiest way to get your head around this is by using the flow chart and HET code side by side and trying to follow the logic.

This is doable. Much more difficult (to me) is writing a significant HET program from scratch. That's a challenge I'm going to battle this year.

 

Related Blog
1: adapt TI example to a LaunchPad
2: Generate Dynamic Duty Cycle
3: Measure a PWM Signal and HET Interrupts
4: Getting Started
5: Getting Started with the Wave Form Simulator
Attachments:
TMS570LC43_Async_NHET1_PWM_NHET2_Monitoring.zip
  • Sign in to reply

Top Comments

  • Jan Cumps
    Jan Cumps over 5 years ago in reply to neuromodulator +3
    neuromodulator wrote: There are a couple of advantages in using delta-sigma, it does noise shaping (it pushes noise power to higher frequencies), making it easier to filter it out. Definitely. The triangle…
  • DAB
    DAB over 5 years ago +2
    Good update Jan. DAB
  • Jan Cumps
    Jan Cumps over 5 years ago in reply to jc2048 +2
    HET1 output: digital signal with duty cycle modulation. The same signal, after the RC filter HET2 output. High hen the duty cycle is outside a given range. A full cycle: Rising edge: The lowest point almost…
  • Jan Cumps
    Jan Cumps over 4 years ago

    better late than ...

    I attached the CCS projects for a TMS570LC43 LaunchPad

    • Cancel
    • Vote Up +1 Vote Down
    • Sign in to reply
    • More
    • Cancel
  • Jan Cumps
    Jan Cumps over 5 years ago in reply to neuromodulator

    neuromodulator  wrote:

     

    There are a couple of advantages in using delta-sigma, it does noise shaping (it pushes noise power to higher frequencies), making it easier to filter it out.

    Definitely. The triangle wave here is just a gimmick, to explain how the HET timer can be programmed with visual appealing evidence.

     

    It's more suited as a digital signal generator/sampler. It's at its best as a state machine, and as such can be programmed to act as a UART, I2C or SPI peripheral without CPU involvement (except delivering/retrieving the data).

    But that would make this intro article too complex. Incrementing a duty cycle from 0 to 100% and back is a simple use case that still shows the module can be programmed to do that autonomously.

    • Cancel
    • Vote Up +3 Vote Down
    • Sign in to reply
    • More
    • Cancel
  • Jan Cumps
    Jan Cumps over 5 years ago in reply to Jan Cumps

    You don't have permission to edit metadata of this video.
    Edit media
    x
    image
    Upload Preview
    image

    • Cancel
    • Vote Up +2 Vote Down
    • Sign in to reply
    • More
    • Cancel
  • Jan Cumps
    Jan Cumps over 5 years ago in reply to Jan Cumps

    ... so I changed my code to 54.62:

     

    image

     

    I've filmed a video of the duty cycle increasing. I'll process it and upload (it was too fast for the PC software of my scope so I filmed it with a phone).

     

    image

    • Cancel
    • Vote Up +2 Vote Down
    • Sign in to reply
    • More
    • Cancel
  • Jan Cumps
    Jan Cumps over 5 years ago in reply to jc2048

    The theoretical maximum I have (this is based on the number of instruction the HET processor has to be able to crunch):

     

     

    Clock frequency is 110 MHz, the clock going to HET 75 MHz.

    75 MHz = 13.33 ns

     

    I need a minimal pre-scaler of that clock of 5, that allows for 32 HET clock ticks in one execution loop.

    (unfunny enough HALCoGen shows pre-scaler of 5 as the number 4)

     

    For the HET program here that's enough. It covers the longest (most HET clockticks) flow through the flowchart.

    Prescaler 5 means that bit 5 from right on is set to 1 -> 0x10000 = 16

     

    Means that I can run one loop every 13.33 * 16 = 213.33 ns.

    In that loop (I am unsure about all of the following!) I can generate one edge for a given pin. That is either a rising or falling one.

    So we have 2 cycles for a full pulse, that gives 426.66 ns

    The place where I can put the edge is at one of the available High resolution ticks (75 MHz clock).

    So I have (426.66 / 13.3) = 32 places in a  426.66 ns where I can place the edge. That's 5 bit.

     

    If we slow the LR down with prescaler 6, we divide the clock by 32:

    13.33 ns * 32 = 426.66 ns

    is 853.33 ns per cycle.

    Is a resolution 64 places or 6 bits

     

    The one used in the example from TI has prescaler 7 (clock divided  by 64:

    13.33ns * 64 = 853.33 ns

    is 1706.66 ns

    is a resolution of 128 places is 7 bits

     

     

    image

    So far for the theory if you flip a pin each low resolution loop.

     

    The trick they do, however, is not neccessary flip the bit in a LR loop.

    They calculate the desired time, then calculate how many 13.33 ns ticks are needed. That has to be equal or more than the LR loop time (you can't go faster than that).

    They keep the remaining ticks-still-needed-to-give-you-your-desired-frequency in a register, so even though they can't get a higher resolution as above in the same time,

    they can get more bits resolution (but longer time of one cycle, lower frequency) if they postpone the edges.

    To keep the frequency constant, they have to maintain that running count correct and equal over all the loops.

    It makes their HET program somewhat more complex.

     

     

     

     

    (attention, they use a slightly faster clock, 90 MHz):

     

    /* Change to desired PWM Period in terms of (uS)
     * the default 45.52uS will generate a 12-bit resolution on the PWM
     * with each resolution equal to HR=VCLK2=11.11nS.
     * 45.52uS / 11.11ns = 4096.
     */
    #define PWM_PERIOD    45.52F

     

     

    edit: for me, with my slower clock to get 12 bits, I'd have to do 13.33 * 4096 = 54.62F (must round the last digit UP)

     

     

    I can't be trusted with figures so I will try this out.

    • Cancel
    • Vote Up +2 Vote Down
    • Sign in to reply
    • More
    • Cancel
>
element14 Community

element14 is the first online community specifically for engineers. Connect with your peers and get expert answers to your questions.

  • Members
  • Learn
  • Technologies
  • Challenges & Projects
  • Products
  • Store
  • About Us
  • Feedback & Support
  • FAQs
  • Terms of Use
  • Privacy Policy
  • Legal and Copyright Notices
  • Sitemap
  • Cookies

An Avnet Company © 2025 Premier Farnell Limited. All Rights Reserved.

Premier Farnell Ltd, registered in England and Wales (no 00876412), registered office: Farnell House, Forge Lane, Leeds LS12 2NE.

ICP 备案号 10220084.

Follow element14

  • X
  • Facebook
  • linkedin
  • YouTube