|
Нужна помощь разобраться с asm рутиной FIRа, Моя первая самостоятелсьная FIR рутина... |
|
|
|
Jun 3 2007, 18:35
|
Знающий
   
Группа: Свой
Сообщений: 921
Регистрация: 6-04-07
Из: Israel
Пользователь №: 26 822

|
После долгих моих тугодумных мук родил FIR код в asm который будет част проэкта (вызывается из кода С). Почему-то после добавления ее в проэкт (данного файла asm) - проэкт не компилируется - падает ессно на этой рутине выдавая кучу ошибок. Первая из них весьма странная мне, не могу понять что его не устраивает. Может подскажете чего я не вижу: Код .mmregs .global _p_buffer_in,_p_buffer_out,_dline,_fcoeff,_fir_ord,_p_buff_lenth .global _fir_processing
_fir_processing: ; saving regs content into stack pshm ar0; used as delay line and coeff. cycling addressing increment pshm ar1; holds input data array start address pshm ar2 ; holds pointer to filter coeff. array addressing pshm ar3; holds pointer to delay line array addressing pshm ar4; holds output data array start address pshm ar5; holds output data array nop nop ; Initialization stm #1,ar0 ;set increment step for cycling buffers mvdm *(_fir_ord),BK ;set cyclic buffer size (for delay line and coeff buffer) stm #_p_buff_in,ar1 ;load data_in array start address stm #_fcoeff,ar2 ;load coeff. array start address stm #_dline,ar3 ;load delay line array start address stm #_p_buffer_out,ar4 ;load output data buffer array address mvdm *(_p_buff_length)-1,brc ;load BRC with processing data block length (PROC_BUFFER_LENGTH) nop nop ; Filtration rptb fir_loop_end-1 ; repeat FIR routine for entire processing data buffer mvdd *ar1+,*ar3+% ; load next input sample from input proc. array into delay line array rptz a,_fir_ord-1 ; FIR order less 1 iterations per each input data sample mac *ar2+0%,*ar3+0%,a ; MAC operation on cyclic delay line and coeff. arrays rnd a ; round off value in acc. A to 16 bits sth a,*ar4+ ; store output value into data output array fir_loop_end: popm ar5 popm ar4 popm ar3 popm ar2 popm ar1 popm ar0 Первая ошибка которую выдает компилятор: Цитата > ERROR ! at line 29: [E0004] Expecting dual memory addressing mvdd *ar1+, *ar3+% Дальше еще есть кучу ошибок, подозреваю что некоторые завязаны на предыдущих, посему буду исправлять по одной от первой к последней с перекомпиляцией после каждой. Итак, что ему не нравиться в mvdd ? Она-то вроде перекидывает из памяти в память, и вроде у меня так и есть в коде....  Что я в упор не вижу ????? Кроме того, если видите у другие ошибки в коде алгоритма - буду благодарен за указание таковых... P.S. Все переменные в данном asm определены в основном С коде.
|
|
|
|
3 страниц
1 2 3 >
|
 |
Ответов
(1 - 33)
|
Jun 4 2007, 05:59
|
Знающий
   
Группа: Свой
Сообщений: 921
Регистрация: 6-04-07
Из: Israel
Пользователь №: 26 822

|
Цитата(BratherLU @ Jun 4 2007, 09:16)  1 - В mvdd можно использовать только регистры ar2,ar3,ar4,ar5 2 - rnd не стоит использовать т к она работает неправильно читайте эррату на процессор заменить на ADD #1,15,src[,dst] 3 - Загляните в хелп CCS в разделы Register Conventions и Function Conventions Да, спасибо. Я вчера рылся в нете насчет инфы по rnd (error подозрительным показался...) и действител-ьно наткнулся на упоминание эрраты, скачал SPRZ 155d - там вторая advisory как раз об этом и говорит. Рекомендуют заменять rnd на то что вы пердложили. Так и сделал в сорсе. Кстати, вопрос - этот вариант округления результата я видел в примере FIR кода: http://cnx.org/content/m10023/2.19/, и оттуда его стянул (rnd). Честно говоря не совсем понял резонность такого способа округления до 16 бит. Хелп на rnd говорит о прибавлении к аккумулятору 2^15 степени, затем они там в примере беру как результат старшие 16 бит аккумулятора. е могли бы вы пояснить чайнику каким образом так получаем 16 эффектиных бит (включая знак) ? Насчет mvdd - понял, спасибо. Загляну в conventions. Пока заменил ее на две инструкции переброски данного через аккумулятор Б. Еще одна вещь: при прогоне в дебаггере, обнаружил что: mvdm *(_p_buff_length)-1,brc не правильно работает - загружает не то значение которое по адресу _p_buff_length. Не знаю почему (может стоит тоже проверить register conventions), но пока заменяю ее на три другие: ld *(_p_buff_length), b sub #1, b stl b, brc тут загвоздка - в runе, последняя не загружает brc регистр вообще. Наверно применил не ту инструкцию для загрузки mеmory-mapped регистра из аккумулятора. Как правильно это сделать ? В целом, вам кажется код OK ? Нет каких-либо явных ошибок в имплементации алгоритма ?
|
|
|
|
|
Jun 4 2007, 10:14
|
Знающий
   
Группа: Свой
Сообщений: 921
Регистрация: 6-04-07
Из: Israel
Пользователь №: 26 822

