Разовью мысль
scifi: а почему бы не отдать на откуп компилятору С и компоновщику всё и без ковыряния в ассемблере?
Как внутри самой функции всё протекает алгоритмически, уже было описано - запрет прерываний, сон, и т.п. Это можно изобразить на C. Остается засунуть всю функцию в RAM.
Это делается под KEIL именованными секциями и скаттером "нетрадиционной направленности"

. Не знаю степень владения автором топика таких понятий, поэтому разъясню, что скаттер - это описатель для компоновщика, куда помещать программные секции при сборке.
Размещение функции в RAM можно понять на примере из библиотеки родственного Cortex-Mx от energy micro. Там функции работы с флэш ДОЛЖНЫ быть в оперативной памяти (спецификация процессора). Поэтому приведена такая заморочка:
Код
#ifdef __CC_ARM /* MDK-ARM compiler */
#pragma arm section code="ram_code"
#endif /* __CC_ARM */
msc_Return_TypeDef MSC_ErasePage(uint32_t *startAddress)
{
int timeOut = MSC_PROGRAM_TIMEOUT;
И так далее.
Затем в скаттер-файле необходимо указать:
Код
...
RW_IRAM1 0x20000000 0x00004000 {; RW data
*(ram_code); flash erase/write functions
.ANY (+RW +ZI)
}
...
Внимание: скаттер взят из проекта для EFM32; для STM32 надо взять тот, что автоматически генерируется, переименовать его, модифицировать и подключить явно в соответствующей закладке опций проекта.
Теперь как это все работает в итоге: компоновщик кладет код функции куда-то во флэш как данные, генерирует собственный код, который при старте программы переписывает код функции оттуда в RAM, а все вызовы к ней заменяет вызовом сначала к небольшой примочке (veneer), которая уже переадресует в RAM по месту.
Достоинства:
- никакой возни с ассемблером и регистрами (не случайно основным кличем ARM был "never asm more" или типа того).
- никакой возни с перезаписью кода в RAM с предшествующей настройкой адресов или написанием перемещаемого кода.
Успехов!