OSD на ATmega1281

MikeMDR
msv:

Дык сообщение 222… Там правда тоже неточности по номиналам есть, но пока повторять никто не собирается- не принципиально…

Признаю свою ошибку - проглядел!!! (Когда тема ушла в сторону БП - читать стал менее внимательно…😌)
А теперь, восстановив былые навыки кодинга и получив АрдуиноМега1280 - решил начать с повторения чужого опыта. Поэтому, (если не сильно затруднит), можно чуть-чуть подробнее о неточностях в номиналах…😋

MikeMDR

P.S. забыл сказать САМОЕ главное: Большое Спасибо!!!

korall
msv:

За длинные выходные, в перерывах между “отмечаниями” великого празника, осилил передачу телетексто-подобных тестовых строк с OSD на свою GrounStation. Передаю в двух строках по 24-байта. 1,5 байта теряется на синхронизацию+0.5байта номер фрейма+2байта на CRC итого в остатке 40 байт чистых данных на полукадр. Более чем достаточно выдать практически все что можно с самолета, по сути в реальном времени…

Тоже озадачился данной темой, если не секрет расскажите по подробней алгоритм синхронизации начала посылки, есть ли привязка к КСИ и ССИ или вполне возможно выловить синхробайт из видео сигнала, а также пару слов ,как реализована аналоговая часть декодара ?

msv
korall:

есть ли привязка к КСИ и ССИ

Да. Первоначально планировал синхру ловить встроенным в мегу компаратором, а для данных- внешний LM311. Но почему то (не понял почему) данные надежнее (при больших изменения опорного напряжения) хватались через встроенный компаратор, хотя по дш быстродействие у него значительно меньше… Пришлось внешний пустить для синхро. Знал бы, поставил вместо него 1881…
Так что по импульсам видео-синхронизации, отсчитываю нужный номер строки от начала кадра, дальше захват синхро-байта и синхронный прием.

korall:

как реализована аналоговая часть декодара ?

Был уверен, что выкладывал схему… За точность номиналов не гарантирую, может что слегка менял…
В принципе могу и исходники GS выложить, но там понять кроме меня что-то довольно сложно…😃
ЗЫ Забыл для 311 подтягивающий резистор на выходе нарисовать…

korall

Если есть привязка к СИ видео сигнала, зачем тогда нужен целый синхро байт? почему нельзя сразу начать прием данных после нужного ССИ за старт используя первый же перепад уровня по типу USARTA . А уж если использовать синхронизирующую последовательность байт, то ведь можно её отловить и без видео СИ, и как мне кажется так будет более надежно.
Проводились ли испытания на устойчивость передачи данных в условиях плохого приема изображения ?
Если исходники не на СИ то интересно былобы взглянуть ,особенно интересует начало приема синхро байта и момент где принимается решение, что закончился синхробайт и начинаем прем пакета. если не в напряг то это место с коментами, или просто на словах опишите процедуру.
За ламерские вопросу прошу сильно не пинать, так как в теме не оч. шарю,и пытаюсь вникнуть в суть.
Спасибо за внимание !

MikeMDR
korall:

Если исходники не на СИ то интересно былобы взглянуть

А если на С, то тогда уже мне тоже интересно взглянуть!

msv
korall:

Проводились ли испытания на устойчивость передачи данных в условиях плохого приема изображения ?

Полевых испытаний пока не проводил. Имитируя плохой сигнал интерференциями в комнате, вполне доволен результатом. Пока картинка хоть немного читаема, данные, хоть и с дропами, идут.

korall:

зачем тогда нужен целый синхро байт?

Ну это не синхро-байт в полном смысле слова. Нужен лишь его передний фронт для фазовой синхронизации. А дальше время входа в процедуру прерывания, сохранение регистров, инициализация… Вообщем на все про все теряю 1,5 байта (5 бит пропускаю, дабы сразу попадать бит в бит не занимаясь дополнительно их сдвигами). Может и возможно сделать многие вещи заранее и не “зарыться” в стеке при всех возможных ситуациях, ну уж как сделал…

korall:

А уж если использовать синхронизирующую последовательность байт, то ведь можно её отловить и без видео СИ

Представляется очень сложно… Ведь потребуется постоянная фазовая коррекция, а с ней будут пропуски бит… К тому же надо еще и сервами успевать шевлить и светодиодами моргать и на хост данные сливать…
Вообщем пока так:
прерывание от синхроимпульсов:


