Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Keil uVision 5 вставка ассемблера в C код.
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
Omnicake
Здравствуйте, уважаемые. Пытаюсь научится правильно вставлять в код на 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, что, как я понимаю, не совсем здорово. Я предполагаю, что где-то накосячил с адресацией, но опять же, все брал из дизассемблерных команд, которые до этого нормально выполнялись. В чем моя ошибка?
kolobok0
Цитата(Omnicake @ Mar 31 2014, 14:56) *
...но при пошаговом выполнении после команды END в systick, вываливается на HardFault_Handler...В чем моя ошибка?


ну наверное в том, что для ассемблера нет команды END(как инструкции для железа имеется ввиду).
Т.е. он продолжает и дальше выполнять следующие инструкции за данным адресом флэша.
наверное надо Вам поставить ретурн... если хотите возвратиться в то место откуда была вызвана даная функция.

Вообще совет дня типа:
Тупо напишите всё на сях. Подсматривайте потом компильнутый ассемблерный листинг. Многое узнаете нового. А! не забудьте оптимизацию
выставлять на максимум для этого сишнего кода - тогда азм получится лаконичней...
Golikov A.
а вы командой END чего добиться то хотели?
Omnicake
Без END компилятор ругался на его отсутствие. Я считал что при выполнении END он выйдет из ассемблерной функции и продолжит выполнять C-код. Видимо, ошибался, спасибо за советы.
Golikov A.
если речь идет о вставках, то они и должны быть вставками, нефиг функции делать. А вы прочитали как из функции выходить? Ведь надо восстановить: стэк, регистры, счетчик команд, и так далее и так далее... А всем этому должно предшествовать канетель с правильным сохранением этого всего перед входом.

вот
http://infocenter.arm.com/help/index.jsp?t...a/BABECGJD.html

это первоисточник, найдите там команду END....
toweroff
Я делал так:
BX LR
jcxz
Цитата(Omnicake @ Mar 31 2014, 16:56) *
LDR R0,[pc,#32]

Что у вас находится по адресу PC+32?
Совет: начинать нужно с изучения асма и архитектуры CPU, а не с выдёргивания чужих кусков наугад.
Omnicake
По адресу pc+32 лежит записанное значение частоты процессора, а если быть точнее, преобразованная частота используемая для таймера. Я прекрасно понимаю, что я выдергиваю чужие команды, но чтобы начинать учится нужна какая-та практическая база. Любой reference manual для меня пока что - огромная куча регистров и функций, которые я пока не использую. Кстати после добавления BX LR все заработало, большое спасибо toweroff.
Golikov A.
а что делает BX LR поняли?

дергать чужое - ок, но надо же читать что инструкции то делают. Если бы вы шли этим путем то узнали бы что ENDP, END это не инструкция проца, а кейловское слово для обозначения конца секции и файла...

toweroff
Цитата(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)"
Omnicake
Цитата
Нужно просто разобраться, как компилятор формирует вызов функций вида "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 не распознает объект как метку. Где можно почитать про это поподробней?
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.