|
LPC4337, свой загрузчик. Инициализация SDRAM, мешает работе приложения |
|
|
2 страниц
1 2 >
|
 |
Ответов
(1 - 28)
|
May 22 2018, 08:30
|
Гуру
     
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713

|
Цитата(scifi @ May 22 2018, 11:01)  Переход из загрузчика в приложение надо делать так: ... 4) Если да, запускает приложение. Если нет, затирает метку и продолжаем исполнять загрузчик. Тогда никаких проблем с повторными инициализациями не будет. Не совсем правильно. При такой последовательности действий, если потом, при работе основного приложения, произошёл сброс МК без потери питания (по WDT например) или с кратковременной потерей, то при старте будет пропуск бутлоадера, чего очевидно не должно быть. Так что метку надо затирать и перед передачей управления из бута в основное ПО, а в основном ПО не использовать это место в ОЗУ. А можно просто корректно написать инициализацию EMC-контроллера (и остальной периферии) не рассчитывающую, что в регистрах периферии находятся дефолтные значения. По-крайней мере той периферии, которая используется в бутлоадере и основной программе.  У меня в бутлоадере я знаю какую периферию использовал и просто перед передачей управления основной программе делаю RESET для данных периферийных модулей. Благо что возможность подать RESET на конкретный периферийный блок в моём МК имеется (да и в LPC43xx она есть).
|
|
|
|
|
May 22 2018, 08:45
|
Гуру
     
Группа: Свой
Сообщений: 3 020
Регистрация: 7-02-07
Пользователь №: 25 136

|
Цитата(jcxz @ May 22 2018, 11:30)  Не совсем правильно. При такой последовательности действий, если потом, при работе основного приложения, произошёл сброс МК без потери питания (по WDT например) или с кратковременной потерей, то при старте будет пропуск бутлоадера, чего очевидно не должно быть. Так что метку надо затирать и перед передачей управления из бута в основное ПО, а в основном ПО не использовать это место в ОЗУ. Ну да, про это запамятовал. Впрочем, как следует подумать, прежде чем хватать клавиатуру и говнокодить, никто не отменял. В конце концов, они там разработчики или где?
|
|
|
|
|
May 23 2018, 05:01
|

Местный
  
Группа: Участник
Сообщений: 492
Регистрация: 12-11-11
Пользователь №: 68 264

|
Хм. А я не использую никаких зарезервированных меток в ОЗУ. Вот мой какой-то и загрузчиков: Код unsigned int BootloaderInputStatus = HW_BootloaderInput(); if((BootloaderInputStatus == BOOT_INPUT_NONE) || (BootloaderInputStatus == BOOT_INPUT_HARD_RESET)) HW_JumpToApplication(); HW_RCCInit(); HW_TimerInit(); HW_ExchangeUARTInit(); ... // основная программа ... // перед выходом в приложение деактивирую всю использованную периферию
HW_ExchangeUARTStop(); HW_TimerStop(); HW_RCCStop();
HW_JumpToApplication(); HW_BootloaderInput() - считывает значение специального регистра, в котором есть статусные биты, какой вид сброса произошел и от кого. Цитата ...то при старте будет пропуск бутлоадера, чего очевидно не должно быть. Почему это? Если сработал WDT, о какой прошивке должна идти речь? Как раз-таки после сброса по WDT загрузчик должен быть пропущен и должно запуститься снова приложение, на мой взгляд.
|
|
|
|
|
May 23 2018, 18:30
|
Гуру
     
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713

