Косвенная адресация в STM32F4

Кто любит RISC в жизни, заходим, не стесняемся.
Ответить
Вымогатель припоя
Сообщения: 671
Зарегистрирован: Вт июн 29, 2010 12:31:49

Сообщение TripleKill »

Подскажите, пожалуйста, как включить сабж в кейле?
Пробовал так [R0] и так @R0, не катит. На сайте кейла по запросам addressing modes и indirect addressing ничего толкового.
Реклама
Сверлит текстолит когтями
Аватара пользователя
Сообщения: 1163
Зарегистрирован: Ср янв 05, 2011 16:25:15

Сообщение ChipKiller »

наберите в поисковике arm assembler instruction и произойдет чудо.....
Реклама
Вымогатель припоя
Сообщения: 671
Зарегистрирован: Вт июн 29, 2010 12:31:49

Сообщение TripleKill »

Спасибо.
Не сразу, но нашёл такое: http://www.keil.com/support/man/docs/ar ... HGCADB.htm.
Попробую, учитывая особенности архитектуры (F4 умеет только thumb2, как я понял).
Вымогатель припоя
Сообщения: 671
Зарегистрирован: Вт июн 29, 2010 12:31:49

Сообщение TripleKill »

Похоже, не все команды умеют работать с косвенной адресацией.
Но LDR вполне работает. Пока на этом остановлюсь.
Реклама
Эиком - электронные компоненты и радиодетали
Вымогатель припоя
Сообщения: 671
Зарегистрирован: Вт июн 29, 2010 12:31:49

Сообщение TripleKill »

Чтоб не создавать ещё тему, спрошу здесь.
Нижеприведённый код описывает перемножение с накоплением массива с замерами сигнала по массивам синусов и косинусов, затем вычисляется значение амплитуды.

Код: Выделить всё

Sqrt    PROC

label0
         LDR R4, [R2,R3]
		
         LDR R6, [R0,R3]
         LDR R7, [R1,R3]
		
         SMLAL R8, R9, R4, R6
         SMLAL R10, R11, R4, R7
		
        CBZ R3, label1
        SUB R3, #4
        B label0	
		
label1
        VMOV S0, S1, R8, R9
        VMOV S2, S3, R10, R11
		
        ???	
				
        VMUL.F32 S0,S0,S0
        VMUL.F32 S1,S1,S1
        VADD.F32 S0,S0,S1
        VSQRT.F32 S0,S0
		
        BX  LR
		
ENDP
Получается что-то вроде БПФ с фильтрацией. Впрочем, теория не важна. Запинка случилась там, где в коде вопросительные знаки. Дело в том, что по инструкции SMLAL заполняются два регистра ядра - старшее и младшее слово.
По VMOV окончательные суммы передаются в FPU. Далее нужно взять квадраты этих чисел, сложить и взять из них корень.
Однако команды FPU работают только с одиночными регистрами, а суммы, с которыми требуется проводить операции, лежат в двух каждая. Есть какой-нибудь способ обойти это в асме, или придётся вылезать в С? Судя по осциллографу, получается приличная экономия: 40 мкс в чистом асме против 100 для того же алгоритма в С (хотя кто знает, может с костылями то же получится?).
Реклама
Вымогатель припоя
Аватара пользователя
Сообщения: 535
Зарегистрирован: Вт авг 28, 2012 22:21:33

Сообщение menzoda »

Мне не совсем понятен код. Сначала ты выполняешь целочисленное умножение 32х32=64. А потом кладешь целочисленный же результат в регистр FPU. Если я не ошибаюсь, то VMOV просто копирует данные, она не переведет целочисленное значение в формат IEEE754. Это твоего вопроса не касается, просто непонятка.

Ну а что касается вопроса - я вижу несколько вариантов.
Первое - оставить все как есть и использовать программную конвертацию int64 во float. Не знаю, есть ли такая функция в компиляторе или нет. Естесственно о скорости можно забыть. Хотя... Надо эксперементировать.
Второе - если твои операнды в сумме (я про длину) меньше 64 бит, то можно использовать не 32х32=64, а 32х32=32 умножение. Результат, опять же, придется переводить во float. Но здесь уже легче, ибо компилятор стопроцентно поддерживает такое преобразование, а самое главное, что есть аппаратная инструкция конвертации VCVT (почитай про нее в даташите).
Реклама
Сверлит текстолит когтями
Аватара пользователя
Сообщения: 1163
Зарегистрирован: Ср янв 05, 2011 16:25:15

