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.

HET PWM Duty Cycle

Other Parts Discussed in Thread: HALCOGEN, TMS470R1B1M, SEGGER

Hi, 

I am trying to understand how to access HET from my application program and update PWM duty cycle. I found an example from TI forums (http://e2e.ti.com/support/microcontrollers/hercules/f/312/t/132571). In this example the file "include/het.h" defines an array of hetRAMBASE_t on line 405. This is an array of 160 elements. Could you please explain how you came up with 160?    

Also in "source/het.c" on line 1600: 

double   period = hetRAM->Instruction[(pwm << 1U) + 42U].Data + 128U;

Please explain how was the indexing obtained in this array? 

I am using this as a reference to implement PWM usin HET on TMS470R1B1M-HT. 

Pinakin 

 

  • Hi Pinakin,   the array size of 160 is due to the device configuration - the HET RAM size is 160 words.

    I don't know exactly what this will be on the TMS470R4B1M-HT but it is normally listed on the first page of the datasheet.

    The R1B1M also has the HET, not the NHET or the N2HET.   So it's different than what you'll find in HalCoGen.   Not different in a 'big picture' way except for the fact that it's got a much smaller memory and maximum LRP.   But different when you start getting into details at the level of:

    Pinakin Potdar said:

    Also in "source/het.c" on line 1600: 

    double   period = hetRAM->Instruction[(pwm << 1U) + 42U].Data + 128U;


    Now, the above example is from HalCoGen, and it refers to the black box N2HET code that comes with HalCoGen.   This is example 'hard coded' HET code to do the things a typical timer might do:  8 PWMs,  8 Input Captures, plus some edge detects.  

    I'm not actually sure of the flow that was used to create this program,  but that's not how you will create your HET program.   You will need to use the HET assembler. 

    The HET assembler will take your HET program and output a .C and a .H file corresponding to your program.   These are files that you will compile into your ARM7 code,  but they include: 

       a) the actual program contents that have to be copied into HET RAM by the ARM7 on startup

       b) data structures  for accessing the HET program symbolically 

    I actually just posted a program -- again for Hercules - but using non-black box driver code - here 

    Instead of the black box code I'm using the headers output by the HET assembler.

    HalCoGen *is* taking care of the initialization for me, but you can see that when using the HET assembler you can access instructions in your code like this  (from sys_main.c in the hcg/source folder...) 

    hetINSTRUCTION_t *pLOOPCNT = &(hetRAM1->Instruction[pHET_START_0]);
    hetINSTRUCTION_t *pPC1ENA = &(hetRAM1->Instruction[pHET_PC1ENA_0]);
    hetINSTRUCTION_t *pPC1RST = &(hetRAM1->Instruction[pHET_PC1RST_0]);
    hetINSTRUCTION_t *pPC1    = &(hetRAM1->Instruction[pHET_PC1_0]);
    hetINSTRUCTION_t *pPC1EXP = &(hetRAM1->Instruction[pHET_PC1EXP_0]);
    hetINSTRUCTION_t *pPC1MIN = &(hetRAM1->Instruction[pHET_PC1MIN_0]);
    hetINSTRUCTION_t *pPC1MAX = &(hetRAM1->Instruction[pHET_PC1MAX_0]);
    hetINSTRUCTION_t *pPC1SUM = &(hetRAM1->Instruction[pHET_PC1SUM_0]);
    hetINSTRUCTION_t *pPC1CNT = &(hetRAM1->Instruction[pHET_PC1CNT_0]);
    
    hetINSTRUCTION_t *pPC2ENA = &(hetRAM1->Instruction[pHET_PC2ENA_0]);
    hetINSTRUCTION_t *pPC2RST = &(hetRAM1->Instruction[pHET_PC2RST_0]);
    hetINSTRUCTION_t *pPC2    = &(hetRAM1->Instruction[pHET_PC2_0]);
    hetINSTRUCTION_t *pPC2EXP = &(hetRAM1->Instruction[pHET_PC2EXP_0]);
    hetINSTRUCTION_t *pPC2MIN = &(hetRAM1->Instruction[pHET_PC2MIN_0]);
    hetINSTRUCTION_t *pPC2MAX = &(hetRAM1->Instruction[pHET_PC2MAX_0]);
    hetINSTRUCTION_t *pPC2SUM = &(hetRAM1->Instruction[pHET_PC2SUM_0]);
    hetINSTRUCTION_t *pPC2CNT = &(hetRAM1->Instruction[pHET_PC2CNT_0]);
    
    hetINSTRUCTION_t *pWC1ENA = &(hetRAM1->Instruction[pHET_WC1ENA_0]);
    hetINSTRUCTION_t *pWC1RST = &(hetRAM1->Instruction[pHET_WC1RST_0]);
    hetINSTRUCTION_t *pWC1    = &(hetRAM1->Instruction[pHET_WC1_0]);
    hetINSTRUCTION_t *pWC1NEW = &(hetRAM1->Instruction[pHET_WC1NEW_0]);
    hetINSTRUCTION_t *pWC1LAST= &(hetRAM1->Instruction[pHET_WC1LAST_0]);
    hetINSTRUCTION_t *pWC1DIFF= &(hetRAM1->Instruction[pHET_WC1DIFF_0]);
    hetINSTRUCTION_t *pWC1EXP = &(hetRAM1->Instruction[pHET_WC1EXP_0]);
    hetINSTRUCTION_t *pWC1MIN = &(hetRAM1->Instruction[pHET_WC1MIN_0]);
    hetINSTRUCTION_t *pWC1MAX = &(hetRAM1->Instruction[pHET_WC1MAX_0]);
    hetINSTRUCTION_t *pWC1SUM = &(hetRAM1->Instruction[pHET_WC1SUM_0]);
    hetINSTRUCTION_t *pWC1CNT = &(hetRAM1->Instruction[pHET_WC1CNT_0]);
    
    hetINSTRUCTION_t *pWC2ENA = &(hetRAM1->Instruction[pHET_WC2ENA_0]);
    hetINSTRUCTION_t *pWC2RST = &(hetRAM1->Instruction[pHET_WC2RST_0]);
    hetINSTRUCTION_t *pWC2    = &(hetRAM1->Instruction[pHET_WC2_0]);
    hetINSTRUCTION_t *pWC2NEW = &(hetRAM1->Instruction[pHET_WC2NEW_0]);
    hetINSTRUCTION_t *pWC2LAST= &(hetRAM1->Instruction[pHET_WC2LAST_0]);
    hetINSTRUCTION_t *pWC2DIFF= &(hetRAM1->Instruction[pHET_WC2DIFF_0]);
    hetINSTRUCTION_t *pWC2EXP = &(hetRAM1->Instruction[pHET_WC2EXP_0]);
    hetINSTRUCTION_t *pWC2MIN = &(hetRAM1->Instruction[pHET_WC2MIN_0]);
    hetINSTRUCTION_t *pWC2MAX = &(hetRAM1->Instruction[pHET_WC2MAX_0]);
    hetINSTRUCTION_t *pWC2SUM = &(hetRAM1->Instruction[pHET_WC2SUM_0]);
    hetINSTRUCTION_t *pWC2CNT = &(hetRAM1->Instruction[pHET_WC2CNT_0]);
    
    
    ....   later in the code .... 
    
    					pPC1ENA->Data = 0U;
    					pPC2ENA->Data = 0U;
    					pWC1ENA->Data = 0U;
    					pWC2ENA->Data = 0U;
    					dly200loop();
    
    					pPC1->Program = ((pPC1->Program) & 0xFFFFFF00U) | (pc1_types[test])<<6 | pc1_pins[test];
    					pPC2->Program = ((pPC2->Program) & 0xFFFFFF00U) | (pc2_types[test])<<6 | pc2_pins[test];
    					pWC1->Control = ((pWC1->Control) & 0xFFFFE09FU) | (wc1_types[test])<<5 | wc1_pins[test] << 8;
    					pWC2->Control = ((pWC2->Control) & 0xFFFFE09FU) | (wc2_types[test])<<5 | wc2_pins[test] << 8;
    

    Now, hetInstruction_t is declared in a header file from HalCoGen 'reg_het.h' but you can copy it to your non HalCoGen project, it's simply 

    /** @struct hetInstructionBase
    *   @brief HET Instruction Definition
    *
    *   This structure is used to access the HET RAM.
    */
    /** @typedef hetINSTRUCTION_t
    *   @brief HET Instruction Type Definition
    *
    *   This type is used to access a HET Instruction.
    */
    typedef volatile struct hetInstructionBase
    {
        uint32 Program;
        uint32 Control;
        uint32 Data;
        uint32   rsvd1;
    } hetINSTRUCTION_t;
    

    Same sort of thing goes for hetRAM1 which is just the address of the HET's RAM  ... the dual-port RAM used for both HET program execution and data storage as well as for communicating between the HET and the ARM7 core.

    The key thing that you get from the HET assembler is that the .h file it outputs for you includes macro definitions for each instruction in your HET program, using the LABEL from the assembly language program as the name of the macro.   

    For example:  pHET_WC1NEW_0  is a # define output by the HET assembler and corresponding to the index of the instruction in my program with the label "WC1NEW'  ..  which is a label that I put on a WCAP instruction.


    So when I want to initialize the data field of this WCAP instruction to 0,  I just have to write  pWC1ENA->Data = 0U;  and this will be correct even if I add / remove instructions to the HET program and the actual address of that WCAP instruction changes.

    Also if I want to change the behavior of the WCAP instruction, I can set/clear bits in it's Control or Program fields as well (best done while the HET is not executing these instructions)  

    For example by modifying the Program word of the PCNT instruction below: 

    					pPC1->Program = ((pPC1->Program) & 0xFFFFFF00U) | (pc1_types[test])<<6 | pc1_pins[test];

    We can switch out which pin it is counting and what type of PCNT to use (RISE2RISE, RISE2FALL, etc... )

    This is all N2HET stuff, but in the big picture you'll find equivalents for HET on the R1B1M.

  • Anthony,

    Thanks for this information. I have implemented my first HET code (using assembler). Here is the code:

    PWM freq = 4KHz,
    SysClk = 48 MHz,
    LR = 1,
    HR = 48


    het.het file:

    ; Configure the virtual counter
    L00: CNT {next=L01, reg=A, irq=OFF, max=250, data=0}
    ; Pulse the HET0 pin
    L01: ECMP {next=L00, reg=A, hr_lr=LOW, en_pin_action=ON, pin=CC0, action=PULSEHI, irq=OFF, data=250}

    When this code is passed through assembler then it created a het.c and het.h file.


    het.h file:

    #define HET_L00_0 (e_HETPROGRAM0_UN.Program0_ST.L00_0)
    #define HET_L01_0 (e_HETPROGRAM0_UN.Program0_ST.L01_0)

    #define PWM_FULL_OFF_COUNT 250
    #define PWM_FULL_ON_COUNT 0

    typedef union
    {
    HET_MEMORY Memory0_PST[2];
    struct
    {
    CNT_INSTRUCTION L00_0;
    ECMP_INSTRUCTION L01_0;
    } Program0_ST;

    } HETPROGRAM0_UN;

    extern volatile HETPROGRAM0_UN e_HETPROGRAM0_UN;

    extern const HET_MEMORY HET_INIT0_PST[2];




    Here is het.c file:

    #include "std_het.h"

    HET_MEMORY const HET_INIT0_PST[2] =
    {

    /* L00_0 */
    {
    0x00001600,
    0x000000FA,
    0x00000000,
    0x00000000
    },

    /* L01_0 */
    {
    0x00000080,
    0x00102018,
    0x00001F40,
    0x00000000
    }
    };


    I understand that the structure for each label is 4 int32 values (Program/Control/Data/Reserved). On page 31 of "TMS470R1x High End Timer (HET) Reference Guide SPNU199D" there is a table where it indicates that for LR = 8 the lower 2 bits of HR (Bit 0 and bit 1) are ignored (only top 3 bits are valid). So for label L01 in het.het the data value is 250 (data=250). This has to be shifted left by 2 bits so it can be multiplied by 4 which is 250 * 4 = 1000 (0x03E8). But this is not what the data value reflects in het.c. Instead I see a value of 0x00001F40 - which is shifted left by only 1 bit (250 * 2 = 500 = 0x1F40).

    Why is the value shifted by only 1 bit? Is there something that I am missing?

    Pinakin
  • Anthony,

    One more question regarding the above details I provided. the label L01 specifies data = 250, why is hr_data not specified. The value of hr_data is the lower 5 bits of DATA word in L01_0 structure. So is it the lower 5 bits of data value specified in ECMP instruction?

    Pinakin
  • Hi Pinakin,

    It might be time to start posting these questions to the Hi-Rel forum ...  I don't have the SM470R1B1M docs handy.

    But going by memory on the TMS470R1x HET the loop resolution maxes out at /32 of the HR clock and not at /128 like on the N2HET.

    So you need to know where the division line is between the LR and the HR.   On the N2HET where the loop resolution period can go up to /128 of the high-res clock,  the N2HET uses a 25.7 fixed point notation.  

    Meaning that when you look at the 32-bit value for the data field -  (which is what you see in the .C file generated by the HET assembler) you have to think about it as a 25.7 fixed point number.    

    To give some examples (N2HET not HET):  

    0x0000 0080  is 1.0 loop resolution clocks.

    0x0000 00C0  is 1.5 loop resolution clocks     (1 + 1/2 )

    0x0000 00E0  is 1.75 loop resolution clocks  (1 + 1/2 + 1/4)

    0x0000 00F0  is 1.875 loop resolution clocks (1 + 1/2 + 1/4 + 1/8)

    0x0000 01F0  is 3.875 loop resolution clocks (2 + 1 + 1/2 + 1/4 + 1/8).

    So sometimes you'll see where we talk about the loop resolution field being shifted by 7 (<<7) or (I *think* - please confirm ) << 5 on the HET.

    In the example above,  3 << 7 is 0x0000 00180 and this is the 'whole number' of loop resolution periods.   It's what goes in the 'data=' field of the HET.

    The hr_data field gets the fractional part.    That's where it gets tricky in HET assembler, because if you want 1/2 this is 0x40  (1 << 6).

    The 250 in the CNT instruction is *always* the loop resolution value.   CNT doesnt' take a hr_data value.  It always counts whole numbers of loop clocks.

    But the ECMP can work in hi-res mode.   So basically, it executes once per loop, and compares it's loop resolution value against the loop resolution value of CNT.   if they match, then the ECMP schedules a pin action for the next loop resolution clock boundary.

    The hi-res capability of ECMP gives it the ability to schedule not just at the next loop resolution boundary - but at the loop res boundary plus some offset.  
    This offset is measured in terms of HR clocks and the action is handed off to a small hardware counter in the high-res structure for each pin to manage the delay.

    If you want to specify the lower 5 bits,  you do it separately using the 'hr_data=' parameter for the ECMP instruction.  You also may need to set it for hr_lr = HIGH.  In reality all these fields go into the HET RAM but when you write HET assembler, a lot of the fields are 'optional' and if you leave them out of the assembler, then the assembler sets them to a default value.   For the hr_data field I believe this is almost always optional so you won't get assembler errors if you don't specify it, instead the assembler just sets the field to zero.  But try adding   'hr_data=0x40' to your code on the ECMP and see what the result is.. 

     

  • Anthony,

    This was helpful. I understand that the value is shifted by 5. My question was the validity of bits is decided based on the LR value. There is a table where it shows that for LR = 1, the HR bits (for TMS470R1B1M HR has 5 bits) bits 0 - 4 are all ignored. For LR = 2 HR bits 4 is valid. For LR = 4, bit 3 and bit 4 are valid. So my data is shifted based on LR value. I just wanted to check this with you.

    Sorry for the confusion. I verified my question by changing some values in het.het file. Thank you again for prompt responses. 
     
    Pinakin

  • Hi Pinakin,

    Sorry if I didn't understand your question.  But I think we're almost there...

    You can imagine that if the weights are:

    data[5] = 1 LRP

    data[4] = 1/2 LRP

    data[3] = 1/4 LRP

    data[2] = 1/8 LRP

    data[1] = 1/16 LRP

    data[0] = 1/32 LRP

    Then take the case where LR is set to 4 HR clocks.  The HET only schedules to HR clock resolution.   HR = 1/4 LR in this example.
    So it makes sense that data[4:3] are significant when scheduling a hi-res offset, but also that data[2:0] are ignored because they represent time intervals faster than an HR clock period. 

    On the other hand, if you set LR to be 16 HR clocks, then data[4:1] are significant and only data[0] is ignored.*   

    Finally, when you set LR to the maximum of 32 HR clocks, all your fraction bits data[4:0] are significant. 

    *Note: while we *could* probably have implemented rounding, we simply truncate... 

  • Hi Anthony,

    You have been great help. I understand this now. By the way I am having another issue with HET. When I load the program onto my hardware, at the end of HET initialization code when I turn on HET (by setting the ON bit in HETGCR) my code crashes. I am using IAR with segger J-Link. Here is my HET init code:

    __no_init volatile HETPROGRAM0_UN e_HETPROGRAM0_UN @ 0x800000;
    static void MemCopy32(unsigned long *dst, unsigned *src, int bytes)
    {
    for (int i = 0; i < (bytes + 3) / 4; i++)
    *dst++ = *src++;
    }

    void Init_HET(void)
    {
    HETGCR = CLK_MASTER + IGNORE_SUSPEND; // Disable HET & configure as master

    MemCopy32((void *) &e_HETPROGRAM0_UN, (void *) HET_INIT0_PST, sizeof(HET_INIT0_PST));

    HETPFR = LRPRES_FACTOR_1 + HRPRES_FACTOR_48; // Set the PFR register (LR=1,HR=48)
    HETDIR = HETDIR0; // Set the pin directions
    HETGCR |= ON; // Enable HET
    }


    The moment I turn on HET in the last statement of Init_HET() the program crashes. If I comment out that line then the program runs fine. Any idea what I might be doing wrong here.

    Pinakin
  • Hi Pinakin,

    Great. Sorry I'm not that familiar with the R1B1M.

    But since you have a memcopy in the Init_HET code I'd think there could be a possibility of a pointer problem.
    If this trashes the stack, then you'd see the crash occur when you exit the function.
    So maybe assembly step through the exit of the Init_HET function - and keep careful note of which values
    are being read from the stack. If they look corrupted, then you can restart the program and try to find where the corruption occurs.
  • Anthony,

    I figured that I am doing something wrong with my HET code in het.het. I have changed my code as follows:

    het.het:

    ; Implement a counter that uses register A and rolls over at 250 (0xFA)

    L00: CNT  {next=L01, reg=A, irq=OFF, max=250, data=0}

    ; PWM (0% duty cycle)

    L01: ECMP {next=L02, reg=A, hr_lr=LOW, en_pin_action=ON, pin=CC0, action=PULSELO, irq=Off, data=250}

    ; When count reaches 0, trigger interrupt. Now the ISR loads

    ; a new data value into the MOV32 instruction.

    L02: ECMP {next=L03, reg=A, hr_lr=LOW, en_pin_action=OFF, pin=CC0, cond_addr=L03, irq=ON, data=0x0 }

    ; When count reaches 250 (0xFA), load the next

    ; ECMP compare value used for PWM generation.

    L03: ECMP {next=L00, reg=A, hr_lr=LOW, en_pin_action=OFF, pin=CC0, cond_addr=L04, irq=OFF, data=250 }

    ; Load ECMP data value with the value stored

    ; in the MOV32 instruction

    L04: MOV32 {next=L00, remote=L01, control=OFF, init=OFF, type=IMTOREG&REM, reg=NONE, data=0x0, hr_data=0x0} 

    I have enabled the HET 1 interrupt as follows:

    void Init_HET(void)
    {

    HETGCR = CLK_MASTER + IGNORE_SUSPEND; // Disable HET & configure as master
    // Copy the HET instructions to HET RAM
    MemCopy32((void *) &e_HETPROGRAM0_UN, (void *) HET_INIT0_PST, sizeof(HET_INIT0_PST));
    HETPFR = LRPRES_FACTOR_1 + HRPRES_FACTOR_48; // Set the PFR register (LR=1,HR=48)
    HETPRY = HETPRY2; // Instruction 0 interrupt is high priority
    HETDIR = HETDIR0; // Set the pin directions
    HETGCR = CLK_MASTER + IGNORE_SUSPEND + ENABLE_HET; // Enable HET

    }

    void HET_IrqHandler (void)
    {
    static int iToggle = 0;
    iToggle = !iToggle;

    switch ((HETOFF1 & 0xff) - 1)
    {

    case 2 : // Int on instruction 0
    if(iToggle)

    HET_L04_0.memory.data_word = (0x01FFFFE0) & (pwmHighCount << 5);
    break;

    }

    }

    I am toggling the value in pwmHighCount  between 40% and 75% after few seconds. When I run the program, the scope shows the output = 0 all the time. Any idea if I am doing anything incorrect here. 

    Here is the function which updates PWM (this function is triggered every ~0.5sec). 

    static void HEATER_SetPWM(uint8_t data)
    {
    static int iChange = 15;
    static uint8_t val = 250;
    if(iChange-- <= 1)
    {
    iChange = 15;
    if(val < 100)
    val = 150; // 40%
    else
    val = 63; // 75%
    }
    data = val;

    __disable_interrupt();
    pwmHighCount = (uint16_t)data;
    __enable_interrupt();
    }

    Thanks. 

  • Pinakin,

    You might try simulating your code in the HET IDE, selecting the TMS470MF0xx07 device. This has the "HET". I doubt it is the *exact* same as what you have on the R1B1M because it is most likely a newer revision of the module, but it's the same module (as opposed to NHET or N2HET which are different modules).

    The code seems a bit odd to me in the sense that you shouldn't need to use multiple ECMPs for this job.

    I'd probably try something roughly like this:

    CNT
    BR (event = zero) to ECMP
    MOV64 - update CNT instruction
    MOV32 - update ECMP instruction
    ECMP

    The CNT instruction will set the Z flag when the count reaches it's max value and resets to zero.
    At this time you can test for Z and if it is set, execute the MOV64 and MOV32 instructions to update the period (CNT)
    and duty cycle (ECMP) values respectively.

    Note that the CNT instruction *control* field is where MAXCNT lives so you'll need to write your buffered count max value to the control field, and the data field of that mov64 should be left 0. The MOV32 that updates the ECMP to the data field since this is where ECMP stores the value that it is comparing.

    The BR, MOV64, and MOV32 are not supposed to modify the Z flag. So the Z flag when ECMP should be still the value set by CNT, and this is critical for making the 'opposite action' work. Opposite action comes with PULSEHI and PULSELO types, these set the pin when ECMP matches the compare value but reset the pin when the Z flag is set. (Whereas CLEAR and SET types don't do the reset on Z flag).

    -Anthony
  • Anthony,

    I looked at the memory location of HET RAM and the values seem to be updating the first ECMP instruction which should be generating PWM output. So I believe the HET code is good but for some reason the pin is not outputting the signal. In Init_HET() function I do set the pin direction. I have copy - pasted the code for Init_HET once again below. Is there anything else you can think of which is preventing it from outputting the signal on HET[0] pin (Pin73)?

    Please note I have attached a screenshot of HET RAM memory when the program was running and was about to update PWM to a new value. 7571.HET_RAM_Memory.docx

    void Init_HET(void)

    {

     HETGCR        = CLK_MASTER + IGNORE_SUSPEND;                          // Disable HET & configure as master

     // Copy the HET instructions to HET RAM

     MemCopy32((void *) &e_HETPROGRAM0_UN, (void *) HET_INIT0_PST, sizeof(HET_INIT0_PST));

     HETPFR        = LRPRES_FACTOR_1 + HRPRES_FACTOR_48;                   // Set the PFR register (LR=1,HR=48)

     HETPRY        = HETPRY2;                                              // Instruction 0 interrupt is high priority  

     HETDCLR       = HETDOUT0;

     HETDIR        = HETDIR0;                                              // Set the pin directions

     HETGCR        |= ENABLE_HET;                                          // Enable HET  

    }

    Is there a way to toggle HET[0] pin to see if the HET pin works or is configured correctly (I am guessing HETDSET and HETDCLR can be used)? Can you give me some example or any idea how I can use it to toggle HET pin 0? Your help is very much appreciated. 

    Thanks. 

     

  • Hi Pinakin,

    Yes you can use the DSET and DCLR registers. The HET module doesn't have dedicateds GIO versus Functional mode though, so you might set the pin (or clear it) using the GIO register and then the HET might undo that action almost immediately. So you could first try toggling the pin through the GIO registers before you start the HET executing it's program. Or make sure you have a scope on the pin and you can catch a very short event.

    I'd still suggest the simulator. Just because the MOV instruction updates the ECMP data field, this doesn't mean that the CNT instruction ever gets to the compare value or that the compare ever triggers. These things are best seen on the simulator.
  • Anthony,

    I did a quick test with HETDCLR/HETDSET and was able to see the pin output toggle. I also understand there is Static Memory Control Reg 1 SMCR1 for HET RAM access. Is this something that I have to set in the code (assuming it should be in HET initialization). Could you please share any examples on this?

    I will try out the simulator next.

    Pinakin
  • Hi Pinakin,

    Yes, I think you need to setup things *like* the SMCR register - this is in the category of device initialization.
    For me it's been way too long since I worked in the R1X series - the folks on the hi-rel forum should be best suited to help w. any questions about the system module (where SMCR lives).

    But if you had a problem in the system module usually you wouldn't be able to access the HET at all. Or you wouldn't be able to access it's RAM.
    (I think the HET registers use a peripheral frame and the RAM uses something like a 'peripheral ram chip select' in the system). When you earlier reported the debugger hanging .. that's the kind of problem that you'd run into if you don't have the system module up. Or maybe you'd just read 0's / writes wouldn't stick....

    However - now it sounds like you can access both of these things though. And if that is the case - then I think the problem is more likely in the HET code - something you can most easily figure out w. the simulator.

    When you get the HET IDE, you *might* also need two patches: txn.box.com/het-patches
    See this thread: e2e.ti.com/.../1385889 for details.
    Basically the HET front end and back end talk to each other over a TCP/IP port and in the distribution that port # is hardcoded.
    If your machine has something else setup on that port # - the distribution won't work. The patches just make the IDE find an open port by asking the OS instead of using a hard-coded port.
  • Anthony,

    I am new to HET IDE. I am trying to simultate my test code in HET IDE. I added my new code as follows:

    ; LR = 1    HR = 48

    ; Implement a counter that uses register A and rolls over at 249 (0xF9)

    L00: CNT  {next=L01, reg=A, irq=OFF, max=249, data=0}  

    L01: ECMP {next=L00, cond_addr=L02, en_pin_action=ON, pin=CC0, action=PULSEHI, reg=A, irq=Off, data=150, hr_lr=LOW}

    ; Load ECMP data value with the value stored in the MOV32 instruction    

    L02: MOV32 {next=L00, remote=L01, type=IMTOREG&REM, reg=NONE, data=248, hr_data=0, control=OFF, init=OFF}  

    In HET IDE I selected the device TMS470MF0XX07. The attached document shows screenshots of my steps and the waveform output.  3252.HET_IDE_output_1.docx

    1. I am not sure how to interpret the waveform. Could you please explain how I infer the PWM output

    2. On the top right corner it shows HR = 1 and LR = 32. How do I change this? I wanted to set HR = 48 and LR = 1. 

    Note: I have tried this code in my IAR project and I do see the memory locations being updated and the counter running from 0x00000000 to 0x00001F40 (which is 0 through 249 << 5 as LR = 1). Also the value is copied from MOV32 data to ECMP data when the compare matches. So I suppose the counter and compare and move instructions are fine but yet there is no output on the HET0 pin. Please help. 

    Alright, I think I understand now how the waveform works. It was outputting 0% PWM all the time from MOV32 Data. So now I modified the value in Mov32 data and I do see the varying PWM. I do see the output in the waveform (8233.HET_IDE_output_2.docx)  but this does not show anything on my code when I load it onto hardware. 

    Thanks 

  • Pinakin,

    Hi, your 2nd picture definitely looks better.

    If you right click on the  watch_out[31:0] bus and select "Show Bus Member Signals" it'll expand the bus to individual pins. That's usually easier to interpret than viewing all the HET pins as a bus.

    But already you can see the Z flag being set periodically in your simulation (The CNT rolling over) and the pin outputs changing.

    For better or worse the pins are disjointed in the simulator meaning that there is no connection between watch_in and watch_out.   on the real device if you drive the pin high or low and it's configured as an output, you also see the input value of the pin toggling to match the output.   In the HET IDE there's no connection - just keep that in mind for later.

    To change the HR divider, you need to double click in the HET registers and change the value of the 'PFR' register.   Other behaviors of the HET can also be changed by modifying the register values.   They're somewhat 'sticky' - between runs in the same project the register values are saved in a file somewhere in the project folder.  So you only have to set these once.  

    Anyway there's a bit of a learning curve but you're ramping fast now.    Try stepping through the code or putting breakpoints at key locations as well.  You might even set a different conditional address for the ECMP (even though it's not required for your program) just to have a place you can break on only when the compare matches. 

  • Anthony,

    Thanks for prompt response. I looked at the signal members and still not sure what is wrong with the output. I do see the compare match happpen successfully (I enforced the value in counter to a value close to compare value and then stepped through. When the value matches it goes to MOV32 instruction and loads the new value from mov32 into ECMP. So I do see the code execution happening the way I expect it to but still the output is not correct. Do you see anything wrong with my logic or is there something I would be missing with the pin settings?

    Attached is the new output and it still continues to show Z condition in the waveform output 5023.HET_IDE_output_3.docx

    Pinakin 

     

  • Hi Pinakin,

    From your output_2.docx file, it looked to me like a pin was toggling, but you're right I don't see it in output_3.docx.

    Maybe the duty cycle got reset to 0% again?   If not - do you see the DOUT register toggling as you step through the code?

  • Anthony,

    I had incorrect values for the HR/LR resolution. I do see the simulated output now changing with the PWM value I set. Also I do see the value in ECMP matched with that of CNT and then it loads the new value from MOV32 data. So the simulation does show that my HET code is right. Yet I do not see the output on HET 0 pin when I run my code.

    I suppose I am doing incorrect calculations for the MAX value in CNT() and for the data values that go into ECMP. Can you verify if my understanding is correct here.  I am attaching an excel sheet (2330.HETComputations.xlsx) which shows the formulas in grey color and there are comments in red. I am mainly concerned about

    1. the value that goes in CNT instruction max field (this corresponds to the formula on line 17 of spreadsheet) and

    2. the maximum value (for 0% PWM) that goes into the ECMP or MOV32 data field (this corresponds to line 19 of spreadsheet).

    I have noticed that with certain combinations of LR and HR values the For LR=8 and HR=1 the CNT_MAX value is less that the data value fed into ECMP data field. So CNT never reaches the ECMP value and so there is no compare match.

    Is my calculation wrong?

    Also now that I see that simulation works but I do not see the output on hardware - can you think of anything I am missing? 

    Pinakin

  • Pinakin,

    The value for CNT max is already in units of LRP. So in your calculation for PWM Duty,
    when you multiply again by LR .. that's wrong I think. The obvious indicator is that the duty cycle 'count'
    of 12000 comes out greater than the period 1499.

    If I remove the *B5 from the formula then it comes out as 1500 for 0% and 0 for 100%.
    You need to examine the cases of 0% and 100% carefully - so I'll neglect getting into them for now.
    But these are special cases as the pin may never take the action or the action and opposite action might
    wind up occurring together (in which case one takes precedence). So always test 0%->100% and 100%->0%.
    You might find a problem there. The easiest fix is to not take this transition and always go 0% -> 99% -> 100%
    or 100% -> 1% -> 0% or the like. There's another post on this forum w. the same discussion but with regard to the
    blackbox driver for N2HET in HalCoGen.

    Now, the value 5DB (1499) and 5DC (1500) measured in LRP get << 5 when written by the *CPU* into the RAM.
    But if you use the HET ASSEMBLER they are separate fields in the instruction, so you'd still write 'data=1499' in the assembler.
    The assembler will shift the data (initial settings) for you.

    At run time when you update via the CPU, then you need to << 5.

    -Anthony
  • Anthony, 

    I think I see what is happening. On our board we have a I2C4SCL pin connected to switch input which controls the HET-0 pin output to the heater module. When I set up HET for PWM output, I do not see anything on the HET0 pin but there is an output on the I2C4SCL line. One thing I can think of is that the I2C4SCL pin is not properly configured for GPIO output function. Is there an example or any document listing the steps to do this? 

    Pinakin 

     

  • Hi Pinakin,

    If you just need to set the I2C pin as a GIO, there is probably a GIO control register inside the module.
    On the R1x series, the GIO functions are distributed within each module if memory serves me.
    But this type of question I'd definitely pose to the Hi-Rel forum - they're more current on the R1x product there.
  • Anthony,

    Can you give me the link to the forum you mentioned.

    Pinakin
  • Oh, sorry. We used to have a note in the forum header saying that if you have a SM470R1x Question post to the High Reliability forum and a link.
    Looks like that link is gone now - probably after the forum face-lift that happened.

    Here's the link: e2e.ti.com/.../hirel
  • On the R1x I2C module, there is a single bit (bit # 0) in the I2CPFNC (Pin Function) Register at offset 0x48 to control this functionality. This bit is set by default so that the SCL and SDA pins are general-purpose I/O pins. You must be clearing this bit somewhere in your I2C module initialization code.

    Sunil
  • Sunil,

    I am using HET pin 0 to output a pwm signal. I am not seeing the correct output and not on the right pin. Here are the details of the tools I use:

    Controller = TMS470R1B1M-HT.

    IDE = IAR EW ARM. 

    There is a 6 MHz crystal connected to TMS470. In the clock initialize I set GCR.MULT4 bit to zero so SYSCLK = 8 * 6MHz = 48 MHz. 

    Here is the clock initialize routine:

    void Init_SCLK(void)
    {
       PCR = CLKDIV_1;                                       // ICLK = SYSCLK
       GCR = ZPLL_CLK_DIV_PRE_1;                   // SYSCLK = 8 x fOSC(6MHz) = 48MHz
       PCR |= PENABLE;                                      // Enable peripherals

    The HET program for generating PWM signal for HET-0 pin (pin 73) is as follows:

    File het.het:

    ; Heater PWM (250us period) Default to PWM=OFF duty cycle

    ; LR = 1, HR = 48, PWM Freq = 4KHz,

    ; Implement a counter that uses register A and rolls over at 249 (0xF9)
    L00: CNT {next=L01, reg=A, irq=OFF, max=249, data=0}

    ; PWM (0% duty cycle)
    L01: ECMP {next=L00, cond_addr=L02, en_pin_action=ON, pin=CC0, action=PULSEHI, reg=A, irq=Off, data=150, hr_lr=LOW}

    ; Load ECMP data value with the value stored in the MOV32 instruction
    L02: MOV32 {next=L00, remote=L01, type=IMTOREG&REM, reg=NONE, data=248, hr_data=0, control=OFF, init=OFF}

    I verified the code by running it in HET IDE simulator and it seems to give right outputs in the simulator. The HET initialization code is as follows:

    void Init_HET(void)
    {
       HETGCR = CLK_MASTER + IGNORE_SUSPEND;                               // Disable HET & configure as master
       
       MemCopy32((void *) &e_HETPROGRAM0_UN, (void *) HET_INIT0_PST, sizeof(HET_INIT0_PST));
       HETPFR = LRPRES_FACTOR_1 + HRPRES_FACTOR_48;                  // Set the PFR register (LR=1,HR=48)
       HETPRY = HETPRY2;                                                                          // Instruction 0 interrupt is high priority
       
       HETDIR = HETDIR0;                                                                            // Set the pin directions

       HETGCR |= 1;                                                                                       // Enable HET

    I have attached a file (1680.HET_Issue_1.docx) which shows in figure 1 that a 6 MHz crystal is connected to TMS470. The figure 2 shows HET0 pin which is connected to a level shifter and a I2C4SCL (pin 40 on controller) is connected to a MOSFET gate which can control the output of HET0 pin. 

    When I run my program I do not see anything on HET0 pin but I see a owm signal on I2C4SCL pin (pin 40 on controller). The signal on I2C4SCL is showing the PWM signal but it is streched on time. Instead of 48MHz frequency it is 19.73milliHz. 

    Any idea what is wrong here. Please help. 

    Pinakin 

     

  • Please ignore my questions above. I figured out the problem.

    Thank you.