Понадобился тут мне ШИМ контроллер, а готового в библиотеках cadence не было, пришлось выкручиваться на Verilog-A.
Остальное внутри поста 🙂
Итак мне нужен ШИМ контроллер с возможностью изменения скважности, причем управление скважностью должно осуществляться с помощью напряжения, чтобы организовать нормальную обратную связь в некоторых применениях. Картинка в начале поста кстати результат моделирования моего контроллера 🙂 А да, период шим не должен быть установленным намертво в коде.
Ну поехали:
// VerilogA for TB_sarge, PWMController, veriloga `include "constants.vams" `include "disciplines.vams" module PWMController(Clk, Duty, Out); output Out; input Clk; input Duty; electrical Clk; electrical Out; electrical Duty; parameter real Vh = 2.5; //Максимальное напряжение parameter real Vl = 0; //Минимальное напряжение parameter real vth = (Vh+Vl)/2; //Напряжение, при котором состояние будет переключаться parameter real PWMperiod = 2.5u; //Период ШИМ real state; //Переменная для обработки напряжения по входу Duty integer n; //переменная индикатор состояния real timeper; //характеристика скважности analog begin @(initial_step) state = 0; //Инициализация @(cross(V(Clk) - vth, +1)) begin //По каждому возрастающему фронту n = 1; timeper = $abstime; //timeper = текущее время state = V(Duty); //state = напряжение на управляющем входе end @(timer(0, timeper+state*PWMperiod)) //таймер срабатывает через текущее время + часть периода шим begin n = 0; //и затягивает состояние выхода в противоположное end V(Out) <+ transition(n ? Vl:Vh, 0, 100p); //выход равен либо Vh либо Vl, время нарастания 100 пс end endmodule
Контроллер готов, можно цеплять к нему источник с меандром по выходу и напряжением регулировать скважность, но есть одно но – код будет адекватно работать лишь если на входе у него напряжение от 0 до 1 (0-100% скважность). Поэтому пришлось еще приделать небольшой конвертер напряжений:
// VerilogA for TB_sarge, PWMConverter, veriloga `include "constants.vams" `include "disciplines.vams" module PWMConverter(In, Out); input In; output Out; electrical In; electrical Out; parameter real VHpeak = 2.5; parameter real VLpeak = 0; analog begin V(Out) <+ (VHpeak - VLpeak -V(In))/(VHpeak-VLpeak); //Разбиваем наш диапазон напряжений на 100 частей и получаем в итоге напряжение от 0 до 1 end endmodule
В данной версии кода кроме конвертирования происходит еще и инвертирование напряжения, то есть в максимально напряжении на входе, на выходе будет минимальное, то есть 0. Если инверсия не нужна, то строку 16 нужно переписать:
<pre>V(Out) <+ V(In)/(VHpeak-VLpeak);</pre>
Вот, теперь собираем тестовую схемку:
И наслаждаемся результатом 🙂