AT91SAM7SE256, reboots in low power-mode

In my program, I enter and leave low-power mode (all function calls are made from system mode, where the main code runs) back and forth. With low power-mode, I am referring to the 32kHz RC oscillator, with a prescaler of 64 which yields 500Hz. The full power-mode is bases on an external crystal that with PLL yields 24MHz MCK.

My problem is that when I enter the low-power mode by selecting slow clock, the chip restarts (at least the debug output on the rs232 console makes it look that way). I am using the following code to power down/power up:

void LowLevelPowerDown(void)
{
  AT91C_BASE_PMC->PMC_MCKR = AT91C_PMC_CSS_SLOW_CLK;
  while(!(AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MCKRDY));

  AT91C_BASE_PMC->PMC_MCKR |= AT91C_PMC_PRES_CLK_64;
  while(!(AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MCKRDY));

  AT91C_BASE_PMC->PMC_PLLR = 0;
  AT91C_BASE_PMC->PMC_MOR = 0;

  AT91C_BASE_VREG->VREG_MR = AT91C_VREG_PSTDBY;
}

void LowLevelPowerUp(void)
{
  AT91C_BASE_VREG->VREG_MR = 0;

  AT91C_BASE_PMC->PMC_MOR = BOARD_OSCOUNT | AT91C_CKGR_MOSCEN;
  while (!(AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MOSCS));

  AT91C_BASE_PMC->PMC_PLLR = BOARD_USBDIV | BOARD_CKGR_PLL | BOARD_PLLCOUNT | BOARD_MUL | BOARD_DIV;
  while (!(AT91C_BASE_PMC->PMC_SR & AT91C_PMC_LOCK));

  while (!(AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MCKRDY));

  AT91C_BASE_PMC->PMC_MCKR = AT91C_PMC_PRES_CLK_4;
  while (!(AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MCKRDY));

  AT91C_BASE_PMC->PMC_MCKR |= AT91C_PMC_CSS_PLL_CLK;
  while(!(AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MCKRDY));
}

I have already tried not setting VREG in low power-mode, the result is the same - rebooting.

Any ideas?

I have now tested with global interrupts (F and I) disabled - it still reboots.