Сообщение ChipKiller »

Однако команды FPU работают только с одиночными регистрами, а суммы, с которыми требуется проводить операции, лежат в двух каждая.
... сам то понял, что написал? FPU работает через стек. Чтобы избежать ненужных вопросов посоветую старую книжку - "Архитектура и программирование арифметического сопроцессора" Григорьев В.Л. Хотя там описан i8087, но принцип тот же.
Вымогатель припоя
Аватара пользователя
Сообщения: 535
Зарегистрирован: Вт авг 28, 2012 22:21:33

Сообщение menzoda »

ChipKiller писал(а):сам то понял, что написал? FPU работает через стек.
Ну так-то он все правильно сказал. В Cortex-M4 есть регистры R0...Rn, которые могут быть операндами целочисленных инструкций, и регистры S0...Sn, которые могут быть операндами FPU инструкций. Причем здесь стек мне не совсем понятно.
Сверлит текстолит когтями
Аватара пользователя
Сообщения: 1163
Зарегистрирован: Ср янв 05, 2011 16:25:15

Сообщение ChipKiller »

menzoda писал(а):Причем здесь стек мне не совсем понятно.
TripleKill писал(а):.....Однако команды FPU работают только с одиночными регистрами, а суммы, с которыми требуется проводить операции, лежат в двух каждая. Есть какой-нибудь способ обойти это в асме, или придётся вылезать в С?
... речь шла о VPUSH,VPOP ....может не совсем понятно выразился - пардон.
Вымогатель припоя
Сообщения: 671
Зарегистрирован: Вт июн 29, 2010 12:31:49

Сообщение TripleKill »

Всем спасибо.
Действительно, VMOV просто копирует данные, в итоге получается фигня.
Процедуру разделил вылазкой в С, т.е. из кода вызывается сначала MAC, потом операции с корнем. Зато передаётся всё как нужно.

Позже оказалось, что суперская точность тут не нужна (код по работе, проталкиваю STM32 как более современный), и результат MAC можно сдвинуть вправо, оставив только старшие разряды в одном 32-битном регистре. SMLAL остаётся на месте, просто потом производятся манипуляции с двумя регистрами результата.

Итого: +4 мкс из-за лишних телодвижений, и всё равно STM уделывает XC166) У обоих время преобразования в районе 80-90 мкс (на два канала), при том, что стм обрабатывает массив из 100 измерений по каналу, а с166 - из 39.

Есть вопрос по косметике. Вот код в С:

Код: Выделить всё

STM_EVAL_LEDOn(LED3);
	MacOp(POS1_isintable, POS1_icostable, samples, (POS1_FFTLENGTH-1)*4);
	
	f1[0] = R8;
	f1[1] = R10;
	
	f2[0]=(float)f1[0];
	f2[1]=(float)f1[1];
	
	w1=(float)Ampl(f2[0], f2[1]);
	STM_EVAL_LEDOff(LED3);
Как видно, сначала данные из регистров вытаскиваются в массив int, потом преобразуются и попадают в массив float. Казалось, почему бы передачу типа не сделать в вызове процедуры Ampl, да и вообще, обойтись без массивов? Однако компилятор ни то, ни другое не проглатывает (w1 не изменяется вообще), а вот как приведено - работает. В чём тут может быть дело? К слову, если сделать не массив f1, а две переменные int, то даже из регистров данные не вытаскиваются.
Вымогатель припоя
Аватара пользователя
Сообщения: 535
Зарегистрирован: Вт авг 28, 2012 22:21:33

Сообщение menzoda »

К сожалению, у меня нет под рукой компилятора, чтобы посмотреть в чем проблема. Но какая-то она странная, ведь так не должно быть. Посмотри что за ассемблер он генерирует из твоей Си-вставки. И может быть вообще ее убрать? Я же нашел ассемблерную инструкцию конвертации во float, чего ее не использовать?
Мучитель микросхем
Сообщения: 478
Зарегистрирован: Ср окт 15, 2008 09:33:03
Откуда: Воронеж

