Author Topic: can't SLEEP() for worrying  (Read 2324 times)

0 Members and 1 Guest are viewing this topic.

Offline PerranOakTopic starter

  • Frequent Contributor
  • **
  • Posts: 581
  • Country: gb
can't SLEEP() for worrying
« on: March 16, 2021, 05:08:53 pm »
I have a 12F683 hooked-up to a 74HC595 (circuit attached) and this simple programme (relevant parts):

Code: [Select]
#define  data GPIObits.GP0
#define clock GPIObits.GP1

void main(void)
{
    int display = 7;
   
    for (int count = 0; count <8; count++)
    {
       data = (display >> count) & 1;   //right shifts by 0,1,2,3.. then blanks all but bit0
       clock = 1;                       //clock pulse on
       clock = 0;                       //clock pulse off
    }
    clock = 1;                           //Final pulse that RCLK is expecting as
    clock = 0;                           // it is one pulse behind SRCLK.

    __delay_ms(2000);
    //SLEEP();
}

Like it is here, the prog works fine and displays the number 7 on the LEDs.

It does flicker though which surprised me as I thought it would run through once then stop but it seems to repeat like there was a while command?

Anyway, that's not why I rang. When I comment-out the __delay and "un-comment-out" the SLEEP() all LEDs are off. It seems to be in sleep mode because the CLKOUT shows no clock.

I expected that the 7 would be displayed, the uC would go to sleep and the LEDs would remain on.

I am obviously doing something wrong. Any advice would be most welcome, thank you.

N.B.
Please assume that the appropriate connects to ground, Vcc and required resistors are made - left out for clarity.

You can release yourself but the only way to go is down!
RJD
 

Offline MikeK

  • Super Contributor
  • ***
  • Posts: 1364
  • Country: us
Re: can't SLEEP() for worrying
« Reply #1 on: March 16, 2021, 06:10:03 pm »
How long do you think it takes to get to the Sleep() command?
 

Offline ajb

  • Super Contributor
  • ***
  • Posts: 2867
  • Country: us
Re: can't SLEEP() for worrying
« Reply #2 on: March 16, 2021, 07:46:04 pm »
It does flicker though which surprised me as I thought it would run through once then stop but it seems to repeat like there was a while command?

