I want to make a counter with the 4 LEDs on a Zybo board that counts from 0 to 15. Also I want the 4 buttons of the board to correspond to a different frequency for the changes of the LEDs (0.5Hz, 1Hz, 2Hz, 4Hz). I have already achieved the simple counter with a fixed frequency but not the second part with the button frequency changes.
In the Block Design, I have a Zynq Processing System, an AXI GPIO which reads the button data and a custom IP that functions as the driver for the LEDs, the clock divider and the frequency changer.
Custom IP
The clock divider module code.
module Clock_Divider(
input clk,
input rst,
input reg0,
output reg clk_out
);
reg [31:0] count;
reg constantNumber;
always @ (reg0)
begin
if(reg0 == 0000)
constantNumber = 50000000;
else if(reg0 == 0001)
constantNumber = 100000000;
else if(reg0 == 0010)
constantNumber = 50000000;
else if(reg0 == 0100)
constantNumber = 25000000;
else if(reg0 == 1000)
constantNumber = 12500000;
else
constantNumber = 50000000;
end
always @ (posedge(clk), posedge(rst))
begin
if (rst == 1'b1)
begin
count <= 32'b0;
end
else if (count == constantNumber - 1)
begin
count <= 32'b0;
end
else
begin
count <= count + 1;
end
end
always @ (posedge(clk), posedge(rst))
begin
if (rst == 1'b1)
clk_out <= 1'b0;
else if (count == constantNumber - 1)
clk_out <= ~clk_out;
else
clk_out <= clk_out;
end
endmodule
The register constantNumber takes the corresponding value in order to change the clock frequency.
The rest of the custom IP logic.
Clock_Divider UIP (.clk(S_AXI_ACLK), .rst(), .reg0(slv_reg0), .clk_out(clk_out));
reg [3:0] counter = 0;
always @(posedge clk_out)
begin
if(counter < PWM_COUNTER_MAX-1)
begin
counter <= counter + 1;
end
else
counter <= 0;
end
assign PWM0 = counter[0];
assign PWM1 = counter[1];
assign PWM2 = counter[2];
assign PWM3 = counter[3];
The button data are sent to the first register of the custom IP (slv_reg0) which in turn sends them to reg0 in the Clock_Divider module.
Main C program
#include <stdio.h>
#include "platform.h"
#include <xgpio.h>
#include "xparameters.h"
#include "sleep.h"
#include "xil_io.h"
//#define MY_PWM XPAR_MY_PWM_CORE_0_S00_AXI_BASEADDR //Because of a bug in Vivado 2015.3 and 2015.4, this value is not correct.
#define MY_PWM 0x43C00000 //This value is found in the Address editor tab in Vivado (next to Diagram tab)
int main(){
XGpio input;
int button_data = 0;
XGpio_Initialize(&input, XPAR_AXI_GPIO_0_DEVICE_ID); //initialize input XGpio variable
XGpio_SetDataDirection(&input, 1, 0xF); //set first channel tristate buffer to input
init_platform();
while(1){
button_data = XGpio_DiscreteRead(&input, 1); //get button data
if(button_data == 0b0000){
Xil_Out32(MY_PWM, button_data);
}
else if(button_data == 0b0001){
xil_printf("button 0 pressed\n\r");
Xil_Out32(MY_PWM, button_data);
}
else if(button_data == 0b0010){
xil_printf("button 1 pressed\n\r");
Xil_Out32((MY_PWM), button_data);
}
else if(button_data == 0b0100){
xil_printf("button 2 pressed\n\r");
Xil_Out32((MY_PWM), button_data);
}
else if(button_data == 0b1000){
xil_printf("button 3 pressed\n\r");
Xil_Out32((MY_PWM), button_data);
}
else{
xil_printf("multiple buttons pressed\n\r");
Xil_Out32(MY_PWM, 0b0000);
}
}
cleanup_platform();
return 0;
}
I can confirm that the button data are correctly read by the AXI GPIO because when they are pressed the correct lines are printed in the terminal. But when I press the buttons, the frequency does not change. Also it runs with a very slow frequency, much slower than the 1Hz that should be the default even if the button data did not get sent to the custom IP.
The problem has to lie somewhere either with the reg0 case logic in the custom IP or the sending of the button data from the cpu to the register of the custom IP.
I made the changes that Greg proposed plus some of my own and I got it working at last.
In the clock divider file I made the following changes.
input [3:0] reg0,
reg [31:0] constantNumber;
always @ (reg0)
begin
if(reg0 == 4'b0000)
constantNumber = 50000000;
else if(reg0 == 4'b0001)
constantNumber = 100000000;
else if(reg0 == 4'b0010)
constantNumber = 50000000;
else if(reg0 == 4'b0100)
constantNumber = 25000000;
else if(reg0 == 4'b1000)
constantNumber = 12500000;
else
constantNumber = 50000000;
end
I made consantNumber 32 bits in order to be sure there are no overflows.
In the custom IP logic I changed the parameter for the reg0 in order to send the correct (last) bits of the slv_reg0 to it.
Clock_Divider UIP (.clk(S_AXI_ACLK), .rst(), .reg0(slv_reg0[3:0]), .clk_out(clk_out));
And last but not least the changes in the c program.
if(button_data == 0b0001){
xil_printf("button 0 pressed\n\r");
Xil_Out32(MY_PWM, 0b0001);
}
else if(button_data == 0b0010){
xil_printf("button 1 pressed\n\r");
Xil_Out32((MY_PWM), 0b0010);
}
else if(button_data == 0b0100){
xil_printf("button 2 pressed\n\r");
Xil_Out32((MY_PWM), 0b0100);
}
else if(button_data == 0b1000){
xil_printf("button 3 pressed\n\r");
Xil_Out32((MY_PWM), 0b1000);
}
else if(button_data > 0b0000){
xil_printf("button 3 pressed\n\r");
Xil_Out32((MY_PWM), 0b0000);
}
I got rid of the:
if(button_data == 0b0000){
Xil_Out32(MY_PWM, button_data);
}
because after a few clock ticks no button is pressed and it would send a 0000 signal to the slv_reg0.