nabbla (nabbla1) wrote,
nabbla
nabbla1

Categories:

Управление осветителем через QuatCore

Похоже, я тут неправильную терминологию продвигал, считая, что делаю ФазоИмпульсную Модуляцию (ФИМ). Но посмотрев повнимательнее, обнаружил: на самом деле это частотно-импульсная модуляция (даже не уверен, что её сокращают до ЧИМ), она же Pulse-Frequency Modulation, PFM.

Именно в ней длительность импульса неизменна, но при этом частота их поступления меняется в широких пределах. В ФИМ и ШИМ частота следования фиксирована, в ШИМ меняется ширина импульса (логично), а в ФИМ - время его появления.

То есть, классический ФИМ - это те импульсы, что управляют симисторам в диммерах и "гашетках" электродрелей и прочих инструментов, работающих от 220 вольт: импульс для симистора всегда имеет одну длительность, ровно ту, которой достаточно для надёжного его отпирания, и частота их следования всегда одна и та же, 100 Гц, меняется лишь фаза - либо импульс приходит сразу же по пересечении нуля, давая максимальную мощность (ВСЕГДА открытый симистор), либо под самый конец, что соответствует предельно маленькой мощности.

А вот такой зверь, что у меня, как пишут, довольно редко встречается как раз-таки из-за своей "непредсказуемости" - довольно сложно работать с сигналом, частота которого варьируется от 20 кГц до 12,5 МГц :) Хотя нишевые применения есть, например, понижающие преобразователи на малых нагрузках, когда совсем "истончать" импульс не хочется (там кроме переключения ничего толком не останется, половина энергии начнёт в тепло уходить), уж лучше зафиксировать длительность импульса, просто выпускать их пореже!

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


У нас до сих пор очень "разрежены" команды DestAddr в диапазоне от 0x00 до 0x7F: на доступные 128 адресов приходится всего 7 команд:

0x00 .. 0x0F - OUT (выдать слово на одно из устройств ввода-вывода, UART/SPI/LCD),
0x10 .. 0x1F - SIO (Select I/O, выбрать устройство ввода-вывода),
0x20 .. 0x2F - ACQ (ACQuire, "захват" на видеопроцессоре, выдать максимальную яркость на указанном отрезке и координату, где она первый раз достигается),
0x30 .. 0x3F - TRK (TRacKing, "сопровождение" на видеопроцессоре, посчитать две суммы на отрезки, поделив одну на другую мы сможем найти яркостный центр с субпиксельной точностью)
0x40 .. 0x4F - ERL (External Register Low) - установить "нижние биты" регистра внешней памяти (на данной момент статической, 1 МБайт),
0x50 .. 0x5F - ERH (External Register High) - установить "верхние биты". Здесь у нас, как ни странно, адресация по байтам, нужен 20-битный адрес, в одно 16-битное слово он не влезает!
0x60 .. 0x7F - [ER++] - записать слово во внешнюю память и сделать инкремент регистра. 


Пожалуй, "наиболее вольготно" устроилась внешняя память, забрав ПОЛОВИНУ из этих 128 адресов, при том что команд всего 3. Заглянем в модуль QuatCoreFastSram и посмотрим, как там декодируются адреса:

wire IsOurDest = (~DestStall)&(~DestAddr[7])&DestAddr[6];

wire LoadERL = IsOurDest & (~DestAddr[5]) & (~DestAddr[4]);
wire LoadERH = IsOurDest & (~DestAddr[5]) & DestAddr[4];
wire WriteMem = IsOurDest & DestAddr[5];


То есть все адреса 01xx_xxxx (собственно, 0x40..0x7F) "принадлежат" этому модулю. Что ж, немного потесним их, упихнув в пространство 010x_xxxx, или 0x40..0x5F:

wire IsOurDest = (~DestStall)&(~DestAddr[7])&DestAddr[6]&(~DestAddr[5]);

wire LoadERL = IsOurDest & (~DestAddr[4]) & (~DestAddr[3]);
wire LoadERH = IsOurDest & (~DestAddr[4]) & DestAddr[3];
wire WriteMem = IsOurDest & DestAddr[4];


Как ни странно, такое изменение УМЕНЬШИЛО размер проекта: было 1522 ЛЭ (1550 после Place&Route), стало 1520 ЛЭ (1548 после Place&Route). Не знаю, почему, как всегда великий рандом.

Теперь у нас появились свободные адреса 0x60..0x7F

