Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Передать блок данных с мк на мк
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > AVR
zombi
Нужно в одном изделии передавать с одной xmega на другую каждую миллисекунду 12288 бит = 1536 байт.
Чем побыстрее, но не дольше чем за 200 мкс.
Оба мк тактируются от общего внешнего генератора 32MHz.
Свободных ног у каждого по 10 шт. есть.
RadiatoR
При 32МГц в 200мкс 6400 тактов. Как раз должно хватить на инкремент индекса и запихивание в порт.
Одну ногу дергать как клок - на приеме юзать как прерывание. Остальные 8 юзать как шину - меньше придется манипуляций делать с битами.
ЗЫ. можно даже на асме накидать. хотя сейчас компиляторы еще похлеще сделают
zombi
Цитата(ЯadiatoR @ Mar 22 2016, 17:52) *
Одну ногу дергать как клок - на приеме юзать как прерывание.

За 4 такта войти в прерывание чего-то там сделать и выйти обратно biggrin.gif
Цитата(ЯadiatoR @ Mar 22 2016, 17:52) *
хотя сейчас компиляторы еще похлеще сделают

не верю
RadiatoR
Ну вариантов определения первого байта не много - либо ожидать что дернется управляющая ножка, либо по крайней мере 1 раз перейти в прерывание. Ну да - не подумал, что пока в прерывание войдет в стэк что-нить положит и прочее... пройдут такты. Но и обработка прерывания на длительный процесс (а все 1536 байт это долго) не оч хорошая идея. Ну если прога позволяет - можно периодически проверять ножку и если есть активный сигнал вешать 10 ногу - и начинать передачу. В таком случае трансивер подождет какое-то непродолжительное время, пока ресивер увидит активный сигнал и потом без задержек начнут передачу.
zombi
Цитата(ЯadiatoR @ Mar 22 2016, 18:37) *
(а все 1536 байт это долго) не оч хорошая идея.

Почему не хорошая? очень даже ничего ведь всего-то ~200 мкс обработка.
Так и сделаю наверное.
В прерывании ресивера дёрну ногой готовности.
И дальше синхронно приму все 1536.
Спасибо за идею.
_pv
это если они от одного источника тактируются или от хороших стабильных генераторов,
а так за 200мкс могут и разъехаться приёмник и передатчик и к концу какой-нибудь из последних байтов будет либо два раза прочитан, либо пропущен.
Lerk
_pv,
Цитата(zombi @ Mar 22 2016, 17:20) *
Оба мк тактируются от общего внешнего генератора 32MHz.


...
_pv
да, действительно.
тогда проблем не должно быть, только у передатчика надо количество nopов подобрать между синхроимпульсом и началом передачи данных, чтобы приёмник в прерывание запрыгнул и принимать начал в нужной фазе по середине.

хотя у xmegi есть вроде и по 4ре такта команды, так что джиттер входа в прерывание может быть большим и может понадобится дополнительная синхронизация через таймер в режиме захвата если он случайно среди тех 2 оставшихся ног оказался.

ну либо в начале передавать несколько байт синхронизации 0х55 0х55 .. 0х55 0х5d и потом уже в приёмнике найти окуда именно данные начались.
501-q
Цитата(zombi @ Mar 22 2016, 19:20) *
Нужно в одном изделии передавать с одной xmega на другую каждую миллисекунду 12288 бит = 1536 байт.
Чем побыстрее, но не дольше чем за 200 мкс.
Оба мк тактируются от общего внешнего генератора 32MHz.
Свободных ног у каждого по 10 шт. есть.

Т.е. шина должна быть способна прокачать 7.5 МБ в секунду. Ну, наверное можно попробовать. У меня есть работающее решение, но там всего 16 байтов в пакете. Передатчик и приёмник тактируются одним сигналом (32МГц), передача пакета синхронизируется внешним (по отношению к передатчику и приёмнику) сигналом. Приём и передача выполняется без сигнала строба. Каждые 3 такта принимаю байт.

Такие большие пакеты я бы попробовал передавать и принимать с помощью DMA и таймеров. Синхронный запуск передачи и приёма решаем. Лишь бы у каждого был свободный порт целиком. Кроме того, нужно проверить влияние конфликтов доступа к памяти со стороны DMA и ядра.

Впрочем, и на асме можно:
Код
; приёмник
.rep 1536
   in r16, PORTx_PIN
   st Z+, r16
   nop
.endr

; передатчик
.rep 1536
  ld r16, Z+
  out PORTy_OUT, r16
.endr

