Вы должны поместить функцию запуска в положение 0x80000, чтобы загрузчик мог выполнить ее правильно.
Другая проблема - прерывания. Поскольку у вас есть загрузчик, и я думаю, что он работает всю жизнь программы, вы не должны заменять вектор прерывания. В загрузчике, вероятно, есть некоторые функции для установки прерываний, поэтому вы должны использовать их вместо перемещения вектора ISR.
Размещение функции запуска по известному адресу:
Поскольку вы используете MCUXpresso и KDS, я полагаю, что вы используете набор инструментов, предоставленный NXP, базирующийся в GCC.
Если это так, вам нужно будет использовать sections
, чтобы установитьфункция по определенному адресу. В SDK функция запуска находится в файле startup_XXX.S
, а в моем файле (я не знаю, используют ли они всегда одинаковые имена), она называется Reset_Handler
. Вы также можете найти его по вектору ISR, являющемуся второй записью (запись сброса).
В моем случае это определяется следующим образом:
.section .reset_handler_section, "a" //EDIT 3: This is the line added
.thumb_func
.align 2
.globl Reset_Handler
.weak Reset_Handler
.type Reset_Handler, %function
Reset_Handler:
//Actual reset code follows
У вас должно быть что-тоаналогично вашему ASM-коду.
Теперь, когда вы знаете, какая у вас функция запуска, поместите ее в 0x80000. Это делается в вашем файле компоновщика, в разделе SECTIONS
.
Но сначала ваша новая карта памяти должна включать в себя только память, которую вы можете изменять, это раздел под названием «Область приложения» визображение, которое вы приложили.
Итак, карта памяти для нашего приложения должна быть:
MEMORY
{
m_text (RX) : ORIGIN = 0x00080000, LENGTH = 0x00080000
m_data (RWX) : ORIGIN = 0x20000000, LENGTH = 0x00030000
}
ВНИМАНИЕ: Вы должны знать, где ваши данные (m_data
) могут начинаться в ОЗУ, так как вы не хотитепереопределить данные загрузчика. Вы не показывали его на своем изображении, поэтому я просто выбрал ORIGIN
в ОЗУ, но вы должны проверить это.
Обратите внимание, что нет ни прерываний, ни разделов flash_config. Я предполагаю, что загрузчик уже имеет их, поэтому вам не нужно добавлять их снова.
Как только вы определили свою карту памяти, вы можете добавить в нее всю свою программу:
SECTIONS
{
/* The startup code*/
.startup_text :
{
. = ALIGN(4);
KEEP(*(.reset_handler_section)) /* Startup data */ /*EDIT 3: This is the modification*/
KEEP(*(.isr_vector)) /* EDIT 6: Startup code. It is needed in order to avoid modifying source files. It is not used, since the reset vector is the defined in the Bootloader build */
*(.text) /* .text sections (code) */
*(.text*) /* .text* sections (code) */
*(.rodata) /* .rodata sections (constants, strings, etc.) */
*(.rodata*) /* .rodata* sections (constants, strings, etc.) */
*(.glue_7) /* glue arm to thumb code */
*(.glue_7t) /* glue thumb to arm code */
KEEP (*(.init)) /*EDIT 2: The init section. If there are more
* sections like this, just keep adding them here.
*/
} > m_text
/*EDIT 5. Added entire section*/
.ARM :
{
__exidx_start = .;
*(.ARM.exidx*)
__exidx_end = .;
} > m_text
__DATA_ROM = .; /* Symbol is used by startup for data initialization */ /*EDIT 7: This symbol must be placed at the end of the text sections, so the data can follow all the code in ROM*/
__etext = .; /* define a global symbol at end of code */ /*EDIT 4*/
/*The application variables and other data in RAM*/
.data : AT(__DATA_ROM)
{
. = ALIGN(4);
__DATA_RAM = .;
__data_start__ = .; /* create a global symbol at data start */
*(.data) /* .data sections */
*(.data*) /* .data* sections */
KEEP(*(.jcr*))
KEEP(*(.ramSection))
. = ALIGN(4);
__data_end__ = .; /* define a global symbol at data end */
} > m_data
/* Uninitialized data section */
.bss :
{
/* This is used by the startup in order to initialize the .bss section */
. = ALIGN(4);
__START_BSS = .;
__bss_start__ = .;
*(.bss)
*(.bss*)
*(COMMON)
. = ALIGN(4);
__bss_end__ = .;
__END_BSS = .;
} > m_data
}
В качестве небольшого пояснения мы говорим компоновщику поместить все в раздел ".startup_text" (это может быть любое имя) в память m_text
, всегда в порядке. Таким образом, в первом адресе m_text
(это 0x80000) будет помещен Reset_Handler
. После этого будут размещены все остальные функции (.text
) и постоянные данные (rodata
).
Мы также определим символ __DATA_ROM
, который будет в последнем адресе раздела. После всех постоянных данных мы также добавляем инициализированные данные. Эти данные имеют постоянные значения, которые будут помещаться в ПЗУ, но компоновщик также должен зарезервировать для них память в ОЗУ, чтобы иметь возможность их изменять. Это то, что делается в разделе data
.
Редактировать 1: Чтобы компоновщик знал, где запустить вашу программу, и, таким образом, чтобы он мог посмотреть, какой код понадобится, вы должны указатьэто точка запуска вашей программы, так как компоновщик не понимает аппаратное обеспечение конкретного чипа (например, запись вектора сброса). Это делается путем добавления этого в начало файла компоновщика, перед разделом MEMORY:
/* Entry Point */
ENTRY(Reset_Handler)
STACK_SIZE = 0x0400;
M_VECTOR_RAM_SIZE = 0x0400;
Я не знаю, действительно ли нужны определения размера, но на всякий случай я также разместил их здесь.