The goal of this project is to demonstrate the capability of HLS in designing digital systems. For this purpose, I explain how to describe a digital clock in HLS. The NEXYS-4 evaluation board would be our target FPGA platform. If you are interested in learning HLS coding techniques please refer here or here.
The clock shows hours, minutes, and seconds on 7-segment displays.
It has two modes of operation: clock and setting. The clock mode is the standard mode during which the current time is shown on display. In the setting mode, you can use push-buttons to set the time.
The following figure shows the clock configuration on the board.
As shown in the following figure, the design has three main modules: one-second clock generator, digital clock engine and display driver.
The following pipelined loop is used to implement the one-second clock generator.
bool delay(long long int n) {
#pragma HLS INLINE off
static bool dummy = 0;
for (long long int j = 0; j < n; j++) {
#pragma HLS pipeline
dummy = !dummy;
}
return dummy;
}
void one_second_clock_generator(bool &second) {
#pragma HLS INTERFACE ap_none port=second
#pragma HLS INTERFACE ap_ctrl_none port=return
static bool s = 0;
s=!s;
second = s;
delay(50000000L);
}
The digital clock engine keeps track of hours, minutes and seconds and updates them when it receives a clock tick from the one-second clock generator module. The following code does this task.
void debounce(bool pulse, bool &out) {
#pragma HLS INLINE off
static bool out0 = 0;
static bool out1 = 0;
static bool out2 = 0;
static bool state = 0;
if (state == 0) {
out2 = out1;
out1 = out0;
out0 = pulse;
state = 1;
} else {
delay(2500000);
state = 0;
}
out = out0 & out1 & out2;
}
void set_time(
ap_uint<6> &seconds,
ap_uint<6> &minutes,
ap_uint<5> &hours,
bool set_second,
bool set_minute,
bool set_hour)
{
//--------------------------------------------------
static bool second_state = 0;
if (second_state == 0 && set_second == 1 ) {
seconds++;
if (seconds == 60) {
seconds = 0;
}
second_state = 1;
}
if (second_state == 1 && set_second == 0 ) {
second_state = 0;
}
//---------------------------------------------------
static bool minute_state = 0;
if (minute_state == 0 && set_minute == 1 ) {
minutes++;
if (minutes == 60) {
minutes = 0;
}
minute_state = 1;
}
if (minute_state == 1 && set_minute == 0 ) {
minute_state = 0;
}
//----------------------------------------------------
static bool hour_state = 0;
if (hour_state == 0 && set_hour == 1) {
hours++;
if (hours == 24) {
hours = 0;
}
hour_state = 1;
}
if (hour_state == 1 && set_hour == 0) {
hour_state = 0;
}
//----------------------------------------------------
}
void clock_ticking(
ap_uint<5> &hours,
ap_uint<6> &minutes,
ap_uint<6> &seconds)
{
seconds++;
if (seconds == 60) {
seconds = 0;
minutes++;
if (minutes == 60) {
minutes = 0;
hours++;
if (hours == 24)
hours = 0;
}
}
}
void digital_clock(
bool set_time_sw,
bool &set_time_led,
bool set_second,
bool set_minute,
bool set_hour,
bool one_second_delay,
ap_uint<6> &seconds_out,
ap_uint<6> &minutes_out,
ap_uint<5> &hours_out
)
{
#pragma HLS INTERFACE ap_none port=set_time_sw
#pragma HLS INTERFACE ap_none port=set_time_led
#pragma HLS INTERFACE ap_none port=set_minute
#pragma HLS INTERFACE ap_none port=set_hour
#pragma HLS INTERFACE ap_none port=seconds_out
#pragma HLS INTERFACE ap_none port=minutes_out
#pragma HLS INTERFACE ap_none port=hours_out
#pragma HLS INTERFACE ap_ctrl_none port=return
static ap_uint<6> seconds = 0;
static ap_uint<6> minutes = 0;
static ap_uint<5> hours = 0;
ap_uint<8> segment_data;
ap_uint<8> segment_enable;
static bool state_clock = 0;
bool one_second = one_second_delay;
bool set_time_flag = set_time_sw;
if (one_second==1&&set_time_flag==0&&state_clock==0) {
clock_ticking(hours, minutes, seconds);
state_clock = 1;
}
if (one_second==0&&set_time_flag==0&&state_clock==1) {
state_clock = 0;
}
if (set_time_flag == 1) {
bool set_minute_debounce;
bool set_hour_debounce;
bool set_second_debounce;
debounce (set_minute, set_minute_debounce);
debounce (set_hour, set_hour_debounce);
debounce (set_second, set_second_debounce);
set_time(seconds, minutes, hours, set_second_debounce, set_minute_debounce, set_hour_debounce);
}
seconds_out = seconds;
minutes_out = minutes;
hours_out = hours;
set_time_led = set_time_sw;
}
And the last HLS code shows the current time on the 7-segment display.
#include <ap_int.h>
const ap_uint<8> seven_segment_code[10] = {
0b11000000,
0b11111001,
0b10100100,
0b10110000,
0b10011001,
0b10010010,
0b10000010,
0b11111000,
0b10000000,
0b10010000
};
bool delay(long long int n) {
#pragma HLS INLINE off
static bool dummy = 0;
for (long long int j = 0; j < n; j++) {
#pragma HLS pipeline
dummy = !dummy;
}
return dummy;
}
void seven_segment_display(
ap_uint<5> hours,
ap_uint<6> minutes,
ap_uint<6> seconds,
ap_uint<8> &seven_segment_data,
ap_uint<8> &seven_segment_enable)
{
#pragma HLS INTERFACE ap_none port=hours
#pragma HLS INTERFACE ap_none port=minutes
#pragma HLS INTERFACE ap_none port=seconds
#pragma HLS INTERFACE ap_none port=seven_segment_data
#pragma HLS INTERFACE ap_none port=seven_segment_enable
#pragma HLS INTERFACE ap_ctrl_none port=return
ap_uint<4> second_digit_1 = seconds%10;
ap_uint<4> second_digit_2 = seconds/10;
ap_uint<4> minute_digit_1 = minutes%10;
ap_uint<4> minute_digit_2 = minutes/10;
ap_uint<4> hours_digit_1 = hours%10;
ap_uint<4> hours_digit_2 = hours/10;
ap_uint<8> segment_data;
ap_uint<8> segment_enable;
static ap_uint<3> state = 0;
switch (state) {
// second
case 0:
segment_data = seven_segment_code[second_digit_1];
segment_enable = 0b11111110;
delay(250000L);
state = 1;
break;
case 1:
segment_data = seven_segment_code[second_digit_2];
segment_enable = 0b11111101;
state = 2;
delay(250000L);
break;
// minutes
case 2:
segment_data = seven_segment_code[minute_digit_1];
segment_enable = 0b11110111;
state = 3;
delay(250000L);
break;
case 3:
segment_data = seven_segment_code[minute_digit_2];
segment_enable = 0b11101111;
state = 4;
delay(250000L);
break;
// hours
case 4:
segment_data = seven_segment_code[hours_digit_1];
segment_enable = 0b10111111;
state = 5;
delay(250000L);
break;
case 5:
segment_data = seven_segment_code[hours_digit_2];
segment_enable = 0b01111111;
state = 0;
delay(250000L);
break;
default:
segment_data = seven_segment_code[0];
segment_enable = 0b11111111;
state = 0;
delay(250000L);
break;
}
seven_segment_data = segment_data;
seven_segment_enable = segment_enable;
}
After synthesising these codes, we should use the Xilinx Vivado toolset to connect them together and generate the FPGA bitstream.
After programming the board, you can test the design.
Comments
Please log in or sign up to comment.