Day 5: Infineon’s Embedded Systems Summer Course (2024)
27/04/24: We disscussed the assignmment given below, OpenOCD, Resets.
Assignment-1
- Extend the given project by adding a new C file Add.c. You must do so by creating a new source folder and creating the file in that folder
- This Add.c is the same file that you created for last week’s assignment
- Create a child Makefile and have it contribute Add.o to the list of objects that must be linked together
- Call your add function from main() and pass two favourite integers of yours
- Do a “make clean” and later do a “make all”
- Open the map file and find out where in the processor address space is your new function allocated
- Now modify main() and this time do not call the add function
- Rebuild the project by following Step <5>
- Open the map file and determine where in the processor address space do you now find your add function.
So when you use the funnction in your make file then it is reflected on the memory map else it is not. even if you dont use it in main it will allocate some memory if it is present in make file i.e if you include the child make file that says how to compile and link the Add.o file in parent make file it will come up in make file.
Assignment-2
In the startup.c file, navigate to the Reset_Handler function. What it does there is quite obvious. But there seems to be an error with handling of the data section. What is the error? Hint: You may perhaps need to refer to the linker script.
#include <stdint.h>
#define SRAM_START 0x20000000U
#define SRAM_SIZE (16U * 1024U) //16KB
#define SRAM_END ((SRAM_START) + (SRAM_SIZE))#define STACK_START SRAM_END
#define CYREG_WDT_DISABLE_KEY 0x40030038u
#define CY_SYS_WDT_KEY ((uint32_t)(0xACED8865u))extern uint32_t __etext;
extern uint32_t __data_start;
extern uint32_t __data_end;
extern uint32_t _la_data;extern uint32_t __bss_start__;
extern uint32_t __bss_end__;extern uint32_t __STACK_START;
extern uint32_t __STACK_END;
extern void _init(void) {;}
/* The static objects constructors initializer */
extern void __libc_init_array(void);int main(void);
void Reset_handler(void);
//void Reset_handler(void) __attribute__((section(“.rand_vector”))) ;
void Default_Handler(void);void NMI_Handler (void) __attribute__ ((weak, alias(“Default_Handler”)));
void HardFault_Handler (void) __attribute__ ((weak));
void SVC_Handler (void) __attribute__ ((weak, alias(“Default_Handler”)));
void PendSV_Handler (void) __attribute__ ((weak, alias(“Default_Handler”)));
void SysTick_Handler (void) __attribute__ ((weak, alias(“Default_Handler”)));void ioss_interrupts_gpio_0_IRQHandler (void) __attribute__ ((weak, alias(“Default_Handler”))); /* GPIO P0 */
void ioss_interrupts_gpio_1_IRQHandler (void) __attribute__ ((weak, alias(“Default_Handler”))); /* GPIO P1 */
void ioss_interrupts_gpio_2_IRQHandler (void) __attribute__ ((weak, alias(“Default_Handler”))); /* GPIO P2 */
void ioss_interrupts_gpio_3_IRQHandler (void) __attribute__ ((weak, alias(“Default_Handler”))); /* GPIO P3 */
void ioss_interrupt_gpio_IRQHandler (void) __attribute__ ((weak, alias(“Default_Handler”))); /* GPIO All Ports */
void lpcomp_interrupt_IRQHandler (void) __attribute__ ((weak, alias(“Default_Handler”))); /* LPCOMP trigger interrupt */
void srss_interrupt_wdt_IRQHandler (void) __attribute__ ((weak, alias(“Default_Handler”))); /* WDT */
void scb_0_interrupt_IRQHandler (void) __attribute__ ((weak, alias(“Default_Handler”))); /* SCB #0 */
void scb_1_interrupt_IRQHandler (void) __attribute__ ((weak, alias(“Default_Handler”))); /* SCB #1 */
void scb_2_interrupt_IRQHandler (void) __attribute__ ((weak, alias(“Default_Handler”))); /* SCB #2 */
void scb_3_interrupt_IRQHandler (void) __attribute__ ((weak, alias(“Default_Handler”))); /* SCB #3 */
void scb_4_interrupt_IRQHandler (void) __attribute__ ((weak, alias(“Default_Handler”))); /* SCB #4 */
void pass_0_interrupt_ctbs_IRQHandler (void) __attribute__ ((weak, alias(“Default_Handler”))); /* CTBm Interrupt (all CTBms) */
void wco_interrupt_IRQHandler (void) __attribute__ ((weak, alias(“Default_Handler”))); /* WCO WDT Interrupt */
void cpuss_interrupt_dma_IRQHandler (void) __attribute__ ((weak, alias(“Default_Handler”))); /* DMA Interrupt */
void cpuss_interrupt_spcif_IRQHandler (void) __attribute__ ((weak, alias(“Default_Handler”))); /* SPCIF interrupt */
void csd_interrupt_IRQHandler (void) __attribute__ ((weak, alias(“Default_Handler”))); /* CSD #0 (Primarily Capsense) */
void tcpwm_interrupts_0_IRQHandler (void) __attribute__ ((weak, alias(“Default_Handler”))); /* TCPWM #0, Counter #0 */
void tcpwm_interrupts_1_IRQHandler (void) __attribute__ ((weak, alias(“Default_Handler”))); /* TCPWM #0, Counter #1 */
void tcpwm_interrupts_2_IRQHandler (void) __attribute__ ((weak, alias(“Default_Handler”))); /* TCPWM #0, Counter #2 */
void tcpwm_interrupts_3_IRQHandler (void) __attribute__ ((weak, alias(“Default_Handler”))); /* TCPWM #0, Counter #3 */
void tcpwm_interrupts_4_IRQHandler (void) __attribute__ ((weak, alias(“Default_Handler”))); /* TCPWM #0, Counter #4 */
void tcpwm_interrupts_5_IRQHandler (void) __attribute__ ((weak, alias(“Default_Handler”))); /* TCPWM #0, Counter #5 */
void tcpwm_interrupts_6_IRQHandler (void) __attribute__ ((weak, alias(“Default_Handler”))); /* TCPWM #0, Counter #6 */
void tcpwm_interrupts_7_IRQHandler (void) __attribute__ ((weak, alias(“Default_Handler”))); /* TCPWM #0, Counter #7 */
void pass_0_interrupt_sar_IRQHandler (void) __attribute__ ((weak, alias(“Default_Handler”))); /* SAR */
void can_interrupt_can_IRQHandler (void) __attribute__ ((weak, alias(“Default_Handler”))); /* CAN Interrupt */
void crypto_interrupt_IRQHandler (void) __attribute__ ((weak, alias(“Default_Handler”))); /* Crypto Interrupt */const uint32_t vector[] __attribute__((section(“.isr_vector”)))= {
STACK_START,
(uint32_t)&Reset_handler, /* Reset Handler */
(uint32_t)NMI_Handler, /* -14 NMI Handler */
(uint32_t)HardFault_Handler, /* -13 Hard Fault Handler */
(uint32_t)0, /* Reserved */
(uint32_t)0, /* Reserved */
(uint32_t)0, /* Reserved */
(uint32_t)0, /* Reserved */
(uint32_t)0, /* Reserved */
(uint32_t)0, /* Reserved */
(uint32_t)0, /* Reserved */
(uint32_t)SVC_Handler, /* -5 SVCall Handler */
(uint32_t)0, /* Reserved */
(uint32_t)0, /* Reserved */
(uint32_t)PendSV_Handler, /* -2 PendSV Handler */
(uint32_t)SysTick_Handler, /* -1 SysTick Handler *//* Interrupts */
(uint32_t)ioss_interrupts_gpio_0_IRQHandler, /* 0 GPIO P0 */
(uint32_t)ioss_interrupts_gpio_1_IRQHandler, /* 1 GPIO P1 */
(uint32_t)ioss_interrupts_gpio_2_IRQHandler, /* 2 GPIO P2 */
(uint32_t)ioss_interrupts_gpio_3_IRQHandler, /* 3 GPIO P3 */
(uint32_t)ioss_interrupt_gpio_IRQHandler, /* 4 GPIO All Ports */
(uint32_t)lpcomp_interrupt_IRQHandler, /* 5 LPCOMP trigger interrupt */
(uint32_t)srss_interrupt_wdt_IRQHandler, /* 6 WDT */
(uint32_t)scb_0_interrupt_IRQHandler, /* 7 SCB #0 */
(uint32_t)scb_1_interrupt_IRQHandler, /* 8 SCB #1 */
(uint32_t)scb_2_interrupt_IRQHandler, /* 9 SCB #2 */
(uint32_t)scb_3_interrupt_IRQHandler, /* 10 SCB #3 */
(uint32_t)scb_4_interrupt_IRQHandler, /* 11 SCB #4 */
(uint32_t)pass_0_interrupt_ctbs_IRQHandler, /* 12 CTBm Interrupt (all CTBms) */
(uint32_t)wco_interrupt_IRQHandler, /* 13 WCO WDT Interrupt */
(uint32_t)cpuss_interrupt_dma_IRQHandler, /* 14 DMA Interrupt */
(uint32_t)cpuss_interrupt_spcif_IRQHandler, /* 15 SPCIF interrupt */
(uint32_t)csd_interrupt_IRQHandler, /* 16 CSD #0 (Primarily Capsense) */
(uint32_t)tcpwm_interrupts_0_IRQHandler, /* 17 TCPWM #0, Counter #0 */
(uint32_t)tcpwm_interrupts_1_IRQHandler, /* 18 TCPWM #0, Counter #1 */
(uint32_t)tcpwm_interrupts_2_IRQHandler, /* 19 TCPWM #0, Counter #2 */
(uint32_t)tcpwm_interrupts_3_IRQHandler, /* 20 TCPWM #0, Counter #3 */
(uint32_t)tcpwm_interrupts_4_IRQHandler, /* 21 TCPWM #0, Counter #4 */
(uint32_t)tcpwm_interrupts_5_IRQHandler, /* 22 TCPWM #0, Counter #5 */
(uint32_t)tcpwm_interrupts_6_IRQHandler, /* 23 TCPWM #0, Counter #6 */
(uint32_t)tcpwm_interrupts_7_IRQHandler, /* 24 TCPWM #0, Counter #7 */
(uint32_t)pass_0_interrupt_sar_IRQHandler, /* 25 SAR */
(uint32_t)can_interrupt_can_IRQHandler, /* 26 CAN Interrupt */
(uint32_t)crypto_interrupt_IRQHandler /* 27 Crypto Interrupt */
};void Reset_handler(void)
{
//disable watchdog
(*(uint32_t *) CYREG_WDT_DISABLE_KEY) = CY_SYS_WDT_KEY;//copy .data section to SRAM
uint32_t size = &__data_end — &__data_start;
uint8_t *pDst = (uint8_t*)&__data_start;
uint8_t *pSrc = (uint8_t*)&_la_data;for(uint32_t i = 0; i< size; i++)
{
*pDst++ = *pSrc;
}
//int the .bss section to zero in SRAM
size = &__bss_end__ — &__bss_start__;
*pDst = (uint8_t*)&__bss_start__;for(uint32_t i = 0; i< size; i++)
{
*pDst++ = 0;
}// Init C std libs
__libc_init_array();//call main()
main();while (1)
{
/* If main returns, make sure we don’t return. */
}
}/* — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — —
Default Handler for Exceptions / Interrupts
* — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — */
void Default_Handler(void)
{
while(1);
}/* — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — —
Default Handler for Hard Fault
* — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — */
void HardFault_Handler(void)
{
//Cy_SysLib_ProcessingFault();
}
Code2: startup.c
#include <stdint.h>
#define SRAM_START 0x20000000U
#define SRAM_SIZE (16U * 1024U) //16KB
#define SRAM_END ((SRAM_START) + (SRAM_SIZE))#define STACK_START SRAM_END
#define CYREG_WDT_DISABLE_KEY 0x40030038u
#define CY_SYS_WDT_KEY ((uint32_t)(0xACED8865u))extern uint32_t __etext;
extern uint32_t __data_start;
extern uint32_t __data_end;
extern uint32_t _la_data;extern uint32_t __bss_start__;
extern uint32_t __bss_end__;extern uint32_t __STACK_START;
extern uint32_t __STACK_END;
extern void _init(void) {;}
/* The static objects constructors initializer */
extern void __libc_init_array(void);int main(void);
void Reset_handler(void);
//void Reset_handler(void) __attribute__((section(“.rand_vector”))) ;
void Default_Handler(void);void NMI_Handler (void) __attribute__ ((weak, alias(“Default_Handler”)));
void HardFault_Handler (void) __attribute__ ((weak));
void SVC_Handler (void) __attribute__ ((weak, alias(“Default_Handler”)));
void PendSV_Handler (void) __attribute__ ((weak, alias(“Default_Handler”)));
void SysTick_Handler (void) __attribute__ ((weak, alias(“Default_Handler”)));void ioss_interrupts_gpio_0_IRQHandler (void) __attribute__ ((weak, alias(“Default_Handler”))); /* GPIO P0 */
void ioss_interrupts_gpio_1_IRQHandler (void) __attribute__ ((weak, alias(“Default_Handler”))); /* GPIO P1 */
void ioss_interrupts_gpio_2_IRQHandler (void) __attribute__ ((weak, alias(“Default_Handler”))); /* GPIO P2 */
void ioss_interrupts_gpio_3_IRQHandler (void) __attribute__ ((weak, alias(“Default_Handler”))); /* GPIO P3 */
void ioss_interrupt_gpio_IRQHandler (void) __attribute__ ((weak, alias(“Default_Handler”))); /* GPIO All Ports */
void lpcomp_interrupt_IRQHandler (void) __attribute__ ((weak, alias(“Default_Handler”))); /* LPCOMP trigger interrupt */
void srss_interrupt_wdt_IRQHandler (void) __attribute__ ((weak, alias(“Default_Handler”))); /* WDT */
void scb_0_interrupt_IRQHandler (void) __attribute__ ((weak, alias(“Default_Handler”))); /* SCB #0 */
void scb_1_interrupt_IRQHandler (void) __attribute__ ((weak, alias(“Default_Handler”))); /* SCB #1 */
void scb_2_interrupt_IRQHandler (void) __attribute__ ((weak, alias(“Default_Handler”))); /* SCB #2 */
void scb_3_interrupt_IRQHandler (void) __attribute__ ((weak, alias(“Default_Handler”))); /* SCB #3 */
void scb_4_interrupt_IRQHandler (void) __attribute__ ((weak, alias(“Default_Handler”))); /* SCB #4 */
void pass_0_interrupt_ctbs_IRQHandler (void) __attribute__ ((weak, alias(“Default_Handler”))); /* CTBm Interrupt (all CTBms) */
void wco_interrupt_IRQHandler (void) __attribute__ ((weak, alias(“Default_Handler”))); /* WCO WDT Interrupt */
void cpuss_interrupt_dma_IRQHandler (void) __attribute__ ((weak, alias(“Default_Handler”))); /* DMA Interrupt */
void cpuss_interrupt_spcif_IRQHandler (void) __attribute__ ((weak, alias(“Default_Handler”))); /* SPCIF interrupt */
void csd_interrupt_IRQHandler (void) __attribute__ ((weak, alias(“Default_Handler”))); /* CSD #0 (Primarily Capsense) */
void tcpwm_interrupts_0_IRQHandler (void) __attribute__ ((weak, alias(“Default_Handler”))); /* TCPWM #0, Counter #0 */
void tcpwm_interrupts_1_IRQHandler (void) __attribute__ ((weak, alias(“Default_Handler”))); /* TCPWM #0, Counter #1 */
void tcpwm_interrupts_2_IRQHandler (void) __attribute__ ((weak, alias(“Default_Handler”))); /* TCPWM #0, Counter #2 */
void tcpwm_interrupts_3_IRQHandler (void) __attribute__ ((weak, alias(“Default_Handler”))); /* TCPWM #0, Counter #3 */
void tcpwm_interrupts_4_IRQHandler (void) __attribute__ ((weak, alias(“Default_Handler”))); /* TCPWM #0, Counter #4 */
void tcpwm_interrupts_5_IRQHandler (void) __attribute__ ((weak, alias(“Default_Handler”))); /* TCPWM #0, Counter #5 */
void tcpwm_interrupts_6_IRQHandler (void) __attribute__ ((weak, alias(“Default_Handler”))); /* TCPWM #0, Counter #6 */
void tcpwm_interrupts_7_IRQHandler (void) __attribute__ ((weak, alias(“Default_Handler”))); /* TCPWM #0, Counter #7 */
void pass_0_interrupt_sar_IRQHandler (void) __attribute__ ((weak, alias(“Default_Handler”))); /* SAR */
void can_interrupt_can_IRQHandler (void) __attribute__ ((weak, alias(“Default_Handler”))); /* CAN Interrupt */
void crypto_interrupt_IRQHandler (void) __attribute__ ((weak, alias(“Default_Handler”))); /* Crypto Interrupt */const uint32_t vector[] __attribute__((section(“.isr_vector”)))= {
STACK_START,
(uint32_t)&Reset_handler, /* Reset Handler */
(uint32_t)NMI_Handler, /* -14 NMI Handler */
(uint32_t)HardFault_Handler, /* -13 Hard Fault Handler */
(uint32_t)0, /* Reserved */
(uint32_t)0, /* Reserved */
(uint32_t)0, /* Reserved */
(uint32_t)0, /* Reserved */
(uint32_t)0, /* Reserved */
(uint32_t)0, /* Reserved */
(uint32_t)0, /* Reserved */
(uint32_t)SVC_Handler, /* -5 SVCall Handler */
(uint32_t)0, /* Reserved */
(uint32_t)0, /* Reserved */
(uint32_t)PendSV_Handler, /* -2 PendSV Handler */
(uint32_t)SysTick_Handler, /* -1 SysTick Handler *//* Interrupts */
(uint32_t)ioss_interrupts_gpio_0_IRQHandler, /* 0 GPIO P0 */
(uint32_t)ioss_interrupts_gpio_1_IRQHandler, /* 1 GPIO P1 */
(uint32_t)ioss_interrupts_gpio_2_IRQHandler, /* 2 GPIO P2 */
(uint32_t)ioss_interrupts_gpio_3_IRQHandler, /* 3 GPIO P3 */
(uint32_t)ioss_interrupt_gpio_IRQHandler, /* 4 GPIO All Ports */
(uint32_t)lpcomp_interrupt_IRQHandler, /* 5 LPCOMP trigger interrupt */
(uint32_t)srss_interrupt_wdt_IRQHandler, /* 6 WDT */
(uint32_t)scb_0_interrupt_IRQHandler, /* 7 SCB #0 */
(uint32_t)scb_1_interrupt_IRQHandler, /* 8 SCB #1 */
(uint32_t)scb_2_interrupt_IRQHandler, /* 9 SCB #2 */
(uint32_t)scb_3_interrupt_IRQHandler, /* 10 SCB #3 */
(uint32_t)scb_4_interrupt_IRQHandler, /* 11 SCB #4 */
(uint32_t)pass_0_interrupt_ctbs_IRQHandler, /* 12 CTBm Interrupt (all CTBms) */
(uint32_t)wco_interrupt_IRQHandler, /* 13 WCO WDT Interrupt */
(uint32_t)cpuss_interrupt_dma_IRQHandler, /* 14 DMA Interrupt */
(uint32_t)cpuss_interrupt_spcif_IRQHandler, /* 15 SPCIF interrupt */
(uint32_t)csd_interrupt_IRQHandler, /* 16 CSD #0 (Primarily Capsense) */
(uint32_t)tcpwm_interrupts_0_IRQHandler, /* 17 TCPWM #0, Counter #0 */
(uint32_t)tcpwm_interrupts_1_IRQHandler, /* 18 TCPWM #0, Counter #1 */
(uint32_t)tcpwm_interrupts_2_IRQHandler, /* 19 TCPWM #0, Counter #2 */
(uint32_t)tcpwm_interrupts_3_IRQHandler, /* 20 TCPWM #0, Counter #3 */
(uint32_t)tcpwm_interrupts_4_IRQHandler, /* 21 TCPWM #0, Counter #4 */
(uint32_t)tcpwm_interrupts_5_IRQHandler, /* 22 TCPWM #0, Counter #5 */
(uint32_t)tcpwm_interrupts_6_IRQHandler, /* 23 TCPWM #0, Counter #6 */
(uint32_t)tcpwm_interrupts_7_IRQHandler, /* 24 TCPWM #0, Counter #7 */
(uint32_t)pass_0_interrupt_sar_IRQHandler, /* 25 SAR */
(uint32_t)can_interrupt_can_IRQHandler, /* 26 CAN Interrupt */
(uint32_t)crypto_interrupt_IRQHandler /* 27 Crypto Interrupt */
};void Reset_handler(void)
{
//disable watchdog
(*(uint32_t *) CYREG_WDT_DISABLE_KEY) = CY_SYS_WDT_KEY;//copy .data section to SRAM
uint32_t size = &__data_end — &__data_start;
uint8_t *pDst = (uint8_t*)&__data_start;
uint8_t *pSrc = (uint8_t*)&_la_data;for(uint32_t i = 0; i< size; i++)
{
*pDst++ = *pSrc++;
}
//int the .bss section to zero in SRAM
size = &__bss_end__ — &__bss_start__;
pDst = (uint8_t*)&__bss_start__;for(uint32_t i = 0; i< size; i++)
{
*pDst++ = 0;
}// Init C std libs
__libc_init_array();//call main()
main();while (1)
{
/* If main returns, make sure we don’t return. */
}
}/* — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — —
Default Handler for Exceptions / Interrupts
* — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — */
void Default_Handler(void)
{
while(1);
}/* — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — —
Default Handler for Hard Fault
* — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — */
void HardFault_Handler(void)
{
//Cy_SysLib_ProcessingFault();
}
In code 2: In the data copy loop inside Reset_handler
, changed *pSrc
to *pSrc++.
impact: The change ensures that the source pointer pSrc
is incremented after each data byte is copied to the destination. This ensures correct copying of the data section from flash to SRAM.
In the .bss
section initialization, changed *pDst = (uint8_t*)&__bss_start__
to pDst = (uint8_t*)&__bss_start__
impact: The change correctly assigns the base address of the .bss
section to the destination pointer pDst
, allowing subsequent zero initialization of the .bss
section in SRAM.
since pDst
is declared as a pointer to uint8_t
, attempting to assign the address of __bss_start__
(which is also a pointer) to the value pointed to by pDst
would result in a type mismatch error. This is because pDst
can only hold the address of a uint8_t
variable, not the address of another pointer.
We covered OpenOCD and startup code
Microcontroller: This is the tiny computer chip inside electronic devices, like your smartphone or a car’s engine control unit (ECU). It’s the brain of the device, controlling how it works.
JTAG (Joint Test Action Group): It’s a standard way to communicate with the microcontroller for testing and debugging purposes. Think of it like a special set of instructions to talk to the microcontroller.
USB to JTAG Converter: This is a device that helps your computer talk to the microcontroller using USB, which is a common way computers connect to devices. It converts the USB signals from your computer into the JTAG signals that the microcontroller understands.
High-Level Source Code Debugger (like GDB): This is a tool that helps software developers find and fix problems in their code. It lets them pause the program at specific points, check the values of variables, and step through the code one line at a time.
OpenOCD Software: This is the star of the show! OpenOCD stands for Open On-Chip Debugger. It’s a piece of software that runs on your computer and acts as a bridge between your high-level debugger (like GDB) and the microcontroller. It translates the commands from the debugger into low-level JTAG commands that the microcontroller understands, and vice versa.
User Commands: These are the things you tell the debugger to do, like setting breakpoints (pausing the program at specific points), flashing a new program onto the microcontroller’s memory, halting the program (pausing it completely), resetting the microcontroller, or stepping through the code one line at a time.
Low-Level JTAG Commands: These are the nitty-gritty instructions that OpenOCD sends to the microcontroller via the USB to JTAG converter. They tell the microcontroller to do things like changing its mode, scanning in data, or running tests.
So, in simple terms, OpenOCD is like the middleman between your computer and the microcontroller, helping them talk to each other so you can debug and test your code effectively.
Summary of ppt done by Ananth Kamath: Embedded Systems Course — Demystifying microcontroller start-up and reset concepts
Ah, the Boot Firmware, the unsung hero of the microcontroller world! Picture this: you’ve just pressed the reset button on your device, and like a diligent butler, the Boot Firmware promptly springs into action. It’s the first responder in the digital realm, kicking off a sequence of instructions faster than you can say “reboot.”
Nestled snugly in the ROM (Read-Only Memory) of your microcontroller lies the Boot Firmware, patiently waiting for its moment in the spotlight. During the fabrication process, it’s not just slapped onto the ROM; no, it’s delicately flashed onto the Boot ROM, akin to an artist carefully etching their masterpiece onto a canvas.
Now, let’s talk about the Reset Vector, the compass guiding our microcontroller ship through the stormy seas of startup. It’s the North Star of our code, pointing the way to the application’s startup code. And where does this magical journey begin? At the Reset Vector’s Start Address, graciously provided by the silicon or board vendor. It’s like receiving a treasure map with an X marks the spot, leading us to buried (code) treasure.
But wait, there’s more! After the Boot Firmware has laid the groundwork, it’s time for the Application Startup Code to shine. Think of it as the backstage crew of a Broadway show, busily prepping the stage before the actors make their grand entrance. It’s responsible for initializing the C environment, tidying up loose ends like BSS initialization and data copying, ensuring everything is in tip-top shape for the main event.
And finally, drumroll please, we have the star of the show: the Application Software! At last, it’s time for the curtain to rise and for Main() to take center stage. With a cheeky smile (yes, even software can smile!), Main() begins its performance, executing the heart and soul of our program with finesse and flair.
So there you have it, the Boot Firmware and its merry band of startup companions, setting the stage for our microcontroller adventures with style, grace, and a dash of whimsy.
Boot Firmware/Start-up software ‒ Boot Firmware is the first instruction sequence that is executed immediately after the reset. This prepares the hardware, for generic application needs of targeted domain where the controller is being used. The execution control is then passed to the application startup code.
Boot Rom ‒ Read Only memory where the boot firmware is located. The firmware is flashed onto the boot rom during fabrication process.
Reset Vector/Start address ‒ The start address of the application start-up code. Provided by silicon or board vendor. ‒ Application Startup code further initializes the C environment. Example: Bss init and data copy
Reset/Power Up: Imagine our microcontroller waking up from a deep slumber, stretching its digital limbs, and readying itself for the tasks ahead. It’s like hitting the snooze button on your alarm clock, but in the world of bits and bytes.
Analog Power Up: Ah, the analog side of things! It’s like making sure your morning coffee is brewed to perfection before taking that first sip. We need our voltages stable and our currents flowing smoothly before diving into the digital fray.
Boot Firmware: Enter the Boot Firmware, our trusty guide through the maze of startup procedures. It’s like the seasoned explorer leading the expedition into uncharted territories. With each step, it lays down the groundwork, ensuring our microcontroller is primed and ready for action.
Application Startup Software: Here comes the supporting cast, ready to assist our microcontroller on its journey. Think of them as the backstage crew, setting the stage for the main performance. They initialize the environment, ensuring everything is in place for the star of the show.
- Reset Handler: Disable the watchdog: When the microcontroller starts up or is reset, the reset handler is the first piece of code that runs. Disabling the watchdog is often necessary to prevent it from resetting the device unintentionally during initialization.
- Copy initialized data from Flash to RAM: In this step, data that has been initialized (e.g., global variables with predefined values) is copied from the non-volatile memory (usually Flash) to the volatile memory (RAM). This ensures that the data is available for use by the program.
- Set uninitialized data to zero: Any variables that have not been explicitly initialized in the code need to be set to a known state. Typically, this involves setting uninitialized data sections in RAM to zero to avoid any unpredictable behavior.
- Jump to main(): Once the essential initialization tasks are complete, control is transferred to the
main()
function. This is where the main program logic resides, and from here, the application's execution continues.
In C and C++, symbols and functions can be classified as weak or strong symbols based on how the linker handles them during the linking process. Here’s a breakdown of weak and strong symbols in our example:
Strong Symbol
A strong symbol is a symbol that is always used by the linker if it’s defined. If there are multiple definitions of a strong symbol across different translation units (source files), it leads to a linker error due to multiple definitions.
In our example:
/* Strong Symbol */
unsigned int strong_var = 10;
Both occurrences of strong_var
in sourceFile1.c
and sourceFile2.c
are strong symbols. If you attempt to link these two files together, you'll get a linker error because strong_var
is defined more than once.
Weak Symbol
A weak symbol, on the other hand, is used only if no strong symbol with the same name is present. If there’s a strong symbol defined, the weak symbol is ignored. Weak symbols provide a way to provide default definitions that can be overridden if a strong symbol is defined elsewhere.
In your example:
/* Weak Symbol */
unsigned int __attribute__((weak)) weak_var = 10;
weak_var
in sourceFile1.c
is a weak symbol. It can be overridden by a strong symbol with the same name, as demonstrated in sourceFile2.c
:
/* Strong Symbol */
unsigned int weak_var = 100;
Here, weak_var
in sourceFile2.c
is a strong symbol, and it will override the weak definition in sourceFile1.c
during the linking process.
In summary, strong symbols are always used by the linker if they are defined, while weak symbols are used only if no strong symbol with the same name is present.
A reset in the context of a microcontroller refers to the process of restoring the device to a known state, typically after power-on or in response to a specific event. Here are some common types of resets and their characteristics:
Power-on reset (POR):
- Purpose: Occurs when the device is powered on, holding it in reset until the power supply stabilizes.
- Ensures: Initialization of all internal registers and peripherals.
Brownout reset (BOD):
- Purpose: Triggers when the power supply voltage falls below a specified threshold during operation, preventing unreliable behavior due to insufficient voltage.
- Ensures: Stable operation by resetting the device if the power supply voltage is inadequate.
Watchdog reset (WRES):
- Purpose: Resets the device if firmware execution fails to service the watchdog timer within a specified interval, preventing system hangs or crashes.
- Ensures: Continual monitoring and proper functioning of the system.
Software-initiated reset (SRES):
- Purpose: Allows firmware to reset the device on demand, typically in response to certain conditions or events.
- Ensures: Control over the reset process within the software, enabling customization of reset behavior.
External reset (XRES):
- Purpose: Triggers a reset using an external electrical signal, such as a push button or an external circuit.
- Ensures: Ability to reset the device externally, useful for debugging, testing, or system recovery.
Protection fault reset (PROT_FAULT):
- Purpose: Resets the device if unauthorized operating conditions occur, such as a violation of memory protection mechanisms.
- Ensures: Security and stability by preventing unauthorized access or operation.
Cold reset and warm reset are two different types of resets, each with its own characteristics:
Cold Reset:
- Also known as a hard reset or power-on reset.
- Involves restarting a device from a completely powered-off state.
- All hardware and software components are initialized from scratch.
- Typically occurs when the device is initially powered on or when power is completely removed and reapplied.
- Often used to ensure a clean startup of the system, especially after a power outage or when the device has been off for an extended period.
- It involves a complete power cycle of the device, including reinitializing hardware peripherals, clearing memory, and reloading firmware from non-volatile memory (such as Flash).
Warm Reset:
- Also known as a soft reset or software reset.
- Involves restarting a device without power cycling it.
- Typically initiated by software or firmware executing a specific reset sequence.
- It doesn’t involve a complete reinitialization of hardware peripherals or reloading firmware from non-volatile memory.
- The CPU and internal registers are reset, but other components may retain their states.
- Useful for restarting the system quickly without going through the entire startup sequence, especially for debugging or recovering from certain software errors or glitches.
- It can be initiated by software routines, such as writing to a specific register or executing a particular instruction that triggers the reset.
This week, we explored the intricate dance of resets, from the grand overtures of cold resets to the swift recoveries of warm resets. Characters like the stoic Power-On Reset (POR) and the vigilant Brownout Reset (BOD) emerged, emphasizing stability and security in the tech world. Each reset reminds us of the resilience and control embedded in the ever-evolving landscape of technology. We also covered assignments and learnt about OpenOCD debugger.