The basic gist is I'm trying to write an audio synthesizer. The note sequencer engine is based on a "tick" of 60Hz. Each note duration is a multiple of 5 ticks, let's call this a beat (even though it's really a thirty-second note). As such, I'd like a 1-clock pulse (strobe?) every tick and a 1-clock pulse every beat (5 ticks). Then I can count beat pulses for note duration. For example, a note could play for 8 beats (40 ticks), then another note for 4 beats (20 ticks), etc. However, I'm struggling to figure out how to do this.
The tick pulse is pretty easy:
localparam CLOCKS_PER_TICK = 415_667; // 25MHz / 60Hz
localparam TICK_WIDTH = $clog2(CLOCKS_PER_TICK);
reg [TICK_WIDTH-1:0] r_tick_counter = 0;
reg r_tick_pulse = 0;
always @(posedge i_clk) begin
if (r_tick_counter == CLOCKS_PER_TICK) begin
r_tick_counter <= 0;
r_tick_pulse <= 1;
end else begin
r_tick_counter <= r_tick_counter + 1;
r_tick_pulse <= 0;
end
end
The beat pulse seems like it should pretty straightforward: Count 5 tick pulses. However, it ends up being fairly complicated, which means I'm likely doing it wrong:
localparam TICKS_PER_BEAT = 5;
localparam BEAT_WIDTH = $clog2(TICKS_PER_BEAT);
reg [BEAT_WIDTH-1:0] r_beat_counter = 0;
reg r_beat_clk = 0;
reg r_last_beat_clk = 0;
always @(posedge i_clk) begin
if (r_tick_pulse) begin
if (r_beat_counter == TICKS_PER_BEAT-1) begin
r_beat_counter <= 0;
r_beat_clk <= ~r_beat_clk;
end else begin
r_beat_counter <= r_beat_counter + 1;
end
end
r_last_beat_clk <= r_beat_clk;
end
wire r_beat_pulse = r_beat_clk != r_last_beat_clk;
The idea here is r_beat_counter
counts up on every r_tick_pulse
from 0
to 4
. However, figuring out how to get a 1-clock wide pulse seems to require making a fake "clock" r_beat_clk
and then using r_last_beat_clk
to effectively detect any edge (both pos and neg) in this "clock". This feels overly complicated, though. Is there some simpler way to accomplish this?