OSD на ATmega1281

msv

Код вывода строки сделан “в лоб” и не отличается особым изяществом:

;
;gNumLine++
    MOV  R26,gNumLineL
    MOV  R27,gNumLineH
    ADIW R26,1
    MOV  gNumLineL,R26
    MOV  gNumLineH,R27
;if(gNumLine>=TOPLINE_SCR && gNumLine<TOPLINE_SCR+VSIZE_SCR)
    CPI  R26,LOW(TOPLINE_SCR)
    LDI  R16,HIGH(TOPLINE_SCR)
    CPC  R27,R16
	BRLT _end1
    CPI  R26,LOW(TOPLINE_SCR+VSIZE_SCR)
    LDI  R16,HIGH(TOPLINE_SCR+VSIZE_SCR)
    CPC  R27,R16
	BRLT _con1
    BRNE _end1
    LDI  R16,1
    MOV  f_work,R16
_end1:
	RJMP _USART_RX
; pause
_con1:
    LDI  R16,WAIT_START_OUT
_pause:
	DEC	 R16
	BRNE _pause
; out string
  	MOV	 R27,gScrBuffPointH
	MOV	 R26,gScrBuffPointL
    LDI  R16,BYTES_FROM_STRING
    LD   R18,X+
_out_ch:
    MOV  R17,R18
    OUT  V_PORT,R17	;1
	NOP
	NOP
	LSR	 R17
    OUT  V_PORT,R17	;2
	NOP
	NOP
	LSR	 R17
    OUT  V_PORT,R17	;3
	NOP
	NOP
	LSR	 R17
    OUT  V_PORT,R17	;4
	NOP
	NOP
	LSR	 R17
    OUT  V_PORT,R17	;5
	NOP
	NOP
	LSR	 R17
    OUT  V_PORT,R17	;6
    LD   R18,X+
	LSR	 R17
    OUT  V_PORT,R17	;7
	LSR	 R17
	DEC  R16
	NOP
    OUT  V_PORT,R17	;8
    brne _out_ch
    LDI  R17,0
    NOP
    OUT  V_PORT,R17	;8
    SBIW R26, 1
    MOV	 gScrBuffPointL,R26
    MOV	 gScrBuffPointH,R27
a_freeman

Пасиб.

Если здесь:
LDI R16,BYTES_FROM_STRING
LD R18,X+
убрать плюс, то в конце можно будет убрать всю инструкцию:
SBIW R26, 1
Мелочь, а приятно )

Пишу в IAR, и всю голову поломал - как красиво передать ассемблерной части адрес на видеобуфер.
Как у вас это получилось - так и не понял. Или gScrBuffPoint задан вручную? (как и размещение видеобуфера в опертивке)

msv

…как красиво передать ассемблерной части адрес на видеобуфер

Не уверен, что это красиво, но у меня так:

register unsigned char* gScrBuffPoint @5;
#asm (".def gScrBuffPointL=R5")
#asm (".def gScrBuffPointH=R6")

Инициализация в прерывании от КСИ:

interrupt [INT0] void ext_int0_isr(void)
{ // КСИ
gNumLine=0;
gScrBuffPoint=gScrBuff;
}
21 days later
a_freeman

Что-то и топикстартер молчит и окружающие не интересуюццо…

Появилась мысля как увеличить точность измерения тока - ставим в меге источником опорного внутренние 2.56 вольта - и при нулевом токе (через датчик) считываем значение порядка 950.
И работаем на отрицательной ветви токового датчика - т.е. при растущем токе значение с АЦП будет падать до нуля.
Даст повышение точности в два раза.

/*
еще немного мыслей просто из записной книжки:
Ток и напряжение лучше мерить тинькой в режиме ADC noise reduction, с полной обвязкой АЦП и как можно ближе к датчику - результат будет чище и лучше.
Работаем на пониженной частоте АЦП.
Имеет смысл вставить RC фильтр от помех между датчиком и мегой
Датчик чувствителен в магнитному полю - ставим рядом катушку, включаем, измеряем ток, отключаем, измеряем ток, усредняем два измерения - это неопробовано, неизвестно что из этого получится, неоправданно…
*/