|
Цитата(haker_fox @ May 23 2018, 04:46)  При сбросе EMC модуля через RGU возникает hardfault. Уже перечитали документацию. Ничего не помогает. Нет ли у кого внятного примера, как использовать RGU? Так расшифруйте причину HF. Все возможности для этого есть. С внешней ОЗУ на LPC43xx не работал, но для SPIFI делал так: Код CGU.IDIV.C = PCLK_DIVC - 1 << 2 | B11 | CLK_SRC_ID_PLL1 << 24; CGU.BASE.SPIFI = B11 | CLK_SRC_ID_IDIVC << 24; PeripheralOn(BRANCH_CLK_M4_SPIFI); PeripheralOn(BRANCH_CLK_SPIFI, RGU_RST_SPIFI); Для USB: Код PeripheralOn(BRANCH_CLK_M4_USB0); PeripheralOn(BRANCH_CLK_USB0, RGU_RST_USB0); И для всех остальных драйверов - аналогично. HF нет. CODE enum RGU_RST { RGU_RST_CORE = 0, RGU_RST_PERIPH = 1, RGU_RST_MASTER = 2, RGU_RST_none = 3, RGU_RST_WWDT = 4, RGU_RST_CREG = 5, RGU_RST_BUS = 8, RGU_RST_SCU = 9, RGU_RST_M0SUB = 12, RGU_RST_M4 = 13, RGU_RST_LCD = 16, RGU_RST_USB0 = 17, RGU_RST_USB1 = 18, RGU_RST_DMA = 19, RGU_RST_SDIO = 20, RGU_RST_EMC = 21, RGU_RST_ENET = 22, RGU_RST_FLASHA = 25, RGU_RST_EEPROM = 27, RGU_RST_GPIO = 28, RGU_RST_FLASHB = 29, RGU_RST_TIMER0 = 32, RGU_RST_TIMER1 = 33, RGU_RST_TIMER2 = 34, RGU_RST_TIMER3 = 35, RGU_RST_RITIMER = 36, RGU_RST_SCT = 37, RGU_RST_MCPWM = 38, RGU_RST_QEI = 39, RGU_RST_ADC0 = 40, RGU_RST_ADC1 = 41, RGU_RST_DAC = 42, RGU_RST_UART0 = 44, RGU_RST_UART1 = 45, RGU_RST_UART2 = 46, RGU_RST_UART3 = 47, RGU_RST_I2C0 = 48, RGU_RST_I2C1 = 49, RGU_RST_SSP0 = 50, RGU_RST_SSP1 = 51, RGU_RST_I2S = 52, RGU_RST_SPIFI = 53, RGU_RST_CAN1 = 54, RGU_RST_CAN0 = 55, RGU_RST_M0APP = 56, RGU_RST_SGPIO = 57, RGU_RST_SPI = 58, RGU_RST_ADCHS = 60 };
//--------------------------------------------------------------------------- //CCU1 branch clocks enum BRANCH_CLK { BRANCH_CLK_APB3 =0x000, //APB3 bus clock. BRANCH_CLK_I2C1 =0x001, //clock to the I2C1 register interface and I2C1 peripheral clock. BRANCH_CLK_DAC =0x002, //clock to the DAC register interface. BRANCH_CLK_ADC0 =0x003, //clock to the ADC0 register interface and ADC0 peripheral clock. BRANCH_CLK_ADC1 =0x004, //clock to the ADC1 register interface and ADC1 peripheral clock. BRANCH_CLK_CAN0 =0x005, //clock to the C_CAN0 register interface and C_CAN0 peripheral clock. BRANCH_CLK_APB1 =0x020, //APB1 bus clock. BRANCH_CLK_MCPWM =0x021, //clock to the PWM Motor control block and PWM Motor control peripheral clock. BRANCH_CLK_I2C0 =0x022, //clock to the I2C0 register interface and I2C0 peripheral clock. BRANCH_CLK_I2S =0x023, //clock to the I2S0 and I2S1 register interfaces and I2S0 and I2S1 peripheral clock. BRANCH_CLK_CAN1 =0x024, //clock to the C_CAN1 register interface and C_CAN1 peripheral clock. BRANCH_CLK_SPIFI =0x040, //clock for the SPIFI SCKI clock input. BRANCH_CLK_M4 =0x060, //M4 bus clock. BRANCH_CLK_M4_SPIFI =0x061, //clock to the SPIFI register interface. BRANCH_CLK_M4_GPIO =0x062, //clock to the GPIO register interface BRANCH_CLK_M4_LCD =0x063, //clock to the LCD register interface. BRANCH_CLK_M4_ENET =0x064, //clock to the Ethernet register interface. BRANCH_CLK_M4_USB0 =0x065, //clock to the USB0 register interface. BRANCH_CLK_M4_EMC =0x066, //clock to the External memory controller. BRANCH_CLK_M4_SDIO =0x067, //clock to the SD/MMC register interface. BRANCH_CLK_M4_DMA =0x068, //clock to the DMA register interface. BRANCH_CLK_M4_M4CORE =0x069, //clock to the Cortex-M4 core BRANCH_CLK_M4_SCT =0x06D, //clock to the SCT register interface. BRANCH_CLK_M4_USB1 =0x06E, //clock to the USB1 register interface. BRANCH_CLK_M4_EMCDIV =0x06F, //clock to the EMC with clock divider. BRANCH_CLK_M4_FLASHA =0x070, //clock to the flash bank A BRANCH_CLK_M4_FLASHB =0x071, //clock to the flash bank B BRANCH_CLK_M4_M0APP =0x072, //clock to the M0APP coprocessor. BRANCH_CLK_M4_ADCHS =0x073, //clock to the ADCHS. BRANCH_CLK_M4_EEPROM =0x074, //clock to the EEPROM BRANCH_CLK_M4_WWDT =0x080, //clock to the WWDT register interface. BRANCH_CLK_M4_UART0 =0x081, //clock to the USART0 register interface. BRANCH_CLK_M4_UART1 =0x082, //clock to the UART1 register interface. BRANCH_CLK_M4_SSP0 =0x083, //clock to the SSP0 register interface. BRANCH_CLK_M4_TIMER0 =0x084, //clock to the timer0 register interface and timer0 peripheral clock. BRANCH_CLK_M4_TIMER1 =0x085, //clock to the timer1 register interface and timer1 peripheral clock. BRANCH_CLK_M4_SCU =0x086, //clock to the System control unit register interface. BRANCH_CLK_M4_CREG =0x087, //clock to the CREG register interface. BRANCH_CLK_M4_RITIMER =0x0A0, //clock to the RI timer register interface and RI timer peripheral clock. BRANCH_CLK_M4_UART2 =0x0A1, //clock to the UART2 register interface. BRANCH_CLK_M4_UART3 =0x0A2, //clock to the UART3 register interface. BRANCH_CLK_M4_TIMER2 =0x0A3, //clock to the timer2 register interface and timer2 peripheral clock. BRANCH_CLK_M4_TIMER3 =0x0A4, //clock to the timer3 register interface and timer3 peripheral clock. BRANCH_CLK_M4_SSP1 =0x0A5, //clock to the SSP1 register interface. BRANCH_CLK_M4_QEI =0x0A6, //clock to the QEI register interface and QEI peripheral clock. BRANCH_CLK_PERIPH =0x0C0, //clock to the peripheral bus and the Cortex-M0 subsystem AHB multilayer matrix. BRANCH_CLK_PERIPH_CORE =0x0C2, //clock to the Cortex-M0 subsystem core. BRANCH_CLK_PERIPH_SGPIO =0x0C3, //clock to the SGPIO interface. BRANCH_CLK_USB0 =0x0E0, //USB0 peripheral clock. BRANCH_CLK_USB1 =0x100, //USB1 peripheral clock. BRANCH_CLK_SPI =0x120, //clock to the SPI interface. BRANCH_CLK_ADCHS =0x140, //ADCHS clock. //CCU2 branch clocks BRANCH_CLK_AUDIO =0x200, //audio system (I2S) clock. BRANCH_CLK_UART3 =0x220, //USART3 peripheral clock. BRANCH_CLK_UART2 =0x240, //USART2 peripheral clock. BRANCH_CLK_UART1 =0x260, //UART1 peripheral clock. BRANCH_CLK_UART0 =0x280, //USART0 peripheral clock. BRANCH_CLK_SSP1 =0x2A0, //SSP1 peripheral clock. BRANCH_CLK_SSP0 =0x2C0, //SSP0 peripheral clock. BRANCH_CLK_SDIO =0x2E0 //SD/MMC peripheral clock. };
//return: 1 - если соотв.периферия доступна (включена, затактирована). int PeripheralReady(BRANCH_CLK branchClk) { CCU_CFG_STAT volatile *p = &CCU1.BRANCH[0]; if (branchClk >> 9) p = &CCU2.BRANCH[0]; return p[branchClk & B9 - 1].STAT & B0; }
void PeripheralResetOn(RGU_RST periph) { if (periph == RGU_RST_none) return; __DMB(); /// *BITBAND_IO(&RGU.CTRL[periph >> 5], periph & B5 - 1) = 1;
/// u64 q = 1ull << periph | 1ull << RGU_RST_M0APP | 1ull << RGU_RST_M0SUB; if (periph >> 5) q >>= 32; RGU.CTRL[periph >> 5] = q;
}
void PeripheralResetOff(uint periph) { if (periph == RGU_RST_none) return; *BITBAND_IO(&RGU.CTRL[periph >> 5], periph & B5 - 1) = 0; __DMB(); }
//Подаёт импульс RESET (или снимает постоянный RESET) на указанную периферию. //И включает её ветвь тактирования. Не конфигурит базовую частоту! void PeripheralOn(BRANCH_CLK branchClk, RGU_RST periphRst) { CCU_CFG_STAT volatile *p = &CCU1.BRANCH[0]; if (branchClk >> 9) p = &CCU2.BRANCH[0]; p += branchClk & B9 - 1; p->CFG = B0; while (!(p->STAT & B0)); if (periphRst == RGU_RST_none) return; PeripheralResetOn(periphRst); /// /// int i = 1; /// if (periphRst == RGU_RST_M0SUB || periphRst == RGU_RST_M0APP) i = 0; /// *BITBAND_IO(&RGU.CTRL[periphRst >> 5], periphRst & B5 - 1) = i; while (!*BITBAND_IO(&RGU.ACTIVE[periphRst >> 5], periphRst & B5 - 1)); __DMB(); } сорри: исходник захламлен, так как проект не был закончен, но периферия работала и так. Цитата(Arlleex @ May 23 2018, 08:01)  Почему это? Если сработал WDT, о какой прошивке должна идти речь? Как раз-таки после сброса по WDT загрузчик должен быть пропущен и должно запуститься снова приложение, на мой взгляд. Что мешает делать после приёма прошивки рестарт по WDT?
|
|
|
|
|
May 23 2018, 20:00
|

