2014-10-08 4 views
1

Я хочу сделать очень короткий импульс после входного сигнала восходящего фронта.Точные задержки на Arduino, используя nop-сборку?

Жесткая часть здесь заключается в том, что я хотел бы контролировать (до высокого разрешения) время задержки перед моим импульсом и длительность моего импульса. Я могу легко контролировать это, просто набирая nops самостоятельно, жесткие задержки кодирования, но я не уверен, как это сделать для некоторой произвольной задержки с одинаковым уровнем точности.

После многих головных болей, преследующих таймеров, а затем, в конце концов, понимая, что я в конечном счете ограничен временным временем входа/выхода в режиме interupt, я теперь решаюсь, пытаясь контролировать свою задержку через nops.

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

switch(delayTime){ case 10: __asm__ __volatile__("nop"); case 9: __asm__ __volatile__("nop"); case 8: __asm__ __volatile__("nop"); case 7: __asm__ __volatile__("nop"); case 6: __asm__ __volatile__("nop"); case 5: __asm__ __volatile__("nop"); case 4: __asm__ __volatile__("nop"); case 3: __asm__ __volatile__("nop"); case 2: __asm__ __volatile__("nop"); case 1: __asm__ __volatile__("nop"); } PORTD = 0x10; ...

в идеале, я хотел бы в основном работать через некоторый код, который будет компилировать в этом: (это какой-то странный psuedocode с и сборки, до сих пор не знаю, как сделать некоторые из них в сборке)

0x005 Reg1 = 0xFF-val1 %(where somehow 0xFF is known?/found out?) 0x006 Reg2 =0x1FF-val2 0x007 IJMP Reg1 0x008 NOP 0x009 NOP 0x00A NOP ... 0x0FF MOV 0x40, PORTD % assign the value 0x40 to the static variable "PORTD" 0x100 IJMP Reg2 0x101 NOP 0x102 NOP 0x103 NOP 0x104 NOP ... 0x1FF MOV 0x00, PORTD % assign the value 0x00 to the static variable "PORTD"

Я просто не уверен, как найти место памяти для кода после/во время выполнения, так что аспекты «0xFF» и «0x1FF» этой программы не так уж плохи (кажется, что это супер опасно просто, получите сборку кода, а затем жесткий код, который в ... Я бы не хотел этого делать). Кроме того, в то время как легко просто налить его на 200+ nops, как заставить командлет IJMP вести себя так, как я этого хочу? (Я, честно говоря, даже не знаю, нужна ли мне такая команда).

Я предполагаю, что в общем, я ищу команду сборки (которую я не могу найти), которая позволяет мне «добавить N на счетчик программ », и я могу просто убедиться, что эта команда запущена в сборе с по меньшей мере N + 1 командами сборки впереди, жестко закодирована.

В качестве побочного примечания все это выполняется внутри прерывание, поэтому я не чувствую себя так плохо, чтобы играть с ПК ... Кроме того, я знаю, что это плохое блокирование до 500 операций, но для этой задачи время важнее, чем плохо блокирует как рутину.

+0

Что случилось с процедурами задержки в AVR Libc? –

+1

Чтобы получить точность, которую я хочу, я думаю, что мне нужно использовать что-то вроде «__builtin_avr_delay_cycles». Однако для этой функции требуется константа (это макрос, который, кажется, создается во время компиляции), в то время как вместо этого я ищу какую-то функцию, которая Я могу позвонить с переменной во время выполнения. Насколько я могу судить, простое перемещение ПК в память, чтобы получить точное количество nops, является самым надежным решением, но, возможно, я пропустил что-то в AVR libc. (Я вижу только способы сделать 3,4 цикла на итерацию), что недостаточно для разрешения времени на то, что я хочу, из этих 16 МГц часов. – BlueCoconut

ответ

1

Я не знаком с набором инструкций AVR, но общая идея заключается в использовании инструкции CALL для установки счетчика программ (ПК) в стек. Затем используйте POP, чтобы переместить ПК в регистр Z. Затем вы можете указать ADD номер в регистр Z и использовать IJMP, чтобы перейти к результирующему адресу.

Так что-то вдоль этих линий

delay: call delay1    ; push the PC onto the stack 
delay1: pop r30    ; pop the PC into the Z registers 
     pop r31 
     add r30,r0    ; add some amount to the PC value 
     addc r31,r1 
     ijmp     ; use IJMP to jump to the resulting address 
     nop 
     nop 
     nop 
     ... 

Случайные мысли:

  • На машинах 8MB, требуется третий поп удалить третий байт из ПК из стека.
  • Z - это только шестнадцать бит, поэтому этот код должен быть в первом 128 Кбайт памяти программы.
  • Я не уверен, какой регистр (r30 или r31) должен быть выбит .
  • Добавленная стоимость на Z должна быть равна delay1, так как call - , нажимая адрес delay1 на стек. Другими словами, минимальная сумма, которую необходимо добавить, равна 6, так как это количество инструкций от delay1 до первого nop.
  • Минимальная задержка определяется шестью инструкциями до и , включая ijmp. Вы должны увеличить r1/r0 (уменьшите количество nops) соответственно.

Как я уже сказал, я не эксперт в наборе инструкций AVR, поэтому вы должны принять это как общее предложение и быть готовым потратить некоторое время на разработку деталей. Удачи!