|
Цитата(BratherLU @ Jun 4 2007, 12:54)  В Conventions описано как праввильно делать вызов асм функций из С, как передать параметры через стэк, и какие регистры использует компилятор для своих нужд (какие регистры требуют сохранения на стэке), а какие можно свободно использовать без сохранения контекста
Код смотрел бегло - то что бросилось в глаза и написал
Да еще при использовании циклической адрессации в mvdd необходимо использовать ar0 для модификации адресных регистров типа mvdd *ar2+,ar3+0% Тогда будет работать
mvdm *(_p_buff_length)-1,brc заменить на mvdk *(_p_buff_length-1),brc
По поводу округления - ссылку не смотрел. Отвечу опираясь на эррату - здесь округление до соответствующего 2-чного разряда (младшего значащего в формате Q15 (15 - бит дробная часть 1 бит -3нак)), а не десятичного. Дорустим: (АH:AL)=0x00008000 = 0.000015259(=0x8000*(1/0x80000000)) в формате Q31. Добавляем (единицу сдвинутую на 15)-> AH:AL+0x8000=> (АH:AL)=0x00008000 =0.000015259(q31) + 0x00008000 =0.000015259(q31) (АH:AL)=0x00010000 = 0.000030517578125(Q31)=0x0001(Q15) То есть берем старшую часть аккумулятора, а младшую отбрасываем в итоге получается верный 16-битный округленный до ближайшего большего результат в формате (Q15) =0x0001 (PS точка находится между msb msb-1 результата как для Q31 так и для Q15) OK, спасибо но заменив на mvdk *(_p_buff_length-1),brc ничего не дало, работает так-же ошибочно как и с mvdm (т.е. загружается в BRC ошибочная переменная и единица не вычитается).. Странно..пока заменил 4мя другими коммандами чтоб работало: Код .bss temp, 1 . . ld *(_pbuff_length), b sub #1, b stl, b, *(temp) mvdm *(temp), brc не эффективно, но работает... вернул обратно mvdd *ar2+,ar3+0% (в ar2 -> pointer на массив данных, ar3 -> pointer на линию задержки = 150) - приняло. Но в дебаггере при runе, вследствии поядка следваания комманд: Код mvdd *ar1+,*ar3+% ; load next input sample from input proc. array into delay line array rptz a,_fir_ord-1 ; FIR order less 1 iterations per each input data sample mac *ar2+0%,*ar3+0%,a ; MAC operation on cyclic delay line and coeff. array наблюдаю что указатель на линию задержки (в ar3) после каждого люпа (150 итераций) прыгает через 6 адресов (т.в. если первый sample из массива данных он положил по первому адресу линии задержки: 0х2000, то после люпа, след. sample он ложит в 0х2007). Мне казалось что должна происходить циркуляция по заданному циклу (150), т.е. каждый послед. sample из массива данных должен ложиться в послед. адрес линии задержки (0х2000 -> 0х2001 -> 0х2003 и т.д.). Я не прав ?
|
|
|
|
|
Jun 4 2007, 11:06
|
Частый гость
 
Группа: Свой
Сообщений: 103
Регистрация: 16-05-06
Пользователь №: 17 126

|
mvdk *(_p_buff_length-1),brc сорри Вас запутал и сам заплутал mvdk *(_p_buff_length-1),brc - такая штука загрузит в брс значение из ячейки с абсолютным адресом (_p_buff_length-1).
Поэтому - по адресу _p_buff_length должно лежать сразу нужное значение (на единицу меньше), если хотите использовать mvdk *(_p_buff_length),brc
По поводу циркулярной адрессации и rptz грабли таки rptz a,_fir_ord-1 , если _fir_ord - адрес внешней константы (в сях), то компилер реально считает, что число повторений следующей инструкции лежит по адресу _fir_ord-1 и выполняет инструкцию это число раз +1 - ничего общего с Вашей задумкой я думаю => два способа вызова rptz (Mnemonic insruction Set) 1 rptz a,#_fir_ord-1 повторит след инструкция _fir_ord раз, где _fir_ord - константа объявленная в этом же асме или еще где во внешнем асме чере .set 2 rptz a,*(_fir_ord) в этом случае повторит след инструкция число раз +1 лежащих по адрес _fir_ord .
|
|
|
|
|
Jun 4 2007, 11:27
|
Знающий
   
Группа: Свой
Сообщений: 921
Регистрация: 6-04-07
Из: Israel
Пользователь №: 26 822

|
Цитата(BratherLU @ Jun 4 2007, 15:06)  mvdk *(_p_buff_length-1),brc сорри Вас запутал и сам заплутал mvdk *(_p_buff_length-1),brc - такая штука загрузит в брс значение из ячейки с абсолютным адресом (_p_buff_length-1).
Поэтому - по адресу _p_buff_length должно лежать сразу нужное значение (на единицу меньше), если хотите использовать mvdk *(_p_buff_length),brc
По поводу циркулярной адрессации и rptz грабли таки rptz a,_fir_ord-1 , если _fir_ord - адрес внешней константы (в сях), то компилер реально считает, что число повторений следующей инструкции лежит по адресу _fir_ord-1 и выполняет инструкцию это число раз +1 - ничего общего с Вашей задумкой я думаю => два способа вызова rptz (Mnemonic insruction Set) 1 rptz a,#_fir_ord-1 повторит след инструкция _fir_ord раз, где _fir_ord - константа объявленная в этом же асме или еще где во внешнем асме чере .set 2 rptz a,*(_fir_ord) в этом случае повторит след инструкция число раз +1 лежащих по адрес _fir_ord . Спасибо, понял. Пробую: rptz a, *(_fir_ord) не проходит компиляцию - компайлер выдает ошибку утверждая что rptz не принимает indirect addressing. У меня, все глобальные констатнты и определения (включая -fir_ord) определены через главный С файл, посему действительно как вы и говорите нужно indirectt addressing, но засада видимо в том что комманда rptz не принимает indirect. Неужели нет выхода и нужно в asm коде определять временную переменную и в нее кидать значение _fir_ord данное извне ?
|
|
|
|
|
Jun 4 2007, 12:03
|
Знающий
   
Группа: Свой
Сообщений: 921
Регистрация: 6-04-07
Из: Israel
Пользователь №: 26 822

|
Цитата(BratherLU @ Jun 4 2007, 15:46)  ld #0x00,a rpt *(_fir_ord) ОК, уже скомпилировалось, но при прогоне ар3 адресация (т.е. pointer в линии задержки) прыгает через один адрес при его загрузке (загрузке очередного sample сигнала). Странно, неужели опять не то число циркуляций ? С дургой стороны, заменил ради интереса rptz a, *(_fir_ord) (который не компилировался) на прямое: rptz a, #150-1 (150 - порядок фильтра) - тогда загрузка в линию задержки в цикле шла нормально, но зато в mac *ar4+0%, *ar3+0%, a поинтер в ar4 (буфер коэффициентов) прыгал меду началом и след. адресом, туда - обратно и не продвигался дальше по буферу. Чего-то я теряю нить...
|
|
|
|
|
Jun 4 2007, 12:28
|
Знающий
   