Напишем небольшой модулёк с частотно-импульсной модуляцией, "согласованный" с QuatCore:
module QuatCorePFM (input clk, input DestStall, input [7:0] DestAddr, input [15:0] D, output reg Q = 1'b0);

parameter PFMwidth = 3;

wire isOurAddr = (~DestStall) & (~DestAddr[7]) & DestAddr[6] & DestAddr[5];

reg [PFMwidth-1:0] val = 1'b0;

always @(posedge clk) if (isOurAddr)
	val <= D[PFMwidth-1:0];

wire c_PFM;

lpm_counter counter (
			.clock (clk),
			.data (val),
			.sload (c_PFM),
			.cout (c_PFM)	);
					
defparam
	counter.lpm_direction 	= "UP",
	counter.lpm_port_updown = "PORT_UNUSED",
	counter.lpm_type 	= "LPM_COUNTER",
	counter.lpm_width 	= PFMwidth;
	
always @(posedge clk)
	Q <= c_PFM;

endmodule


У нас используется счётчик непосредственно для модуляции (как и в прошлый раз), а перед ним стоит простейший триггер-защёлка :) Когда приходит новая команда IR (Infra-Red) - защёлкивает новое значение, и хранит его до прихода следующей команды, супер-халява.

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

Синтезируется такой модуль всего в 10 ЛЭ, а не поставь я защёлку на выходе - и вовсе в 9.

Теперь надо его добавить в процессор:


Он сиротливо сидит справа снизу этого фрагмента схемы. Тут вообще задумываться не надо, соединяешь входы с соответствующими шинами - вот и всё!

А старые модули, получавшие байт напрямую с UART, можно выкинуть. В результате, весь проект синтезируется в 1505 ЛЭ (было 1522), или 1533 ЛЭ после Place&Route (было 1550). Как ни странно, "железо" даже упростилось, хотя сейчас придётся программу усложнить.

Теперь надо подкорректировать файл конфигурации компилятора - три команды "внешней памяти" подправить и ещё одну, IR - добавить

Вот этот кусочек нас интересует:
  object TQuatCoreCommand
    Key = 'ERL'
    Code = 64
    Mask = 240
    Description = 'Sets lower 16 bits of external memory register'
    Place = [cpDest]
    Resources = []
    DataType = dtNumeric
  end
  object TQuatCoreCommand
    Key = 'ERH'
    Code = 80
    Mask = 240
    DataMask = 15
    Description = 'Sets upper 16 bits of external memory register'
    Place = [cpDest]
    Resources = []
    DataType = dtNumeric
  end
  object TQuatCoreCommand
    Key = '[ER++]'
    Code = 96
    Mask = 224
    DataMask = 255
    Description = ''
    Place = [cpDest]
    Resources = []
    DataType = dtNumeric
  end


А теперь будет вот так:
  object TQuatCoreCommand
    Key = 'ERL'
    Code = 64
    Mask = 248
    Description = 'Sets lower 16 bits of external memory register'
    Place = [cpDest]
    Resources = []
    DataType = dtNumeric
  end
  object TQuatCoreCommand
    Key = 'ERH'
    Code = 72
    Mask = 248
    DataMask = 15
    Description = 'Sets upper 16 bits of external memory register'
    Place = [cpDest]
    Resources = []
    DataType = dtNumeric
  end
  object TQuatCoreCommand
    Key = '[ER++]'
    Code = 80
    Mask = 240
    DataMask = 255
    Description = ''
    Place = [cpDest]
    Resources = []
    DataType = dtNumeric
  end
  object TQuatCoreCommand
    Key = 'IR'
    Code = 96
    Mask = 224
    DataMask = 7
    Description = 'IR lighter control'
    Place = [cpDest]
    Resources = []
    DataType = dtNumeric
  end


Запустим компилятор, посмотреть, есть ли у него претензии по конфигурации:

Загружаем файл конфигурации транслятора
Файл конфигурации прочитан, готовы к работе


Никаких претензий. А ещё можно посмотреть таблицу инструкций процессора, которую он составляет из файла конфигурации:

DestAddr