//-----------------------------------------------------
interrupt [EXT_INT0] void ext_int0_isr(void)
{  // ССИ+КСИ
u_char ind;
static u_char fpv=0;

if(!(PIND & 0x4)) TCNT2=0; // Начало СИ
else
  { // Окончание СИ
  if(TCNT2>30) { gNumLine=0; return; } // КСИ
  if(gNumLine<200) gNumLine++;
  if(gNumLine>=START_LINE_TT)
    { // Пора поработать...
    if(fpv) return; // повторное вхождение, ай-ай..
    fpv=1;
    ind=gNumLine-START_LINE_TT;
    if(ind<COUNT_LINE_TT)
      { // Точно пора работать..
      gVideoBuffPoint=gVideoBuff[ind]; // Указатель на буфер для приема
      ACSR=0x1B;  //AC_int=rising, int_flag=clear
      MCUCR=0x80; //sleep=enable, int0=disable
      #asm("sei")
      #asm("sleep") //wait AC_int, всего готово, спим и ждем прерывания от синхро байта
      }
    if(ind==COUNT_LINE_TT)
      {
      #asm("sei")
      rec_v_data(); // Разбираем, что напринимали.. Контроль CRC, распихиваем по структурам..
      }
    fpv=0;
    }
  }
}

Продолжение следует… (Если еще кому интересно…)

MikeMDR
msv:

Продолжение следует… (Если еще кому интересно…)

КОНЕЧНО интересно!

korall

В целом идея понятна, примерно так себе и представлял.

msv:

Ведь потребуется постоянная фазовая коррекция, а с ней будут пропуски бит…

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

msv:

К тому же надо еще и сервами успевать шевлить и светодиодами моргать и на хост данные сливать…

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

msv
korall:

Фазу чего и относительно чего нужно постоянно корректировать?

Момент чтения бита видеоданных из порта должен по возможности приходиться на середину бита. Именно для этого укладываю спать МК в ожидании прихода первого фронта данных. При этом время неопределенности момента чтения составит 1такт проца, что всего в 4 раза меньше длины бита данных. Естественно из-за несинхронности кварцев, фаза момента чтения будет сдвигаться. На длину строки хватает, оценивал в цифрах…
Не настаиваю, возможно как-то сделать по другому, но пока не представляю практическую структуру такой программы…
Собственно дальше все просто, приходит первый бит, генерируется прерывание, и в нем синхронно читаются данные в буфер:

//-----------------------------------------------------
#pragma savereg-
interrupt [ANA_COMP] void ana_comp_isr(void)
{
#asm
    ST   -Y,R16   ;2t
    ST   -Y,R17   ;2t
    ST   -Y,R18   ;2t
    ST   -Y,R26   ;2t
    ST   -Y,R27   ;2t
    IN   R16,SREG
    ST   -Y,R16
;
    MOV  R26,gVideoBuffPointL      ;1t
    MOV  R27,gVideoBuffPointH      ;1t
    LDI  R16,(BYTES_FROM_STRING-1) ;1t
;
    LDI  R17,5
_wait_n:       ; skeep 5-bits
    DEC  R17
    NOP
    BRNE _wait_n
    NOP
;    SBI  0x12,3 ;PORTD.3=1
_in_ch:
    SBIC 0x8,5 ;ACSR & 0x20
    SBR  R17,0x10
    NOP
    NOP

	SBIC 0x8,5 ;ACSR & 0x20
    SBR  R17,0x20
    NOP
    NOP

	SBIC 0x8,5 ;ACSR & 0x20
    SBR  R17,0x40
    NOP
    NOP

	SBIC 0x8,5 ;ACSR & 0x20
    SBR  R17,0x80
    MOV  R18,R17
    CLR  R17

	SBIC 0x8,5 ;ACSR & 0x20
    SBR  R17,0x1
    ST   X+,R18  ; 2t

	SBIC 0x8,5 ;ACSR & 0x20
    SBR  R17,0x2
    NOP
    NOP

	SBIC 0x8,5 ;ACSR & 0x20
    SBR  R17,0x4
    SUBI R16,1 ;1t
    NOP

	SBIC 0x8,5 ;ACSR & 0x20
    SBR  R17,0x8
    BRSH _in_ch ;2t
;
	LDI  R16,LOW(0) ;ACSR=0x0; //AC_int=disable
	OUT  0x8,R16
	LDI  R16,LOW(1); MCUCR=0x01; //int0=enable, sleep=disable
	OUT  0x35,R16
;    CBI  0x12,3    ;PORTD.3=0
;
    LD   R16,Y+
    OUT  SREG,R16
    LD   R27,Y+
    LD   R26,Y+
    LD   R18,Y+
	LD   R17,Y+
    LD   R16,Y+
#endasm
}
#pragma savereg+
//-----------------------------------------------------

Ну а для особо пытливых - весь проект: GS.rar 😃

korall

Возможно не совсем по теме, но все же интересно, с какой целью в прерывании используется такой извращенный метод сохранения регистров, вместо PUSH и POP обычно применяемых в таких случаях?
Исходник глянул , но будучи написанный на С, (что для меня равносильно китайской грамоте) данный трюк не прояснил.

msv

Честно говоря не разбирался, почему CVAVR использует стек, адресуемый SP, только для хранения адресов возврата из подпрограмм. А для всего остального использует Data Stack, адресуемый Y регистром. Просто принял правила игры. Могу выложить asm, который генерит CVAVR для этого проекта…