Если будет менее трёх тактов, то приём, я думаю, будет нестабильным, т.к. на установку бита в схеме приёма микроконтроллера нужно два такта.

Я то вместо nop'а полезную работу ещё выполняю: данные идут со скоростью 1.5 МБ в секунду и их нужно обработать (терять 16 тактов каждые 10 мкс -- непозволительная роскошь, это же 5% времени).

Ну и если пакеты идут раз в мс, то на синхронизацию будешь тратить в сто раз меньше, чем я. А я трачу как раз около 10% времени на это.

Илья

Цитата(501-q @ Mar 23 2016, 08:35) *
передавать и принимать с помощью DMA и таймеров.


Вспомнил. Может не получиться. Надо уточнять минимальный цикл DMA. Он запросто может быть больше пяти тактов.

Илья
RadiatoR
Да что вы заморачиваетесь, если обработка в прерывании устраивает (хотя я бы так не делал) то сделал бы примерно так (помойму в атхмеге есть команда на изменение значения 1 ноги):
1. на приемнике прерывание на управляющей ноге по спаду сигнала
Это код для передатчика, для приемника будет похожий, но с обработкой 1 прерывания и мониторингом состояния активного сигнала.
Код
SendSignal=1;//Устанавливаем активный сигнало о готовности к передаче;
while(ReadyToSend);// Тут ожидаем от 10 ноги сигнала, тчо приемник вошел в прерывание и готов принимать. Можно тут добавить еще пожарный таймер, что бы вышел из цикла если долго ожидает.
for(ushort i=0; i<1536;i++)
{
    SendSignal=1;// Управляющая нога сбрасывается в 1
    Portx=buf[i];
    SendSignal=0;// Устанавливаем сигнал в активное состояние - для мониторинга приемником
}

В принципе если выдерживать эту последовательность то и вставлять nop не придется, т.к. вместо него будут выполняться полезные такты - инкремент счетчика, сброс активного сигнала управления и загрузка регистра с новым значением. Как раз на прием должно хватать. Ну если что можно довести нопами если приемник не будет успевать.
_pv
Цитата(ЯadiatoR @ Mar 23 2016, 11:21) *
Да что вы заморачиваетесь, если обработка в прерывании устраивает (хотя я бы так не делал) то сделал бы примерно так
for(ushort i=0; i<1536;i++){
SendSignal=1;// Управляющая нога сбрасывается в 1
Portx=buf[i];
SendSignal=0;// Устанавливаем сигнал в активное состояние - для мониторинга приемником
}[/code]

скомпилируйте это и посмотрите что получится, напомню у ТС есть всего 4 такта

я так понимаю без дма можно сделать только
:loop
IN REG, PORT
ST Y+, REG
RJMP loop
NOP
NOP
NOP
NOP

будет как раз четыре такта на цикл, и выходить из этого бесконечного цикла придётся по прерыванию от таймера или от внешнего, исправляя адрес возврата на стэке чтобы на те нопы после цикла выпрыгнуть
RadiatoR
Ну на деле есть 6400 тактов.
Конечно, компилятор развезет это на много операций. Я описал примерно алгоритм работы.
То есть вы собрались выйти из передачи только по таймеру заранее зная сколько прйдет тактов на операции?
А как будет приемник принимать данные за 3 такта? 3 такта это 93нс. Только если их соединить чуть ли не вплотную, ибо 10+МГц будет и принимать без синхронизации. Непонятно
501-q
Цитата(_pv @ Mar 23 2016, 12:49) *
я так понимаю без дма можно сделать только
:loop
IN REG, PORT
ST Y+, REG
RJMP loop
NOP
NOP
NOP
NOP

будет как раз четыре такта на цикл, и выходить из этого бесконечного цикла придётся по прерыванию от таймера или от внешнего, исправляя адрес возврата на стэке чтобы на те нопы после цикла выпрыгнуть


С прерыванием от таймер -- это тоже хорошо. И, кстати, в икс-меге обязательно нужно возвращаться из прерывания (но не обязательно в то же место, где прерывание начали обрабатывать; в меге можно было бы вообще не возвращаться из прерыания от таймера, а только убрать адрес возврата из стека).

Но если памяти хватает, то можно тупо повторить 1536 раз фрагмент:
in reg, PORT_PIN
st Y+, reg
rjmp 1f
1:

Вот так:
.rep 1536
in reg, PORTx_PIN
st Y+, reg
rjmp 1f
1:
.endr

Если устраивает три такта на передачу байта, то rjmp заменить на nop.

