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.

CCS/TMS320F280049C: Assembly testing function of Xtal clock drift integrity

Part Number: TMS320F280049C

Tool/software: Code Composer Studio

Dear support team, 

     I am trying to implement a simple test function for Xtal frequency drift with the help of the timer2 and OSC2 as described in the TI safety pack, file: STL_oscillator_test.c. I would like to perform this test in the beginning of the boot file, so I am doing this in assembly, together with other basic checks like register testing, etc.

   I am facing an issue, hope is something easy to solve. The routine is attached below. Before this routine I disable watchdog, test CPU registers, configure couple of GPIO, and set PLL to generate a SYSCLK of 100Mhz out of OSC2.

 The issue is: if I place a breakpoint on the BREAKPOINT1 position (please check code below), the TIM count is as expected: 0xFFEB  (It went from 0xFFFF to 0xFFEB) that is 20 counts. Since XTAL used is 20Mhz, it results 5 times lower than actual PLL OSC2 running at 100Mhz. And the timer has a div /2 set on pre-scaler.

  But if I DISABLE BREAKPOINT1, and ENABLE breakpoint on the BREAKPOINT2 position, the TIM count is 0xFF78, which is far from the 20 counts expected.

   Funny thing is that if I comment out the  NOP and the next RPT #TEST_COUNT_NOPs || NOP line, no matter where I place the breakpoint, it always work as expected (count of 0xFFF0 which is 15 counts as expected). This lead me to think that there is maybe an issue with the pipeline that I am not understanding....

   Thanks in advance for your kindly help!

Regards,

Alberto Peyro

This is my  test routine:

