Инфракрасный выход в Verilog

Мне нужно разработать инфракрасный передатчик с использованием FPGA и Verilog.

Одним из условий является отправка пакета каждые 10 Гц, у меня есть счетчик, который создает вторичные часы на частоте 10 Гц от основных часов (100 МГц). Пакет содержит Start-Gap-Select-Gap-Right-Gap-Left-Gap-Forward-Gap-Backwards-Gap. У меня есть FSM, который выполняет этот переход на положительном фронте вторичного тактового сигнала 10 Гц. Каждый из этих блоков в пакете имеет свой размер, а Gap — это просто пустое пространство, которое их разделяет. Блоки направления имеют больший размер при выборе и меньший в противном случае. При условии, что приемник имеет частоту импульсов 36 кГц, у меня есть еще один счетчик, который уменьшает основные часы до 36 кГц, которые я использую для генерации размеров импульсов для запуска, выбора и т. Д. И делаю выходной светодиод 1, в то время как счетчик считает до этот размер (для запуска случаев выберите ..) и 0 для состояния разрыва.

Однако, когда я смотрю на светодиод через камеру своего смартфона, он показывает, что он включен все время, что я и ожидаю увидеть, поскольку он должен отправлять пакеты 10 раз в секунду.

Проблема в том, что машина вообще не двигается, мой вопрос в том, это правильная логика действий или я что-то упускаю? Спасибо

Запрашиваемый код:

Счетчик для импульса 36 кГц

always@(posedge CLK) begin
    if(RESET) begin
       Counter <= 0;
        SEC_CLK <= 0; 
    end
    else if(Counter == 2778) begin
        Counter <= 0;
        SEC_CLK <= 1'b1;
    end
    else begin
        Counter <= Counter + 1;
        SEC_CLK <= 1'b0;
    end
end

Счетчик 10 Гц, не знаю, хорошо ли уменьшить 36 кГц или использовать Master Clock, но это хорошее круглое число, поэтому я использовал Master Clock.

always@(posedge CLK) begin
    if(sec_counter == 100000) begin
        sec_counter <= 0;
        send <= 1;
    end
    else begin
        sec_counter <= sec_counter +1;
        send <= 0;
    end
 end`

Логика конечного автомата:

always@(Curr_State) begin
           case(Curr_State) 
               1'd0: begin //START 
                   Next_State <= 1'd1;
                   Previous_State <= Next_State;
                   max_count <= StartBurstSize;
                   flag <= 0;
               end
               1'd1: begin //GAP
                   if(Previous_State <= 1'd7)
                       Next_State<=1'd0;
                   else 
                      Next_State <= Previous_State +1;
                   max_count <= GapSize;
                   flag <= 1;
                                       IR_LED = 1'b1;

                  if(change)
                      Curr_State <= Next_State;
                  else 
                      Next_State <= Curr_State;
               end
               1'd2: begin //SELECT
                   Next_State <= 1'd1;
                   Previous_State <= Curr_State;
                   max_count <= CarSelectBurstSize;
                   IR_LED = 1'b0;
                   flag <= 0;
                   if(change)
                       Curr_State <= Next_State;
                   else 
                       Next_State <= Curr_State;
               end
               1'd3: begin //RIGHT
                   if(BTNR)
                       max_count <= AsserBurstSize;
                   else
                       max_count <= DeAssertBurstSize;
                   Next_State <= 1'd1;
                   Previous_State <= Curr_State;
                   flag <= 0;
                   if(change)
                      Curr_State <= Next_State;
                   else 
                      Next_State <= Curr_State;
                       IR_LED = 1'b1;
               end
               1'd4: begin //LEFT
                   if(BTNL)
                       max_count <= AsserBurstSize;
                   else
                       max_count <= DeAssertBurstSize;
                   Next_State <= 1'd1;
                   Previous_State <= Curr_State;
                   flag <= 0;
                   if(change)
                      Curr_State <= Next_State;
                   else 
                      Next_State <= Curr_State;
                       IR_LED = 1'b1;
               end
               1'd5: begin //FORWARD
                   if(BTNU)
                       max_count <= AsserBurstSize;
                   else
                       max_count <= DeAssertBurstSize;
                   Next_State <= 1'd1;
                   Previous_State <= Curr_State;
                   flag <= 0;
                    if(change)
                      Curr_State <= Next_State;
                   else 
                      Next_State <= Curr_State;
                       IR_LED = 1'b1;
               end
               1'd6: begin //Backwards
                   if(BTND)
                       max_count <= AsserBurstSize;
                   else 
                       max_count <= DeAssertBurstSize;
                   Next_State <= 1'd1;
                   Previous_State <= Curr_State;
                   flag <= 0;
                    if(change)
                      Curr_State <= Next_State;
                   else 
                      Next_State <= Curr_State;
                       IR_LED = 1'b1;
               end
           
          endcase
end

ПОСЫЛКА ИМПУЛЬСОВ НА ИК-СВЕТОДИОД

always@(posedge SEC_CLK) begin
    if(send) begin
        if(Pcounter == max_count) begin //COUNTING BLOCK SIZE
            Pcounter <= 0;
            IR_LED=1'b0;   
       end
       else begin
            if(flag)
                IR_LED=1'b0; //GAP
            else 
                IR_LED=1'b1;
            Pcounter <= Pcounter+1;
        end
   end
 end

person Nick    schedule 27.02.2017    source источник
comment
Трудно сказать, не видя вашего кода. Пожалуйста, укажите свой код в вопросе. Скриншот выходных сигналов (например, в ISim) также был бы чрезвычайно полезен.   -  person    schedule 28.02.2017


Ответы (2)


Счетчик sec_counter не сбрасывается, поэтому поведение может быть непредсказуемым (если только вы не указали начальное значение при объявлении регистра). Поскольку вы не включили декларацию в код, трудно сказать.

Дизайн вашего конечного автомата немного необычен, и я думаю, что вы не получаете ожидаемого поведения. Обычно конечные автоматы кодируются одним из двух способов. Один метод помещает вычисление next_state в комбинаторный блок со всеми входными данными конечного автомата и текущим состоянием в списке чувствительности блока. Второй синхронный всегда блок (т. е. список чувствительности posedge clk) кода присваивает next_state текущему_состоянию в положении часов конечного автомата. Второй метод использует один синхронный всегда блок как для конечных автоматов, так и для выходов. В этом случае нет переменной next_state, вы просто присваиваете новое значение непосредственно переменной состояния, обязательно присваивая значение состояния для каждой ветви case или оператора if/else. Вторая версия может работать быстрее, так как все выходы зарегистрированы, первая версия использует меньше логики, и лично мне легче декодировать. Поскольку ваш дизайн очень медленный, я бы предложил использовать первую версию.

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

person Barry Moss    schedule 01.03.2017

Я не знаю, волнует ли вас все еще этот вопрос, но в ваших заявлениях о случаях у вас есть что-то вроде

  1'd2: begin //SELECT

или даже

Previous_State <= 1'd7

Однако 1 означает десятичное число шириной 1 бит, поэтому оно никогда не может быть чем-то отличным от 0 или 1, самые значащие биты просто отбрасываются.

Вы пробовали смоделировать это?

person Marco    schedule 04.06.2017