Hybrid-Input Effects Pedalboard for Guitar

Herma

.
Joined
Mar 1, 2016
Messages
63
Likes
87
Location
Tokyo
Hay guise.

This is my senior project, figured I'd share it. I'm doing a large chunk of the SystemVerilog code (and some C code to control a menu).

It's ongoing for the next two months or so. I can gradually post PCB designs and such we have to come up with.

Basically my lab partner and I are making an FPGA based guitar guitar effects pedal board with routing between external guitar effects pedals and the internal DSP modules we will have.

That is, there are 3 internal DSP modules, you can plug in 3 pedals and route them as you please. Initially we were doing 4 instead of 3, but we decided to cut back to 3 to make things a bit easier (since there are 3 that means there are 3! possible routing combinations, so 6. For 4 there are 24, etc. So this isn't too scalable, but yeah).

If you want I can give you some of the test SystemVerilog I am currently using, though right now it's still pretty early on. Things will be really rolling in the next 2 weeks once we get parts in and start actually testing.
Block diagram:
445_Overview.png

A really quick gate level simulation on the routing:
gatesim.png

Code:
module router_control
(
    input [2:0] route_case,
    output logic [1:0] a_mux, b_mux, c_mux,
    output logic [1:0] a_demux, b_demux, c_demux
);
always_comb
begin
    a_mux = 2'b00;
    b_mux = 2'b00;
    c_mux = 2'b00;
    a_demux = 2'b00;
    b_demux = 2'b00;
    c_demux = 2'b00;
    case(route_case)
    0 : /*default case*/; //abc
    1 : begin                 //acb
    a_mux = 2'b00;
    b_mux = 2'b10;
    c_mux = 2'b10;
    a_demux = 2'b01;
    b_demux = 2'b10;
    c_demux = 2'b01;
    end
    2 : begin                 //bac
    a_mux = 2'b10;
    b_mux = 2'b01;
    c_mux = 2'b10;
    a_demux = 2'b10;
    b_demux = 2'b01;
    c_demux = 2'b00;
    end
    3 : begin                 //bca
    a_mux = 2'b10;
    b_mux = 2'b01;
    c_mux = 2'b00;
    a_demux = 2'b10;
    b_demux = 2'b00;
    c_demux = 2'b10;
    end
    4 : begin                 //cab
    a_mux = 2'b01;
    b_mux = 2'b00;
    c_mux = 2'b01;
    a_demux = 2'b00;
    b_demux = 2'b10;
    c_demux = 2'b10;
    end
    5 : begin                 //cba
    a_mux = 2'b10;
    b_mux = 2'b10;
    c_mux = 2'b01;
    a_demux = 2'b10;
    b_demux = 2'b01;
    c_demux = 2'b01;
    end
    default : ;
    endcase
end

endmodule : router_control
Code:
module router(input [1:0] a_mux, b_mux, c_mux,
                                  a_demux, b_demux, c_demux,
                  input          a_pedal, b_pedal, c_pedal, stomp_a, stomp_b, stomp_c,
                  input [23:0] audio_in, pedal_ao, pedal_bo, pedal_co,
                  output [23:0] audio_out, pedal_ai, pedal_bi, pedal_ci
);
//internal signals
logic [23:0] a_in, a_out, b_in, b_out, c_in, c_out;
logic [23:0] a_b,a_c,a_o,b_c,b_a,b_o,c_a,c_b,c_o;

//a
mux_24 mux_a(.a(audio_in),.b(b_a),.c(c_a),.d(),.sel(a_mux),.out(a_in));
dsp_pedal a(.audio_in(a_in),.out(a_out),.pedal_out(pedal_ao),.is_pedal(a_pedal),.pedal_in(pedal_ai),.stomp(stomp_a));
demux_24 demux_a(.in(a_out),.sel(a_demux),.out_a(a_b),.out_b(a_c),.out_c(a_o),.out_d());

//b
mux_24 mux_b(.a(a_b),.b(audio_in),.c(c_b),.d(),.sel(b_mux),.out(b_in));
dsp_pedal b(.audio_in(b_in),.out(b_out),.pedal_out(pedal_bo),.is_pedal(b_pedal),.pedal_in(pedal_bi),.stomp(stomp_b));
demux_24 demux_b(.in(b_out),.sel(b_demux),.out_a(b_c),.out_b(b_a),.out_c(b_o),.out_d());

//c
mux_24 mux_c(.a(b_c),.b(audio_in),.c(a_c),.d(),.sel(c_mux),.out(c_in));
dsp_pedal c(.audio_in(c_in),.out(c_out),.pedal_out(pedal_co),.is_pedal(c_pedal),.pedal_in(pedal_ci),.stomp(stomp_c));
demux_24 demux_c(.in(c_out),.sel(c_demux),.out_a(c_o),.out_b(c_b),.out_c(c_a),.out_d());


assign audio_out = (a_o + b_o + c_o);

endmodule : router
Demux _24 is a 24 bit 1:4 demux (the non-used outputs are defaulted to 24'b0). mux_24 is a 24 bit 4:1 mux.
 
Last edited:

ShockSlayer

Ivan - the tyranny of evil men
.
.
Joined
Jan 16, 2016
Messages
1,493
Likes
3,757
Location
Ragnarok, re-entry
Portables
All

Herma

.
Joined
Mar 1, 2016
Messages
63
Likes
87
Location
Tokyo
Small update, have some code for the DAC/ADC. Gonna probably change it some, and it's not tested yet. But once that works it's just implementing the guitar effects and making a software menu and handshake state machine for sending data and I think it's about done. Gonna have some PCBs ordered this evening I think, as well.
Code:
module deserializer
(
    input SCK,
    input in,
    input begin_receive,
    output LRCK,
    output BCK,
    output [23:0] left,
    output [23:0] right
);
logic [23:0] running_left, running_right;
/*
BCK = 48*f_s = SCK / 8
LRCK = f_s
SCK = 384*f_s = 16934400 Hz
f_s = 44.1 kHz


Binary 2's complement MSB-first audio data
*/
clk_div_2N div_8 //Divide SCK by 8 to get BCK, set defaults to 8
(
.clk(SCK),
.reset(begin_receive),
.clk_out(BCK)
);

clk_div_2N  #(.WIDTH(8), .N(9'd192)) div_384 //Since you do a division by 2N, 192 * 2 = 384
(
.clk(SCK),
.reset(begin_receive),
.clk_out(LRCK)
);

logic [4:0] count;
logic old_lrck, lr_rise, lr_fall;
assign lr_rise = (LRCK & !old_lrck);
assign lr_fall = (old_lrck & !LRCK);

always @(posedge BCK or posedge begin_receive)
begin
    if(begin_receive)
    begin
        count <= 5'b10111;
    end
   
    if (lr_rise)
    begin
        running_left[count] <= in; //left channel
    end
    else if (lr_fall)
    begin
        running_right[count] <= in; //right channel
    end
   
    if (count == 5'h00) //last one
    begin
    count <= 5'b10111;
    left <= running_left;
    right <= running_right;
    end
    else
    count = count - 1;
end

endmodule : deserializer
Code:
module serializer
(
    input SCK,
    input [23:0] left,
    input [23:0] right,
    input begin_transmit,
    output LRCK,
    output BCK,
    output out
);
/*
BCK = 48*f_s = SCK / 8
LRCK = f_s
SCK = 384*f_s = 16934400 Hz
f_s = 44.1 kHz


Binary 2's complement MSB-first audio data
*/
clk_div_2N div_8 //Divide SCK by 8 to get BCK, set defaults to 8
(
.clk(SCK),
.reset(begin_transmit),
.clk_out(BCK)
);

clk_div_2N #(.WIDTH(8), .N(9'd192))div_384 //Since you do a division by 2N, 192 * 2 = 384
(
.clk(SCK),
.reset(begin_transmit),
.clk_out(LRCK)
);

logic [4:0] count; // count from 00000 to 10111 (24)
logic old_lrck, lr_rise, lr_fall;
assign lr_rise = (LRCK & !old_lrck);
assign lr_fall = (old_lrck & !LRCK);

always @ (posedge BCK or posedge begin_transmit)
begin
    if (begin_transmit)
    begin
    count <= 5'b10111;
    end
    if (lr_rise) //left channel
    begin
        out <= left[count];
    end
    else if (lr_fall) //right channel
    begin
        out = right[count];
    end
   
    if (count == 5'h00) //last one
    begin
    count <= 5'b10111;
    end
    else
    count = count - 1;
end


endmodule : serializer
Code:
module clk_div_2N #(parameter WIDTH = 3, parameter N = 4) //default for division by 8
(
    input clk,
    input reset,
    output clk_out
);
logic [WIDTH-1:0] count;
logic [WIDTH-1:0] next;
logic running_clk;

always @ (posedge clk or posedge reset)
begin
    if (reset)
    begin
        count <= 0;
        running_clk <= 0;
    end
   
    else if (next == N)
    begin
        count <= 0;
        running_clk <= ~running_clk;
    end
   
    else
        count <= next;
end

assign next = count + 1;
assign clk_out = running_clk;

endmodule : clk_div_2N
 

ShockSlayer

Ivan - the tyranny of evil men
.
.
Joined
Jan 16, 2016
Messages
1,493
Likes
3,757
Location
Ragnarok, re-entry
Portables
All
brb stealing your code and making my own
 

Herma

.
Joined
Mar 1, 2016
Messages
63
Likes
87
Location
Tokyo
Tbh probs doesn't work right now. I think I forgot to assign the old LRCK value in the always block. I mean, quick fix. But there's still a chance that my code doesn't work, plus it depends on the format you're sending to/from the DAC/ADCs. This is for left justified. Originally we were going to use I2S but then decided nah. (Mostly because the default setting of the DAC is left justified, otherwise I would have to make another state machine to program the internal registers).
 

Herma

.
Joined
Mar 1, 2016
Messages
63
Likes
87
Location
Tokyo
Too lazy to do a full writeup, here's our final report. Long story short, didn't get everything working, most of it was working, but there were a few things that forced the whole project to not be operational. (Mostly ADC/GPIO problems, the ADC wasn't able to send the signal through the FPGA GPIO, there were current draw issues, more than likely it was the GPIO for the dev kit being weird. This could have been fixed with a high speed buffer had we noticed it in time, however we noticed this was the issue far too late and couldn't realistically order a buffer in the time needed).

Also github:
https://github.com/jdwilsn2/ECE445
 

Attachments

Last edited:
Top