реклама на сайте
подробности

 
 
3 страниц V  < 1 2 3  
Reply to this topicStart new topic
> быстрый тайминг GPIO для LPC
alexander55
сообщение Jan 9 2008, 07:23
Сообщение #31


Бывалый
*****

Группа: Свой
Сообщений: 1 584
Регистрация: 7-08-07
Пользователь №: 29 615



Вопрос к автору.
Что Вы хотите сделать ?
Варианты :
- генератор сигналов произвольной формы
- систему регулирования какого-то параметра.
В зависимости от ответа на этот вопрос, решение будет различным.
Go to the top of the page
 
+Quote Post
ГУ-49А
сообщение Jan 9 2008, 18:16
Сообщение #32


Участник
*

Группа: Участник
Сообщений: 32
Регистрация: 26-11-07
Пользователь №: 32 699



Цитата(alexander55 @ Jan 9 2008, 09:23) *
Вопрос к автору.
Что Вы хотите сделать ?
Варианты :
- генератор сигналов произвольной формы
- систему регулирования какого-то параметра.
В зависимости от ответа на этот вопрос, решение будет различным.

Ответ: Вариант 1-й, т.е. генератор сигналов произвольной формы (на фоне выполнения другой менее приоритетной задачи).
Повторюсь, интересуют программные, а не аппаратные решения.

Цитата(GetSmart @ Jan 8 2008, 21:57) *
кол-во NOPов тоже нужно подобрать получше. Вобщем я обрисовал только идею. Возможно этот пример нужно немного доработать.

Идею уловил, спасибо.
Go to the top of the page
 
+Quote Post
alexander55
сообщение Jan 10 2008, 06:23
Сообщение #33


Бывалый
*****

Группа: Свой
Сообщений: 1 584
Регистрация: 7-08-07
Пользователь №: 29 615



Цитата(ГУ-49А @ Jan 9 2008, 21:16) *
Ответ: Вариант 1-й, т.е. генератор сигналов произвольной формы (на фоне выполнения другой менее приоритетной задачи).

Понятно.

Цитата(ГУ-49А @ Jan 9 2008, 21:16) *
Повторюсь, интересуют программные, а не аппаратные решения.

Самым лучшим вариантом Вашей задачи является программно-аппаратное решение (это мое мнение).
Go to the top of the page
 
+Quote Post
GetSmart
сообщение Jan 13 2008, 11:41
Сообщение #34


.
******

Группа: Участник
Сообщений: 4 005
Регистрация: 3-05-06
Из: Россия
Пользователь №: 16 753



Попытался применить код, который я тут запостил и нашёл в нём некоторые недоработки. Во-первых прибавлять к PC (R15) нужно смещение, умноженное на 4. Остальное в коде:
Код
LDR  R9,[R8] ; R8 = T0CR (инициализируется во время LowLevelInit)
AND  R9,R9,#15; с небольшим риском эту команду можно убрать
ADD  R15,R15,R9,LSL #2
NOP
...
NOP

PS. Странно, что никто другой не заметил.


--------------------
Заблуждаться - Ваше законное право :-)
Go to the top of the page
 
+Quote Post
GetSmart
сообщение Jan 21 2008, 07:23
Сообщение #35


.
******

Группа: Участник
Сообщений: 4 005
Регистрация: 3-05-06
Из: Россия
Пользователь №: 16 753



Попробывал применить этот алгоритм в своём генераторе сигнала. Оказалось от джиттера полностью не избавиться. Оказалось что либо команда чтения таймера (или периферии вообще) занимает разное число тактов, либо перенос инфы из таймера происходит в разные моменты исполнения данной команды. Вобщем очень забавные аномалии происходят в данном коде. Хотя с виду он выглядит идеально. В AVR он точно работал бы идеально.

Точнее так: с момента чтения таймера и до вывода чего-то в порт (после NOPов) всё равно проходит разное количество тактов. Очень может быть что и команда вывода в порт исполняется за разное кол-во тактов.

Процессор LPC2132 revA. Процедура прерывания во флэше. Частота 59 МГц, MAM = 2 (full).


--------------------
Заблуждаться - Ваше законное право :-)
Go to the top of the page
 
+Quote Post
Alex03
сообщение Jan 21 2008, 08:47
Сообщение #36


Местный
***

Группа: Свой
Сообщений: 359
Регистрация: 9-12-05
Пользователь №: 12 034



А если MAM=0?
Go to the top of the page
 
+Quote Post
GetSmart
сообщение Jan 21 2008, 10:12
Сообщение #37


.
******

Группа: Участник
Сообщений: 4 005
Регистрация: 3-05-06
Из: Россия
Пользователь №: 16 753



