Let me first talk about the IDE and hardware I use. The IDE is IAR integrated development environment. I have used IAR since I learned microcontrollers. I have also used CCS, but I don’t think it is as easy to use as IAR. If you are a CCS enthusiast, please study how to set up CCS to debug the MSP430 program in RAM. In theory, it is also very simple. The hardware is MSP-EXP430F5529LP, which is the red MSP430F5529 LaunchPad. As for why you need to debug the program in RAM, go to Baidu to find out the benefits of doing so. I am too lazy to explain.
First, let's briefly analyze the startup process of MSP430F5529. According to its official data sheet, the interrupt vector table is as follows:
It can be seen that the interrupt vector table is at 0xFF80-0xFFFF, and the reset vector is at 0xFFFE-0xFFFF, a total of two bytes, 16 bits. After the system is powered on or reset, 16 data is taken from here as the value of PC, and then the MCU starts to execute the "main" function. In fact, it is not the main function that is executed first, but the program entry point __program_start function defined by the IAR compiler, which is defined by the compiler as the cstart_begin function, followed by the cstart_call_main function, which will call the main function. Words are not enough, experiments are proof.
Use IAR to create a project, write a few lines of code in main.c, and then uncheck Run to main in the Debugger sub-tab of the project options. The reason for unchecking this option is that this option will directly let the microcontroller run to the first line of code in the main function and then pause during debugging. In this way, the code before the main function cannot be seen. I am using software simulation here, and hardware simulation will have the same result.
After setting, click the debug button and the disassembly window will appear. As shown in the figure below, you can see that the program does not stop in the source code window on the left, but in the disassembly window on the right, and the address of the current program is 0x4400. It has two labels, cstart_begin and __program_start. This function has only one line of code "MOV.W #0x4400,SP". It is not difficult to see that this is setting the stack pointer SP to 0x4400 (note not to confuse it with the current PC value, although the value is the same). The function labeled cstart_call_main follows. The first line of code in this function calls the main function, and the second line calls the exit function. The exit function is a function automatically defined for us by the compiler, which is not explained here.
Then enter the interrupt vector table address 0xFFFE in Go to, and the result is as shown below. The red box is the reset vector, and its value is 0x4400, followed by one of the emulator instructions mentioned in the 5529 reference manual, which will not be analyzed. This verifies the startup process of the MSP430F5529 mentioned above.
Now that we know the startup process of MSP430F5529, the next step is to find the linker script. However, IAR calls it XLINK configuration file, and its suffix is .xcl. There are options related to the linker in the Linker sub-tab of the project options, as shown below
You can see that there is an Override default option in the Linker configuration file option column. Check it, and then you can find the linker script file used by IAR by default. Its path is X:\
Program Files (x86)\IAR Systems\Embedded Workbench 7.2\430\config\linker. There are many xcl files in this folder. Just find the one that corresponds to the microcontroller.
It should be mentioned that under the Linker configuration file option there is an option called Override default program entr, where the function name of the program entry point defined by IAR itself is located.
Before analyzing the xcl file of MSP430F5529, let's analyze the memory image of MSP430F5529. There is a Memory Organization table in its data sheet, as shown below
From this table, we can see that the address space of the main FLASH of F5529 is 0x4400-0x243FF, with a total size of 128KB, and the address space of RAM is 0x2400-0x43FF, with a total size of 8KB. We will not look at other address spaces for now, as they are not used here anyway.
Next, we will analyze the xcl file of F5529. The xcl file of F5529 has many lines, so I will not post them here. Just focus on a few lines. The following are the segments stored in RAM. As for what a segment is, I will not explain it. This is the knowledge about linkers in embedded development. You can go to Baidu to find it yourself.
// -----------------------------------------------
// RAM memory
//
-Z(DATA)DATA16_I,DATA16_Z,DATA16_N,TLS16_I=2400-43FF
-Z(DATA)DATA16_HEAP+_DATA16_HEAP_SIZE
-Z(DATA)CODE_I
-Z(DATA)DATA20_I,DATA20_Z,DATA20_N,DATA20_HEAP+_DATA20_HEAP_SIZE
-Z(DATA)CSTACK+_STACK_SIZE#
It can be seen that the RAM address space defined here is 0x2400-0x43FF, which is consistent with the RAM address space in the data sheet.
The following are the segments stored in the main FLASH
// -----------------------------------------------
// Read-only memory
//
// -------------------------------------
// Low memory 0-0FFFF
//
// ---------------------------
// Constant data
//
-Z(CONST)DATA16_C,DATA16_ID,TLS16_ID,DIFUNCT,CHECKSUM=4400-FF7F
// ---------------------------
// Code
//
-Z(CODE)CSTART,ISR_CODE,CODE16=4400-FF7F
// -------------------------------------
// All memory 0-FFFFF
//
// ---------------------------
// Code
//
-P(CODE)CODE=4400-FF7F,10000-243FF
// ---------------------------
// Constant data
//
-Z(CONST)DATA20_C,DATA20_ID,CODE_ID=4400-FF7F,10040-243FF
// -------------------------------------
// Interrupt vectors
//
-Z(CODE)INTVEC=FF80-FFFF
-Z(CODE)RESET=FFFE-FFFF
It can be seen that the main FLASH address space defined here is 0x4400-0xFF7F, 0xFF80-0xFFFF and 0x10000-0x243FF. It seems that the storage address of some segments starts from 0x10040, but this is not a big deal, anyway, they are all in the main FLASH space.
After analyzing the linker script, the next step is to debug the program in RAM. Here, you only need to change the FLASH address space in the linker script to the RAM address space to debug the program in RAM. Then divide the RAM into three parts: 0x2400-0x33FF, 0x3400-0x437F, and 0x4380-0x43FF, which are used as FLASH, RAM, and interrupt vector table respectively. As for why the interrupt vector table is placed at 0x4380-0x43FF, it will be explained later when debugging the program that needs to use interrupts in RAM. The modified part of the xcl file is as follows
// -----------------------------------------------
// RAM memory
//
-Z(DATA)DATA16_I,DATA16_Z,DATA16_N,TLS16_I=3400-437F
-Z(DATA)DATA16_HEAP+_DATA16_HEAP_SIZE
-Z(DATA)CODE_I
-Z(DATA)DATA20_I,DATA20_Z,DATA20_N,DATA20_HEAP+_DATA20_HEAP_SIZE
-Z(DATA)CSTACK+_STACK_SIZE#
// -----------------------------------------------
// Read-only memory
//
// -------------------------------------
// Low memory 0-0FFFF
//
// ---------------------------
// Constant data
//
-Z(CONST)DATA16_C,DATA16_ID,TLS16_ID,DIFUNCT,CHECKSUM=2400-33FF
// ---------------------------
// Code
//
-Z(CODE)CSTART,ISR_CODE,CODE16=2400-33FF
// -------------------------------------
// All memory 0-FFFFF
//
// ---------------------------
// Code
//
-P(CODE)CODE=2400-33FF
// ---------------------------
// Constant data
//
-Z(CONST)DATA20_C,DATA20_ID,CODE_ID=2400-33FF
// -------------------------------------
// Interrupt vectors
//
-Z(CODE)INTVEC=4380-43FF
-Z(CODE)RESET=43FE-43FF
Put the modified xcl file in the root directory of the project, or other directories, anyway IAR can change the path of the linker script file. Then check Override default in Linker configuration file in Linker sub-tab of project options, and fill in the path of the modified xcl file. I fill in $PROJ_DIR$\lnk430f5529_ram.xcl here, because I renamed the modified file to lnk430f5529_ram.xcl and put it in the root directory of the project. You can also use the selection button on the right to select an absolute path.
Then I changed the debugger to a hardware emulator and downloaded the debugger. After entering the debugging state, I found that the microcontroller did not stop. I went to the disassembly window and found that the value of the reset vector at 0xFFFE was 0xFFFF. Then I looked at the value at 0x43FE and found that it was the correct 0x2400, as shown in the figure below.
Before testing RAM debugging, I downloaded a program in FLASH that changes the level of P4.7 every 1 second, which is also the program that flashes the green light on the LaunchPad. When debugging, the reset vector at 0xFFFE was the same as the software simulation above, which is 0x4400. However, it is not the same now. Theoretically, I put the FLASH address space in RAM and will not erase the FLASH. But in fact, the simulator erased the FLASH. So I started to look for options related to FLASH erasure in the Debugger of the project options, and it turned out that there was one.
Select "Retain unchanged memory" for "Flash erase". This option is to retain the memory with unchanged contents. The sub-options "Compare with image on target" and "Compare with image cached on PC" are similar options. You can choose any one of them. In this way, the original FLASH contents will not be erased. However, during download and debugging, it was found that although the program in FLASH was not erased and the new program was downloaded to RAM, the MCU was still running the program in FLASH.
Reviewing the startup process of MSP430F5529 again, I found that the reason was that the value of the reset vector at 0xFFFE was not changed to the correct 0x2400, but was still 0x4400 when using FLASH, so the program in FLASH was still running. So I thought of two solutions:
1. The interrupt vector table is still placed at 0xFF80-0xFFFF. In this way, the reset vector at 0xFFFE will be updated when the program is downloaded, pointing it to the RAM address 0x2400. However, after the power is turned off and then powered on again, the program in RAM disappears, and the MCU will still run in RAM instead of running the program in FLASH.
2. When using the default xcl file to download the FLASH program, add a function before the main function of the FLASH program. This function determines whether the "reset vector" at 0x43FE is 0x2400. If it is, it jumps to 0x2400 to execute the program in RAM, otherwise it continues to run the main function in FLASH.
Obviously, method 2 is better, although it requires adding more content to the FLASH program. Now the question is how to add a function before the main function to judge. By searching for the reference manual in the IAR document directory (X:\Program Files (x86)\IAR Systems\Embedded Workbench 7.2\430\doc), I found a pdf file called EW430_CompilerReference. In its bookmark Part 1. Using the compiler->The DLIB runtime environment->System startup and termination, I found the System Startup process, as shown below
What we need to pay attention to are the parts marked with red lines. These parts mainly say that the system will first execute an initialization sequence when it starts. This initialization sequence is executed before the main function.
There is a __low_level_init function in the initialization sequence. If the user defines it, it will be executed. Otherwise, it will not be executed. The code that handles the startup and end process is in
IAR's directory is X:\Program Files (x86)\IAR Systems\Embedded Workbench 7.2\430\src\lib, and there seem to be several directories in this directory.
Select, and find cstartup.s43 and low_level_init.c in the 430\src\lib\430 directory. cstartup.s43 is an assembly file. The manual says that you should try not to modify this file. Then the rest
It is low_level_init.c. There is only one __low_level_init function in this file. The code is as follows
#include
int __low_level_init(void)
{
/* Insert your low-level initializations here */
/*
* Return value:
*
* 1 - Perform data segment initialization.
* 0 - Skip data segment initialization.
*/
return 1;
}
Then copy this file to the project root directory, then add this file to the project, and then modify this function to the following code
#include
#define RUN_IN_RAM 1
#define NEW_RESET (*(volatile unsigned int*)0x43FE)
int __low_level_init(void)
{
if(NEW_RESET == 0x2400)
{
if(!RUN_IN_RAM)
asm("MOV #2400h, PC");
}
return 1;
}
The reason why the RUN_IN_RAM macro is defined here is that when compiling the code to be debugged in RAM, the low_level_init.c file will also be compiled, so the code in RAM will also contain the __low_level_init function. When the __low_level_init function in FLASH detects that the value at 0x43FE is 0x2400, it will jump to the RAM address 0x2400 to
continue executing the code, and then execute the __low_level_init code in RAM. If it is not determined whether it is running in RAM, the program will jump to 0x2400 to execute the code, thus forming an infinite loop. So when downloading to FLASH, RUN_IN_RAM is 0, it will jump, and when downloading to RAM, RUN_IN_RAM is 1, it will not jump. This function jump uses the assembly code "MOV #2400h, PC", which means setting the value of PC to 0x2400. If you don't understand assembly, there is no way. Anyway, the jump is basically written like this because C language cannot use the PC register, only assembly can use it.
Then it is time to compile and download. First, download the default xcl file into FLASH, and then download the modified xcl file into RAM to run it. However, the result still fails. The program downloaded to RAM still does not run, and the FLASH program is still running.
After debugging, I found that the low_level_init function in FLASH gave a negative result when judging whether NEW_RESET (address 0x43FE) was 0x2400. However, when I used Go to jump to 0x43FE, I found that the displayed value was the correct 0x2400 (PS: Here I was looking at the IAR disassembly window, and its memory refresh seemed to be slower, so it still displayed the correct value, but it had actually been modified). Later, I used the intermediate variable to check the NEW_RESET value read by the program and found that it was 0.
Then I debugged for a while, and suddenly I found that the value at 0x43FC was 0x4408 during one debugging, and 0x4408 was exactly the address of the code after calling the low_level_init program in the FLASH program, which should be 0x004408 to be precise. In this way, the value of 0x43FE at 0 is well explained, because the program in FLASH sets the stack pointer SP at 0x4400. When low_level_init is called, the MCU automatically pushes the stack, that is, the address of the next code 0x004408 is stored at 0x43FC. Note that 32-bit data is stored here, so if represented by 8 bits, 0x43FC stores 0x08, 0x43FD stores 0x44, 0x43FE stores 0x00, and 0x43FF stores 0x00, which are stored in little-endian mode.
Now that we know that the reset vector is overwritten because of stack push, we can successfully avoid the interrupt vector table in RAM by defining the RAM space as 0x2400-0x437F when compiling the FLASH program. Considering that there is no interrupt at 0x80-0xD0 of the interrupt vector table, it is no problem to locate the end of RAM at 0x43CF (PS: Although there is no data at 0xD0 and 0xD1, the end of RAM cannot be set to 0x43D2, because the stack must be 4-byte aligned, and 0x43D2 does not meet the 4-byte alignment condition).
Modify the RAM address space in the default xcl file to 0x2400-0x437F, then select this file as the linker configuration file, download it in FLASH once, and then use the modified xcl file suitable for RAM to download it to RAM. It is found that the program in RAM can be run. However, to run the program in FLASH, the power must be turned off for a few seconds and then powered on again. Pressing reset is useless, and the program in RAM will still run. The reason is that the RAM will not be cleared when the MSP430 is reset. The reason for powering off for a few seconds is that the power consumption of the MSP430 is too low, and the operating voltage can be as low as 1.8V. Only when the voltage drops below 1.8V will the RAM be cleared.
As for programs with interrupts, you only need to add a sentence SYSCTL |= SYSRIVECT after the code to turn off the watchdog in your main function. The function of the SYSRIVECT bit of the SYSCTL register is shown in the figure below:
The red line indicates that if the SYSRIVECT bit is 1, the interrupt vector table stored at the top of the RAM is used. The top of the RAM is 0x43FF, and the length of the interrupt vector table 0x7F is subtracted to 0x4380, so I set the address space of the interrupt vector table to 0x4380-0x43FF. This is to debug the program with interrupts normally when debugging in RAM. I tested the IO port interrupt and it can be recognized normally.
Previous article:Analysis of the Causes of Program Failure
Next article:Low power consumption comparison between STM8L and MSP430
- Popular Resources
- Popular amplifiers
- Naxin Micro and Xinxian jointly launched the NS800RT series of real-time control MCUs
- How to learn embedded systems based on ARM platform
- Summary of jffs2_scan_eraseblock issues
- Application of SPCOMM Control in Serial Communication of Delphi7.0
- Using TComm component to realize serial communication in Delphi environment
- Bar chart code for embedded development practices
- Embedded Development Learning (10)
- Embedded Development Learning (8)
- Embedded Development Learning (6)
Professor at Beihang University, dedicated to promoting microcontrollers and embedded systems for over 20 years.
- Intel promotes AI with multi-dimensional efforts in technology, application, and ecology
- ChinaJoy Qualcomm Snapdragon Theme Pavilion takes you to experience the new changes in digital entertainment in the 5G era
- Infineon's latest generation IGBT technology platform enables precise control of speed and position
- Two test methods for LED lighting life
- Don't Let Lightning Induced Surges Scare You
- Application of brushless motor controller ML4425/4426
- Easy identification of LED power supply quality
- World's first integrated photovoltaic solar system completed in Israel
- Sliding window mean filter for avr microcontroller AD conversion
- What does call mean in the detailed explanation of ABB robot programming instructions?
- Ultrasound patch can continuously and noninvasively monitor blood pressure
- Ultrasound patch can continuously and noninvasively monitor blood pressure
- Europe's three largest chip giants re-examine their supply chains
- Europe's three largest chip giants re-examine their supply chains
- Breaking through the intelligent competition, Changan Automobile opens the "God's perspective"
- The world's first fully digital chassis, looking forward to the debut of the U7 PHEV and EV versions
- Design of automotive LIN communication simulator based on Renesas MCU
- When will solid-state batteries become popular?
- Adding solid-state batteries, CATL wants to continue to be the "King of Ning"
- The agency predicts that my country's public electric vehicle charging piles will reach 3.6 million this year, accounting for nearly 70% of the world
- Please help me see if this 12864 is bad.
- 【Repost】Power supply loop stability evaluation indicators and evaluation methods
- MSP430F5529 Timer_A
- -------------------------------------------------- ----------
- Authorization code problem
- Butterworth filter, Chebyshev filter
- Hey guys, I want a Kinetis K50 development board
- Initial LPC8N04 development board and power-on test
- The beautiful president NS Nuo Shen has been refreshing the record
- PLC IO port, wireless switch controller wiring