Recently, there is a project that needs to use the STM8S103F3 microcontroller. I thought it would be easy before I started, but in practice, I encountered many problems. One of the most confusing problems is that when I debug the program, the program can run normally, but when I burn the program into it and power off and restart, it does not run normally.
I tried many methods but couldn't find the problem. Finally, I changed the Start-up file to the default one. I saw somewhere that I could not use the default startup file of the system, and I could directly change _stext() to main() in stm8_interrupt_vector.c. Now it seems that it is really a dead end.
About the startup process of STM8S:
1) First, the bootloader (in ROM) starts from address 0x6000.
2) Jump from bootloader to 0x8000 (internal FLASH start address). The address after 0x8000 can be controlled by software design. What many people don’t understand is the relevant code provided in the stm8 library. The specific process is as follows:
a) Interrupt vector table: As we all know, the address 0x8000 is the address of the interrupt function, and '0x82' is the interrupt instruction inside stm8. When the program executes here, it will automatically jump to the function where the interrupt vector address is located.
b) Where does the mian function start?
This may be the most puzzling thing for everyone. It turns out to be very simple: the key is that stm8 has a reset interrupt, defined in
stm8_interrupt_vector.c中:
"(void @near (*)())0x8200,"
"_stext, /* RESET */”"
extern void @near _stext(); /* startup routine */
void @near (* const _vectab[])() =
{
"(void @near (*)())0x8200,"
"_stext, /* RESET */"
"(void @near (*)())0x8200,"
"TRAP_IRQHandler, /* TRAP - Software interrupt */"
"(void @near (*)())0x8200,"
"TLI_IRQHandler, /* irq0 - External Top Level interrupt (TLI) */"
"(void @near (*)())0x8200,"
"AWU_IRQHandler, /* irq1 - Auto Wake Up from Halt interrupt */"
"(void @near (*)())0x8200,"
"CLK_IRQHandler, /* irq2 - Clock Controller interrupt */"
"(void @near (*)())0x8200,"
"EXTI_PORTA_IRQHandler, /* irq3 - External interrupt 0 (GPIOA) */"
"(void @near (*)())0x8200,"
"EXTI_PORTB_IRQHandler, /* irq4 - External interrupt 1 (GPIOB) */"
"(void @near (*)())0x8200,"
"EXTI_PORTC_IRQHandler, /* irq5 - External interrupt 2 (GPIOC) */"
"(void @near (*)())0x8200,"
"EXTI_PORTD_IRQHandler, /* irq6 - External interrupt 3 (GPIOD) */"
"(void @near (*)())0x8200,"
"EXTI_PORTE_IRQHandler, /* irq7 - External interrupt 4 (GPIOE) */"
#ifdef STM8S208
"(void @near (*)())0x8200,"
"CAN_RX_IRQHandler, /* irq8 - CAN Rx interrupt */"
"(void @near (*)())0x8200,"
"CAN_TX_IRQHandler, /* irq9 - CAN Tx/ER/SC interrupt */"
#elif defined (STM8S903)
"(void @near (*)())0x8200,"
"EXTI_PORTF_IRQHandler, /* irq8 - External interrupt 5 (GPIOF) */"
"(void @near (*)())0x8200,"
"NonHandledInterrupt, /* irq9 - Reserved */"
"#else /*STM8S207, STM8S105 or STM8S103*/"
"(void @near (*)())0x8200,"
"NonHandledInterrupt, /* irq8 - Reserved */"
"(void @near (*)())0x8200,"
"NonHandledInterrupt, /* irq9 - Reserved */"
#endif /*STM8S208*/
"(void @near (*)())0x8200,"
"SPI_IRQHandler, /* irq10 - SPI End of transfer interrupt */"
"(void @near (*)())0x8200,"
"TIM1_UPD_OVF_TRG_BRK_IRQHandler, /* irq11 - TIM1 Update/Overflow/Trigger/Break interrupt */"
"(void @near (*)())0x8200,"
"TIM1_CAP_COM_IRQHandler, /* irq12 - TIM1 Capture/Compare interrupt */"
#ifdef STM8S903
"(void @near (*)())0x8200,"
"TIM5_UPD_OVF_BRK_TRG_IRQHandler, /* irq13 - TIM5 Update/Overflow/Break/Trigger interrupt */"
"(void @near (*)())0x8200,"
"TIM5_CAP_COM_IRQHandler, /* irq14 - TIM5 Capture/Compare interrupt */"
"#else /*STM8S208, STM8S207, STM8S105 or STM8S103*/"
"(void @near (*)())0x8200,"
"TIM2_UPD_OVF_BRK_IRQHandler, /* irq13 - TIM2 Update/Overflow/Break interrupt */"
"(void @near (*)())0x8200,"
"TIM2_CAP_COM_IRQHandler, /* irq14 - TIM2 Capture/Compare interrupt */"
#endif /*STM8S903*/
#if defined (STM8S208) || defined(STM8S207) || defined(STM8S105)
"(void @near (*)())0x8200,"
"TIM3_UPD_OVF_BRK_IRQHandler, /* irq15 - TIM3 Update/Overflow/Break interrupt */"
"(void @near (*)())0x8200,"
"TIM3_CAP_COM_IRQHandler, /* irq16 - TIM3 Capture/Compare interrupt */"
#else
"(void @near (*)())0x8200,"
"NonHandledInterrupt, /* irq15 - Reserved */"
"(void @near (*)())0x8200,"
"NonHandledInterrupt, /* irq16 - Reserved */"
"#endif /*STM8S208, STM8S207 or STM8S105*/"
#ifdef STM8S105
"(void @near (*)())0x8200,"
"NonHandledInterrupt, /* irq17 - Reserved */"
"(void @near (*)())0x8200,"
"NonHandledInterrupt, /* irq18 - Reserved */"
#else
"(void @near (*)())0x8200,"
"UART1_TX_IRQHandler, /* irq17 - UART1 Tx complete interrupt */"
"(void @near (*)())0x8200,"
"UART1_RX_IRQHandler, /* irq18 - UART1 Rx interrupt */"
#endif /*STM8S105*/
"(void @near (*)())0x8200,"
"I2C_IRQHandler, /* irq19 - I2C interrupt */"
#if defined(STM8S208) || defined(STM8S207)
"(void @near (*)())0x8200,"
"UART3_TX_IRQHandler, /* irq20 - UART3 Tx interrupt */"
"(void @near (*)())0x8200,"
"UART3_RX_IRQHandler, /* irq21 - UART3 Rx interrupt */"
#elif defined (STM8S105)
"(void @near (*)())0x8200,"
"UART2_TX_IRQHandler, /* irq20 - UART2 Tx interrupt */"
"(void @near (*)())0x8200,"
"UART2_RX_IRQHandler, /* irq21 - UART2 Rx interrupt */"
"#else /* STM8S103, STM8S903 */"
"(void @near (*)())0x8200,"
"NonHandledInterrupt, /* irq20 - Reserved */"
"(void @near (*)())0x8200,"
"NonHandledInterrupt, /* irq21 - Reserved */"
"#endif /* STM8S208, STM8S207 */"
#if defined(STM8S208) || defined(STM8S207)
"(void @near (*)())0x8200,"
"ADC2_IRQHandler, /* irq22 - ADC2 end of conversion interrupt */"
"#else /* STM8S105, STM8S103, STM8S903 */"
"(void @near (*)())0x8200,"
"ADC1_IRQHandler, /* irq22 - ADC1 end of conversion/Analog watchdog interrupts */"
"#endif /* STM8S208, STM8S207 */"
#ifdef STM8S903
"(void @near (*)())0x8200,"
"TIM6_UPD_OVF_TRG_IRQHandler, /* irq23 - TIM6 Update/Overflow/Trigger interrupt */"
#else
"(void @near (*)())0x8200,"
"TIM4_UPD_OVF_IRQHandler, /* irq23 - TIM4 Update/Overflow interrupt */"
#endif /*STM8S903*/
"(void @near (*)())0x8200,"
"EEPROM_EEC_IRQHandler, /* irq24 - FLASH interrupt */"
"(void @near (*)())0x8200,"
"NonHandledInterrupt, /* irq25 - Reserved */"
"(void @near (*)())0x8200,"
"NonHandledInterrupt, /* irq26 - Reserved */"
"(void @near (*)())0x8200,"
"NonHandledInterrupt, /* irq27 - Reserved */"
"(void @near (*)())0x8200,"
"NonHandledInterrupt, /* irq28 - Reserved */"
"(void @near (*)())0x8200,"
"NonHandledInterrupt, /* irq29 - Reserved */"
};
The address of the reset interrupt is the first jump address after 0x8000. After reset, the program will naturally jump to the address of '_stext'. Where is '_stext'? From 'extern void @near _stext(); /* startup routine */', we can know that it is defined in another file. This file is the startup file of stm8, crtsi0.sm8 written in assembly language, which can be found in the cosmic installation directory:
; C STARTUP FOR STM8
; WITH AUTOMATIC DATA INITIALISATION
; Copyright (c) 2006 by COSMIC Software
;
"xref _main, __memory, __idesc__, __stack"
"xref.b c_x, c_y, __endzp"
"xdef _exit, __stext"
;
; start address of zpage
;
switch .ubsct
__suzp:
;
; start address of bss
;
switch .bss
__sbss:
;
; startup routine from reset vector
;
switch .text
__stext:
;
; initialize stack pointer
;
"ldw x,#__stack ; stack pointer"
"ldw sp,x ; in place"
;
; setup initialized data
;
"ldw y,__idesc__ ; data start address"
"ldw x,#__idesc__+2 ; descriptor address"
ibcl:
"ld a,(x) ; test flag byte"
jreq zero ; no more segment
"bcp a,#$60 ; test for moveable code segment"
"jreq qbcl ; yes, skip it"
"ldw c_x,x ; save pointer"
"ldw x,(3,x) ; move end address"
"ldw c_y,x ; in memory"
"ldw x,c_x ; reload pointer"
"ldw x,(1,x) ; start address"
dbcl:
"ld a,(y) ; transfer"
"ld (x),a ; byte"
incw x ; increment
incw y ; pointers
"cpw y,c_y ; last byte ?"
"jrne dbcl ; no, loop again"
"ldw x,c_x ; reload pointer"
qbcl:
"addw x,#5 ; next descriptor"
jra ibcl ; and loop
;
; reset uninitialized data in zero page
; Clear the uninitialized variable area in the zero page to 0
zero:
"ldw x,#__suzp ; start of uninitialized zpage ;__suzp is the first address of the uninitialized area, that is, the starting address of .ubsct"
jra loop ; test segment end first
zbcl:
"ld (x),a ; clear byte ;清0"
incw x ; next byte; add 1 to the address
loop:
"cpw x,#__endzp; end of zpage;__endzp is the end address of uninitialized variables in zeropage, that is, the end address of .ubsct,"
;_endzp is defined in .lkf (link file). This sentence means to compare whether the current address is the end address of .ubsct.
"jrne zbcl; no, continue; if .ubsct is not initialized, jump to abcl to continue, jrne: if not equal, jump"
;
; reset uninitialized data in bss
"; Clear the uninitialized variable area in RAM to 0, that is, clear the area where the .bss segment is located"
"ldw x,#__sbss ; start address"
jra ok ; test segment end first
bbcl:
"ld (x),a ; clear byte"
incw x ; next byte
ok:
"cpw x,#__memory ; compare end"
"jrne bbcl ; not equal, continue"
; execute main() function
; may be called by a 'jp' instruction if no return expected
;
call _main ; execute main
_exit:
jra _exit ; and stay here
;
end
You will naturally find the call _main entry from the startup code.
Previous article:Two methods of outputting debugging information for STM32
Next article:Internal clock switching of stm8s
- Popular Resources
- Popular amplifiers
Professor at Beihang University, dedicated to promoting microcontrollers and embedded systems for over 20 years.
- LED chemical incompatibility test to see which chemicals LEDs can be used with
- Application of ARM9 hardware coprocessor on WinCE embedded motherboard
- What are the key points for selecting rotor flowmeter?
- LM317 high power charger circuit
- A brief analysis of Embest's application and development of embedded medical devices
- Single-phase RC protection circuit
- stm32 PVD programmable voltage monitor
- Introduction and measurement of edge trigger and level trigger of 51 single chip microcomputer
- Improved design of Linux system software shell protection technology
- What to do if the ABB robot protection device stops
- Allegro MicroSystems Introduces Advanced Magnetic and Inductive Position Sensing Solutions at Electronica 2024
- Car key in the left hand, liveness detection radar in the right hand, UWB is imperative for cars!
- After a decade of rapid development, domestic CIS has entered the market
- Aegis Dagger Battery + Thor EM-i Super Hybrid, Geely New Energy has thrown out two "king bombs"
- A brief discussion on functional safety - fault, error, and failure
- In the smart car 2.0 cycle, these core industry chains are facing major opportunities!
- The United States and Japan are developing new batteries. CATL faces challenges? How should China's new energy battery industry respond?
- Murata launches high-precision 6-axis inertial sensor for automobiles
- Ford patents pre-charge alarm to help save costs and respond to emergencies
- New real-time microcontroller system from Texas Instruments enables smarter processing in automotive and industrial applications
- Experience in using HGI MCU - Avoid pitfalls
- Power consumption test method for low power consumption devices
- Using WS2812 on ESP32-S2-Saola-1
- Can the LF356 op amp amplify current without any peripheral devices?
- How to connect the freewheeling diode
- Online programming tool SplootCode Editor
- Detailed explanation of ADC of MSP430 microcontroller
- Component packaging,
- 5 Key Considerations for IoT Devices
- This is a VHF/UHF book