Частота 5 МГц, PLL off, MAM=0, MAMTIM=1. Прерывание во флэш.
Ощущение такое, что джиттера не стало. Однако как это проверить "на коленке" я пока не знаю. Цифрового осциллографа под руками нет. У меня сейчас программа формирует меандр от ШИМа на одном пине, а в прерывании я программно устанавливаю другой пин как бы синфазно с шимом и на лету могу корректировать сдвиг программного пина с точностью до такта. На древнем осциллографе с полосой 5 МГц (!) еле-еле видна иголка, которую можно уширять, можно убрать или перенести вниз изменяя сдвиг буквально на такт. Вроде всё красиво.


--------------------
Заблуждаться - Ваше законное право :-)
Go to the top of the page
 
+Quote Post
GetSmart
сообщение Jan 23 2008, 12:46
Сообщение #38


.
******

Группа: Участник
Сообщений: 4 005
Регистрация: 3-05-06
Из: Россия
Пользователь №: 16 753



Частота 59 МГц, прерывание в RAMe, MAM = 2, MAMTIM = 3.

Джиттера нет. Скорость изменения уровня на пине не менее двух тактов.

Видмио ограничена мощностью выходного каскада и собственной ёмкостью пина.


--------------------
Заблуждаться - Ваше законное право :-)
Go to the top of the page
 
+Quote Post
ГУ-49А
сообщение Feb 18 2008, 22:42
Сообщение #39


Участник
*

Группа: Участник
Сообщений: 32
Регистрация: 26-11-07
Пользователь №: 32 699



Позвольте изложить некоторые результаты по открытой мной теме.

1. Удалось реализовать метод интерлива кода вывода в порт (16 бит) и фоновой задачи.
2. При простых командах (см. ниже) фоновой задачи удалось достичь частоты дискретизации 14 МГц (!), без джиттера (LPC2103, 70 MHz), т.е. за 5 тактов.
3. При большинстве сложных команд частота дискретизации = 7 МГц, без джиттера (за 10 тактов).

Теперь подробности.

1) Реализация подобного вывода в порт реальна, если код выполняется из RAM (ramfunc). В этом случае тайминг команд становится предсказуем, т.е.:
- простая арифметика и логика = 1 такт;
- запись в память и в FIO-порт = 2 такта;
- чтение из памяти, команды перехода = 3 такта, и т.д.
Как видим, это соответствует заявленным таймингам для данного семейства ARM7TDMI-S. К сожалению, вызов более сложной функциональности LPC2103 требует существенно большего количества тактов, например:
- запись байта в регистр SSP = 7 тактов;
- чтение слова данных из ADC (независимо от режима) = целых 8 тактов.
(Кстати, скажем, отправку по SSP/SPI в некоторых случаях можно выполнить программно - работает не хуже, и тайминг команд остаётся 3 такта вместо 7-ми.)
2) Использование встроенного таймера позволяет с точностью до такта определять тайминги участков кода и проверять результат.
3) Общее правило подсчёта максимальной частоты дискретизации при таком методе:
Fs = Fclk/(Cycles_max + 2),
где Cycles_max - длительность самой медленной команды, в тактах (но не менее 3 тактов).
4) Инструментарий писать не стал, по 2-м причинам:
4.1) В общем случае ldr/str может обращаться к каким угодно спец.регистрам периферии, и тайминг будет существенно меняться. Отследить это можно только при эмуляции прошивки, что неоправданно усложняет задачу.
4.2) Для простых же команд тайминги вычисляются слишком просто, нопы вставлять для выравнивания (align) тактов тоже просто - польза от такой утилиты в моём случае неочевидна.

Если интересно, как можно за 5 тактов и в порт выводить 16 бит из памяти, и фоновую программу по 3 такта выполнять, с контролем оверрана DDS-буфера - расскажу и покажу.
Go to the top of the page
 
+Quote Post
GetSmart
сообщение Feb 19 2008, 04:31
Сообщение #40


.
******

Группа: Участник
Сообщений: 4 005
Регистрация: 3-05-06
Из: Россия
Пользователь №: 16 753



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


--------------------
Заблуждаться - Ваше законное право :-)
Go to the top of the page
 
+Quote Post
alexander55
сообщение Feb 19 2008, 06:18
Сообщение #41


Бывалый
*****

Группа: Свой
Сообщений: 1 584
Регистрация: 7-08-07
Пользователь №: 29 615



Цитата(GetSmart @ Feb 19 2008, 07:31) *
Конечно интересно! Думаю даже не мне одному smile.gif

Это интересно.
Go to the top of the page
 
+Quote Post
ГУ-49А
сообщение Feb 19 2008, 09:47
Сообщение #42


Участник
*

Группа: Участник
Сообщений: 32
Регистрация: 26-11-07
Пользователь №: 32 699



Цитата(GetSmart @ Feb 19 2008, 06:31) *
Конечно интересно! Думаю даже не мне одному smile.gif


Можно сделать, например, так:

Код
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; 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-х тактов, то подобный метод необходимо соответственно адаптировать. Чем за большее кол-во тактов идёт вывод, тем красивее становится код. wink.gif

