Quality RTOS & Embedded Software

 Real time embedded FreeRTOS RSS feed 
Quick Start Supported MCUs PDF Books Trace Tools Ecosystem


Loading

PIC32 Soft Reset to Application Start

Posted by Jason on August 24, 2012
Hello,

I am running FreeRTOS on a PIC32. My design has a bootloader and due to an error in the bootloader for units already in the field, I have the need to reset the micro to the start of the application. Basically I enter a sleep mode and need to shutdown a ton of stuff in a task before I do. When i wake up I would just reset the processor to restart everything from fresh. Unforutnately the bootloader bug prevents me from doing this. So what I have done is suspended the sheduler and performed a Jump to the start address of my application code. I am doing the jump to the start of the C startup routine not just the main function.

I am seeing that the code correctly executes the jump, runs the code before my main app and then starts running my main app where I initialize the RTOS and its tasks.

When I start the scheduler it remembers where I was in my sleep task and loads it back up to the spot where i jump to my application startup. So I reset over and over again.

I am using C32 V1.12 I am wondering if anyone else has had experience with FreeRTOS remembering things. Its also possible that C32 isn't performing effective clear on the startup.

Does anyone have a better suggesting for reinitializing everything so that the RTOS doesn't remember its self?

Thanks for your help!
Jason

RE: PIC32 Soft Reset to Application Start

Posted by Jason on August 24, 2012
** added to monitor post

RE: PIC32 Soft Reset to Application Start

Posted by Richard on August 24, 2012
If I understand your post correctly, then you are jumping to the start, running the C start up code which should zero out variables and initialise variables as necessary, then running main() again to create your tasks - but you are then finding that tasks that were running before the reset start running again from where they left off.

Do you then have two copies of the task - or is it that a task that was recreated executes from where it left off?

It is very hard to see how that could happen if everything was cleared to zero.

Do you have any special linker sections that the standard C start up code is not clearing?

Which heap implementation are you using (heap_1, heap_2, heap_3 or heap_4, or your own)?

Are you also disabling the tick interrupt before you restart?

Can you experiment by having file scope static and global variables, and function scope static variables, set to both zero and non-zero values and ensure they get reset to their initial state when you restart your program.

Regards.

RE: PIC32 Soft Reset to Application Start

Posted by Jason on August 27, 2012
You understand perfectly!

I have one copy of the task. When the main reinitializes everything and starts the scheduler, that task resumes from where it left off which is right before I do my jump to reinitialize everything.

Using Heap_3
I disable the tick interrupt (all interrupts for that matter) before i restart.

I am not 100% sure that the linker is performing a C flush. I will have to experiment with that to be sure what I think is happening is actually happening.

Below is the linker script. I am leaving a section of calibration request data present so my bootloader can pick it up, but that should be it.



OUTPUT_FORMAT("elf32-tradlittlemips")
OUTPUT_ARCH(pic32mx)
ENTRY(_reset)

EXTERN (_min_stack_size _min_heap_size)
PROVIDE(_min_stack_size = 0x400) ;
PROVIDE(_min_heap_size = 0) ;

INPUT("processor.o")

PROVIDE(_vector_spacing = 0x00000001);
_ebase_address = 0x9D00C000;

_ORIGINAL_RESET_ADDR = 0xBFC00000;
_RESET_ADDR = 0x9D00B000;
_BEV_EXCPT_ADDR = 0x9D00B380;
_DBG_EXCPT_ADDR = 0x9D00B480;
_DBG_CODE_ADDR = 0xBFC02000;
_GEN_EXCPT_ADDR = _ebase_address + 0x180;

