0

I'm working in PIC24F microcontroller. My main program doesn't have infinite loop, but it is run like an infinite loop. Before I test the code with infinite while loop (while (1)), but when I remove the while loop, it's still running like an infinite loop. What's the problem?

Thanks

Voltage Spike
  • 75,799
  • 36
  • 80
  • 208
user6161
  • 144
  • 2
  • 10

3 Answers3

6

Microcontrollers are often programmed bare metal , meaning your program has to initialize the CPU and RAM to get your program going. This is called a startup script and some IDEs/compilers may hide it from the user at first glance.

The startup script does the bare minimum to get to a C main, combined with the C "environment". That is (optionally sometimes) filling RAM with zeros, and most importantly copying variables with predefined values from FLASH to RAM. E.g. if you declare a (global) variable with an initial value, it is stored in program FLASH and copied to RAM before main is called.

I suspect you use XC16 or C30 compiler. You can find these scripts in XC16/v*.**/src/libpic30.zip in the files crt0_standard.s. It contains the following (simplified for this example) start-up code:

        mov      #__SP_init,w15    ; initialize w15
        mov      #__SPLIM_init,w14


        mov      w14,_SPLIM        ; initialize SPLIM
        nop                        ; wait 1 cycle
    mov  #__enable_fixed, w0
        cp0      w0
        bra  z, CORCON_RESET 
        mov      #0x0010,w0
        mov      w0,CORCON         ; enable super saturation and clear IF

CORCON_RESET:
        rcall    __psv_init        ; initialize PSV
        mov      #__dinit_tbloffset,w0 ; w0,w1 = template
        mov      #__dinit_tblpage,w1   ;
        rcall    __data_init_standard  ; initialize data

        mov      #__has_user_init,w0
        cp0      w0                ; user init functions?
        bra      eq,1f             ; br if not
        call     __user_init       ; else call them
1:
        call  _main                ; call user's main()

        .pword 0xDA4000            ; halt the simulator
        reset                      ; reset the processor

Even if you don't speak assembler fluently you should see what is going on. The script initializes the stack, some CPU registers, initialize PSV & data memory (e.g. copying pre-initialized variable contents from FLASH to RAM), and then call your main function.

The script more or less expects the main will never return, which is why you often see a while(1) at the end of any embedded program.

If it does return for some reason, it will execute the reset instruction. This reinitializes everything again and eventually call main again. This turns into the behavior you're seeing, namely it's looping.

Hans
  • 7,238
  • 1
  • 25
  • 37
2

There's no operating system on this microcontroller, right? What happens if you allow your main() function to exit, is up to the C startup code (which is what calls your main() in the first place). Presumably there's another equivalent while(1) loop surrounding the call to main(); halting would not generally be as useful as restarting the program.

If you actually want a microcontroller to run once and then halt, you must explicitly halt instead of returning from main().

MarkU
  • 14,413
  • 1
  • 34
  • 53
2

A hosted program in a HLL returns to the operating system when it finishes. If there is no operating system the behaviour is undefined- it might jump back to the beginning, it might execute random bytes in program memory until the PC rolls over or it gets stuck in some kind if loop, or something else entirely.

Of course it is deterministic at some level- you can gain insight by examining the start-up assembly code, the emitted code, and by single stepping the code through an emulator or simulator. You should have reasonable understanding of machine language programming.

Spehro Pefhany
  • 376,485
  • 21
  • 320
  • 842