Matt Venn | dfc149e | 2022-11-24 16:39:10 +0100 | [diff] [blame] | 1 | `default_nettype none |
| 2 | |
| 3 | module krasin_3_bit_8_channel_pwm_driver ( |
| 4 | input [7:0] io_in, |
| 5 | output [7:0] io_out |
| 6 | ); |
| 7 | |
| 8 | wire clk = io_in[0]; |
| 9 | wire pset = io_in[1]; |
| 10 | wire [2:0] addr = io_in[4:2]; |
| 11 | wire [2:0] level = io_in[7:5]; |
| 12 | |
| 13 | wire [7:0] pwm_out; |
| 14 | assign io_out[7:0] = pwm_out; |
| 15 | |
| 16 | // This register is used to determine if the execution just started and we need to reset. |
| 17 | // It's a bullshit implementation and will most likely not work. I am curious to test it anyway. |
| 18 | // The idea is that initially this register has a somewhat random value. If it does not match what we expect, |
| 19 | // we're in a reset mode and set this register to the expected state + reset all other registers. |
| 20 | // This is not a great way, as it does not guarantee anything, but I already use all input pins and |
| 21 | // like to live dangerously. |
| 22 | reg[8:0] reset_canary = 0; |
| 23 | |
| 24 | // 3-bit PWM counter that goes from 0 to 7. |
| 25 | reg [2:0] counter; |
| 26 | |
| 27 | function is_reset (input [8:0] a); |
| 28 | begin |
| 29 | is_reset = (a != 8'b01010101); |
| 30 | end |
| 31 | endfunction |
| 32 | |
| 33 | // PWM level for channel0. |
| 34 | // 0 means always off. |
| 35 | // 1 means that PWM will be on for just 1 clock cycle and then off for the other 6, giving 1/7 on average. |
| 36 | // 6 means 6/7 on. |
| 37 | // 7 means always on. |
| 38 | reg [2:0] pwm0_level; |
| 39 | // The rest of the channels. |
| 40 | reg [2:0] pwm1_level; |
| 41 | reg [2:0] pwm2_level; |
| 42 | reg [2:0] pwm3_level; |
| 43 | reg [2:0] pwm4_level; |
| 44 | reg [2:0] pwm5_level; |
| 45 | reg [2:0] pwm6_level; |
| 46 | reg [2:0] pwm7_level; |
| 47 | |
| 48 | function is_on(input [3:0] level, input[3:0] counter); |
| 49 | begin |
| 50 | is_on = (counter < level); |
| 51 | end |
| 52 | endfunction // is_on |
| 53 | |
| 54 | assign pwm_out[0] = is_on(pwm0_level, counter); |
| 55 | assign pwm_out[1] = is_on(pwm1_level, counter); |
| 56 | assign pwm_out[2] = is_on(pwm2_level, counter); |
| 57 | assign pwm_out[3] = is_on(pwm3_level, counter); |
| 58 | assign pwm_out[4] = is_on(pwm4_level, counter); |
| 59 | assign pwm_out[5] = is_on(pwm5_level, counter); |
| 60 | assign pwm_out[6] = is_on(pwm6_level, counter); |
| 61 | assign pwm_out[7] = is_on(pwm7_level, counter); |
| 62 | |
| 63 | // external clock is 1000Hz. |
| 64 | always @(posedge clk) begin |
| 65 | // if reset, set counter and pwm levels to 0 |
| 66 | if (is_reset(reset_canary)) begin |
| 67 | reset_canary = 8'b01010101; |
| 68 | counter <= 0; |
| 69 | pwm0_level <= 0; |
| 70 | pwm1_level <= 0; |
| 71 | pwm2_level <= 0; |
| 72 | pwm3_level <= 0; |
| 73 | pwm4_level <= 0; |
| 74 | pwm5_level <= 0; |
| 75 | pwm6_level <= 0; |
| 76 | pwm7_level <= 0; |
| 77 | end else begin // if (is_reset(reset_canary)) |
| 78 | if (counter == 6) begin |
| 79 | // Roll over. |
| 80 | counter <= 0; |
| 81 | end else begin |
| 82 | // increment counter |
| 83 | counter <= counter + 1'b1; |
| 84 | end |
| 85 | if (pset) begin |
| 86 | case (addr) |
| 87 | 0: pwm0_level <= level; |
| 88 | 1: pwm1_level <= level; |
| 89 | 2: pwm2_level <= level; |
| 90 | 3: pwm3_level <= level; |
| 91 | 4: pwm4_level <= level; |
| 92 | 5: pwm5_level <= level; |
| 93 | 6: pwm6_level <= level; |
| 94 | 7: pwm7_level <= level; |
| 95 | endcase |
| 96 | end // if (set) |
| 97 | end |
| 98 | end // always @ (posedge clk) |
| 99 | endmodule |