MEMORY
{
startup_without_bootloader : ORIGIN = 0xBFC00000, LENGTH = 0x8
kseg0_program_mem (rx) : ORIGIN = 0x9D00D000, LENGTH = 0x72000
kseg0_boot_mem : ORIGIN = 0x9D00B490, LENGTH = 0x970
exception_mem : ORIGIN = 0x9D00C000, LENGTH = 0x1000
kseg1_boot_mem : ORIGIN = 0x9D00B000, LENGTH = 0x490
debug_exec_mem : ORIGIN = 0xBFC02000, LENGTH = 0xFF0
upgradeword : ORIGIN = 0x9D07FFF8,LENGTH = 0x04
checkword : ORIGIN = 0x9D07FFFC,LENGTH = 0x04

config3 : ORIGIN = 0xBFC02FF0, LENGTH = 0x4
config2 : ORIGIN = 0xBFC02FF4, LENGTH = 0x4
config1 : ORIGIN = 0xBFC02FF8, LENGTH = 0x4
config0 : ORIGIN = 0xBFC02FFC, LENGTH = 0x4
kseg1_data_mem (w!x) : ORIGIN = 0xA0000000, LENGTH = 0x18000
reset_safe_area (w!x) : ORIGIN = 0xA0018000, LENGTH = 0x7FF0
calibration_request (w!x) : ORIGIN = 0xA001FFF0, LENGTH = 0x10
sfrs : ORIGIN = 0xBF800000, LENGTH = 0x100000
configsfrs : ORIGIN = 0xBFC02FF0, LENGTH = 0x10
}
SECTIONS
{
.config_BFC02FF0 : {
KEEP(*(.config_BFC02FF0))
} > config3
.config_BFC02FF4 : {
KEEP(*(.config_BFC02FF4))
} > config2
.config_BFC02FF8 : {
KEEP(*(.config_BFC02FF8))
} > config1
.config_BFC02FFC : {
KEEP(*(.config_BFC02FFC))
} > config0
}

SECTIONS
{

.upgradeword :
{
LONG(0x0091A000);
} >upgradeword

.checkword :
{
LONG(0x02B3C000);
} >checkword


.startup_without_bootloader _ORIGINAL_RESET_ADDR :
{
/* creates a “j _reset” instruction at address _ORIGINAL_RESET_ADDR
_reset must be within the same 256MB boundary as the original reset
vector in order for this to work do to the limitations of the ‘j’ instruction.
*/
LONG( ((_reset >> 2) & 0x03FFFFFF) | 0x08000000);
LONG(0);
} > startup_without_bootloader

/* Boot Sections */
.reset _RESET_ADDR :
{
KEEP(*(.reset))
/*KEEP(*(.reset.startup))*/
} > kseg1_boot_mem
.bev_excpt _BEV_EXCPT_ADDR :
{
KEEP(*(.bev_handler))
} > kseg1_boot_mem
.dbg_excpt _DBG_EXCPT_ADDR (NOLOAD) :
{
. += (DEFINED (_DEBUGGER) ? 0x8 : 0x0);
} > kseg1_boot_mem
.dbg_code _DBG_CODE_ADDR (NOLOAD) :
{
. += (DEFINED (_DEBUGGER) ? 0xFF0 : 0x0);
} > debug_exec_mem
.app_excpt _GEN_EXCPT_ADDR :
{
KEEP(*(.gen_handler))
} > exception_mem
.vector_0 _ebase_address + 0x200 :
{
KEEP(*(.vector_0))
} > exception_mem
ASSERT (_vector_spacing == 0 || SIZEOF(.vector_0) <= (_vector_spacing << 5), "function at exception vector 0 too large")
.vector_1 _ebase_address + 0x200 + (_vector_spacing << 5) * 1 :
{
KEEP(*(.vector_1))
} > exception_mem
ASSERT (_vector_spacing == 0 || SIZEOF(.vector_1) <= (_vector_spacing << 5), "function at exception vector 1 too large")
.vector_2 _ebase_address + 0x200 + (_vector_spacing << 5) * 2 :
{
KEEP(*(.vector_2))
} > exception_mem

cut the rest of the vectors off

.startup ORIGIN(kseg0_boot_mem) :
{
KEEP(*(.startup))
} > kseg0_boot_mem
/* Code Sections */
.text ORIGIN(kseg0_program_mem) :
{
_text_begin = . ;
*(.text .stub .text.* .gnu.linkonce.t.*)
KEEP (*(.text.*personality*))
/* .gnu.warning sections are handled specially by elf32.em. */
*(.gnu.warning)
*(.mips16.fn.*)
*(.mips16.call.*)
_text_end = . ;
} >kseg0_program_mem =0
/* Read-only sections */
.rodata :
{
*(.rodata .rodata.* .gnu.linkonce.r.*)
*(.rodata1)
. = ALIGN(4) ;
} >kseg0_program_mem
/*
* Small initialized constant global and static data can be placed in the
* .sdata2 section. This is different from .sdata, which contains small
* initialized non-constant global and static data.
*/
.sdata2 ALIGN(4) :
{
*(.sdata2 .sdata2.* .gnu.linkonce.s2.*)
. = ALIGN(4) ;
} >kseg0_program_mem
/*
* Uninitialized constant global and static data (i.e., variables which will
* always be zero). Again, this is different from .sbss, which contains
* small non-initialized, non-constant global and static data.
*/
.sbss2 ALIGN(4) :
{
*(.sbss2 .sbss2.* .gnu.linkonce.sb2.*)
. = ALIGN(4) ;
} >kseg0_program_mem
.eh_frame_hdr : { *(.eh_frame_hdr) }
.eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) }
.dbg_data (NOLOAD) :
{
. += (DEFINED (_DEBUGGER) ? 0x200 : 0x0);
} >kseg1_data_mem
/* Persistent data */
.persist :
{
_persist_begin = .;
*(.persist .persist.*)
_persist_end = .;
} >kseg1_data_mem
.data :
{
_data_begin = . ;
*(.data .data.* .gnu.linkonce.d.*)
KEEP (*(.gnu.linkonce.d.*personality*))
*(.data1)
} >kseg1_data_mem AT>kseg0_program_mem
_data_image_begin = LOADADDR(.data) ;
.eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) }
. = .;
_gp = ALIGN(16) + 0x7ff0;
.got ALIGN(4) :
{
*(.got.plt) *(.got)
} >kseg1_data_mem AT>kseg0_program_mem
/*
* We want the small data sections together, so single-instruction offsets
* can access them all, and initialized data all before uninitialized, so
* we can shorten the on-disk segment size.
*/
.sdata ALIGN(4) :
{
_sdata_begin = . ;
*(.sdata .sdata.* .gnu.linkonce.s.*)
_sdata_end = . ;
} >kseg1_data_mem AT>kseg0_program_mem
.lit8 :
{
*(.lit8)
} >kseg1_data_mem AT>kseg0_program_mem
.lit4 :
{
*(.lit4)
} >kseg1_data_mem AT>kseg0_program_mem
. = ALIGN (4) ;
_data_end = . ;
_bss_begin = . ;
.sbss ALIGN(4) :
{
_sbss_begin = . ;
*(.dynsbss)
*(.sbss .sbss.* .gnu.linkonce.sb.*)
*(.scommon)
_sbss_end = . ;
} >kseg1_data_mem
.bss :
{
*(.dynbss)
*(.bss .bss.* .gnu.linkonce.b.*)
*(COMMON)
/*
* Align here to ensure that the .bss section occupies space up to
* _end. Align after .bss to ensure correct alignment even if the
* .bss section disappears because there are no input sections.
*/
. = ALIGN(4) ;
} >kseg1_data_mem
. = ALIGN(4) ;
_end = . ;
_bss_end = . ;
/* Heap allocating takes a chunk of memory following BSS */
.heap ALIGN(8) :
{
_heap = . ;
. += _min_heap_size ;
. = ALIGN(8);
} >kseg1_data_mem
/* Stack allocation follows the heap */
.stack ALIGN(8) :
{
_splim = . ;
_SPLIM = . ;
. += _min_stack_size ;
. = ALIGN(8);
} >kseg1_data_mem