Илья
_pv
Цитата(501-q @ Mar 23 2016, 14:48) *
Но если памяти хватает, то можно тупо повторить 1536 раз фрагмент:
in reg, PORT_PIN
st Y+, reg
rjmp 1f
1:

Вот так:
.rep 1536
in reg, PORTx_PIN
st Y+, reg
rjmp 1f
1:
.endr
Если устраивает три такта на передачу байта, то rjmp заменить на nop.


от прерывания по таймеру из цикла придётся выходить на передатчике, на приёмнике можно таймер сэкономить и заканчивать по внешнему прерыванию от передатчика.
и что-то не припомню наличие аппаратных циклов у xmegи, то есть вот этот макрос .rep он не бесплатный, а всё равно развернётся в dec и brne, так что тактов на нормальный цикл там в любом случае не хватит.
а вот ценой нескольких кб флэша цикл можно действительно полностью развернуть, и передать всё за пару тактов на байт или за ~100мкс.
RadiatoR
Ну флеш то заиспользовать не проблема - а принимать то за 2 такта как он будет? Успеет ли?
501-q
Цитата(_pv @ Mar 23 2016, 14:10) *
и что-то не припомню наличие аппаратных циклов у xmegи, то есть вот этот макрос .rep он не бесплатный, а всё равно развернётся в dec и brne, так что тактов на нормальный цикл там в любом случае не хватит.
а вот ценой нескольких кб флэша цикл можно действительно полностью развернуть, и передать всё за пару тактов на байт или за ~100мкс.

.rep -- это директива ассемблера (в частности, gas), повторяет фрагмент до .endr указанное число раз.

И за пару тактов не получится. Передатчик не может тратить меньше трёх тактов на передачу байта. Вот если передатчик ПЛМ'ка какая... то тут возникает вопрос со стабильностью приёма, т.к. входной тракт вывода порта микроконтроллера требует стабильного состояния сигнала в течении двух тактов минимум.

Илья
_pv
Цитата(ЯadiatoR @ Mar 23 2016, 13:59) *
Ну на деле есть 6400 тактов.
Конечно, компилятор развезет это на много операций. Я описал примерно алгоритм работы.
То есть вы собрались выйти из передачи только по таймеру заранее зная сколько прйдет тактов на операции?
А как будет приемник принимать данные за 3 такта? 3 такта это 93нс. Только если их соединить чуть ли не вплотную, ибо 10+МГц будет и принимать без синхронизации. Непонятно

6400 тактов есть для передачи 1536 байт, то есть по 4 такта на байт.
такты на операции у авров вполне себе предсказуемо считаются, и контроллеры работают от одного тактового сигнала, поэтому если в передачике сделать
LD .. 1 такт
OUT .. 1 такт
RJMP -2 2 такта
и предварительно завести таймер на N*4 вперёд то он сработает когда надо.

а в приёмнике
IN .. 1 такт
ST .. 1 такт
RJMP -2 2 такта

то передатчик будет выдавать данные каждые 4ре такта, а приёмник забирать.
синхронизацию можно сделать по самим данным отправив сначала несколько байт известной перамбулы перед данными, тогда приёмник потом сможет разобраться где именно начались данные.
единственное может пару nopов надо будет где-то воткнуть перед циклом чтобы приёмник не сэмплил данные именно на том же такте когда передатчик их меняет.
RadiatoR
rjmp это хорошо, а кто инкремент будет делать? Или он оффсетом будет идти?
_pv
Цитата(ЯadiatoR @ Mar 23 2016, 16:44) *
rjmp это хорошо, а кто инкремент будет делать? Или он оффсетом будет идти?

ST Y+, reg у хмеги всё равно за 1 такт вроде, не?
RadiatoR
сначала написал - потом подумал, жалко удалить коммент нету кнопки
501-q
Цитата(_pv @ Mar 23 2016, 14:48) *
ST Y+, reg у хмеги всё равно за 1 такт вроде, не?

Да. 'LD reg, Z+' 2 такта. Так что три такта -- минимум.

Синхронизацию можно глянуть на avrfreaks.net. Там есть проект вывода видеосигнала из икс-меги, и в нем есть синхронизация сигналов до такта. И я там же код для синхронизации приводил.

Илья

Цитата(_pv @ Mar 23 2016, 14:34) *
синхронизацию можно сделать по самим данным отправив сначала несколько байт известной перамбулы перед данными, тогда приёмник потом сможет разобраться где именно начались данные.