Группа: Свой
Сообщений: 921
Регистрация: 6-04-07
Из: Israel
Пользователь №: 26 822

|
Цитата(BratherLU @ Jun 4 2007, 16:07)  Коэффициенты тоже должны быть выровнены по соответствующей границе Да, так и есть, оба буфера (и коеффициенты и линия задержки выровняны по нужным boundaries (они 150, значит оба буфера выровняны по 256 кратности: один начинается на 0х2000, другой на 0х2100) - это проверено. Это я определил в конфигурации памяти в .cmd (выделил по секции на них, каждая начиная с вышеупомянутых адресов) и соотв. pragmaой в С коде. Так они и сидят. Не понимаю что ему не хватает, все выровняно, вроде правильная индексация в коде, ...
|
|
|
|
|
Jun 4 2007, 13:07
|
Знающий
   
Группа: Свой
Сообщений: 921
Регистрация: 6-04-07
Из: Israel
Пользователь №: 26 822

|
Цитата(BratherLU @ Jun 4 2007, 16:43)  Еще смотрите - что у вас в BK и в ar0 если все ок значит все таки с числом повторений что-то не то если BK=число повторений и ar0=1 (-1), то оба указателя должны вернутся в начало буферов после rpt. Не хочу навязывать свои способы, но попробуйте этот цикл организовать через rptb - сможете отследить промежуточные состояния адресных регистров при расчете выборки и отловить ошибку Да нет, что-вы, вы ничего не навязываете, ваша помощь очень существенна для новичка типа меня, есть много чему поучиться. ar0 стабильно держит 1, в BK стабильно сидит загруженное число (150 - порядок фильтра), в BRC стабильно сидит размер буфера входных данных - 1 (буфер у меня 290 samples, в BRC загоняю 289 (0х121)). Хмм, бред какой-то... Кстати, для уточнения: размер линии задержки это порядок фильтра (и кол-во элементов задержки), т.е. для FIRа порядка 150, размер линии задержки (BK) и есть 150, так ? Иногда есть путанница и адже в литературе по DSP длинной фильтра называют то его порядок то кол-во коеффициентов (которое на 1 больше порядка)...
|
|
|
|
|
Jun 4 2007, 14:13
|
Частый гость
 
Группа: Свой
Сообщений: 103
Регистрация: 16-05-06
Пользователь №: 17 126

|
В Данной реализации длина линии задержки==число коэффициентов FIR А так совет пусть не эффективно но наглядно - отлаживайтесь по частям - добейтесь, чтоб после обсчета ОДНОЙ выборки у Вас указатели внутри буферов оказались там где должны оказаться раз уж взялись за циклическую адрессацию. Ну типа -> ... инициализация ar3,ar4, ... stm #1,ar0 stm #(число коэффициентов FIR),bk stm #(число коэффициентов FIR -1),brc ld #0x00,a nop nop ... ;//(подгружаем отсчет в линию задержки) ld #0x00,a rptb _loop_end-1 mac *ar4+0%,*ar3+0%,a _loop_end ;//(указатели ar4, ar3 при таком контексте будет такими же как и до rptb) ... и т.д. Смотрите в симуляторе как где и что меняется и где заканчивается. Заведется это - перепишите уже как Вам нравится с использованием rpt внутри и rptb снаружи На перед скажу, если Ваш FIR считает правильно то подав на вход сигнал - дельта функцию (единичный импульс) на выходе получите вектор коэффициентов фильтра
Сообщение отредактировал BratherLU - Jun 4 2007, 14:17
|
|
|
|
|
Jun 4 2007, 18:18
|
Знающий
   
Группа: Свой
Сообщений: 921
Регистрация: 6-04-07
Из: Israel
Пользователь №: 26 822

|
Цитата(BratherLU @ Jun 4 2007, 18:13)  В Данной реализации длина линии задержки==число коэффициентов FIR А так совет пусть не эффективно но наглядно - отлаживайтесь по частям - добейтесь, чтоб после обсчета ОДНОЙ выборки у Вас указатели внутри буферов оказались там где должны оказаться раз уж взялись за циклическую адрессацию. Ну типа -> ... инициализация ar3,ar4, ... stm #1,ar0 stm #(число коэффициентов FIR),bk stm #(число коэффициентов FIR -1),brc ld #0x00,a nop nop ... ;//(подгружаем отсчет в линию задержки) ld #0x00,a rptb _loop_end-1 mac *ar4+0%,*ar3+0%,a _loop_end ;//(указатели ar4, ar3 при таком контексте будет такими же как и до rptb) ... и т.д. Смотрите в симуляторе как где и что меняется и где заканчивается. Заведется это - перепишите уже как Вам нравится с использованием rpt внутри и rptb снаружи На перед скажу, если Ваш FIR считает правильно то подав на вход сигнал - дельта функцию (единичный импульс) на выходе получите вектор коэффициентов фильтра Да, спасибо, так и сделал (проверочную рутину с rptb). по выходу из цикла (_loop_end), ar4 (коефф.) действительно вернулся на начало (0х2100) а вот ar3 (линия задержки) оказалась на 0х2001, т.е. ушла на 1 вперед (ее начало в 0х2000). Но в приципе это кажется логично ибо изначально указатель линии задержки инкрементировался до входа в цикл (mvdd *ar1+,*ar3+%), т.е. он по идее опережает инкремент коеффициентов на 1. Вроде все логично, так ? Если это правильно - верну обратно "оперативный" вариант и проверю еще раз... Насчет проверки рутины подачей импульса - это вы правы, импульс на входе LTI системы (которой и являются наши фильтры) даст передаточную функцию системы, то бишь коеффициенты фильтра...хороший способ само-проверки...
|
|
|
|
|
Jun 5 2007, 08:49
|
Частый гость
 
Группа: Свой
Сообщений: 103
Регистрация: 16-05-06
Пользователь №: 17 126

|
Цитата(Саша Z @ Jun 4 2007, 22:18)  ..., т.е. ушла на 1 вперед (ее начало в 0х2000). Но в приципе это кажется логично ибо изначально указатель линии задержки инкрементировался до входа в цикл (mvdd *ar1+,*ar3+%), т.е. он по идее опережает инкремент коеффициентов на 1. Вроде все логично, так ? Если это правильно - верну обратно "оперативный" вариант и проверю еще раз... После обсчета каждой выборки указатель внутри линии задержки должен ув-ся(или уменьшаться на единицу) и указывать на самый новый (или старый отсчет) после подгрузки очередного отсчета, а указатель на коэффициенты до повторяющихся маков всегда должен указывать на начало массива коэффициентов PS Новый/старый и +- 1 зависит от того в какую сторону подгружаете отсчеты в буфер и в каком порядке у Вас лежат коэффициенты фильтра
|
|
|
|
|
Jun 5 2007, 11:48
|
Знающий
   
Группа: Свой
Сообщений: 921
Регистрация: 6-04-07
Из: Israel
Пользователь №: 26 822

|
Цитата(BratherLU @ Jun 5 2007, 12:49)  После обсчета каждой выборки указатель внутри линии задержки должен ув-ся(или уменьшаться на единицу) и указывать на самый новый (или старый отсчет) после подгрузки очередного отсчета, а указатель на коэффициенты до повторяющихся маков всегда должен указывать на начало массива коэффициентов
PS Новый/старый и +- 1 зависит от того в какую сторону подгружаете отсчеты в буфер и в каком порядке у Вас лежат коэффициенты фильтра OK, в моем случае коеффициенты расположены в прямом порядке (т.е. индексация коеффициентов от 0 до 150ого идет по старшинству адресов а буфере памяти). Заполнение линии задержки тоже последовательное (от начала буфера т.е. младшего адреса к старшему). В ar0 = 1, т.е. incerement. Хочу еще раз уточнить на свою тупую голову детали: Длинна линии задержки FIRа равна его порядку (т.е. 150 в моем случае), что на 1 меньше кол-ва коеффициентов (151 у меня). Так ? Число повторений внутреннего цикла (mac) должно быть равно порядку, т.е. 150, но т.к. инструкция rpt делает на 1 больше повторений в цикле поэтому загружаем в RC (число коефф. - 2), т.е. 149 (или число повторений должно быть равно числу коефф. ?) . Моя проблема это то что новые входные samples загружаются в линию задержки через один адрес, а не послеовательно один адрес за другим. Это при том что адресация коеффициентво (в mac) идет вроде правильная - последовательная. Значит думаю проблема у меня где-то в соотношении числа повторений внутреннего цикла (mac) к длинне линии задержки....
|
|
|
|
|
Jun 5 2007, 12:25
|
Знающий
   
Группа: Свой
Сообщений: 921
Регистрация: 6-04-07
Из: Israel
Пользователь №: 26 822

|
Цитата(BratherLU @ Jun 5 2007, 16:03)  Еще раз в данной реализации -> длина линии задержки (151) == числу коэффициентов FIR(151) == число маков(151) Проверил у себя в программе - так и есть, но все-равно поинтер в линии задержки прыгает через один про загрузке след. входного sample. Странно Кстати, в дебаггере при проходе цикла маков: Код rpt *(_fir_ord) ; _fir_ord = 150 mac *ar4+0%, ar3+0%, a прохождение не заходит во внутрь самого цикла маков (ни с F10, ни с F11), посему нет возможности отследить адресацию линии задержки (ar3) внутри цикла маков...только по выходу из него...
|
|
|
|
|
Jun 5 2007, 13:02
|
Знающий
   
Группа: Свой
Сообщений: 921
Регистрация: 6-04-07
Из: Israel
Пользователь №: 26 822

|
Цитата(BratherLU @ Jun 5 2007, 16:45)  Давйте кусочек кода начиная с внешнего цикла (там где новый отсчет подгружается) Большое спасибо, сочту за хороший урок.. BRC предварительно загружен кол-вом samples в буфере входных данных. _fir_ord = 150 Код ; Filtration rptb fir_loop_end-1 ; repeat FIR routine for entire processing data buffer mvdd *ar2+,*ar3+0% ; load next input sample from input proc. array into delay line array ld #0, a ; reset A rpt *(_fir_ord) ; FIR order (here equal to the number of FIR coefs) ;iterations per each input data sample mac *ar4+0%,*ar3+0%,a ; MAC operation on cyclic delay line and coeff. arrays
add #1, 15, a ; round off value in acc. A to 16 bits - replaces rnd a instruction sth a,*ar5+ ; store output value into data output array fir_loop_end:
|
|
|
|
|
Jun 5 2007, 14:07
|
Частый гость
 
Группа: Свой
Сообщений: 103
Регистрация: 16-05-06
Пользователь №: 17 126

|
Да незачта.В своем проекте дописал чуть-чуть Код *.c ... const unsigned short fir_ord=150; ... *.asm .ref _fir_ord .ref _IN_BUFF .ref _OUT_BUFF ...;Only for test in Simulator stm #0x2000,ar4 stm #0x2100,ar3
stm #_IN_BUFF,ar2 stm #_OUT_BUFF,ar5
stm #151,bk stm #1,ar0 nop ;дальше Ваш код без изменений Filtration rptb fir_loop_end-1 ; repeat FIR routine for entire processing data buffer mvdd *ar2+,*ar3+0% ; load next input sample from input proc. array into delay line array ;ar3 указывает на самый старый отсчет все ОК ld #0, a ; reset A rpt *(_fir_ord) ; FIR order (here equal to the number of FIR coefs) ;iterations per each input data sample mac *ar4+0%,*ar3+0%,a ; MAC operation on cyclic delay line and coeff. arrays ;ar3 снова указывает на тот же самый старый отсчет все ОК add #1, 15, a ; Это я бы убрал на время отладки sth a,*ar5+ ; store output value into data output array fir_loop_end: Все должно работать ничего в Вашем куске не менял, указатели меняются как положено
Сообщение отредактировал BratherLU - Jun 5 2007, 14:14
|
|
|
|
|
Jun 5 2007, 14:52
|

Ambidexter
    
Группа: Свой
Сообщений: 1 589
Регистрация: 22-06-06
Из: Oxford, UK
Пользователь №: 18 282

|
Цитата(Саша Z @ Jun 3 2007, 17:35)  Кроме того, если видите у другие ошибки в коде алгоритма - буду благодарен за указание таковых... Мне кажется, у вас имеется логическая ошибка в программе фильтрации. Данные вы кладёте в циклический буфер, это хорошо, но затем вы циклически крутите буфер коэффициентов, это плохо. Должно быть так. 1) Вы записали новое данное в циклический буфер, указатель стал указывать на самую старую выборку. 2) Установили начало буфера коэффициентов. 3) Обработали 151 сампл, выдали результат, указатель опять указывает на самую старую выборку. 4) Перешли к пункту 1, пока не закончатся исходные данные.
--------------------
Делай сразу хорошо, плохо само получится
|
|
|
|
|
Jun 5 2007, 14:55
|
Знающий
   