I know this isn't your main question, but this is because your main function is exiting.  On a computer application this may be fine, because then execution will return to the desktop/command line/whatever, but on an MCU there's no place to exit to!  So your application completes main, and then probably just runs through the rest of the program memory (which hopefully has been erased to something equivalent to NOP or some invalid instruction that won't do any harm), and then runs right back to the beginning when the program counter overflows.  This is why you always see a `while(1){ }` block in embedded main functions, because you want the application to stay there forever.  In the case of your test program here, where you truly want it to only execute once, you can simply put a `while(1);` statement at the end which will cause the MCU to just spin there forever.

The sleep problem may depend on the sleep configuration.  What does the datasheet see about what peripherals are active in sleep? There may be multiple sleep levels as well, and it may be possible/necessary to configure individual peripherals for operation during sleep.
 

Offline DavidAlfa

  • Super Contributor
  • ***
  • Posts: 6934
  • Country: es
Re: can't SLEEP() for worrying
« Reply #3 on: March 16, 2021, 09:54:25 pm »
As they already told you, the main function MUST be a loop.
What you're doing is undefined behavior. If there's more code after the main end address (initialization, whatever), it will inmediately excecute it.
Or skip everything until it reaches the end of the flash, causing a reset (hence the flickering you see).
If you want to stop forever at some point, then use while(1).
Something like this:

Code: [Select]
#define data GPIObits.GP0
#define clock GPIObits.GP1
#define repeat_val (unsigned long)500000 // Value to use as a timer. Adjust as you need for longer or shorter time

void main(void){
unsigned char display = 7; // Digit to display. Better to use char (int is 16 bit, slower on 8bit PIC12), as you can only display 0x0-0xF digits (0-15 decimal)
unsigned long tim = 0; // Huge 32bit variable to use as a timer (Better to use a real timer)

while(1){ // Forever

for (int count = 0; count <8; count++)    { // Update display
data = (display >> count) & 1; // Right shifts by 0,1,2,3.. then blanks all but bit0
clock = 1;                        // Clock pulse on
clock = 0;                        // Clock pulse off
}
clock = 1;                            // Final pulse that RCLK is expecting as
clock = 0;                            // it is one pulse behind SRCLK.

if(++tim>repeat_val){ // Increase value. If reached limit:
tim=0; // Reset variable
asm("sleep"); // Sleep (CPU stops here)
// sleep(); // I think this worked too...

// When it wakes up, it will repeat the cycle (You need to enable some event to wake up. Like an external input, a timer...)
}

while(1); // If at some point you want to stop the CPU forever, do this.
// This program code will never reach this, as it's locked inside the previous while(1).
}
}
« Last Edit: March 16, 2021, 10:02:28 pm by DavidAlfa »
Hantek DSO2x1x            Drive        FAQ          DON'T BUY HANTEK! (Aka HALF-MADE)
Stm32 Soldering FW      Forum      Github      Donate
 

Offline DrG

  • Super Contributor
  • ***
  • !
  • Posts: 1199
  • Country: us
Re: can't SLEEP() for worrying
« Reply #4 on: March 16, 2021, 10:25:49 pm »
As they already told you, the main function MUST be a loop.
What you're doing is undefined behavior. If there's more code after the main end address (initialization, whatever), it will inmediately excecute it.
Or skip everything until it reaches the end of the flash, causing a reset (hence the flickering you see).
If you want to stop forever at some point, then use while(1).
Something like this:
/--/

I hope I am not being too nit-picky here but I don't think that the behavior is undefined. I think that the program termination is implementation specific (and that is right out of some standard or other). We know that main() was intended to return from whatever called it, but 8 pin pics were not what they had in mind.

It makes a point because he could look at the asm list and find out where it goes. Empirically, it goes to some start up code and executes again - he is seeing that when he gets a flicker.

Now, what happens when he does a sleep()? I *think* on that PIC it will compile to load the PC with the next instruction, because that is where it can pick up again, unless it comes out of sleep with a reset. But, because it the last program instruction, I have no idea what it is loading - I have seen people add NOPs in that situation, the asm listing should provide the information.

There are no configuration lines so I don't even know if it is waking up at all (like a WDT TO), in which case, I don't see why the GPIO is getting messed up. But for the reasons already mentioned by you and others, I would only wonder if the OP is just using sleep() instead of while(1) or goto here (which I admit to using something if I am debugging).

In fact, I don't even know if he is using xc8 or ??

In any event, there is something very basic to fix as already noted.
« Last Edit: March 16, 2021, 10:28:36 pm by DrG »
- Invest in science - it pays big dividends. -
 

Offline DavidAlfa

  • Super Contributor
  • ***
  • Posts: 6934
  • Country: es
Re: can't SLEEP() for worrying
« Reply #5 on: March 16, 2021, 11:25:57 pm »
You made me doubt. So I tried.
In STM32, it returns to the init...but after that it jumps to a random address, It changes depending on the flash contents , ex if you add a nop in the main, 2 nops...
So far, if it didn't  cause a hard fault instantly, it jumped to the middle of a timer or a gpio routine, then causing a hard fault.

From what I remember, basic pics just reset themselves ... I will have to remove the dust from my pickit3 :-DD
« Last Edit: March 16, 2021, 11:32:42 pm by DavidAlfa »
Hantek DSO2x1x            Drive        FAQ          DON'T BUY HANTEK! (Aka HALF-MADE)
Stm32 Soldering FW      Forum      Github      Donate
 

Offline ajb

  • Super Contributor
  • ***
  • Posts: 2867
  • Country: us
Re: can't SLEEP() for worrying
« Reply #6 on: March 17, 2021, 02:21:51 am »
The effect of a PC wraparound will depend on the architecture. A lot of architectures put the vector table at the beginning of memory, but how it's stored varies. I think in AVRs, it's a table of jump instructions to the ISR locations, and the first one is the reset vector, so the mcu can just immediately start executing with PC=0, therefore wraparound (or jump to that location) will then jump straight to the reset handler just like when the chip starts up normally. ARMs store the vector table as a list of addresses, the first one being the initial stack pointer, which the core loads to the SP register at startup before jumping to the reset handler which is the second address in the table, so attempting to execute from the beginning of memory will depend on what, if any, instructions the addresses in the vector table resemble. I'm not very familiar with PICs and couldn't immediately find an answer on how their vector tables work.

Of course this is only applicable if the mcu manages to run to the end of memory; it may well crash first, or in the case of something like an ARM end up in a fault handler when it tries to execute an invalid instruction or load an invalid address, which may result in a reset depending on what sort of fault handler is present.  Or it could end up in a ROM bootloader if one is present.  So best to simply not let your main function exit 😛
« Last Edit: March 17, 2021, 02:24:14 am by ajb »
 

Online Renate

  • Super Contributor
  • ***
  • Posts: 1818
  • Country: de
    • Renate's Android Page
Re: can't SLEEP() for worrying
« Reply #7 on: March 27, 2021, 08:26:29 pm »
In AVR8 land:
Code: [Select]
     5e6: 0e 94 ec 0c call 0x19d8 ; 0x19d8 <main>
     5ea: 0c 94 20 0d jmp 0x1a40 ; 0x1a40 <_exit>

00001a40 <_exit>:
    1a40: f8 94        cli

00001a42 <__stop_program>:
    1a42: ff cf        rjmp .-2      ; 0x1a42 <__stop_program>
So, if main ever returns it turns off interrupts and jumps into a tight loop.
 

Offline DavidAlfa

  • Super Contributor
  • ***
  • Posts: 6934
  • Country: es
Re: can't SLEEP() for worrying
« Reply #8 on: March 27, 2021, 11:47:04 pm »
Anyways, who and why did ever returned from main() in a MCU? Not regarding any RTOS.
Hantek DSO2x1x            Drive        FAQ          DON'T BUY HANTEK! (Aka HALF-MADE)
Stm32 Soldering FW      Forum      Github      Donate
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf

 

- - -
-->