0

This is my first post and my first attempt at using a PLD.

I have written some code to make a breathing LED with 7 set points. The code produces a pwm output according to the first set point. It then slowly increases/decreases the pwm towards the next set point (7 in total).

The code works but I think it can be done better as I need to put 16 instantiations of this into a Lattice 4256 CPLD (not possible with my code). I am keen to learn how a professional Verilog programmer would tackle this. Many thanks in advance for your support. PWM Generation

module LED_breath (led, tmr_clk);

output  reg led;
input           tmr_clk;
reg     [7:0]   cnt;
reg     [6:0]   pwm_cnt;
reg     [6:0]   pwm_val;
reg     [2:0]   pat_cnt;
reg     [9:0]   delay_cnt;
reg     [6:0]   cur_pat;
reg     [6:0]   nxt_pat;


parameter pattern = {7'h00, 7'h00, 7'h00, 7'h00, 7'h00, 7'h00, 7'h00, 7'h00};


always @(posedge tmr_clk)
    begin
        pwm_cnt = cnt[7] ? ~cnt[6:0] : cnt[6:0];      //Generate triangle wave
        if(pwm_cnt > pwm_val)                         //Generate pwm
            led <= 1'b0;
        if(pwm_cnt < pwm_val)
            led <= 1'b1;
        cnt = cnt + 1;
    end

always @(posedge tmr_clk)                                   //breathing pattern
    begin
        if(!delay_cnt)                                  //Add delay
            begin

                cur_pat <= ((pattern >> (7*pat_cnt)) & 7'b1111111);     //Find correct pattern No. from parameter list

                if((pat_cnt+1) == 8)                        //Check for last pattern - overflow, set to 0
                    nxt_pat <= (pattern & 7'b1111111);
                else
                    nxt_pat <= ((pattern >> (7*(pat_cnt+1))) & 7'b1111111);

                if(pwm_val == nxt_pat)                      //If pwm is at max or min increment count to get next pattern
                    pat_cnt <= pat_cnt + 1;     

                if(cur_pat <= nxt_pat)                      //Current pattern < next pattern, count up
                    pwm_val <= pwm_val + 1;
                if(cur_pat >= nxt_pat)                      //Current pattern < next pattern, count down
                    pwm_val <= pwm_val - 1;

            end

        delay_cnt <= delay_cnt + 1;

    end

endmodule



module top (led_0, led_1, led_2, led_3);

output  led_0;
output  led_1;
output  led_2;
output  led_3;

defparam I1.TIMER_DIV = "128";
OSCTIMER I1 (.DYNOSCDIS(1'b0), .TIMERRES(1'b0), .OSCOUT(osc_clk), .TIMEROUT(tmr_clk));


LED_breath #(.pattern({7'h20, 7'h70, 7'h50, 7'h70, 7'h40, 7'h10, 7'h60, 7'h10})) led_A(
    .led        (led_0),
    .tmr_clk    (tmr_clk)
    );

LED_breath #(.pattern({7'h70, 7'h10, 7'h30, 7'h20, 7'h60, 7'h40, 7'h70, 7'h10})) led_B(
    .led        (led_1),
    .tmr_clk    (tmr_clk)
    );

LED_breath #(.pattern({7'h10, 7'h30, 7'h10, 7'h18, 7'h40, 7'h50, 7'h30, 7'h60})) led_C(
    .led        (led_2),
    .tmr_clk    (tmr_clk)
    );

LED_breath #(.pattern({7'h50, 7'h70, 7'h40, 7'h50, 7'h40, 7'h70, 7'h60, 7'h70})) led_D(
    .led        (led_3),
    .tmr_clk    (tmr_clk)
    );

endmodule
Greg
  • 18,111
  • 5
  • 46
  • 68
Karl
  • 1
  • 2

1 Answers1

0

Can you explain a bit what you are trying to achieve in this always block ?

always @(posedge tmr_clk)

I think you're using a fixed frequency and changing duty cycle to get desired breathing effect.

1) Is my thinking correct ?

2) If yes, how do you decide when to change the pattern ?

Displayname
  • 25
  • 1
  • 10
  • Thank you for your reply. I am passing 8 7-bit constant values (the led brightness) to the always block. The values are extracted by bit shifting as I cannot access them using an array syntax (like cur_pat[x]). The PWM is constant frequency as you mention. The extracted values are used to determine the next end brightness value. The PWM is slowly incremented (or decremented) to reach this value using the delay_cnt loop. When the brightness level is reached the direction of the count (pwm_val_ is reversed. – Karl Nov 07 '16 at 09:41