/*
* RAM functions go at the end of our stack and heap allocation.
* Alignment of 2K required by the boundary register (BMXDKPBA).
*/
.ramfunc ALIGN(2K) :
{
_ramfunc_begin = . ;
*(.ramfunc .ramfunc.*)
. = ALIGN(4) ;
_ramfunc_end = . ;
} >kseg1_data_mem AT>kseg0_program_mem
_ramfunc_image_begin = LOADADDR(.ramfunc) ;
_ramfunc_length = SIZEOF(.ramfunc) ;
_bmxdkpba_address = _ramfunc_begin - ORIGIN(kseg1_data_mem) ;
_bmxdudba_address = LENGTH(kseg1_data_mem) ;
_bmxdupba_address = LENGTH(kseg1_data_mem) ;

/* RESET SAFE SECTION TO BE LOCATED AT */
.reset_safe():
{
KEEP(*(.reset_safe))
} >reset_safe_area

.calib_request():
{
KEEP(*(.calib_request))
} >calibration_request

/*
* The actual top of stack should include the gap between the stack
* section and the beginning of the .ramfunc section caused by the
* alignment of the .ramfunc section minus 1 word. If RAM functions
* do not exist, then the top of the stack should point to the end of
* the data memory.
*/
_stack = (_ramfunc_length > 0)
? _ramfunc_begin - 4
: ORIGIN(kseg1_data_mem) + LENGTH(kseg1_data_mem) ;
ASSERT((_min_stack_size + _min_heap_size) <= (_stack - _heap),
"Not enough space to allocate both stack and heap. Reduce heap and/or stack size.")
/* The .pdr section belongs in the absolute section */
/DISCARD/ : { *(.pdr) }
/* We don't load .reginfo onto the target, so don't locate it
* in real memory
*/
/DISCARD/ : { *(.reginfo) }
/* Stabs debugging sections. */
.stab 0 : { *(.stab) }
.stabstr 0 : { *(.stabstr) }
.stab.excl 0 : { *(.stab.excl) }
.stab.exclstr 0 : { *(.stab.exclstr) }
.stab.index 0 : { *(.stab.index) }
.stab.indexstr 0 : { *(.stab.indexstr) }
.comment 0 : { *(.comment) }
/* DWARF debug sections.
Symbols in the DWARF debugging sections are relative to the beginning
of the section so we begin them at 0. */
/* DWARF 1 */
.debug 0 : { *(.debug) }
.line 0 : { *(.line) }
/* GNU DWARF 1 extensions */
.debug_srcinfo 0 : { *(.debug_srcinfo) }
.debug_sfnames 0 : { *(.debug_sfnames) }
/* DWARF 1.1 and DWARF 2 */
.debug_aranges 0 : { *(.debug_aranges) }
.debug_pubnames 0 : { *(.debug_pubnames) }
/* DWARF 2 */
.debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
.debug_abbrev 0 : { *(.debug_abbrev) }
.debug_line 0 : { *(.debug_line) }
.debug_frame 0 : { *(.debug_frame) }
.debug_str 0 : { *(.debug_str) }
.debug_loc 0 : { *(.debug_loc) }
.debug_macinfo 0 : { *(.debug_macinfo) }
/* SGI/MIPS DWARF 2 extensions */
.debug_weaknames 0 : { *(.debug_weaknames) }
.debug_funcnames 0 : { *(.debug_funcnames) }
.debug_typenames 0 : { *(.debug_typenames) }
.debug_varnames 0 : { *(.debug_varnames) }
/DISCARD/ : { *(.rel.dyn) }
/DISCARD/ : { *(.note.GNU-stack) }
}