Местный
  
Группа: Участник
Сообщений: 492
Регистрация: 12-11-11
Пользователь №: 68 264

|
Цитата Что мешает делать после приёма прошивки рестарт по WDT? Ничего не мешает. Ровно как и ничего не мешает инициализировать указатель стека и перейти сразу на приложение явно.
|
|
|
|
|
May 24 2018, 04:58
|

Местный
  
Группа: Участник
Сообщений: 492
Регистрация: 12-11-11
Пользователь №: 68 264

|
Цитата(jcxz @ May 24 2018, 02:20)  Какой из указателей?  Про переключение режима CPU конечно забыли? И про сброс периферии тоже.  А при чем тут указатели стека и режим CPU? Загрузчик обязан обеспечить обновление ПО и (если необходимо) переход на приложение. Приложение не должно знать о существовании загрузчика, поэтому компилируется ровно так же, как и без загрузчика (только поправить ld-скрипт и вначале приложения сместить таблицу векторов. Ну или перед переходом на приложение в загрузчике ее сместить). При старте МК с загрузчиком: 1. Проверяется тип сброса - если программный, то (в моем случае) это только означает, что был запрос обновления ПО из приложения, если нет - JumpToApplicatioin(). 2. Инициализируется периферия, необходимая для приема прошивки. 3. Принимается прошивка, сравниваются соответствующие контрольные суммы и т.д. 4. Деинициализируется периферия в случае успешного обновления ПО. 5. JumpToApplication(). Код void HW_JumpToApplication(void) { unsigned int pFunction = *((volatile unsigned int *)(APPLICATION_BASE_ADDRESS + 4)); void (*UserApplication)(void) = (void (*)())pFunction; __set_MSP(*(volatile unsigned int *)APPLICATION_BASE_ADDRESS); UserApplication(); return; } О каком переключении CPU идет речь? И о каком стеке? После сброса CPU всегда использует основной стек и находится в режиме потока с привелегированным доступом, поэтому загрузчик инициализирует именно MSP. Внутри целевого прилоежния первым делом сдвигается таблица векторов прерываний (если это не сделал загрузчик) и поехали. Или Вы о чем?
Сообщение отредактировал Arlleex - May 24 2018, 05:08
|
|
|
|
|
May 24 2018, 06:09
|
Гуру
     
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713