msv

Да, народ не слишком активен… Может по результатам сезона выложу hex (от НАСA похоже не дождусь предложения на приобретение проекта 😃). Может активность увеличится… Хотя финальной печатки нет (то что у меня, уже можно считать макеткой+кучка платок апгрейда, слишком много поменялось, от начальной идеи), поэтому на повальный интерес по повторению не рассчитываю…
Сейчас играюсь с управляющими алгоритмами автопилота. Правда пока чем мудренее алгоритм, тем обычно хуже все в реале, хотя в модели на ПК, все отрабатывается идеально. Видать слишком “хороша” модель, но сделать ее более правдоподобной, задачка посложнее чем саму управляющую программу… 😃
Добавил режим, похожий на настоящий АП- если в режиме стабилизации щелкнуть доп. тумблер- АП начинает удерживать текущий курс и высоту (такого вроде бы нет у “конкурентов”). При выключении этого режима, устанавливаются нули сенсоров горизонта (для этого, автокалибровки, чес. говоря этот режим и задумывался).
Еще не испытал…

a_freeman:

внутренние 2.56 вольта - и при нулевом токе (через датчик) считываем значение порядка 950.
И работаем на отрицательной ветви токового датчика

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

a_freeman:

Имеет смысл вставить RC фильтр от помех между датчиком и мегой

Практика показала, что это обязательно. Датчик слишком быстродействующий и выдает все пульсации на силовом проводе.
Остальное, по вкусу… 😃 Надо считать какую точность хотите получить, достаточно ли мала погрешность самого датчика, дабы ее обеспечить, ну и нужна ли она…

MikeMDR
msv:

Да, народ не слишком активен…

Лето, жара, отпуска, ДАЧА!!😛

msv:

поэтому на повальный интерес по повторению не рассчитываю…

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

Dikoy
a_freeman:

как красиво передать ассемблерной части адрес на видеобуфер.

