Цитата(GetSmart @ Feb 19 2008, 06:31)

Конечно интересно! Думаю даже не мне одному

Можно сделать, например, так:
Код
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; 5-cycles no-jitter 16-bit buffer output to FIO on LPC2103
;; registers used: r7-r12
FIOBUF_5_START MACRO
ldr r10, [r11], #4
ldr r7, [r11], #4
strh r10, [r12]
mov r10, r10, lsr #16
mov r8, r7, lsr #16
nop
ENDM
FIOBUF_5 MACRO
strh r10, [r12]
ldr r9, [r11], #4
strh r7, [r12]
ldr r7, [r11], #4
strh r8, [r12]
mov r10, r9, lsr #16
mov r8, r7, lsr #16
nop
strh r9, [r12]
ENDM
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Usage example:
ldr r11, =buf ; 32-bit aligned!
ldr r12, =FIOPINL
FIOBUF_5_START
FIOBUF_5
; any 3-cycle user command
loop:
FIOBUF_5
; any 3-cycle user command
FIOBUF_5
; any 3-cycle user command
FIOBUF_5
; !buffer overrun check!
FIOBUF_CHECK
FIOBUF_5
b loop
Как видим, между каждыми вызовами FIOBUF_5 мы вызываем команды фоновой задачи, сгруппированные ровно по 3 такта. Например:
Код
FIOBUF_5
ldr r0, [r4, r2] ; [3] cycles
FIOBUF_5
add r2, r2, #2 ; [1]
cmp r2, #20 ; [1]
nop ; [1]
FIOBUF_5
blo skip_label ; [1] or [3] (if jumped)
nop ; [1]
nop ; [1]
FIOBUF_5
strh r0, [r6] ; [2]
mov r0, #1 ; [1]
skip_label:
FIOBUF_5
ldr r0, [r4, r1] ; [3]
FIOBUF_5
; ...
При этом, условные переходы легко учесть, если сразу в начале метки перехода будет стоять макрос вывода в порт, а после команды - 2 нопа для компенсации тактов. Однотактные команды с условиями (напр. subeq) тоже можно спокойно использовать. А вот многотактные условные команды придётся преобразовать в отдельную проверку и условный переход.
Легко заметить, что при каждом вызове FIOBUF_5 читаются сразу 2 32-битных слова из буфера. Поэтому нужно в код фоновой программы вставлять дополнительные проверки для реализации цикличности буфера. Размер буфера может быть произвольный! В конце буфера нужно сделать "запас" из, скажем, 16 семплов (скопировать начальные семплы и выровнять до 32-бит), поскольку мы не можем делать частые проверки - и потом из текущего указателя вычитаем размер буфера при превышении:
Код
FIOBUF_CHECK MACRO ;;; \Warning: Destroys r0,r1 and flags!
ldr r0, =last_buffer_ptr
FIOBUF_5
ldr r1, =buffer_length_in_bytes
FIOBUF_5
cmp r11, r0
subhi r11, r11, r1 ; buffer ptr
nop
ENDM
Как я уже писал, если у вас есть команды больше 3-х тактов, то подобный метод необходимо соответственно адаптировать. Чем за большее кол-во тактов идёт вывод, тем красивее становится код.
Напоминаю, что код надо размещать в секции для копирования в RAM, тогда тайминги команд будут точными. Также не учитываются фоновые прерывания.
Метод хоть и не универсальный, но позволяет сделать полноценный синтез периодических сигналов с точным контролем частоты и формы. Например, табличный синус по этому методу на осциллографе выглядит весьма симпатично.
Спасибо за внимание!