|
Keil uVision 5 вставка ассемблера в C код., Функция на asm не возвращается в main. |
|
|
|
Mar 31 2014, 10:56
|
Участник

Группа: Участник
Сообщений: 56
Регистрация: 12-01-14
Из: Омск
Пользователь №: 80 002

|
Здравствуйте, уважаемые. Пытаюсь научится правильно вставлять в код на C ассемблерные функции. Взял за основу пример с включением SysTick таймера на STM32f10x. Код программы такой: CODE #include "stm32f10x.h" #define F_CPU 72000000UL //Частота процессора для таймера #define TimerTick F_CPU/1000 void Delay(uint32_t Val); extern int systick(void);
//SysTick Interrupt void SysTick_Handler(void) { // Сюда вставляется событие при срабатывании прерывания. }
int main(void) { SystemInit(); //Настройка процессора RCC->APB2ENR |= RCC_APB2ENR_IOPBEN; GPIOB->CRL &= ~GPIO_CRL_CNF5; GPIOB->CRL |= GPIO_CRL_MODE5_0;
systick(); //А это функция, которую я пытаюсь вставить
while(1) { } }
Функция systick() имеет вид: Код AREA HEAP, CODE, READONLY systick PROC EXPORT systick LDR R0,[pc,#32] MOV R1,#0xE000E000 STR R0,[r1,#0x14] STR R0,[r1,#0x18] MOVS R0,#0x07 STR R0,[r1,#0x10] ENDP END И представляет собой последовательность команд, которые выполнялись в дизассемблере ранее, когда таймер там вызывался через C-команды. Проект компилируется без ошибок, но при пошаговом выполнении после команды END в systick, вываливается на HardFault_Handler, что, как я понимаю, не совсем здорово. Я предполагаю, что где-то накосячил с адресацией, но опять же, все брал из дизассемблерных команд, которые до этого нормально выполнялись. В чем моя ошибка?
Сообщение отредактировал IgorKossak - Mar 31 2014, 15:50
Причина редактирования: [codebox] для длинного кода, [code] - для короткого!!!
|
|
|
|
|
 |
Ответов
(1 - 10)
|
Mar 31 2014, 11:39
|
практикующий тех. волшебник
    
Группа: Участник
Сообщений: 1 190
Регистрация: 9-09-05
Пользователь №: 8 417

|
Цитата(Omnicake @ Mar 31 2014, 14:56)  ...но при пошаговом выполнении после команды END в systick, вываливается на HardFault_Handler...В чем моя ошибка? ну наверное в том, что для ассемблера нет команды END(как инструкции для железа имеется ввиду). Т.е. он продолжает и дальше выполнять следующие инструкции за данным адресом флэша. наверное надо Вам поставить ретурн... если хотите возвратиться в то место откуда была вызвана даная функция. Вообще совет дня типа: Тупо напишите всё на сях. Подсматривайте потом компильнутый ассемблерный листинг. Многое узнаете нового. А! не забудьте оптимизацию выставлять на максимум для этого сишнего кода - тогда азм получится лаконичней...
Сообщение отредактировал kolobok0 - Mar 31 2014, 11:40
|
|
|
|
|
Mar 31 2014, 13:19
|
Участник

Группа: Участник
Сообщений: 56
Регистрация: 12-01-14
Из: Омск
Пользователь №: 80 002

|
Без END компилятор ругался на его отсутствие. Я считал что при выполнении END он выйдет из ассемблерной функции и продолжит выполнять C-код. Видимо, ошибался, спасибо за советы.
|
|
|
|
|
Apr 1 2014, 09:00
|
Участник

Группа: Участник
Сообщений: 56
Регистрация: 12-01-14
Из: Омск
Пользователь №: 80 002

|
По адресу pc+32 лежит записанное значение частоты процессора, а если быть точнее, преобразованная частота используемая для таймера. Я прекрасно понимаю, что я выдергиваю чужие команды, но чтобы начинать учится нужна какая-та практическая база. Любой reference manual для меня пока что - огромная куча регистров и функций, которые я пока не использую. Кстати после добавления BX LR все заработало, большое спасибо toweroff.
|
|
|
|
|
Apr 1 2014, 15:05
|

Гуру
     
Группа: Свой
Сообщений: 2 957
Регистрация: 19-09-06
Из: Москва
Пользователь №: 20 514

|
Цитата(Golikov A. @ Apr 1 2014, 16:11)  а что делает BX LR поняли? первоисточник ( тут): Цитата Register r14 is used as the subroutine Link Register (LR).
Register r14 receives the return address when a Branch with Link (BL or BLX) instruction is executed.
You can treat r14 as a general-purpose register at all other times. The corresponding banked registers r14_svc, r14_irq, r14_fiq, r14_abt, and r14_und are similarly used to hold the return values when interrupts and exceptions arise, or when BL or BLX instructions are executed within interrupt or exception routines. Нужно просто разобраться, как компилятор формирует вызов функций вида "void func(void)"
|
|
|
|
|
Apr 6 2014, 23:07
|
Участник

Группа: Участник
Сообщений: 56
Регистрация: 12-01-14
Из: Омск
Пользователь №: 80 002

|
Цитата Нужно просто разобраться, как компилятор формирует вызов функций вида "void func(void)" У меня Keil сформировал файл main.s где прыгает по такой функции командой "B". Мне удалось включить таймер на ассемблере но возникла пара тонкостей, и чтобы новую тему не создавать спрошу тут: 1. Адресация через pc регистр действительно работала не так, как мне хотелось, поэтому адреса нужных мне регистров я стал загонять командой MOV, но встала проблема: адреса 32 битные, а команда MOV на Cortex-M3 ассемблере воспринимает только 16 битные переменные. Я использую команды MOVT и MOVW, по сути записывая адрес в два шага (в нижние 16 бит и в верхние), есть ли возможность как-то записывать адреса по-другому, или мне в дальнейшем так и использовать по две команды MOV. 2. Так и не смог понять правильного синтаксиса для обозначения меток в ассемблерном файле, так, чтобы отрабатывали команды BNE, CBZ и.т.д. Пробовал "Имя метки:" в начале строки, и потом "BNE Имя метки", пишет "Invalid line start". В созданных компилятором файлах, что-то похожее на метки обозначается как ||Имя метки||, но при попытках также сделать у себя, при компиляции Keil не распознает объект как метку. Где можно почитать про это поподробней?
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|