RE: PIC32 Soft Reset to Application Start

Posted by Dave on August 27, 2012
That's a bit complex to look through in detail, and does not show what your start up code is doing. Take a more pragmatic approach and step through the C start up code while it is executing. You don't need to step through each cycle of the zeroing out loop, just see what the start address is and what the end address is (the address the loop will terminate at).

If you are using heap_3 then it is likely your heap is not being cleared to zero, but the data structures used by the heap implementation (which will be the C compilers implementation, not a FreeRTOS implementation) will be. All the same, it might be worth manually memset'ing the heap to zero on reset to. You should be able to get the start and end of the heap as linker variables.

RE: PIC32 Soft Reset to Application Start

Posted by David Thedens on August 27, 2012
yes, the CRT0 code probably inits all the memory that it knows about, but I bet that the heap used by FreeRTOS is not initialized. When the app starts back up, any state not explicitly initialize by will remain.

just zero out the freeRTOS heap area and see what happens.

RE: PIC32 Soft Reset to Application Start

Posted by Jason on August 28, 2012
Turns out I am completely wrong.

When I was doing a jump or initializing C, some interrupt flags were set for some reason. one of those happens to be an interrupt which could cause me to think this was happening.

feel pretty ridiculous. thanks for the help though.


[ Back to the top ]    [ About FreeRTOS ]    [ Privacy ]    [ Sitemap ]    [ ]


Copyright (C) Amazon Web Services, Inc. or its affiliates. All rights reserved.

Latest News

NXP tweet showing LPC5500 (ARMv8-M Cortex-M33) running FreeRTOS.

Meet Richard Barry and learn about running FreeRTOS on RISC-V at FOSDEM 2019

Version 10.1.1 of the FreeRTOS kernel is available for immediate download. MIT licensed.

View a recording of the "OTA Update Security and Reliability" webinar, presented by TI and AWS.


Careers

FreeRTOS and other embedded software careers at AWS.



FreeRTOS Partners

ARM Connected RTOS partner for all ARM microcontroller cores

Espressif ESP32

IAR Partner

Microchip Premier RTOS Partner

RTOS partner of NXP for all NXP ARM microcontrollers

Renesas

STMicro RTOS partner supporting ARM7, ARM Cortex-M3, ARM Cortex-M4 and ARM Cortex-M0

Texas Instruments MCU Developer Network RTOS partner for ARM and MSP430 microcontrollers

OpenRTOS and SafeRTOS

Xilinx Microblaze and Zynq partner