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.

Code placement for L138 DEEPSLEEP mode?

Other Parts Discussed in Thread: SYSBIOS

Hi,

I originally asked this question in OMAP forum. However, a google search shows that many of the questions on L138's DEEPSLEEP mode are asked and answered in the Linux forum so I copied my question to here. I develop using raw code without an OS, but I think the procedure of how L138's Linux PSP employed to put into and wake the device up from deep sleep mode should be an established paradigm that I should follow.

 

I have an urgent question with OMAP L138’s DEEPSLEEP mode. The descriptions below are all about running on the ARM side, not the DSP side.

For purely testing whether DEEPSLEEP and waking up is possible, I used a small project and configured linker.cmd to put all stuff into the 128KB shared memory. The deep sleep and waking up were all successful.

For the real project which is much larger which has lots of its portions put into DDR2 memory, I only tried to put the function pairs intoDeepSleep() and outOfDeepSleep() into the shared 128KB memory by using #pragma directive. However, the waking up was not successful. The external device (an MSP430) correctly performs the due steps of first pulling DEEPSLEEPn low and release it after some time, but when I first disconnect (before the CPU was stopped when it was connected, so I have to reconnect) and then connect (I removed the GEL file first because I don’t want OnTargetConnect() to alter the state of the device) to the CPU I got one of the two errors in CCS Debug view after suspending the execution of the program:

  1. Only one layer of stack: 0x01513004 (no symbols are defined for 0x01513004)
  2. Two layers of stack.
    1. The top layer: UndefInstHandler() [it points to the .out file generated]
    2. The lower layer: 0xC047F1A8 (no symbols are defined for 0xC047F1A8)

Both seem to suggest that the code has erroneously jumped to somewhere that was not a function within the project. I haven’t been able to find what has caused it.

The DEEPSLEEP process is not about setting the SLEEPENABLE bit alone because DDR2 and other peripherals all needs to properly dealt with. Is it possible to identify the cause of the problem from the error information above? And is there a recommended scheme of code placement for DEEPSLEEP mode: which of them should be in the shared 128KB memory, or even ARM’s L1 memory, and which should be placed in DDR2?

 