|
Цитата(Arlleex @ May 24 2018, 07:58)  1. Проверяется тип сброса - если программный, то (в моем случае) это только означает, что был запрос обновления ПО из приложения, если нет - JumpToApplicatioin(). ... Видимо Вы на практике никогда не писали реально работающий в боевых условиях бутлоадер, умеющий обновлять прошивку... Внимание вопрос: Если после приёма прошивки (и записи её во флешь с установленным флажком "имеется новая прошивка") выполняется Ваш программный сброс, загрузчик делает как Вы написали и переходит к пункту 2 вашего списка.... и в этот момент происходит случайный сброс (например - сработал супервизор питания из-за помехи по питанию). Что получится? Да - прошивка не обновится уже никогда. А если сброс произошёл во время прошивки? А если 100 сбросов произошло во время прошивки? ...подумайте. Нормально написанный бутлоадер должен после любого типа сброса проверять флаг наличия новой прошивки и начинать прошивку (или продолжать её с момента обрыва) и проводить до тех пор, пока новая прошивка не будет полностью прошита и снят флаг "имеется новая прошивка". И только тогда может выполнять переход на рабочее ПО. И новая прошивка и флаг "имеется новая прошивка" должны находиться в энергонезависимой памяти. Цитата(Arlleex @ May 24 2018, 07:58)  2. Инициализируется периферия, необходимая для приема прошивки. пункт 2 замечаний: При таком алгоритме загрузчик должен быть рассчитан на старт как после обычного аппаратного сброса так и после передачи управления из ПО с произвольным состояние регистров/режима процессора и периферии. Т.е. - инициализация его должна быть более сложной. А на кой ляд?? Почему не привести всё к начальному состоянию и упростить инициализацию при старте загрзучика? Так будет гораздо меньше кода (что для загрузчика очень важно, так как он: а) часто должен быть как можно меньше; б) должен быть ( обязательно!) как можно более простым, чтобы исключить возможность бага в нём, который потом уже невозможно будет устранить удалённой перепрошивкой. А в вашем случае получается, что стартовое состояние загрузчика постоянно меняется при изменении основного ПО. Сейчас вы загрузчик отладили и он работает (вроде как стабильно), отправили устройства заказчику, а потом сделали новую версию основной прошивки, которая стала инитить периферию немного по-другому или задействовала новую периферию и ... привет! - загрузчик перестал работать, так как заранее не предусмотрели и не отладили его работу со всеми возможными состояниями периферии/регистров на старте. Так что такой метод передачи управления загрузчику допустим разве что в настольно-наколенных поделках. Цитата(Arlleex @ May 24 2018, 07:58)  О каком переключении CPU идет речь? И о каком стеке? После сброса CPU всегда использует основной стек и находится в режиме потока с привелегированным доступом, поэтому загрузчик инициализирует именно MSP. ... Или Вы о чем? О том что Вы передёргиваете. Вы писали о передаче управления бутлоадеру без сброса, только поправив некий SP. На что я Вам написал, что кроме SP надо много чего ещё исправить: Цитата(Arlleex @ May 23 2018, 23:00)  Ничего не мешает. Ровно как и ничего не мешает инициализировать указатель стека и перейти сразу на приложение явно. А после сброса да - состояние МК и стек известны - кто-ж спорит?
|
|
|
|
|
May 24 2018, 06:39
|

