Доступ к массиву по указателю на массив в сборке avr - PullRequest
2 голосов
/ 08 мая 2011

Я программирую микроконтроллер 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 Ответ

4 голосов
/ 08 мая 2011

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

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

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

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

...