Напоминаю, что код надо размещать в секции для копирования в RAM, тогда тайминги команд будут точными. Также не учитываются фоновые прерывания.
Метод хоть и не универсальный, но позволяет сделать полноценный синтез периодических сигналов с точным контролем частоты и формы. Например, табличный синус по этому методу на осциллографе выглядит весьма симпатично.
Спасибо за внимание!
Go to the top of the page
 
+Quote Post
GetSmart
сообщение Feb 19 2008, 10:05
Сообщение #43


.
******

Группа: Участник
Сообщений: 4 005
Регистрация: 3-05-06
Из: Россия
Пользователь №: 16 753



Очень даже неплохо получилось. Можно сказать что это экстремальное программирование! Я такие вещи очень люблю. Жаль только, что весь проект при таком подходе нужно будет писать на асме. И по прерываниям будущий автор будет скучать smile.gif


--------------------
Заблуждаться - Ваше законное право :-)
Go to the top of the page
 
+Quote Post
GetSmart
сообщение Feb 24 2008, 15:04
Сообщение #44


.
******

Группа: Участник
Сообщений: 4 005
Регистрация: 3-05-06
Из: Россия
Пользователь №: 16 753



Цитата(ГУ-49А)
Что ж, давайте ещё раз напомню, в чём заключалась моя задача. Нужно было делать одновременно 2 вещи:
1) Выводить в порт FIO 16 бит информации;
2) Выводить в SPI по 8 бит данных.
Причём, выводить в порт FIO как можно быстрее (это приоритетная задача). Дык вот, если использовать аппаратный SSP, то пока мы кидаем в него данные, проходит 7 тактов, следовательно, мы не можем слать в порт FIO чаще, чем за 7+2 такта (2 идёт на сам вывод в порт), т.е. за 9 тактов. Если же мы используем программный SPI, то шлём эти биты вручную, да, менее эффективно, чем по SSP, но зато у нас появляется возможность выводить в FIO каждые 3+2 такта, т.е. за 5 тактов. Жертвуем при этом скоростью вывода в SPI (примерно 60 тактов за бит, что в моём случае полностью устраивает). Но куда важнее мне было получить максимальную скорость вывода в FIO, что я и сделал. Именно поэтому я и писал, что существуют те редкие случаи, когда целесообразнее использовать программный SPI, и в этом нет ничего страшного.
Можно вопрос? Почему скорость программного SPI была 60 тактов на бит? Вроде бы в Вашей программе можно параллельно с 16 бит основными данными по двум программным линиям выдавать SCK и MOSI со скоростью 10 тактов на бит. То есть "плевать" в GPIO порт сразу 18 бит данных.


--------------------
Заблуждаться - Ваше законное право :-)
Go to the top of the page
 
+Quote Post
ГУ-49А
сообщение Feb 24 2008, 16:02
Сообщение #45


Участник
*

Группа: Участник
Сообщений: 32
Регистрация: 26-11-07
Пользователь №: 32 699



Цитата(GetSmart @ Feb 24 2008, 17:04) *
Можно вопрос? Почему скорость программного SPI была 60 тактов на бит? Вроде бы в Вашей программе можно параллельно с 16 бит основными данными по двум программным линиям выдавать SCK и MOSI со скоростью 10 тактов на бит. То есть "плевать" в GPIO порт сразу 18 бит данных.

Увы, нельзя совместить основные данные с данными SPI, т.к. у них разный период повторения. Данные SPI выводятся по 8 бит, а затем делается большая пауза (порядка 1 мс, поэтому мне скорость вывода через SPI не так важна), а вывод основных данных продолжается всё время (и период повторения может быть любым, с точностью до сэмпла). Кроме того, при наиболее экстремальном способе основного вывода каждые 5 тактов можно успевать доставать только 16 бит за раз, а ведь MOSI1 лежит в верхнем полуслове. Поэтому и получалось у меня 60 бит:
Код
ldr   ; загружаем данные очередного бита для нашего SPI
FIOBUF_5; 17 тактов
str    ; пишем данные этого бита в MOSI1
nop
FIOBUF_5; 17 тактов
str    ; устанавливаем CLK1 в 1 - наш бит идёт во внешний девайс (позже MOSI1).
nop
FIOBUF_5; 17 тактов  -- здесь CLK1 автоматически сбрасывается в 0

Конечно, если подумать, то можно сделать и поменьше - за счёт битовых сдвигов и т.п. Хм, возможно...

Если же можно было основной вывод делать, например, за 8 тактов, то тут уже другая картина. FIOBUF_8 будет занимать всего 5 тактов вместо 17-ти, и скорость вывода в SPI будет уже 24 такта/бит. Ну а если за 9 тактов, то можно спокойно уже через аппаратный SSP выводить.

P.S. Пардон, что немного сумбурно излагаю...
Go to the top of the page
 
+Quote Post

3 страниц V  < 1 2 3
Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 18th July 2025 - 14:33
Рейтинг@Mail.ru


Страница сгенерированна за 0.01485 секунд с 7
ELECTRONIX ©2004-2016