Местный
  
Группа: Участник
Сообщений: 492
Регистрация: 12-11-11
Пользователь №: 68 264

|
Цитата Если после приёма прошивки (и записи её во флешь с установленным флажком "имеется новая прошивка") выполняется Ваш программный сброс, загрузчик делает как Вы написали и переходит к пункту 2 вашего списка.... и в этот момент происходит случайный сброс (например - сработал супервизор питания из-за помехи по питанию). Что получится? Да - прошивка не обновится уже никогда. laughing.gif Есть у меня bootloader-ы, которые выходят из коматоза в любом случае, главное подать питание. Там да, все сделано на энергонезависимом флаге. Я говорил о более-менее простых бутах, на основе которого можно делать хороший загрузчик. Цитата пункт 2 замечаний: Видимо Вы меня не совсем поняли. Из пользовательского ПО я перехожу в bootloader вызовом NVIC_SystemReset(). Поэтому мне не интересно, в каком режиме находится сейчас процессор и что он там выполняет. Цитата Так что такой метод передачи управления загрузчику допустим разве что в настольно-наколенных поделках. Теперь тоже так считаете? Цитата Вы писали о передаче управления бутлоадеру без сброса Нет, я писал Цитата Ровно как и ничего не мешает инициализировать указатель стека и перейти сразу на приложение явно. что контекстно подразумевает, что мы находимся в загрузчике. Речь шла о передаче управления из загрузчика в основную программу. Итого: из приложения в загрузчик - NVIC_SystemReset(), из загрузчика в приложение - как указал выше JumpToApplication(). Это просто как вариант. Я не говорю что у меня все такие загрузчики. Надежные летают щас даже
|
|
|
|
|
May 24 2018, 07:01
|
Гуру
     