korall
msv:

Могу выложить asm, который генерит CVAVR для этого проекта…

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

msv
korall:

Спасибо не не надо

Я забыл смайлик поставить… 😃 Хотя в OSD часто пользовался таким приемом, быстренько писал на си, компилил, смотрел что там CV наассемблировал и оптимизировал уже готовый асм-код. Быстрее получается, тем более с асмом меги никакого опыта нет.

korall:

это геометрическое построение или же зарание подготовленные изображения с разными углами

Конечно геометрия(считаются координаты) плюс графика(рисуются линии). Самое время-прожорливое,- отрисовка текста, пришлось все на асме оптимизировать…

Dikoy
korall:

Спасибо не не надо, разобраться в том что сгенерит компилятор без подробных комментариев, я все равно не смогу.

там код на С в коментах, а потом идёт его перевод на асм.
Например:

;// Прерывание срабатыает, когда таймер досчитывает до значения, записаного в OCR1A.
;interrupt [TIM1_COMPA] void timer1_compa_isr(void)
; 0000 0067 {
_timer1_compa_isr:
ST -Y,R26
ST -Y,R27
ST -Y,R30
ST -Y,R31
IN R30,SREG
ST -Y,R30
; 0000 0068 PORTD INV_B(4);
IN R30,0x12
LDI R26,LOW(16)
EOR R30,R26
OUT 0x12,R30
; 0000 0069
; 0000 006A if(completed_flag == SET) {
LDI R30,LOW(238)
CP R30,R2
BRNE _0x9
; 0000 006B temp = dobavka; // если данные готовы, обновляем значение temp
MOVW R6,R8
; 0000 006C completed_flag = FREE; // помечаем флаг, что данные получены
CLR R2
; 0000 006D }
; 0000 006E
; 0000 006F
; 0000 0070 if((compA + temp) > 0xFFFF ) { // проверяем, не превосходит ли сумма значения таймера с добавкой максимального значения FFFF
_0x9:
MOVW R26,R6
ADD R26,R10
ADC R27,R11
LDI R30,LOW(65535)
LDI R31,HIGH(65535)
CP R30,R26
CPC R31,R27
BRSH _0xA
; 0000 0071 compA = ((compA + temp) - 0xFFFF); // если да, вычисляем значение с учётом переполнения.
MOVW R30,R6
ADD R30,R10
ADC R31,R11
SUBI R30,LOW(65535)
SBCI R31,HIGH(65535)
MOVW R10,R30
; 0000 0072 } else {
RJMP _0xB
_0xA:
; 0000 0073 compA = (compA + temp); // если нет - просто складываем.
__ADDWRR 10,11,6,7
; 0000 0074 }
_0xB:
; 0000 0075 OCR1A = compA; // записываем в таймер новый порог срабатывания.
__OUTWR 10,11,42
; 0000 0076
; 0000 0077 }
LD R30,Y+
OUT SREG,R30
LD R31,Y+
LD R30,Y+
LD R27,Y+
LD R26,Y+
RETI
;
;

korall

Это я в курсе, хотя такую солянку из АСМа, С и машинных кодов крайне тяжело читать не специалисту, так к тому же и проект листинг которого автор предлагал выложить (за исключением кусочка в посте 232) не содержит ни каких комментариев.

Prodigy
Lazy:

Решил проблему радикально.
Собрал себе комп для наземки на базе вот такого:

как сие называется, можно модель?

Pantryk
msv:

Самое время-прожорливое,- отрисовка текста, пришлось все на асме оптимизировать…

Если не секрет, в чем состояла оптимизация? т.е что не так делал С компилятор, и к чему вы привели это в асме?

msv

Например, если объявить локальную переменную- указатель, а потом через него заполнять буфер, компилятор тупо модифицирует эту переменную и каждый раз ее копирует в X-регистр для косвенной адресации, даже если этот регистр больше в цикле не используется… Гораздо короче (ну и соответсвенно быстрее) сразу инициализировать X, и его же модифицировать.
Иногда анализ сгенерированного асма, позволяет существенно оптимизировать Си-шный код, переписав его на Си. Например, в нескольких функциях отказавшись в цикле использовать операцию остаток от деления индекса (один символ на Си, а его реализация весьма много кода за собой тянет), заменил его дополнительной переменной, скорость выполнения функции возросла в несколько раз.

avisenja
abalex:

LSR R18
OUT VIDPORT,R18 ; 0
NOP

и т.д.

Я с мегами сильно не занимался,
но сам делал циклический сдвиг у ПИКов прямо в порту:)

rlf PORTA,F ;
rlf PORTA,F ;
rlf PORTA,F ;
-----------------------------------------------------
меги могут прямо в порту делать сдвиг 😒???

lsr VIDPORT ;
lsr VIDPORT ;
lsr VIDPORT ;

-----------------------------------------------------