Группа: Свой
Сообщений: 921
Регистрация: 6-04-07
Из: Israel
Пользователь №: 26 822

|
Цитата(BratherLU @ Jun 5 2007, 18:07)  Да незачта.В своем проекте дописал чуть-чуть Код *.c ... const unsigned short fir_ord=150; ... *.asm .ref _fir_ord .ref _IN_BUFF .ref _OUT_BUFF ...;Only for test in Simulator stm #0x2000,ar4 stm #0x2100,ar3
stm #_IN_BUFF,ar2 stm #_OUT_BUFF,ar5
stm #151,bk stm #1,ar0 nop ;дальше Ваш код без изменений Filtration rptb fir_loop_end-1 ; repeat FIR routine for entire processing data buffer mvdd *ar2+,*ar3+0% ; load next input sample from input proc. array into delay line array ;ar3 указывает на самый старый отсчет все ОК ld #0, a ; reset A rpt *(_fir_ord) ; FIR order (here equal to the number of FIR coefs) ;iterations per each input data sample mac *ar4+0%,*ar3+0%,a ; MAC operation on cyclic delay line and coeff. arrays ;ar3 снова указывает на тот же самый старый отсчет все ОК add #1, 15, a ; Это я бы убрал на время отладки sth a,*ar5+ ; store output value into data output array fir_loop_end: Все должно работать ничего в Вашем куске не менял, указатели меняются как положено Большое спасибо, проверю еще раз у меня в цельном коде на ссответствие. . .. Проверил - Огромное Спасибо - есть bug - у меня в начале asm кода BK загружался порядком фильтра (150) а не числом коефф. - стандартная путанница понятий (у меня порядок фильтра и кол-во коеф.. - разные вещи хоть и железно связанные друг с другом, а нередко важе в литературе говорят о них как об одном числе (но упоминая ессно о кол-ве элементов delay на 1 меньше)....вот и у нас такая путанница вышла... В общем, мой большой  вам, рутина работает. Теперь приступаю к имлементации IIRов второго порядка которых у меня 15 в проэкте (все параллеьны)....подозреваю что и тут ваша помощь окажется трудно-переоценимой....
|
|
|
|
|
Jun 5 2007, 15:58
|
Знающий
   