It seems like gcc produces broken code for a few of my functions… I have tried both 4.4.2 and 4.1.1 for windows, with the same results. I have attached an excerpt of the problem below (offset -#207 etc)

Disassembly of section .text.LowLevelPowerDown:

00000000 <LowLevelPowerDown>:
#if 0
    AT91C_BASE_PMC->PMC_MCKR = AT91C_PMC_CSS_SLOW_CLK | AT91C_PMC_PRES_CLK_64;
    while (!(AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MCKRDY));
#else
        /* Switch to slow clock */
        AT91C_BASE_PMC->PMC_MCKR = AT91C_PMC_CSS_SLOW_CLK;
   0:   e3e02c03        mvn     r2, #768        ; 0x300
   4:   e3a03000        mov     r3, #0  ; 0x0
   8:   e50230cf        str     r3, [r2, #-207]
        while (!(AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MCKRDY));
   c:   e5123097        ldr     r3, [r2, #-151]
  10:   e3130008        tst     r3, #8  ; 0x8
  14:   e3e03c03        mvn     r3, #768        ; 0x300
  18:   0afffffb        beq     c <LowLevelPowerDown+0xc>

        /* prescaler (32kHz slow osc, pres = 64 => 500Hz */
        AT91C_BASE_PMC->PMC_MCKR |= AT91C_PMC_PRES_CLK_64;
  1c:   e51320cf        ldr     r2, [r3, #-207]
  20:   e3822018        orr     r2, r2, #24     ; 0x18
  24:   e50320cf        str     r2, [r3, #-207]
        while (!(AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MCKRDY));
  28:   e1a01003        mov     r1, r3
  2c:   e5113097        ldr     r3, [r1, #-151]
  30:   e3130008        tst     r3, #8  ; 0x8
  34:   e3e02c03        mvn     r2, #768        ; 0x300
  38:   0afffffb        beq     2c <LowLevelPowerDown+0x2c>
#endif

        AT91C_BASE_PMC->PMC_PLLR = 0;
  3c:   e3a03000        mov     r3, #0  ; 0x0
  40:   e50230d3        str     r3, [r2, #-211]

        AT91C_BASE_PMC->PMC_MOR = 0;
  44:   e50230df        str     r3, [r2, #-223]

    /* VREG in standby mode */
        AT91C_BASE_VREG->VREG_MR = AT91C_VREG_PSTDBY;
  48:   e3a02001        mov     r2, #1  ; 0x1
  4c:   e3e03000        mvn     r3, #0  ; 0x0
  50:   e503229f        str     r2, [r3, #-671]
}
  54:   e12fff1e        bx      lr

Anyone have any idea of what to do? Simply replacing this .c file with assembler wont do it, as I need to formally guarantee that the (rest of the) generated code really is executed.

Have you checked your header-files? I would be very surprised if the compiler could treat registers differently.

So, check the sam7-register definitions, and if you still can’t find anything wrong, try writing and reading the addresses directly in the code.

monstrum:
Have you checked your header-files? I would be very surprised if the compiler could treat registers differently.

So, check the sam7-register definitions, and if you still can’t find anything wrong, try writing and reading the addresses directly in the code.

I did a test - I compiled the file using gcc 3.2.3 in Linux, and there it performs correctly. Only 4.x that misbehaves. Will try to get a 4.4.2 toolchain for linux to give that a try too.

I must be blind, gcc compiles correctly. The problem with reboots still remains.

Do you disable the Watchdog?

monstrum:
Do you disable the Watchdog?

Yes, first thing before jumping to main(). I have tried hanging in a while(1); in main too, the chip never reboots.

Then I would try to find exactly what line is causing the reboot. Dump some text to the terminal, or toggle pins or whatever between each statement and make sure the output buffers are flushed before continuing to the next.

What I came to think of. When you disable the voltage-regulator (although you say this reset occurs even if you leave the regulator on) won’t the brown-out detector be mad and reset the chip?

monstrum:
Then I would try to find exactly what line is causing the reboot. Dump some text to the terminal, or toggle pins or whatever between each statement and make sure the output buffers are flushed before continuing to the next.

What I came to think of. When you disable the voltage-regulator (although you say this reset occurs even if you leave the regulator on) won’t the brown-out detector be mad and reset the chip?

The BOD is disabled (programmed that way using SAM-BA).

The following causes the chip to reboot:

AT91C_BASE_PMC->PMC_MCKR = AT91C_PMC_CSS_SLOW_CLK;

while(!(AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MCKRDY));

while (1);

So the problem lies very early.

Do you have a revision A device?

I’m not sure if the SAM7SE and SAM7S are the same, but this is interesting:

This doesn’t seem to apply to rev B, which I have been working with.

From datasheet:

PMC: Programming CSS in PMC_MCKR Register

Under certain rare circumstances, reprogramming the CSS value in the PMC_MCKR register

(i.e switching the main clock source) might generate malfunction of the device if the following

two actions occur simultaneously.

1.Switching from:

–PLL Clock to Slow Clock or

–PLL Clock to Main Clock or

–Main Clock to PLL Clock or

–Main Clock to Slow Clock

And

2.Program code is being executed out of flash, or a transition is occurring on PA1, either

as an input or output.

Note:This issue does not occur when transitioning from slow clock to main clock or from slow clock to

PLL clock.

Problem Fix/Workaround

When changing CSS in the PMC_MCKR to switch from

–PLL Clock to Slow Clock or

–PLL Clock to Main Clock or

–Main Clock to PLL Clock or

–Main Clock to Slow Clock

Ensure that the processor is executing out of SRAM and ensure no transition occurs on PA1,

either as an input or output, starting from writing to the PMC_MCKR register until MCKRDY = 1

I have rev A devices (are there any newer ones?). Running from FLASH and switching from PLL to slow clock, yes.

monstrum:
Do you have a revision A device?

I’m not sure if the SAM7SE and SAM7S are the same, but this is interesting:

This doesn’t seem to apply to rev B, which I have been working with.

From datasheet:

PMC: Programming CSS in PMC_MCKR Register

Under certain rare circumstances, reprogramming the CSS value in the PMC_MCKR register

(i.e switching the main clock source) might generate malfunction of the device if the following

two actions occur simultaneously.

1.Switching from:

–PLL Clock to Slow Clock or

–PLL Clock to Main Clock or

–Main Clock to PLL Clock or

–Main Clock to Slow Clock

And

2.Program code is being executed out of flash, or a transition is occurring on PA1, either

as an input or output.

Note:This issue does not occur when transitioning from slow clock to main clock or from slow clock to

PLL clock.

Problem Fix/Workaround

When changing CSS in the PMC_MCKR to switch from

–PLL Clock to Slow Clock or

–PLL Clock to Main Clock or

–Main Clock to PLL Clock or

–Main Clock to Slow Clock

Ensure that the processor is executing out of SRAM and ensure no transition occurs on PA1,

either as an input or output, starting from writing to the PMC_MCKR register until MCKRDY = 1

For the SE devices, rev A seem to be the latest. I was referring to the S devices, which also have a rev B.

The errata for SE doesn’t mention this, but as the SE and S are very similar, I would bet that it’s an undocumented bug. At least you could try running the sleep-code from RAM and see if it works.

monstrum:
For the SE devices, rev A seem to be the latest. I was referring to the S devices, which also have a rev B.

The errata for SE doesn’t mention this, but as the SE and S are very similar, I would bet that it’s an undocumented bug. At least you could try running the sleep-code from RAM and see if it works.

I have tried placing the PD-function in SRAM. The result is that the chip reboots one out of ten times, but it never ever gets past the slow clock-selection (the first line in the function). There obviously is something happening that depends on the SRAM, but it doesn’t seem to be the complete solution.

The problem is now solved, cause: gross incompetence on my part…

When I changed to slow clock, I started with switching clock source as stated in the datasheet, but this also sets the prescaler to 1:1, which is way too fast for a 1.8V system running with 96MHz output from the PLL.

The new way I do it now is:

PLL_CLOCK | PRES_64;

wait (until locked);

SLOW_CLOCK | PRES_64;

wait (until locked);

This way I get no too fast glitches for the chip to handle. This works from both flash and sram.