PSoC4 Boot Sequence (Part 3) – Preinitializing Variables before main()

Summary

In the previous articles, I took you through the first part of the PSoC4 Boot Sequence.  I traced from the power on of the chip to the beginning of the “Reset()” function.  Then in the 2nd article I showed you how the exception vectors were placed into the ROM (Flash).  In this article I will show you the steps taken to initialize the system so that your C program runs correctly.

PSoC4 Boot Sequence: Initialize C Global Variables

RAM is a volatile storage area, meaning that when the chip turns on it is in an indeterminate state.  But, what happens when you define a global variable that resides in the RAM, because it can change, and is also initialized.  Consider this block of code:

PSoC4 main.c

We know that when this program starts that the variable “aGlobal” has the value of 10.  But aGlobal can change, so it must be in the RAM and everything in the RAM is scrambled when the PSoC4 is Reset.  We are left with the question: How does the variable aGlobal get to be 10?  Lets start with the listing file for main (which as I discussed in the previous article is called main.lst and can be seen in the Results tab inside of folder “Listing Files”.  Here is the section of code that is material to the definition of aGlobal.

PSoC4 Assembly Listing File Global Variable

Line 87 is creates an assembler label called “aGlobal” (which matches our variable name).  Then line 88 inserts 4-bytes (aka the size of an integer) with the value (0x0000000A) [dont forget that it is little endian] into the current segment.  Line 82 defines the current segment to be “.data”.  Now lets look at the linker map file where you can see that the final address of “aGlobal” is 0x200000c4.

PSoC4 Linker Map File

If you run the debugger you can see that by examining the memory at 0x200000c4

PSoC4 Boot Sequence: Examine memory using debugger

But that address is in the RAM (not the flash).  So how does that address end up with the value of 0x0A like we assigned in the program?

PSoC4 Boot Sequence: Start_c()

It turns out that the only function called by the Reset() function is the Start_c() function. This function does four things

  • Initializes the memory (as it says on line 321)
  • Invoke static objects constructors (as it says on line 345)… what in the world does this mean? (the subject of the next two articles)
  • Calls main() a.k.a the start of your program
  • If something bad happens and you return from main then it does an infinite while(1); loop (lines 349-351)

PSoC4 Boot Sequence: Start_C() Function

PSoC4 Boot Sequence: Initialize the Memory

To answer the question how does 0x0A get into 0x200000c4 the first thing to do is look at the linker script.  After looking around in the linker script I find that .data section on lines 214-237.  On line 237 it has a tricky little command, specifically “>ram AT>rom”.  This tells the linker to assign addresses in the RAM region, but to load the data in ROM region.

PSoC4 Boot Sequence: The Linker File - .data Segment

For the purposes of initializing the memory, a __cy_region is a block of memory that has an initialized part (aka a .data section) and a part that is initialized to 0 (aka .bss section).  You can see this in the definition of the __cy_region structure which is declared on line 224 of Cm0Start.c

PSoC4 Boot Sequence: __cy_region structure

On line 322 of the function Start_C() you can see that there is a loop over all of the __cy_regions.  On lines 329-334 it copies from the ROM to the RAM.  The on lines 336-340 it initializes the BSS to 0.

After all of that we are left with is figuring out how an array of __cy_region structures get into the Flash and how the symbols __cy_regions and __cy_region_num are set.  For the answer to that question we are back to the linker script.  All of these symbols we have met earlier in this article.

PSoC4 Boot Sequence: linker script definition of __cy_regions array

Finally, __cy_region_num is defined on line 62.  This calculation works by calculating the size of the __cy_regions array and dividing it by a hardcoded value for the sizeof(__cy_region) (remember it is a pointer, pointer, int, int which are all 4bytes).  I am not a giant fan of this as if someone changed the structure definition in Cm0Start.c the hardcoded 16 will break.

PSoC4 Boot Sequence: _cy_region_num definition

The __cy_regions was made as an array to future proof the system.  I do not believe that there is ever more than one region initialized by this method.

In this next article I will answer the question “What in the world is that __libc_init_array() function?”

Article Description
PSoC4 Boot Sequence (Part 1) - Debugging to the Reset Vector An introduction to the PSoC4 Boot Sequence
PSoC4 Boot Sequence (Part 2) - Creating the Exception Table using the Linker Building the exception vector table
PSoC4 Boot Sequence (Part 3) - Preinitializing Variables before main() Initializing BSS and Data
PSoC4 Boot Sequence (Part 4) - Linker trickery with __attribute_((constructor(101))) Running initialize_psoc()
PSoC4 Boot Sequence (Part 5) - Initialize PSoC