Группа: Свой
Сообщений: 921
Регистрация: 6-04-07
Из: Israel
Пользователь №: 26 822

|
Цитата(=GM= @ Jun 5 2007, 18:52)  Мне кажется, у вас имеется логическая ошибка в программе фильтрации. Данные вы кладёте в циклический буфер, это хорошо, но затем вы циклически крутите буфер коэффициентов, это плохо.
Должно быть так.
1) Вы записали новое данное в циклический буфер, указатель стал указывать на самую старую выборку.
2) Установили начало буфера коэффициентов.
3) Обработали 151 сампл, выдали результат, указатель опять указывает на самую старую выборку.
4) Перешли к пункту 1, пока не закончатся исходные данные. Да но буфер коефф. тоже можно крутить циклически таким образом избегая его переадресации в начале каждого цикла (каждого нового sample), т.е. таким образом экономим пункт 2).
|
|
|
|
|
Jun 5 2007, 18:13
|

Ambidexter
    
Группа: Свой
Сообщений: 1 589
Регистрация: 22-06-06
Из: Oxford, UK
Пользователь №: 18 282

|
Цитата(Саша Z @ Jun 5 2007, 15:58)  Да но буфер коефф. тоже можно крутить циклически таким образом избегая его переадресации в начале каждого цикла (каждого нового sample), т.е. таким образом экономим пункт 2). Вот что должно получиться по классике (х1 - самая старая выборка)
Код x1 x2 x3 x4 x5 x6 x6 x8 x9 - буфер входных выборок k1 k2 k3 k4 k5 - буфер коэффициентов
На первом этапе j=0 вычисляем сумму y(j) = Σx(i+j)•k(i), i=0,1,…,5. То есть
y(0)=x(1)•k(1)+x(2)•k(2)+x(3)•k(3)+x(4)•k(4)+x(5)•k(5)
На втором этапе j=1 самая старая выборка х(1) уйдёт в небытие, получим
x2 x3 x4 x5 х6 х7 х8 х9 - буфер входных выборок k1 k2 k3 k4 k5 - буфер коэффициентов
y(1)=x(2)•k(1)+x(3)•k(2)+x(4)•k(3)+x(5)•k(4)+x(6)•k(5)
На третьем этапе j=2 самая старая выборка х(2) уйдёт в небытие, получим
x3 x4 x5 х6 х7 х8 х9 - буфер входных выборок k1 k2 k3 k4 k5 - буфер коэффициентов
y(2)=x(3)•k(1)+x(4)•k(2)+x(5)•k(3)+x(6)•k(7)+x(8)•k(5) Ну и так далее. А что у вас? Указатель передвигается на х(2) и одновременно другой указатель на k(2). Вроде бы не получается. По крайней мере, у меня с ходу не получилось.
--------------------
Делай сразу хорошо, плохо само получится
|
|
|
|
|
Jun 6 2007, 06:57
|
Знающий
   