Обычно так и делают - вешают буфер по известному адресу (только не в самом начале:
signed char array [BUFFER] @0xC0;
И обращаются хоть из Си по указателю, хоть из асма. Если буфер небольшой, можно упихать в регистры как у автора. Будет ещё быстрее. Но тут надо в ассме посмотреть, сколько регистров компилер сохраняет. ИАР вообще ассм недолюбливает, и склонность к гонянию регистров из ОЗУ и обратно имеет. То есть разместив буфер в регистрах можно всё равно получить лишнее сохранение/вызов.

a_freeman

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

Но все равно спасибо.

msv

Если буфер небольшой, можно упихать в регистры как у автора.

Какая разница какой размер буфера? У меня в регистрах указатель на него, хоть все ОЗУ адресуй.

Сейчас без указания конкретного адреса все работает прекрасно.

Так поделитесь, как решили задачку?..

msv

Глянул Вашу заготовку OSD. Попиксельный вывод строк символов скорее всего получится слишком тормозной. Можно не успеть обновить все надписи за межкадровый интервал. Мне пришлось оптимизировать вывод строки сразу в одной функции и на асме. Использовать встроенный компаратор для определения синхроимпульсов, мысль хорошая. А в железе уже проверили работу?

a_freeman

Да, скриншоты в архиве это кадры с уже реального железа. Картинку захватывал такой железякой: nix.ru/…/STLab_M320_Grabber_USB2.0_SVideo_86320.ht…
Кстати, телевизор, на котором я проверял качество картиники надежно устранял все факелы - так что “удешевленное” подмешивание тоже жизнеспособно.

Насчет обновления - некоторые данные нет смысла перерисовывать в каждом кадре , можно делать это чуть реже. Я разбил такие фрагменты кода на несколько частей, и в зависимости от счетчика кадров вызывается только один фрагмент:

if (task++>T) task=0;
if (task==0) {compass(ang);}
if (task==1) {alt_ruler(); speed_ruler();}
if (task==2) {discharge(cap);}

Примерно так. Мой GPS приемник отдает данные вообще раз в секунду - поэтому смысла перерисовывать координаты/высоту/скорость/etc в каждом кадре нет.

msv

Уже писАл выше, что у меня вывод графики в каждом условно нечетном полукадре (25Гц, реже -не будет плавности), а вывод текстовой информации в четном, тоже как у Вас, поочередно группами. Хоть GPS у меня 5-ти герцовый, но для получения плавных движений шкал пришлось интерполировать получаемые значения на 25Гц, иначе картинка стробит.
Проблема с факелами у меня началась, когда начал пытаться рисовать тени…

a_freeman

Я поражаюсь с этого чувака: www.rowlhouse.co.uk/main.html 😮

На странице конечно много всего, но больше мне понравился RC-симулятор с автопилотом! Более того, этот товарищ выложил все исходники! (I’ve written a flight simulator for R/C model gliders)

Если посмотреть остальные проекты, остается сказать только “Во дает!” ибо это действительно сильно!

Не удивлюсь если он уже работает в НАСА…

abalex
a_freeman:

Вобсчем вот основа всего OSD. Может кому интересно будет

Вывод строки пикселей по 3 цикла процессора на пиксель вместо четырех ( тогда в строку вроде влезет 32 символа вместо 24 ). Это если в Ваш проект, содержательная часть video_driver.asm
Может, кому интересно будет.

P.S. Реально это не проверял, могут быть ошибки.



    LDI  R16,WAIT
_pause:
    DEC	 R16
    BRNE _pause
      ; Загружаем указатель из оперативки в регистровую пару X:
    LDS	 R27,gScrBuffPointH
    LDS	 R26,gScrBuffPointL

    LDI  R16,STR_LENGTH      ; Загружаем длину строки в счетчик

      ;  Остальные биты порта - могут использоваться для чего-то полезного
      ; ( например, для ввода цифровых сигналов ), и на всякий случай сохраняем
      ; исходное состояние порта ( для входов - подключен ли к нему внутренний
      ; подтягивающий резистор; это м.б. важно ):
    IN   R17,VIDPORT         ; Начальное состояние порта: в конце - восстановим
      ;  Входим в цикл, экономя на RJMP ( первый раз - будет холостой вывод
      ; из R17 в порт того же, что только что ввели оттуда ).

_out_ch:  ; Сюда приходим при продолжении цикла
    OUT  VIDPORT,R17	     ; Выводим 8-й пиксель от предыдущего
      ; Начинаем вывод 8 пикселей следующего символа:
    LD   R18,X+                   ; Загружаем данные из оперативки в регистр
    OUT  VIDPORT,R18          ; 1
      ;  Пока что - переносим 8-й пиксель из R18 в 0-й бит R17, откуда его
      ; в итоге и выведем:
    BST  R18,7		     ; 8-й пиксель - в T ( это бит в SREG )
    LSR	 R18
    OUT  VIDPORT,R18         ; 2
    BLD  R17,0               ; 8-й пиксель - в 0-й бит R17 ( из T )
    LSR	 R18
    OUT  VIDPORT,R18	     ; 3
    NOP
    LSR  R18
    OUT  VIDPORT,R18	     ; 4
    NOP
    LSR	 R18
    OUT  VIDPORT,R18	     ; 5
    NOP
    LSR	 R18
    OUT  VIDPORT,R18	     ; 6
    LSR	 R18
    DEC  R16                 ; Уменьшаем счетчик оставшихся символов
    OUT  VIDPORT,R18	     ; 7
    BRNE _out_ch             ; Если в R16 не ноль - продолжаем
      ; Иначе - это конец строки:
    NOP
    OUT  VIDPORT,R17	     ; 8 последнего символа
    NOP
    ANDI R17,0xFE            ; Сбрасываем 0-й бит в R17 ( чистим пин на выходе )
    OUT  VIDPORT,R17	     ; Чистим пин на выходе

    STS	 gScrBuffPointL,R26  ; Обратно в оперативку
    STS	 gScrBuffPointH,R27
a_freeman

Все работает “из коробки”!
Снимаю перед вами шляпу! ©

Да, пиксель стал квадратный - это здорово 😃

a_freeman

Мысля: взять кристалл с большим количеством оперативки, и на нем собрать “видеокарту”.
И не сваливать всю работу на один контроллер - это неудобно

Появляется вопрос: как общаться с этим контроллерами? И целесообразно-ли это вообще?

msv

Александр, еще раз, теперь публично, громадное спасибо! Честно говоря, я так и не попробовал этот код, когда Вы прислали мне его в личку. Слишком увлекся на тот момент алгоритмами управления…
Кстати по последнему, уже спрашивал, как грамотно получить диф. составляюшую для ПИД-регулятора. Классическое дифференцирование первого порядка d=x[n]-x[n-1] мало пригодно из за слишком малого разрешения. Для уточнения результата с постоянной времени дифференцирования хотя бы 1 сек, приходится буферировать все промежуточные зачения хотя бы за 1/2 сек. Может есть рекурентный алгоритм для целочисленки, позволяющий повысить точность расчета менее варварским способом?

Мысля: взять кристалл с большим количеством оперативки, и на нем собрать “видеокарту”. И не сваливать всю работу на один контроллер - это неудобно Появляется вопрос: как общаться с этим контроллерами? И целесообразно-ли это вообще?

Так все и делают… Но мое мнение- это не спортивно… 😃
PS. Сегодня классно полетали, спасибо Сергей (ubd)! Реализовал свою мечту, пробил 2км ( я скромняга, и мечты соответствующие 😃). Проверил режим стабилизации курса/высоты- набрал какую хочешь высоту, выбрал курс, включил и наслаждайся красотами. Ну и АП подтвердил свое предназначение, тоже можно было не вглядываться нервно в экран, а покурить… Короче, все работает!.. Но поиграться с с коэффициентами ПИД-регуляторов (а их аж 4) еще можно…

16 days later
msv

Не могу не поделиться впечатлением от крайней полетушки… На основе режима стабилизации курса/высоты, реализовал автопилот. Четыре полноценных PID-регулятора теперь позволяют реализовать следующие режимы полетов:

  1. Ручной. Классика, стиками задаётся положение серв.
  2. Режим стабилизации крена/тангажа. Ручками передатчика определяются целевые крен/тангаж, система стабилизации их отрабатывает. Газ задается вручную, но для того, чтобы при уменьшении газа при нейтральных ручках самолет не переходил в парашютирование/сваливание, при уменьшении газа меньше некоторого значения, корректируется в сторону увеличения ноль тангажа обратно пропорционально значению канала газа.
  3. (New!) Режим стабилизации курса/высоты. По сути полноценный автопилот. Стиками можно менять целевые курс/высоту со скоростью, пропорционально отклонению ручек от нейтрали. Газ устанавливается автоматически от значения тангажа.
  4. Возврат домой. Подобно 3, только курс определяется положением базы, а высота просчитывается от высоты и удаления при включения режима и конфигурируемой конечной высоты. По текущему расстоянию в каждой точке линейно определяется необходимая в данной точке высота, в соответсвии с этим корректируется тангаж. В реале самолет выдерживает точную глиссаду.
    Впечатления от нового 3-го режима, самые положительные. Полетав на нем минут 5, переключился на 2-й и вдруг понял, как это тяжело, почти невозможно… 😃 Ведь самолет тримирован не идеально, да еще не слабым ветерком сдувается, надо постоянно следить за высотой/курсом… Первый режим вообще включаю только на взлете с визуальным (не FPV) управлением. Боюсь, что по FPV в этом режиме “убьюсь” через несколько секунд полета…
    ЗЫ Как люди летают по FPV не только без систем стабилизации но и даже без OSD - вообще ума не приложу… 😃 При полете в новом месте, свое авто узнаю уже подлетев по приборам метров на 100.