Адрес +0 +1 +2 +3 +4 +5 +6 +7
00 OUT OUT OUT OUT OUT OUT OUT OUT
08 OUT OUT OUT OUT OUT OUT OUT OUT
10 SIO SIO SIO SIO SIO SIO SIO SIO
18 SIO SIO SIO SIO SIO SIO SIO SIO
20 ACQ ACQ ACQ ACQ ACQ ACQ ACQ ACQ
28 ACQ ACQ ACQ ACQ ACQ ACQ ACQ ACQ
30 TRK TRK TRK TRK TRK TRK TRK TRK
38 TRK TRK TRK TRK TRK TRK TRK TRK
40 ERL ERL ERL ERL ERL ERL ERL ERL
48 ERH ERH ERH ERH ERH ERH ERH ERH
50 [ER++] [ER++] [ER++] [ER++] [ER++] [ER++] [ER++] [ER++]
58 [ER++] [ER++] [ER++] [ER++] [ER++] [ER++] [ER++] [ER++]
60 IR IR IR IR IR IR IR IR
68 IR IR IR IR IR IR IR IR
70 IR IR IR IR IR IR IR IR
78 IR IR IR IR IR IR IR IR
80 Acc PM ADD SUB ABS ABSPM ABSA ABSS
88 ZACC NOP C C DIV2 CDIV2PM DIV2A DIV2S
90 MUL FMPM FMA FMS MULSU SUFMPM SUFMA SUFMS
98 MULU UFMPM UFMA UFMS SQRD2 SQRPMD2 SQRAD2 SQRSD2
A0 i j k Inv i++ j++ k++ ijk
A8 iLOOP jLOOP kLOOP Jik iLoopUp jLoopUp kLoopUp JNik
B0 JMP JMP JMP JMP JMP JMP JMP JMP
B8 JL JL JO JO JGE JGE JNO JNO
C0 [X+1] [X+2i+1] [X+2j+1] [X+4j+1] [X+i] [X+3i] [X+2j+i] [X+4j+i]
C8 [X+k] [X+2i+k] [X+2j+k] [X+4j+k] [X+i^j] X [X+2j+i^j] [X+4j+i^j]
D0 [Y+1] [Y+2i+1] [Y+2j+1] [Y+Treug[j]+1] [Y+i] [Y+3i] [Y+2j+i] [Y+Treug[j]+i]
D8 [Y+k] [Y+2i+k] [Y+2j+k] [Y+Treug[j]+k] [Y+i^j] Y [Y+2j+i^j] [Y+Treug[j]+i^j]
E0 [Z+1] [Z+2i+1] [Z+2j+1] [Z+4j+1] [Z+i] [Z+3i] [Z+2j+i] [Z+4j+i]
E8 [Z+k] [Z+2i+k] [Z+2j+k] [Z+4j+k] [Z+i^j] Z [Z+2j+i^j] [Z+4j+i^j]
F0 [SP+1] [SP+2i+1] [SP+2j+1] [SP++] [SP+i] [SP+3i] [SP+2j+i] [i-1+SP++]
F8 [SP+k] [SP+2i+k] [SP+2j+k] [--SP+k] [SP] SP [SP+2j] [--SP]


Что ж, всё ровно так, как мы и хотели.


Осталось дописать программу, чтобы она управляла осветителем и отображала текущую яркость на ЖК-экранчике - и потом уже поразвлекаться с разнокалиберными генераторами ШИМ, ЧИМ и пр, какой из них для нас будет наиболее подходящим! Вот чем угодно готов заняться, лишь бы "алгоритм обнаружения" не отлаживать!
Tags: ПЛИС, освещение, программки, работа, странные девайсы
Subscribe

Recent Posts from This Journal

  • Нахождение двух самых отдалённых точек

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

  • Слишком общительный счётчик

    Вчера я чуть поторопился отсинтезировать проект,параметры не поменял: RomWidth = 8 вместо 7, RamWidth = 9 вместо 8, и ещё EnableByteAccess=1, чтобы…

  • Балансируем конвейер QuatCore

    В пятницу у нас всё замечательно сработало на симуляции, первые 16 миллисекунд полёт нормальный. А вот прошить весь проект на ПЛИС и попробовать "в…

  • Огари разговаривают

    Сегодня по пути на работу встретил огарей прямо в Лосином острове, на берегу Яузы. Эти были на удивление бесстрашны, занимались своими делами, не…

  • Ковыряемся с сантехникой

    Наконец-то закрыл сколько-нибудь пристойно трубы, подводящие к смесителю, в квартире в Москве: А в воскресенье побывал на даче, там очередная…

  • Мартовское велосипедное

    Продолжаю кататься на работу и с работы на велосипеде, а также в РКК Энергию и на дачу. Хотя на две недели случился перерыв, очередная поломка,…

  • Post a new comment

    Error

    Anonymous comments are disabled in this journal

    default userpic

    Your IP address will be recorded 

  • 1 comment