Группа: Свой
Сообщений: 921
Регистрация: 6-04-07
Из: Israel
Пользователь №: 26 822

|
Цитата(=GM= @ Jun 5 2007, 22:13)  Вот что должно получиться по классике (х1 - самая старая выборка)
Код x1 x2 x3 x4 x5 x6 x6 x8 x9 - буфер входных выборок k1 k2 k3 k4 k5 - буфер коэффициентов
На первом этапе j=0 вычисляем сумму y(j) = Σx(i+j)•k(i), i=0,1,…,5. То есть
y(0)=x(1)•k(1)+x(2)•k(2)+x(3)•k(3)+x(4)•k(4)+x(5)•k(5)
На втором этапе j=1 самая старая выборка х(1) уйдёт в небытие, получим
x2 x3 x4 x5 х6 х7 х8 х9 - буфер входных выборок k1 k2 k3 k4 k5 - буфер коэффициентов
y(1)=x(2)•k(1)+x(3)•k(2)+x(4)•k(3)+x(5)•k(4)+x(6)•k(5)
На третьем этапе j=2 самая старая выборка х(2) уйдёт в небытие, получим
x3 x4 x5 х6 х7 х8 х9 - буфер входных выборок k1 k2 k3 k4 k5 - буфер коэффициентов
y(2)=x(3)•k(1)+x(4)•k(2)+x(5)•k(3)+x(6)•k(7)+x(8)•k(5) Ну и так далее. А что у вас? Указатель передвигается на х(2) и одновременно другой указатель на k(2). Вроде бы не получается. По крайней мере, у меня с ходу не получилось. Ну давайте смотреть... Начнем пожалуй как и вы, с базисной функции которую нужно имплементировать, т.е. конволюции сигнала с transfer function фильтра, то бишь его коеффициентами: y[n] = x[n]h[0] + x[n-1]h[1] + x[n-2]h[2] +....+x[n-(N-1)]h[N-1] где: x - samples вхдпдного сигнала, h - коефф. transfer function фильтра, y - ессно выходные samples. значит: y[0] = x[0]h[0] + 0h[1] + 0h[2]+ ...+ 0 = x[0]h[0] y[1] = x[1]h[0] + x[0]h[1] y[2] = x[2]h[0] + x[1]h[1] + x[0]h[2] y[3] = x[3]h[0] + x[2]h[1] + x[1]h[2] + x[0]h[3] и т.д. В аккумуляторе каждый раз выполняется: y[n] = h[n]х[n-i] где i - индексация коефф. фильтра. Кстати, в такой реализации коефф. фильтра должны располагаться в прямом порядке в буфере - т.е. по возрастающим адресам (как и в буфере линии задержки кида подгружаются входные данные), изначально буфер задержки конечно-же обнулен. Как мы знаем, всегда выполняется полное-кол-во итераций (согласно порядку/длинне фильтра) для каждого нового sample, значит pointer в буфере коефф. должен всегда проходить полный цикл и к началу следующего возвращаться обратно на первый коеффициент. Что и делает циркулярная адресация буфера коеффициентов. Длинна цирк. адресации буфера коефф. и линии задержки - одинакова (что дает возможность одновременной циркуляции по единиму циклу в BK), но в линию задержки, как вы правильно сказали, каждый новый цикл подгружается новый input. В вашем примере вы ведь тоже в буфере коефф. каждый раз (после каждого цикла) возвращаетесь на начало (т.е. на первый коефф.), но делаете видимо это отдельной инструкцией загрузки pointerа начала буфера коеффициентов.
|
|
|
|
|
Jun 6 2007, 07:28
|
Местный
  
Группа: Новичок
Сообщений: 210
Регистрация: 3-11-06
Пользователь №: 21 936

|
Цитата(Саша Z @ Jun 6 2007, 10:57)  ... Кстати, в такой реализации коефф. фильтра должны располагаться в прямом порядке в буфере - т.е. по возрастающим адресам (как и в буфере линии задержки кида подгружаются входные данные), изначально буфер задержки конечно-же обнулен. Все правильно Вы написали, за исключением расположения к-тов в буфере. Они там в инверсном порядке должны располагаться. Иначе Вы получите: y0=x0*h[N-1]; y1=x0*h[N-2]+x1*h[N-1]; ... И вместо свертки Вы вычисляете корреляцию. Для симметричного фильтра это пофигу. Для анти и асимметричных фильтров - нет. С инверсным расположением будет то, что надо  Впрочем допускаю, что Вы к-ты нумеруете задом наперед
|
|
|
|
|
Jun 6 2007, 08:04
|
Знающий
   
Группа: Свой
Сообщений: 921
Регистрация: 6-04-07
Из: Israel
Пользователь №: 26 822