Не-не-не. Так нельзя. Можно нарваться на чтение порта в нестабильном состоянии. Передатчик и приёмник должны быть синхронизированы с точностью до такта. Чтение первого байта любого пакета всегда должно отставать на некоторое (фиксированное!) число тактов от записи этого байта (и у нас должна быть возможность выбрать величину отставания). Если момент чтения сдвигается относительно момента записи (от пакета к пакету; в пределах пакета он точно двигаться не будет), то я бы не стал гарантировать работоспособность.

Цитата
единственное может пару nopов надо будет где-то воткнуть перед циклом чтобы приёмник не сэмплил данные именно на том же такте когда передатчик их меняет.

Ага, Ты тоже это понимаешь. Но если мы можем синхронизироваться в пределах передачи байта (т.е. в пределах 3-х тактов), то это значит, что мы можем синхронизироваться и в пределах пакета.

Илья
ILYAUL
Цитата
Но если памяти хватает, то можно тупо повторить 1536 раз фрагмент:
in reg, PORT_PIN
st Y+, reg
И без всяких jmp-ов и циклов
+
NOP - n раз для синхронизации , где n = 1,2,3.....
piroman
SPI + DMA и нет проблем.
RadiatoR
Цитата(piroman @ Mar 24 2016, 14:41) *
SPI + DMA и нет проблем.

А ничего, тчо тактовая 32Мгц и передавать придется со скоростью 61,5Mbps?
Kovrov
Для приема:
Триггер ДМА завести по прерыванию внешнего входа
источник будет порт приема
назначение будет буфер озу с инкрементом
по истечению нужного колва байт в транзакции ДМА вывести запрос на прерывание у дма
вот и всего делоф.

Для передачи:
добавляем эвент контроллер дергания ноги строба.
загрузка проца минимальна.



zombi
Цитата(Kovrov @ Mar 28 2016, 15:21) *
Триггер ДМА завести...

Предлагаете и в приёмнике и в передатчике использовать DMA?
А сколько тактов необходимо для передачи одного байта из увв во внутр. память и наоборот?
И как оба процесса синхронизировать?
501-q
Цитата(zombi @ Mar 28 2016, 18:51) *
Предлагаете и в приёмнике и в передатчике использовать DMA?

Человек не осознал сложность, поторопился. Этот вариант уже отвергли.
Цитата
А сколько тактов необходимо для передачи одного байта из увв во внутр. память и наоборот?

Не менее 5 тактов (я бы рассчитывал на значение более 7, но если нужно точно, то это можно проверить). Плюс задержки из-за конфликтов во время доступа ядра и DMA к шине данных (в SPI, USART и т.п. эти задержки сглаживаются наличием промежуточного буфера).

Илья
Склихасовский
у меня был подобный опыт
реализация LVDS на хмега
только там 3 порта вывода пришлось реализовывать и внешнюю срам ставить.
примерно 15 гц рефреша получилось
--
ваше беспокойство по поводу сколько тактов нужно чтобы данные успели отобразиться в порту
хотя это как правило 1,5 такта
решается банально таймером с PWM и двумя системами сравнения
этот же таймер будет вам генерировать стробы.
а ширину периода крутите как вам угодно.






Kovrov
Цитата(501-q @ Mar 29 2016, 09:12) *
Человек не осознал сложность, поторопился. Этот вариант уже отвергли.

если это для людей сложность..
нада зарплату пойти больше просить. :-)
----------------------
RadiatoR
Может тут имелась ввиду не сама сложность, а то, что не подходит по временным характеристикам?
Kovrov
Цитата(zombi @ Mar 28 2016, 18:51) *
Предлагаете и в приёмнике и в передатчике использовать DMA?
А сколько тактов необходимо для передачи одного байта из увв во внутр. память и наоборот?
И как оба процесса синхронизировать?


