Доступ к массиву по указателю на массив в сборке avr

#c #assembly #interrupt #avr

#c #сборка #прерывание #avr

Вопрос:

Я программирую микроконтроллер AVR, используя смесь C и ASM, но у меня возникли небольшие проблемы.

В моем C-коде есть следующий код:

 uint8_t amplitudes32[32] = {.. constant values ..};
uint8_t amplitudes64[64] = {.. constant values ..}
uint8_t* amplitudes;
  

(амплитуды 32/64 — это в основном таблицы поиска)

И иногда я хочу, чтобы амплитуды были равны амплитудам32, а иногда хочу, чтобы они были равны амплитудам64.

Я делаю это, переходя

amplitudes = amplitudes32; в моем c-коде.

Затем в моей процедуре прерывания ASM я хочу прочитать адрес массива следующим образом:

 ldi r30, lo8(amplitudes)    
ldi r31, hi8(amplitudes)  
  

Затем я выполняю еще несколько инструкций, чтобы передать значение массива с определенным индексом на конкретный порт. Однако, когда я проверяю вывод, он не работает должным образом, и я получаю то, чего не ожидал. Я получаю одно и то же независимо от того, из чего состоит массив .. это одно и то же, даже когда amplitudes указывает на массив из всех нулей.

Если я изменю код сборки на

 ldi r30, lo8(amplitudes64)      
ldi r31, hi8(amplitudes64) 
  

Затем все работает так, как ожидалось. Но, как я уже сказал, мне нужно иметь разную таблицу поиска в разное время, и из-за проблем со скоростью я не могу принять это решение в рамках процедуры прерывания, поэтому было бы неплохо, если бы у меня был массив ‘variable’, который я мог бы изменить в моем коде C, который затем использует прерывание.

Что я делаю не так?

Ответ №1:

Я не очень хорошо знаком со сборкой AVR. Однако я полагаю, что макросы lo8 и hi8 возвращают младший / старший адрес предоставленной переменной — В случае передачи в amplitudes64 вы заполните r30 / r31 адресом вашей таблицы 64 записей — именно тем, что вы хотите. Однако, если вы передаете амплитуды, вы принимаете адрес указателя, что, скорее всего, не то, что вы хотите. (Переменную amplitudes необходимо будет разыменовать, чтобы вернуться к исходной таблице.)

Поскольку разыменование переменных в микроконтроллере часто выполняется сравнительно медленно (особенно при прерывании, зависящем от времени), я настоятельно рекомендую вам реорганизовать свой код, чтобы иметь один логический флаг для выбора между двумя таблицами. Например:

 if (UseTable64)
 ldi r30, lo8(amplitudes64)      
 ldi r31, hi8(amplitudes64) 
else
 ldi r30, lo8(amplitudes32)      
 ldi r31, hi8(amplitudes32) 
end if
  

Конечным результатом этого должна быть всего одна дополнительная команда перехода — вероятно, быстрее, чем дополнительное время для разыменования указателя амплитуды. В качестве альтернативы, вы могли бы попробовать объединить обе таблицы поиска в одну 96-байтовую таблицу и просто соответствующим образом скорректировать свой индекс. Как и прежде, вы все еще можете принять решение о том, какую таблицу использовать вне прерывания, требующее много времени (путем изменения флага в вашем коде C), чтобы прерывание оставалось быстрым и эффективным.

Комментарии:

1. Спасибо! Очень красноречивое решение, жаль, что я сам до этого не додумался. 🙂