|
Цитата(-=ВН=- @ Jun 6 2007, 11:28)  Все правильно Вы написали, за исключением расположения к-тов в буфере. Они там в инверсном порядке должны располагаться. Иначе Вы получите: y0=x0*h[N-1]; y1=x0*h[N-2]+x1*h[N-1]; ... И вместо свертки Вы вычисляете корреляцию. Для симметричного фильтра это пофигу. Для анти и асимметричных фильтров - нет. С инверсным расположением будет то, что надо  Впрочем допускаю, что Вы к-ты нумеруете задом наперед  Да нет, честно говоря не вижу проблемы инверсии адресации коеффициентов в данной имплементации. Если например посмотреь только на первый цикл (для первого вסםגמםעם sample), то получается как раз y[0] = x[0[0]h[0] (при придложенной вами инвертации порядка коефф. получили-бы: y[0] = x[0]h[N-1]) Вот пример такого типа реализации FIRа от TI: SPRU173 (можно скачать с TIевского сайта, или если хотите могу вам замейлить). Не вижу там намека на инвертацию последовательности коеффициентов.
|
|
|
|
|
Jun 6 2007, 08:52
|
Местный
  
Группа: Новичок
Сообщений: 210
Регистрация: 3-11-06
Пользователь №: 21 936

|
Цитата(Саша Z @ Jun 6 2007, 12:04)  Да нет, честно говоря не вижу проблемы инверсии адресации коеффициентов в данной имплементации. Если например посмотреь только на первый цикл (для первого вסםגמםעם sample), то получается как раз y[0] = x[0[0]h[0] (при придложенной вами инвертации порядка коефф. получили-бы: y[0] = x[0]h[N-1])
Вот пример такого типа реализации FIRа от TI: SPRU173 (можно скачать с TIевского сайта, или если хотите могу вам замейлить). Не вижу там намека на инвертацию последовательности коеффициентов. Плохо, что не видите. Вот и посмотрите на 1 цикл. На примере 4-х точечного фильтра. К-ты фильтра h0,h1,h2,h3. h0 в младшем адресе, h3 в старшем. AR4 указывает на h0. Буфер данных, тоже 4-х точечный, располагаемый по адресам A0-A3. Изначально буфер обнулен. В AR3 содержится адрес A0 до записи первого входного отсчета. Как только Вы его записали, AR3 станет равным A1. Вот и смотрите. Первое выходное значение будет h0*[A1]+h1*[A2]+h2*[A3]+h3*[A0]. Здесь под [A0],[A1],[A2],[A3] обозначено содержимое ячеек по адресам A0-A3. Т.к. по адресам A1-A3 находится 0, а в ячейке с адресом A0 находится x0, то в результате получается h3*x0. А техасовский пример Вы зря упомянули. Вы с ним не разобрались совершенно. Я даже не поленился его посмотреть. Там все абсолютно правильно. Посмотрите хотя бы картинку на странице 77. Там дано расположение к-тов по адресам. Они там расположены именно в инверсном порядке. В тексте же программы неудачно использован симметричный фильтр. У него начало и конец абсолютно одинаковы.
|
|
|
|
|
Jun 6 2007, 09:10
|

Ambidexter
    
Группа: Свой
Сообщений: 1 589
Регистрация: 22-06-06
Из: Oxford, UK
Пользователь №: 18 282

|
Цитата(Саша Z @ Jun 6 2007, 05:57)  Ну давайте смотреть... Начнем пожалуй как и вы, с базисной функции которую нужно имплементировать, т.е. конволюции сигнала с transfer function фильтра, то бишь его коеффициентами:
y[n] = x[n]h[0] + x[n-1]h[1] + x[n-2]h[2] +....+x[n-(N-1)]h[N-1]
где: x - samples вхдпдного сигнала, h - коефф. transfer function фильтра, y - ессно выходные samples.
значит: y[0] = x[0]h[0] + 0h[1] + 0h[2]+ ...+ 0 = x[0]h[0] y[1] = x[1]h[0] + x[0]h[1] y[2] = x[2]h[0] + x[1]h[1] + x[0]h[2] y[3] = x[3]h[0] + x[2]h[1] + x[1]h[2] + x[0]h[3] и т.д.
В аккумуляторе каждый раз выполняется: y[n] = h[n]х[n-i] где i - индексация коефф. фильтра. Кстати, в такой реализации коефф. фильтра должны располагаться в прямом порядке в буфере - т.е. по возрастающим адресам (как и в буфере линии задержки кида подгружаются входные данные), изначально буфер задержки конечно-же обнулен. Как мы знаем, всегда выполняется полное-кол-во итераций (согласно порядку/длинне фильтра) для каждого нового sample, значит pointer в буфере коефф. должен всегда проходить полный цикл и к началу следующего возвращаться обратно на первый коеффициент. Что и делает циркулярная адресация буфера коеффициентов. Длинна цирк. адресации буфера коефф. и линии задержки - одинакова (что дает возможность одновременной циркуляции по единиму циклу в BK), но в линию задержки, как вы правильно сказали, каждый новый цикл подгружается новый input. В вашем примере вы ведь тоже в буфере коефф. каждый раз (после каждого цикла) возвращаетесь на начало (т.е. на первый коефф.), но делаете видимо это отдельной инструкцией загрузки pointerа начала буфера коеффициентов. Бестолковое объяснение надо сказать, но вы правы в одном, сдвиг есть. Я сказал, что указатель передвигается на х(2) и одновременно другой указатель на k(2), это так. Но в команде mvdd *ar2+,*ar3+0% не обратил внимания на последний значок "%", означающий циклическую адресацию с индексом 1. Так что, когда указатель данных переходит на х(2) и одновременно другой указатель на k(2), данная команда для нового цикла передвигает указатель данных на х(3). Кстати, вам везде можно делать такую адресацию *arn+% вместо *arn+0%, поскольку у вас индекс равен 1, заодно и ar0 не надо мучить.
--------------------
Делай сразу хорошо, плохо само получится
|
|
|
|
|
Jun 6 2007, 09:33
|
Знающий
   
Группа: Свой
Сообщений: 921
Регистрация: 6-04-07
Из: Israel
Пользователь №: 26 822

|
Цитата(=GM= @ Jun 6 2007, 13:10)  Бестолковое объяснение надо сказать, но вы правы в одном, сдвиг есть.
Я сказал, что указатель передвигается на х(2) и одновременно другой указатель на k(2), это так. Но в команде mvdd *ar2+,*ar3+0% не обратил внимания на последний значок "%", означающий циклическую адресацию с индексом 1. Так что, когда указатель данных переходит на х(2) и одновременно другой указатель на k(2), данная команда для нового цикла передвигает указатель данных на х(3).
Кстати, вам везде можно делать такую адресацию *arn+% вместо *arn+0%, поскольку у вас индекс равен 1, заодно и ar0 не надо мучить. Объяснять я умею плохо, согласен, но не понял что вы имеете ввиду во втором параграфе (вы не заметили % или я не заметил ?). В целом в самой рутине ошибки нет, думаю вы уже поняли, исключая тот факт о котором упомянул =BH=, сейчас себя перепроверяю - есть подозрение что он прав насчет расположения коефф. в буфере, сейчас с этим разбираюсь. МОя рутина работает как надо (фильтр проверен по анализу результата в Матлабе на тестовом сигнале), но кажется меня спасло симметричность фильтра (был-бы он анти-симметричен - видимо не работал бы без инверсии расположения коеффициентов). Сейчас проверяю... P.S. ar0 не мучается. В него одноразово загружена 1 и все. Хотя оно может работать и как вы сказали (может быть), т.е. без ar0, я еще слабо знаю семантику данного ассемблера. Цитата(-=ВН=- @ Jun 6 2007, 12:52)  Плохо, что не видите. Вот и посмотрите на 1 цикл. На примере 4-х точечного фильтра. К-ты фильтра h0,h1,h2,h3. h0 в младшем адресе, h3 в старшем. AR4 указывает на h0. Буфер данных, тоже 4-х точечный, располагаемый по адресам A0-A3. Изначально буфер обнулен. В AR3 содержится адрес A0 до записи первого входного отсчета. Как только Вы его записали, AR3 станет равным A1. Вот и смотрите. Первое выходное значение будет h0*[A1]+h1*[A2]+h2*[A3]+h3*[A0]. Здесь под [A0],[A1],[A2],[A3] обозначено содержимое ячеек по адресам A0-A3. Т.к. по адресам A1-A3 находится 0, а в ячейке с адресом A0 находится x0, то в результате получается h3*x0. А техасовский пример Вы зря упомянули. Вы с ним не разобрались совершенно. Я даже не поленился его посмотреть. Там все абсолютно правильно. Посмотрите хотя бы картинку на странице 77. Там дано расположение к-тов по адресам. Они там расположены именно в инверсном порядке. В тексте же программы неудачно использован симметричный фильтр. У него начало и конец абсолютно одинаковы. Хмм, есть подозрение что вы правы. Не уделил должного внимания более глубокому изучению их примера (карты памяти расп. коеффициентов). Видимо действительно меня спас факт использования симметричного фильтра. Еще раз перепроверю и видимо нужно будет перевернуть порядок коеффициентов..
|
|
|
|
|
Jun 6 2007, 10:01
|

Ambidexter
    
Группа: Свой
Сообщений: 1 589
Регистрация: 22-06-06
Из: Oxford, UK
Пользователь №: 18 282

|
Цитата(Саша Z @ Jun 6 2007, 08:33)  ... не понял что вы имеете ввиду во втором параграфе (вы не заметили % или я не заметил ?). В целом в самой рутине ошибки нет, думаю вы уже поняли, исключая тот факт о котором упомянул =BH=, сейчас себя перепроверяю - есть подозрение что он прав насчет расположения коэфф. в буфере, сейчас с этим разбираюсь. Моя рутина работает как надо (фильтр проверен по анализу результата в Матлабе на тестовом сигнале), но кажется меня спасло симметричность фильтра (был-бы он анти-симметричен - видимо не работал бы без инверсии расположения коэффициентов). 1) Не заметил я, отсюда весь сыр-бор загорелся(:-). 2) Не путайте нумерацию коэффициентов и содержимое этих самых коэффициентов. Скажем, никто не запрещает загрузить их задом-наперед. 3) Ошибок вроде нет, но программу фильтрации вам ещё шлифовать и шлифовать(:-). Например, вместо rptb fir_loop_end-1 можно использовать rptbd fir_loop_end-1, имеем уменьшение на 2 МС. Кстати, давно не работал с этим процом, компилятор принимает rptz a,_fir_ord-1 вместо rptz a,#_fir_ord-1? Вроде бы в команде должна стоять решетка (#). Цитата(Саша Z @ Jun 6 2007, 08:33)  ar0 не мучается. В него одноразово загружена 1 и все Одна команда, одно слово, ни вреда, ни пользы, хотя можно обойтись, если подумать. Давайте вместо "не мучить" поставлю "не использовать", пойдёт?
--------------------
Делай сразу хорошо, плохо само получится
|
|
|
|
|
Jun 6 2007, 10:36
|
Знающий
   