Группа: Свой
Сообщений: 3 020
Регистрация: 7-02-07
Пользователь №: 25 136

|
Цитата(Arlleex @ May 24 2018, 07:58)  Код void HW_JumpToApplication(void) { unsigned int pFunction = *((volatile unsigned int *)(APPLICATION_BASE_ADDRESS + 4)); void (*UserApplication)(void) = (void (*)())pFunction; __set_MSP(*(volatile unsigned int *)APPLICATION_BASE_ADDRESS); UserApplication(); return; } Мне больше нравится вот так: Код void jump_to_app(void) { static const uint16_t code[] = { 0x1d01, // adds r1, r0, #4 0x6800, // ldr r0, [r0, #0] 0x4685, // mov sp, r0 0x6809, // ldr r1, [r1, #0] 0x4708 // bx r1 }; ((void (*)(int))code)(APP_BASE); }
|
|
|
|
|
May 24 2018, 07:20
|

Местный
  
Группа: Участник
Сообщений: 492
Регистрация: 12-11-11
Пользователь №: 68 264

|
Цитата Мне больше нравится вот так: А какие плюшки от этого? Вообще конечно из Си-кода менять MSP/PSP не есть комильфо, но с другой стороны не вижу криминала, если в функцию перехода на приложение не передавать никаких параметров. Цитата 0x1d01, // adds r1, r0, #4 0x6800, // ldr r0, [r0, #0] 0x4685, // mov sp, r0 0x6809, // ldr r1, [r1, #0] 0x4708 // bx r1 Страшно  И не будь тут комментариев, показалось бы ужасным костылем  Ведь функцию по сути можно было написать чисто на ассемблере (хоть в отдельном .s файле, либо внутри Си-функции инлайн-ассемблером).
|
|
|
|
|
May 24 2018, 08:04
|
Гуру
     
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713

|
Цитата(scifi @ May 24 2018, 10:01)  Мне больше нравится вот так: .h: Код #define PFLASH_BEGIN_C 0x08000000 //адрес начала внутренней флешь МК (кэшированная область) #define FW_WORK_BEGIN 0x00020000 //смещение рабочего ПО (FIRMWARE_TARGET_WORK) относительно начала флешь extern "C" void StartWorkFw(); .cpp (в бутлоадере): Код //деинит/reset использованной в буте периферии и старт рабочего ПО IntCpuDis(); FaultCpuDis(); IntDisAll(); //отключение тактирования периферии SCU.CCU.CGAT[0].SET = B0 | B1 | B2 | B3 | B4 | B7 | B8 | B9 | B10 | B11 | B16; SCU.CCU.CGAT[1].SET = B0 | B3 | B4 | B5 | B6 | B7 | B8; SCU.CCU.CGAT[2].SET = B1 | B2 | B4 | B5 | B6 | B7 | B10; SCU.CCU.CGAT[3].SET = B2; MPUoff(); StartWorkFw(); .asm: Код SECTION .text:CODE:NOROOT(2) THUMB PUBLIC StartWorkFw StartWorkFw: LDR R0, =PFLASH_BEGIN_C + FW_WORK_BEGIN LDRD R1, R2, [R0] MOV SP, R1 BX R2 LTORG
|
|
|
|
|
May 24 2018, 08:13
|

Местный
  
Группа: Участник
Сообщений: 492
Регистрация: 12-11-11
Пользователь №: 68 264

|
Цитата(jcxz @ May 24 2018, 12:04)  .asm: Код SECTION .text:CODE:NOROOT(2) THUMB PUBLIC StartWorkFw StartWorkFw: LDR R0, =PFLASH_BEGIN_C + FW_WORK_BEGIN LDRD R1, R2, [R0] MOV SP, R1 BX R2 LTORG Ну в общем на вкус и цвет, как говорится. А таблицу векторов где смещаете, кстати? Тоже где-то в boot-е или в основном приложении в начале?
|
|
|
|
|
May 24 2018, 08:36
|
Гуру
     
Группа: Свой
Сообщений: 3 020
Регистрация: 7-02-07
Пользователь №: 25 136

|
Цитата(jcxz @ May 24 2018, 11:04)  Код SECTION .text:CODE:NOROOT(2) THUMB PUBLIC StartWorkFw StartWorkFw: LDR R0, =PFLASH_BEGIN_C + FW_WORK_BEGIN LDRD R1, R2, [R0] MOV SP, R1 BX R2 LTORG Точно! Код void jump_to_app(void) { static const uint16_t code[] = { 0xc806, // ldmia r0!, {r1, r2} 0x468d, // mov sp, r1 0x4710 // bx r2 }; ((void (*)(int))code)(APP_BASE); } Этот код будет работать и на Cortex-M0, в отличие от.
|
|
|
|
|
May 28 2018, 12:22
|

Местный
  
Группа: Участник
Сообщений: 492
Регистрация: 12-11-11
Пользователь №: 68 264

|
Цитата(scifi @ May 28 2018, 15:05)  Поправлю сам себя. Последний штрих: Код void jump_to_app(void) { static const uint16_t code[] = { 0xc806, // ldmia r0!, {r1, r2} 0x468d, // mov sp, r1 0x4710 // bx r2 }; ((void (*)(int))(1 + (int)code))(APP_BASE); } ИМХО, лишнее. Компилятор вроде сам это контролирует (я про режим Thumb). На ассемблере да, надо следить. P.S. Может, ошибаюсь.
|
|
|
|
|
May 28 2018, 12:52
|

Местный
  
Группа: Участник
Сообщений: 492
Регистрация: 12-11-11
Пользователь №: 68 264

|
Цитата(scifi @ May 28 2018, 15:46)  Не лишнее. При тестировании вскрылось. Пардон. Я вычитывал слово по нужному адресу, а там было слово из таблицы векторов прерываний (вектор сброса) - а там уже в младшем бите установлена единица. Интересно, а считается ли Ваш способ наглядным примером самомодифицирующегося кода?
Сообщение отредактировал Arlleex - May 28 2018, 12:54
|
|
|
|
|
May 28 2018, 14:42
|

Местный
  
Группа: Участник
Сообщений: 492
Регистрация: 12-11-11
Пользователь №: 68 264

|
Да нет, не запутался. Говорю же что ошибся насчёт лишней установки младшего бита. Признаю, что устанавливать нужно его. А насчёт СМК - слышал, но не встречался, поэтому и подумал, а почему бы коду, копирующего самого себя и передающего управление функции в ОЗУ не называться СМК. Вот и все. Поправьте, если не прав. А, у вас же static const... Все во Flash разместится...
Сообщение отредактировал Arlleex - May 28 2018, 17:57
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|