__CPUREG_SYS				.usect "CpuSysRegsFile",0
TMR2CLKCTL					.set	0x7C 		
__TIMER2_REGS .usect "CpuTimer2RegsFile",0
TEST_COUNT_NOPs .set 49
TIM .set 0x00 PRD .set 0x02 TCR .set 0x04 TPR .set 0x06 TPRH .set 0x07 .section .text ;******************************** ;******************************** ;CHECK RELATIVE XTAL FREQUENCY ;WITH TIMER2 _Xtal_Clock_Drift_Test: MOVL XAR4,#__TIMER2_REGS MOVL XAR5,#(__CPUREG_SYS+TMR2CLKCTL) ;configure timer 2 to perform test MOV *+XAR4[TPR],#1 MOV *+XAR4[TPRH],#0 MOV *+XAR4[PRD],#0xFFFF MOV *+XAR4[PRD+1],#0xFFFF MOV *+XAR4[TCR],#0x0000 OR *+XAR4[TCR],#0x0020 ; reload timer NOP ;set XTAL clock to feed the timer2 EALLOW MOV *XAR5,#0x0000 OR *XAR5,#0x0003 ;select Xtal as input clock for timer2 NOP EDIS ;fire timer DINT ;disable maskable interrupts AND *+XAR4[TCR],#~0xffef ;wait some cycles RPT #TEST_COUNT_NOPs || NOP RPT #TEST_COUNT_NOPs || NOP RPT #TEST_COUNT_NOPs || NOP NOP RPT #TEST_COUNT_NOPs || NOP ;stop timer MOV *+XAR4[TCR],#0x0000 NOP ; <---------- BREAKPOINT 1 ;check if timer overflowed MOVL ACC,*+XAR4[TCR] OR ACC,#1 ; <-------- BREAKPOINT 2

  • Alberto,

    It is Thanksgiving week in US. Most of the TI engineers are on vacation. Please expect delay in response.

    I would realistically expect a response back from TI early next week.

    Regards,
    Manoj
  • Hello Manoj thanks for the advise :)
  • Alberto,

    I'm not actually seeing the timer issue you describe, but I do have a couple of observations on the code:
    Line 27: OR *+XAR4[TCR],#0x0020 ; reload timer
    ...does reload the timer, but the timer is also set running because the TSS bit is written as 0. Consecuently line 39:
    AND *+XAR4[TCR],#~0xffef
    ...doesn't do anything. Be careful with atomic operations like AND and OR when used with registers: this line will read the register, AND it with the mask, and then write back. Since the timer is running, TSS will read as '0', so the AND with '1' results in writing '0' back to the register which starts an already running timer.

    In the later line 49:
    MOV *+XAR4[TCR],#0x0000
    ...you are not stopping the timer because, again, you are writing 0 to the TSS bit. You need to write #0x0010 to stop the timer.

    Regards,

    Richard
  • Hello Richard,

    Thanks for answering and sorry for disturb your holidays :) I had labels on the Masks that I replaced with numbers when opening the ticket and seems I did a mess doing the substitution!

    in line 27 my code has: OR *+XAR4[TCR],#(DISABLE_TIMER+PERFORM_RELOAD) with DISABLE_TIMER .set 0x0010 and PERFORM_RELOAD .set 0x0020, so it should translate to OR *+XAR4[TCR],#0x0030

    in line 39 my code has: AND *+XAR4[TCR],#~DISABLE_TIMER which translate to AND *+XAR4[TCR],#~0xffef which is correct

    and in line 49, my code has: MOV *+XAR4[TCR],#DISABLE_TIMER with DISABLE_TIMER .set 0x0010

    Sorry for the confusion. With the above modifications you still see no issue as I described?


    I placed a breakpoint on line 39, before fire the timer, and collect the relevant register for your reference:

    521177 40
    R ClkCfgRegs_CLKCFGLOCK1 0x0000000B 0x00000000
    R ClkCfgRegs_CLKSRCCTL1 0x0000000B 0x00000000
    R ClkCfgRegs_CLKSRCCTL2 0x0000000B 0x00000004
    R ClkCfgRegs_CLKSRCCTL3 0x0000000B 0x00000000
    R ClkCfgRegs_SYSPLLCTL1 0x0000000B 0x00000003
    R ClkCfgRegs_SYSPLLMULT 0x0000000B 0x00000014
    R ClkCfgRegs_SYSPLLSTS 0x0000000B 0x00000001
    R ClkCfgRegs_SYSCLKDIVSEL 0x0000000B 0x00000001
    R ClkCfgRegs_XCLKOUTDIVSEL 0x0000000B 0x00000003
    R ClkCfgRegs_LOSPCP 0x0000000B 0x00000002
    R ClkCfgRegs_MCDCR 0x0000000B 0x00000000
    R ClkCfgRegs_X1CNT 0x0000000B 0x000003FF
    R ClkCfgRegs_XTALCR 0x0000000B 0x00000004
    R CpuSysRegs_CPUSYSLOCK1 0x0000000B 0x00000000
    R CpuSysRegs_PIEVERRADDR 0x0000000B 0x003FFFFF
    R CpuSysRegs_PCLKCR0 0x0000000B 0x00000039
    R CpuSysRegs_PCLKCR2 0x0000000B 0x00000000
    R CpuSysRegs_PCLKCR3 0x0000000B 0x00000000
    R CpuSysRegs_PCLKCR4 0x0000000B 0x00000000
    R CpuSysRegs_PCLKCR6 0x0000000B 0x00000000
    R CpuSysRegs_PCLKCR7 0x0000000B 0x00000000
    R CpuSysRegs_PCLKCR8 0x0000000B 0x00000000
    R CpuSysRegs_PCLKCR9 0x0000000B 0x00000000
    R CpuSysRegs_PCLKCR10 0x0000000B 0x00000000
    R CpuSysRegs_PCLKCR13 0x0000000B 0x00000000
    R CpuSysRegs_PCLKCR14 0x0000000B 0x00000000
    R CpuSysRegs_PCLKCR15 0x0000000B 0x00000000
    R CpuSysRegs_PCLKCR16 0x0000000B 0x00000000
    R CpuSysRegs_PCLKCR17 0x0000000B 0x00000000
    R CpuSysRegs_PCLKCR18 0x0000000B 0x00000000
    R CpuSysRegs_PCLKCR19 0x0000000B 0x00000000
    R CpuSysRegs_PCLKCR20 0x0000000B 0x00000000
    R CpuSysRegs_PCLKCR21 0x0000000B 0x00000000
    R CpuSysRegs_LPMCR 0x0000000B 0x000000FC
    R CpuSysRegs_GPIOLPMSEL0 0x0000000B 0x00000000
    R CpuSysRegs_GPIOLPMSEL1 0x0000000B 0x00000000
    R CpuSysRegs_TMR2CLKCTL 0x0000000B 0x00000003
    R CpuSysRegs_RESCCLR 0x0000000B 0x00000000
    R CpuSysRegs_RESC 0x0000000B 0xC0000000
    R CpuTimer2Regs_TIM 0x0000000B 0xFFFFFFFF
    R CpuTimer2Regs_PRD 0x0000000B 0xFFFFFFFF
    R CpuTimer2Regs_TCR 0x0000000F 0x0011
    R CpuTimer2Regs_TPR 0x0000000F 0x0101
    R CpuTimer2Regs_TPRH 0x0000000F 0x0000
  • Hello Richard,

      I just created a small project with the test routine to isolate the issue. I attach the project, it was created on CCS Version: 7.3.0.00019 .  I found that if I run the code from RAM (using RAM linker file) it works fine, and if ran from FLASH (using the FLASH linker file) it fails as described at the beginning of the thread.

     Is any of the assembler routines needed to run from RAM? for example configuring clocks?

    Regards,

    Alberto Peyro

    https://e2e.ti.com/cfs-file/__key/communityserver-discussions-components-files/171/4745.test.7z

  • Hello Alberto,

    I'm sorry for the delay in responding. Last week was a public holiday here.

    After discussing with a colleague we think it is something to do with the initialization of the PLL. In your code you write correctly to the PLL registers in these lines:
    ;Set PLL
    MOV @SYSPLLMULT,#SYSMULT_WORD
    MOV @SYSPLLMULT+1,#REG_CLEAR
    MOV @SYSCLKDIVSEL,#PLLSYSCLKDIV_CONFIG
    MOV @SYSPLLCTL1,#PLLCLKEN_CONFIG

    However the PLL must settle before it can be enabled and allowed to generate a reliable clock. In the example code, we do this in the function InitSysPll() in the file "f28004x_sysctrl.c" like this:

    //
    // Wait for the SYSPLL lock
    //
    while((pllLockStatus != 1) && (timeout != 0U))
    {
    pllLockStatus = ClkCfgRegs.SYSPLLSTS.bit.LOCKS;
    timeout--;
    }

    This method should be replicated in the assembly function "_Mcu_ClkSet100Mhz".

    Regards,

    Richard
  • Hello Richard,

    Don't worry I understand. I just added the code you suggested but I am getting the same result. When compiling with flash_linker_file the expected count is increased (in the previously attached code the TIM should have 0xFFFFFFCD and I am getting 0xFFFFFF7D).

    The final routine for XTAL frequency change is attached below, to take worst case scenario I wait fist for PLL lock bit to be set, and then wait around 200usec for stabilization:

    ;-----------------------------------------------------------------
    ;
    ; void _Clk_Set_100Mhz(void)
    ;
    ;-----------------------------------------------------------------
    _Mcu_ClkSet100Mhz:

    EALLOW;
    _Clk_XTAL_Config:
    ;set pointer to Clock registers
    MOVW DP,#__ClkCfgRegs>>6
    ;Reset MCD logic
    MOV @MCDCR,#MCDCR_CONFIG
    ;Clear OSCOFF
    MOV @XTALCR,#XTALCR_CONFIG
    ;Clear X1CNT.CLR
    MOV @X1CNT+1,#X1CNT_CONFIG
    ;wait counter value on X1CNT to reach 0x3FF
    _Clk_CNT1_Wait:
    CMP @X1CNT,#X1CNTR_COMPARE
    SB _Clk_CNT1_Wait,LT
    ;select OSC2
    MOV @CLKSRCCTL1,#OSCCLKSRCSEL_CONFIG
    ;check MCDCR.MCLKSTS and repeat above procedure if needed
    CMP @MCDCR,#BIT_CLEAR
    SB _Clk_XTAL_Config,NEQ

    ;Set PLL
    MOV @SYSPLLMULT,#SYSMULT_WORD
    MOV @SYSPLLMULT+1,#REG_CLEAR
    MOV @SYSCLKDIVSEL,#PLLSYSCLKDIV_CONFIG
    MOV @SYSPLLCTL1,#PLLCLKEN_CONFIG

    ;wait for PLL clock lock
    _Mcu_ClkSet100Mhz$WaitPLLLock:
    MOV AL,@SYSPLLSTS
    AND AL,#1
    SB _Mcu_ClkSet100Mhz$WaitPLLLock,EQ

    ;give PLL clock a stabilization time
    MOV AR6,#200
    _Mcu_ClkSet100Mhz$Loop1:
    RPT #99 || NOP
    BANZ _Mcu_ClkSet100Mhz$Loop1,AR6--

    EDIS
    LB *XAR7
  • Hello Richard,

    I think I managed to make this work... I don't know why it is happening because I don't know the internal architecture of the micro :) but it seems it needed a reset of flash and ram banks after the clock frequency change.

    I will continue testing and will let you know if any new! thanks again and regards,
    Alberto

    The code I added is:


    FlashControllerReg .set 0x5FB00
    RAMBANK_REG1 .set 0x5F412
    RAMBANK_REG2 .set 0x5F432
    RAMBANK_REG3 .set 0x5F452
    FlashControllerCfg .set 0x00
    RAMBANKResetWord1 .set 0x0003
    RAMBANKResetWord2 .set 0x00FF
    RAMBANKResetWord3 .set 0x000F


    ( . . . )

    ;raise clock
    FFC XAR7,_Mcu_ClkSet100Mhz

    ;; Reset Flash ECC
    EALLOW
    MOVL XAR4,#FlashControllerReg
    RPT #2 || NOP
    MOV *+XAR4[0],#FlashControllerCfg
    RPT #2 || NOP

    ;; Reset RAM Bank Memories
    MOVL XAR4,#RAMBANK_REG1
    MOV *+XAR4[0],#RAMBANKResetWord1
    MOVL XAR4,#RAMBANK_REG2
    MOV *+XAR4[0],#RAMBANKResetWord2
    MOVL XAR4,#RAMBANK_REG3
    MOV *+XAR4[0],#RAMBANKResetWord3
    RPT #2 || NOP
    EDIS

    ;; Wait until RAM banks are reset
    RPT #200 || NOP
    RPT #200 || NOP
    RPT #200 || NOP
    RPT #200 || NOP
    RPT #200 || NOP

    ;test timer
    FFC XAR7,_CPU_TIMERS_Tests
  • Hello Richard,

    After testing a little bit more, I realized that that resetting flash/ram banks did not solve the issue. I worked a little bit more the code and realized that when configuring the timer2 I missed some NOPs to avoid pipeline conflicts on successive RAM position writes/reads like this (in this case register mapped in RAM):

    MOV *+XAR4[TCR],#REG_CLEAR
    OR *+XAR4[TCR],#(DISABLE_TIMER+PERFORM_RELOAD)

    This should be:

    MOV *+XAR4[TCR],#REG_CLEAR
    RPT #COUNT_CLYCLE_WAIT2 || NOP
    OR *+XAR4[TCR],#(DISABLE_TIMER+PERFORM_RELOAD)
    RPT #COUNT_CLYCLE_WAIT2 || NOP

    Writing/Reading from this mapped RAM registers seems to be taking more than a cycle, so conflict in C28 pipeline arises. I will continue performing more tests but think this is the root case... anyway I will let in the _Mcu_ClkSet100Mhz routine your suggestions for PLL clock stabilization.

    Thanks and regards,
    Alberto Peyro
  • Hello Richard,

    After more testing, the previous solution with flash/ram bank reset did not resolve the issue. I were reviewing more carefully the code, and realized that Timer mapped registers seemed to be taking more than one cycle so pipeline conflicts arise on consecutive access to them, like for example this section of code:
    MOV *+XAR4[TCR],#REG_CLEAR
    OR *+XAR4[TCR],#(DISABLE_TIMER+PERFORM_RELOAD)

    It should be:

    MOV *+XAR4[TCR],#REG_CLEAR
    RPT #COUNT_CLYCLE_WAIT2 || NOP
    OR *+XAR4[TCR],#(DISABLE_TIMER+PERFORM_RELOAD)
    RPT #COUNT_CLYCLE_WAIT2 || NOP

    I will continue testing but I believe it was the root cause of the issue. Anyway I will keep your PLL clock stabilization suggestion on the Mcu_ClkSet100Mhz: routine...

    Thanks and regards,
    Alberto
  • Hi Alberto,

    Yes, that is possible.  The registers themselves are zero wait state, however there could be a pipeline conflict. The MOV should access the register in the E phase, but the following OR will read it in D2 (I think).  Check this link for more on pipeline conflicts:

    Please let me know what you find.  Thanks.

    Regards,

    Richard

  • Alberto,

    Do you have any update on the problem yet?

    Regards,

    Richard
  • Hello Richard, 

            Sorry for late response I was some days out of office. So far the problem seemed to be the pipeline issue. However I would like to make couple of additional tests before close the ticket if you don't mind!

     Thanks and best regards,

    Alberto Peyro

  • Hi Alberto,

    No problem and no rush. Please let me know what you find.

    Regards,

    Richard
  • Hi Alberto,

    Wondering if there has been any progress on this issue?

    Regards,

    Richard
  •     Hello Richard, 

          Happy new year after all :)    so far no more issues. It seems that it was related to pipeline, and adding the delays solved the problem. However I integrated the recommendations you mentioned as well regarding the routine, so I will mark this as solution!

      Thanks and regards,

    Alberto Peyro