Группа: Свой
Сообщений: 921
Регистрация: 6-04-07
Из: Israel
Пользователь №: 26 822

|
Цитата(=GM= @ Jun 6 2007, 14:01)  1) Не заметил я, отсюда весь сыр-бор загорелся(:-). 2) Не путайте нумерацию коэффициентов и содержимое этих самых коэффициентов. Скажем, никто не запрещает загрузить их задом-наперед. 3) Ошибок вроде нет, но программу фильтрации вам ещё шлифовать и шлифовать(:-). Например, вместо rptb fir_loop_end-1 можно использовать rptbd fir_loop_end-1, имеем уменьшение на 2 МС.
Кстати, давно не работал с этим процом, компилятор принимает rptz a,_fir_ord-1 вместо rptz a,#_fir_ord-1? Вроде бы в команде должна стоять решетка (#).
Одна команда, одно слово, ни вреда, ни пользы, хотя можно обойтись, если подумать. Давайте вместо "не мучить" поставлю "не использовать", пойдёт? Да, насчет оптимизации - тут я конечно-же еще "чайник", только начал вообще асемблер данного процессра изучать, да и то в рамках нужных мне вещей (для проэкта). На доскональное изучение (что требуется для оптимизаций) времени нет, нужно что-бы работало с более-менее (тем более реч не идет о реальном времени, по крайней мере в конкретной реализации). Наверняка есть инструкции позволяющие экономить цикл там, цикл сям и т.д., но пока это не моя преррогатива...  Насчет комамнды, у меня нужна косвенная адресация для _fir_ord (ибо данная константа определена во внешнем C файле и передается в asm код). Посему заменена на: Код ld #0, а rpt *(_fir_ord)
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|