Paul

  • Hi Paul

    I thought I saw similar posts and request for bump in other forums, but I can't seem to find them any more. I recommend that you follow the guidelines/examples highlighted in power module in SYS BIOS

    http://processors.wiki.ti.com/index.php/Power_Module_for_C6748_and_OMAP-L138#Constraints_for_Power_SLEEP_and_Power_DEEPSLEEP

    Are you putting the DDR2 in self refresh mode etc, prior to putting the device in deep sleep?

    Regards

    Mukul

  • Mukul,

    I didn’t find other people’s post on the same topic in the forum. I have also posted the question in OMAP forum and have bumped that thread.

    The link you gave says that

    .text

    .bss

    .vecs

    .far

    must reside in on-chip memory; I have also did experiments myself to see which sections needs to be in on-chip memory in order for waking-up to be succeed. I tested only 128KB L3, and the experimented started from all sections in L3 which had been tested to work for waking-up, to gradually allocate one or some of the sections to locations outside the chip. I have found that

    .text

    .bss

    .const

    .stack

    .intvecs

    must be in L3 for the device to wake up. The difference between my testing and the result at http://processors.wiki.ti.com/index.php/Power_Module_for_C6748_and_OMAP-L138#Constraints_for_Power_SLEEP_and_Power_DEEPSLEEP might due to the difference in structure between my project and the BIOS/PWRM, although it might also be possible that my configurations are not optimal enough. It is also seen that .data, .cint, .sysmem are not required for both mine and the wiki article result.

    If I put all sections in L3 for a small project, and write some data to DDR2, and do

    1. DDR2 into self-refresh
    2. Put CPU into DEEPSLEEP (an external MSP430 pull DEEPSLEEP low)
    3. Wake CPU (MSP430 pull DEEPSLEEP high)
    4. DDR2 out of self-refresh

    Then DDR2 are all preserved. However now I am testing the required code placement scheme for deepsleep’s waking up so I haven’t added DDR2 self-refresh to avoid complications and to keep the variables as less as possible.

     

    In fact there is not a pair of functions intoDeepSleep() and outOfDeepSleep() as said in the top post. There is only one function sleep(), which

    1. Sets pinmux so DEEPSLEEP/RTC_ALARM/GP0[8] pin to DEEPSLEEP
    2. Set DEEPSLEEP.SLEEPENABLE
    3. Tells MSP430 to pull DEEPSLEEP LOW
    4. After waking up polls DEEPSLEEP.SLEEPCOMPLETE until it is set

    And this sleep() function really have minimal dependencies on other functions expect it calls pinmux functions in step (1) above. So although the Wiki article you referred requires putting all .text into on-chip memory, I wonder why can’t we just put sleep() and the a few functions it calls into on-chip memory, and put all other functions in DDR2 as usual? I have in fact tried this with #pragma CODE_SECTION, but haven’t yet succeeded.

    Another idea is that can we force sleep() to inline expand all functions it is called? If we can force the compiler to do this, for example, if

    sleep() ->A() -> B() -> C() (for illustration, in fact just one level of call)

    and we force sleep() to expand A(), B(), C() all within itself so it becomes a monolithic function, then we can only use #pragma CODE_SECTION to specify sleep() to be within on-chip memory without needing to do that for A(), B(), C() individually. Of course, when A(), B(), C() are called elsewhere they are still treated as normal function calls and should not be inline expanded. I haven’t found how to force the compiler to do this yet, but do you think it is a feasible idea? And is there a way to configure the compiler to behave like this (I also posted this inline expansion question in How to force inline all dependent functions calls into a single function in compiler forum)?

     

    Paul

  • Paul

    When you put the device in deep sleep, you are cutting the clock at the "root"  or  input (OSCIN/CLKIN), it would cut clocks to both PLL0 and PLL1. PLL1 supplies the MCLK that generates the mDDR/DDR clock. If you do not put the external memory in self refresh, you are not "gracefully" shutting down the clocks to  mDDR/DDR2 and not ensuring its contents will be in good shape.
    I recommend that you try mDDR/DDR2 in self refresh prior to putting the device in deep sleep and then the critical functions in on chip memory should put the mDDR/DDR2 out of self refresh as part of coming out of deep sleep etc.

    Regards

    Mukul

  • Mukul,

    The information in your linked wiki article was important. I compared the address (0xC047F1A8) with the .map file and found that this address actually contains

    loop0:

            B       loop0   

    which immediately follows

    AbortHandler:

    UndefInstHandler:

    ;

    ; Disable all the interrupts

    ;

            MRS     r0, cpsr                  ; Read from CPSR

            ORR     r0, r0, #0xC0             ; Clear the IRQ and FIQ bits   

            MSR     cpsr_c, r0                  ; Write to CPSR

            ADD     r14, pc, #0               ; Store the return address

            LDR     pc, _CPUAbortHandler      ; Go to C handler

    all are defined in Starterware > system_config_armv5 > exceptionhandler.asm. SPRUH77 says that “abort” exception indicates that the current memory access could not be completed. So I guess what actually happens is that one interrupt or some interrupts are pending after the CPU has been released from DEEPSLEEP and AINTC tries to jump to the ISR location, but as what you said PLL1 and DDR2 memory access has not been restored properly, and the ISR happens to be in the DDR2, so the memory fetch failed and AINTC simply jumps to the vector for abort exception.

     

    If in the normal runtime environment without complications here such that memory device could be irresponsive, then we could simply add a breakpoint in each enabled ISR and we could know which ISR was triggered after the program halts there; but here since the pending ISR cannot be successfully executed even from its first instruction, the breakpoint method won’t be useful. In addition, the debug window won’t show a stack of function invocations in this very particular case (after just released from DEEPSLEEP, and after memory fetch has failed).

    What can I do to find out which ISR the AINTC attempted to execute and has caused the problem? I looked at AINTC.GPVR (Global Prioritized Vector Register), HIPVR1 & 2, SRSR1-4, SECR1-4, and many bits are set. Which bit among these registers should I look at, or should I check registers other than these?

     

    Paul

  • Mukul,

    We finally get this code placement problem resolved. Here is the summary of the most important points:

    1. There is in fact no requirement at the fundamental level on whether .bss, .vecs, .far or other sections need  to be placed in IRAM. The wiki link requires these sections to be in IRAM because of the architecture of its software platform. Instead of letting the deepsleep() function call other driver functions to accomplish pinmuxing (GP0[8] to DEEPSLEEP), DDR2 controller configuration and PSC configurations, we instead simply copied the necessary statements into the deepsleep() functions and eventually made deepsleep() like a “leaf” in the calling graph, i.e., it completes all operations using instructions in itself without calling other functions, this of course also include waking up steps. After making this change we can only place this function into IRAM and it can work successfully for into and out-of DEEPSLEEP operation.
    2. The error that programmer counter jumps to AbortHandler() was due to memory fetch error. However, this memory fetch can be caused by hardware even when CPU is not accessing any code/data outside ISR. In my case although we have disabled interrupt globally so the CPU would strictly execute only the code within IRAM, there is an EDMA controller which was not shut down, and after DEEPLSEEP pin released to high but before DDR2 is out of self-refresh, it attempts to access DDR2, and this caused memory fetch error manifested as jumping to AbortHandler().

    I really feel that these problems, especially point 2 above, are extremely difficult to debug. In fact it is actually documented in the TRM: if one look at chapter 10, there is detailed steps requiring that all peripheral accessing memory be turned off prior to entering DEEPSLEEP mode. However there is relatively scarce debugging information especially regarding that memory-fetch error due to hardware could cause CPU jump to Abort mode handler. Mukul had actually commented in http://e2e.ti.com/support/dsp/omap_applications_processors/f/42/p/66871/710087.aspx#710087 that there had been discussion on writing a power optimization app note but the plan has been shelved. I hope this post could be a testament on how much help such an app note could confer and how deeply it is wanted.

     

    Paul

  • Hi Paul

    I appreciate the update and summary on this. There are challenges in implementing the power management software almost from scratch , like you are trying to accomplish, and I am glad that you have been able to overcome most of it.

    Your feedback on power optimization appnote is noted and I will keep in the log of to do items.

    Regards

    Mukul

  • Hi Mukul,

    The SYS/BIOS does contain a function for entering saving modes including DEEPSLEEP which is

    PMI_Status PMI_sleepCPU(PMI_Sleep state, unsigned scaleVoltage, unsigned sleepArg)

    in

    C:\ti\bios_6_33_04_39\packages\ti\sysbios\family\c674\pmi\ pmi_slp.c

     

    On the other hand, is DEEPSLEEP code also included in the Linux PSP? I searched this Linux forum, and although there are questions related to the DEEPSLEEP mode, many are about devices other than L138 and none refers to the exact location (folder/package) of such code. I cannot confirm whether Linux PSP contains such code.

    Could you give an answer on this?

     

    Paul

  • Mukul,

    I have created a new thread L138 DEEPSLEEP code in Linux PSP? for above question. Please look to that instead of this.

     

    Paul