Может я чето не понял
у вас есть 10 линий ио для реализации параллельного интерфейса
и нужно перекачать 1600 байт за 1 мс
так?
по схемотехнике:
на приемнике:
задействуем 1 полный порт для приема передачи
1 пин ввода вывода произвольный (разрешение интерфейса)
1 пин (строб для чтения данных) - если надумали работать через PWM таймера то зарезервировать вывод OC таймера если через евент систем - то любую ножку.
---
далее:
условимся что приемник будет командовать передатчиком т.е разрешать работу и стробить
----
что делает сигнал строба:
по спаду - передатчик готовит данные на выдачу на порт
по подъему приемник читает это все дело в буфер
можно и наоборот главное четко это для себя определить.
----
в приемнике разрешаем работу ножки вывода строба
определяем длительность спада как ОСА
определяем длительность подъема как ОСВ
задаем вершину счета (переменные PER или TOP) именно по ним коунтер таймера обнуляем
----
длительность периода можно регулировать
мне хватило 3 такта длит спада 3 такта подъема итого 6 на период + ещё запас до вершины таймера (TOP) , хотя top может равняться = OCB
31,25 нС * 6 = 187,5 нС/байт *1600 = 300 мкС
под ваше условие 1мс -
можно спокойно сделать период 10тактов +10тактов = 20*31,25 *1600 = 1000мкС
----
свои тайминги можете крутить как хотите переменными OCA OCB и PER.
---
Главное здесь то, что процу нужно обрабатывать только старт,стоп пакета и флаг прерывания дма.
зыы:
такие опыты я делал когда получил из образцов мега а1 ещё давным давно
_pv
Цитата(Kovrov @ Mar 29 2016, 13:28) *
Может я чето не понял, у вас есть 10 линий ио для реализации параллельного интерфейса и нужно перекачать 1600 байт за 1 мс

Только не за 1мс, а за 200мкс, то есть не больше 4 тактов на байт.
Сколько тактов надо ДМА у хмеги не знаю, но есть подозрение что не успеет и синхронизацией с точностью до такта могут быть проблемы.
А вот процессору, чтобы положить байт из порта в память с инкрементом надо два такта, а чтобы из памяти в порт - три такта.
Если ДМА не успевает на передатчике единственная возможность это развернуть цикл 1536 раз
LD REG, Y+
OUT PORT, REG
LD REG, Y+
OUT PORT, REG
...
3 такта на байт.

А на приёмнике тоже самое только
IN REG, PORT
ST Y+, REG
NOP
IN REG, PORT
ST Y+, REG
NOP
...
и те же 3 такта на байт.

на приёмнике можно флэш можно сэкономить добавив передатчику один NOP чтобы было 4 такта и сделав бесконечный цикл
IN REG, PORT
ST Y+, REG
RJMP -2
4 такта на байт.
Выходить из которого придётся по прерыванию либо внешнему от передатчика, либо по таймеру, меняя адрес возврата на стэке.

Осталось только синхронизироваться, использовать просто прерывание нельзя, будет джиттер, так как не все инструкции однотактовые.

Передатчик должен дёрнуть ногой в 1, подождать несколько NOPов, дернуть обратно в 0, опять подождать определённое количество NOPов и потом уже начинать LD OUT LD OUT.
Приёмник должен сначала сделать поллинг ноги от передатчика, потом включить внешнее прерывание от этой же ноги на спад и сделать десяток другой NOPов, тогда в прерывание приёмник уйдёт строго синхронно с передатчиком, можно точно посчитать такты и вставить в передатчике нужное количество NOPов чтобы приёмник сэмплил данные строго через два такта после того как передатчик их выставил.
SBIS PORT,PIN
RJMP -2 //тут будет джиттер в несколько таков
SEI
NOP //а вот в прерывание по спаду он уже прыгнет с однотактовых NOPов без джиттера.
NOP
NOP
...
Kovrov
а кому нужен этот геморой
чтоб 1/5 времени проц только и крутил поллинг?
_pv
Цитата(Kovrov @ Mar 29 2016, 15:16) *
а кому нужен этот геморой
чтоб 1/5 времени проц только и крутил поллинг?

Есть другой способ передать и принять байт за 4 такта?

что такое 1/5?
поллинг нужен только для синхронизации, да и вообще не нужен, можно и прерывания использовать, главное чтобы было второе внешнее прерывание в которое процессор гарантированно уйдёт с однотактовых инструкций, иначе с точностью до такта не засинхронизоваться
zombi
to _pv - именно так и планирую делать и это единственный вариант похоже.
Kovrov
мое мнение вам нужно в корне пересмотреть вашу идею.
zombi
Цитата(Kovrov @ Mar 29 2016, 12:48) *
мое мнение вам нужно в корне пересмотреть вашу идею.

уточните какую именно идею нужно пересмотреть?
Kovrov
Цитата(zombi @ Mar 29 2016, 15:26) *
уточните какую именно идею нужно пересмотреть?


Цитата(zombi @ Mar 22 2016, 19:20) *
Нужно в одном изделии передавать с одной xmega на другую каждую миллисекунду 12288 бит = 1536 байт.
Чем побыстрее, но не дольше чем за 200 мкс.
Оба мк тактируются от общего внешнего генератора 32MHz.
Свободных ног у каждого по 10 шт. есть.

zombi
Это задача а не идея.
Kovrov
ну остается только пожелать вам удачи в реализации этой задачи на AVR8
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.