Сообщение Galizin »

Если код действительно только такой
ChipKiller писал(а): w1=(float)Ampl(f2[0], f2[1]);
То компилятор должен давать предупреждение - отсутствие предварительной декларации функции Ampl. Без этого компилятор не знает, какие типы аргументов у функции и предполагает, что Вы подсовываете правильные типы.
Необходимо сделать h файл в который поместить декларацию.
float Ampl(float, float);
Включить этот h айл в c файл.
После этого преобразования типов должны выполняться компилятором неявно.
И вообще выносить декларации в h файлы - это правильный стиль. Когда нибудь это спасет Вас от поиска непонятного поведения в течение нескольких дней.
Вымогатель припоя
Сообщения: 671
Зарегистрирован: Вт июн 29, 2010 12:31:49

Сообщение TripleKill »

Функция естественно задекларирована. Буду пробовать с VCVT.
Вымогатель припоя
Аватара пользователя
Сообщения: 535
Зарегистрирован: Вт авг 28, 2012 22:21:33

Сообщение menzoda »

Galizin писал(а):И вообще выносить декларации в h файлы - это правильный стиль. Когда нибудь это спасет Вас от поиска непонятного поведения в течение нескольких дней.
Это точно. Я как-то раз два дня подряд мучался. Оказывается не включил H-файл. Главное компилятор, зараза, не сказал ни слова, обычно то они предупреждают о таком, дескать "Function declared implicitly".
Вымогатель припоя
Сообщения: 671
Зарегистрирован: Вт июн 29, 2010 12:31:49

Сообщение TripleKill »

Всем спасибо за помощь, всё разместилось в одной функции и выглядит так:

Код: Выделить всё

ExtractAmp   PROC

		MOV R8, #0
		MOV R9, #0
		MOV R10, #0
		MOV R11, #0
		
		
label0
		LDR R4, [R2,R3]
		
		LDR R6, [R0,R3]
		LDR R7, [R1,R3]
		
		SMLAL R8, R9, R4, R6
		SMLAL R10, R11, R4, R7
		
		CBZ R3, label1
		SUB R3, #4
		B label0
		
label1
        
		LSR R8, #4
		LSL R9, #28
		ADD R8, R8, R9
		
        LSR R10, #4
		LSL R11, #28
		ADD R10, R10, R11
		
		VMOV S0, R8
		VCVT.F32.S32 S0, S0
		
		VMOV S1, R10
		VCVT.F32.S32 S1, S1
		
		VMUL.F32 S0,S0,S0
		VMUL.F32 S1,S1,S1
		VADD.F32 S0,S0,S1
        VSQRT.F32 S0,S0
		
		BX  LR
		
		ENDP
Однако компилятор как-то странно себя ведёт)
Вот код, которым я замеряю время выполнения преобразования.

Код: Выделить всё

while(1) {	
				
	STM_EVAL_LEDOn(LED3);
	w1=ExtractAmp(POS1_isintable, POS1_icostable, samples, (POS1_FFTLENGTH-1)*4);
	STM_EVAL_LEDOff(LED3);  
	
	
}
Переменная w1 в дебаге не меняет значения, с которым была инициализирована. Я было подумал, что компилятор понимает, что раз я кручусь в бесконечном цикле, и далее нигде переменную не вызываю, то и обрабатывать её не стоит. Видоизменил код, чтоб цикл выполнялся конечное число раз, а w1 дальше вызывалась. Но ничего не изменилось.
Если же я вызываю функцию до цикла, в самом main, то w1 изменяется. Что тут не так? Кроме того, изменяя код функции, при работе цикла я вижу изменение по времени, т.е. код-то вроде как работает. Почему тогда w1 не меняется? Или это дебагер гадит и не показывает?

P.S. Проверил диодом:

Код: Выделить всё

if (w1>(float)100500) STM_EVAL_LEDOn(LED5); 
Похоже, всё-таки дебагер. Досадно. Ну хоть переменная меняется на самом деле.
Ответить

Вернуться в «ARM»