// Synchronizer.v
// 2016/06/29 by marsee
//
`default_nettype none
module Synchronizer #(
parameter integer NUMBER_OF_STAGES = 2,
parameter integer BIT_WIDTHS = 1
)(
input wire clk,
input wire [BIT_WIDTHS-1:0] inp,
output wire [BIT_WIDTHS-1:0] outp
);
integer i;
reg [BIT_WIDTHS-1:0] ff[NUMBER_OF_STAGES-1:0];
always @(posedge clk) begin : proc_gen_ff
for (i=0; i<=NUMBER_OF_STAGES-1; i=i+1) begin
if (i==0) begin
ff[i] <= inp;
end else begin
ff[i] <= ff[i-1];
end
end
end
assign outp = ff[NUMBER_OF_STAGES-1];
endmodule
`default_nettype wire
// Synchronizer_tb.v
// 2016/06/29 by marsee
//
`timescale 100ps / 1ps
module Synchronizer_tb;
parameter integer NUMBER_OF_STAGES = 2;
parameter integer BIT_WIDTHS = 1;
reg [BIT_WIDTHS-1:0] inp;
wire [BIT_WIDTHS-1:0] outp;
reg clk = 1'b0;
Synchronizer # (
.NUMBER_OF_STAGES(NUMBER_OF_STAGES),
.BIT_WIDTHS(BIT_WIDTHS)
) uut (
.clk(clk),
.inp(inp),
.outp(outp)
);
initial begin
inp = 0;
#1000
inp = -1;
#7000
inp = 0;
end
always #(500)
clk = ~clk;
endmodule
の場合のシミュレーション結果を示す。parameter integer NUMBER_OF_STAGES = 3;
parameter integer BIT_WIDTHS = 8;
// motor_monitor.cpp
// 2016/06/15 by marsee
// 2016/06/25 : overflow を削除、return 1 のときがoverflow
//
#include <ap_int.h>
#include <hls_stream.h>
#include "motor_monitor.h"
int motor_monitor(hls::stream<ap_uint_1 >& sa, hls::stream<ap_uint_1 >& sb,
ap_uint<32> & sa_count, ap_uint_1 & sb_level){
#pragma HLS INTERFACE s_axilite port=return
#pragma HLS INTERFACE s_axilite port=sb_level
#pragma HLS INTERFACE s_axilite port=sa_count
#pragma HLS INTERFACE ap_hs port=sa
#pragma HLS INTERFACE ap_hs port=sb
ap_uint_1 sad;
ap_uint_1 sbd;
for (sa_count=0; sa_count!=0xffffffff; sa_count++){ // sa=1の間はループ
#pragma HLS PIPELINE II=1
sa >> sad;
sb >> sbd;
if (!sad)
break;
}
if (sa_count == 0xffffffff) // overflow
return 1;
for (sa_count=1; sa_count!=0xffffffff; sa_count++){ // sa=0の間はループ
#pragma HLS PIPELINE II=1
sa >> sad;
sb >> sbd;
if (sad)
break;
}
if (sa_count == 0xffffffff) // overflow
return 1;
sb_level = sbd; // saが立ち上がった時のsbの値
for (sa_count++; sa_count!=0xffffffff; sa_count++){ // sa=1の間はループ
#pragma HLS PIPELINE II=1
sa >> sad;
sb >> sbd;
if (!sad)
break;
}
if (sa_count == 0xffffffff) // overflow
return 1;
return 0;
}
// motor_monitor_tb.cpp
// 2016/06/15 by marsee
// 2016/06/25 : overflow を削除、return 1 のときがoverflow
//
#include <ap_int.h>
#include <hls_stream.h>
#include "motor_monitor.h"
#define DATASIZE 20
int motor_monitor(hls::stream<ap_uint_1 >& sa, hls::stream<ap_uint_1 >& sb,
ap_uint<32> & sa_count, ap_uint_1 & sb_level);
int main(){
using namespace std;
ap_uint_1 saa[DATASIZE] = {1,1,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,1,1,1};
ap_uint_1 sba[DATASIZE] = {0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1};
hls::stream<ap_uint_1> sa;
hls::stream<ap_uint_1> sb;
ap_uint<32> sa_count;
ap_uint_1 sb_level;
for (int i=0; i<DATASIZE; i++){
sa << saa[i];
sb << sba[i];
}
int ret_val = motor_monitor(sa, sb, sa_count, sb_level);
printf("sa_count = %d, sb_level = %d, return value = %d\n",
(unsigned int)sa_count, (unsigned int)sb_level, ret_val);
return 0;
}
// PWMmodule.cpp
// 2016/06/08 by marsee
// PmodHB5のPWM用モジュール
// 100MHzのクロックで2KHz(500us)のPWM出力(最初に500分周する)
#include <ap_int.h>
#define PWM_MAX_VALUE 100
#define PWM_WAIT_CLOCK 500
void pwm(ap_uint<7> sw_late, ap_uint<1> dir,
volatile ap_uint<1> & pwm_out, ap_uint<1> & dir_out){
#pragma HLS INTERFACE s_axilite port=dir
#pragma HLS INTERFACE ap_none register port=dir_out
#pragma HLS INTERFACE ap_none register port=pwm_out
#pragma HLS INTERFACE s_axilite port=sw_late
#pragma HLS INTERFACE s_axilite port=return
dir_out = dir;
for (int i=1; i<=PWM_MAX_VALUE; i++){
for (int n=0; n<PWM_WAIT_CLOCK; n++){
#pragma HLS PIPELINE II=1 rewind
if (sw_late == 0){
pwm_out = 0;
} else if(i>=1 && sw_late >= i){
pwm_out = 1;
} else if (sw_late < i){
pwm_out = 0;
}
}
}
}
// PWMmodule_tb.cpp
// 2016/06/08 by marsee
// PWMmodule用テストベンチ
//
#include <ap_int.h>
void pwm(ap_uint<7> sw_late, ap_uint<1> dir,
volatile ap_uint<1> & pwm_out, ap_uint<1> & dir_out);
int main(){
ap_uint<1> pwm_out;
ap_uint<1> dir_out;
pwm(0, 0, pwm_out, dir_out);
pwm(50, 1, pwm_out, dir_out);
pwm(100, 0, pwm_out, dir_out);
return 0;
}
/* * PWM_test.c * * Created on: 2016/06/20 * Author: ono */
#include <stdio.h>
#include <stdlib.h>
#include "xil_io.h"
#include "xparameters.h"
#include "sleep.h"
#include "xpwm.h"
int main(){
XPwm XPwmL, XPwmR;
XPwm_Config *XPwmLPtr, *XPwmRPtr;
XPwmLPtr = XPwm_LookupConfig(0);
if(!XPwmLPtr){
fprintf(stderr, "Left XPwm configuration failed.\n");
return(-1);
}
int XPwmL_status = XPwm_CfgInitialize(&XPwmL, XPwmLPtr);
if (XPwmL_status != XST_SUCCESS){
fprintf(stderr, "Could not Initialize Left XPwm\n");
return(-1);
}
XPwmRPtr = XPwm_LookupConfig(1);
if(!XPwmRPtr){
fprintf(stderr, "Right XPwm configuration failed.\n");
return(-1);
}
int XPwmR_status = XPwm_CfgInitialize(&XPwmR, XPwmRPtr);
if (XPwmR_status != XST_SUCCESS){
fprintf(stderr, "Could not Initialize Right XPwm\n");
return(-1);
}
XPwm_Set_sw_late_V(&XPwmL, 0); // 25で車輪が回り始める
XPwm_Set_sw_late_V(&XPwmR, 0); // 25で車輪が回り始める
XPwm_Set_dir_V(&XPwmL, 1); // 1 - 正転、0 - 逆転
XPwm_Set_dir_V(&XPwmR, 0); // 0 - 正転、1 - 逆転
XPwm_DisableAutoRestart(&XPwmL);
while(!XPwm_IsIdle(&XPwmL)) ;
XPwm_Start(&XPwmL);
XPwm_EnableAutoRestart(&XPwmL);
XPwm_DisableAutoRestart(&XPwmR);
while(!XPwm_IsIdle(&XPwmR)) ;
XPwm_Start(&XPwmR);
XPwm_EnableAutoRestart(&XPwmR);
return 0;
}
int PmodHB5_inf(ap_uint<7> sw_late, ap_uint<1> dir, volatile ap_uint<1> & pwm_out, ap_uint<1> & dir_out,
hls::stream<ap_uint_1 >& sa, hls::stream<ap_uint_1 >& sb,
ap_uint<32> & sa_count, ap_uint_1 & sb_level, ap_uint_1 & overflow){
#pragma HLS DATAFLOW
#pragma HLS INTERFACE s_axilite port=dir
#pragma HLS INTERFACE ap_none register port=dir_out
#pragma HLS INTERFACE ap_none register port=pwm_out
#pragma HLS INTERFACE s_axilite port=sw_late
#pragma HLS INTERFACE s_axilite port=return
#pragma HLS INTERFACE s_axilite port=overflow
#pragma HLS INTERFACE s_axilite port=sb_level
#pragma HLS INTERFACE s_axilite port=sa_count
#pragma HLS INTERFACE ap_hs port=sb
#pragma HLS INTERFACE ap_hs port=sa
pwm(sw_late, dir, pwm_out, dir_out);
motor_monitor(sa, sb, sa_count, sb_level, overflow);
return 0;
}
// PmodHB5_inf.h
// 2016/06/20 by marsee
//
#ifndef __MOTOR_MONITOR___
#define __MOTOR_MONITOR___
#include <ap_int.h>
typedef ap_uint<1> ap_uint_1;
#define PWM_MAX_VALUE 100
#define PWM_WAIT_CLOCK 500
#define PWM_ALL_CLOCKS ((PWM_MAX_VALUE)*(PWM_WAIT_CLOCK))
#endif
// PmodHB5_inf_tb.cpp
// 2016/06/20 by marsee
//
// PWMとモーターのフィードバック・ピン処理用IP のテストベンチ
//
#include <ap_int.h>
#include <hls_stream.h>
#include "PmodHB5_inf.h"
#define SASB_PULSE_WIDTH 500
int PmodHB5_inf(ap_uint<7> sw_late, ap_uint<1> dir, volatile ap_uint<1> & pwm_out, ap_uint<1> & dir_out,
hls::stream<ap_uint_1 >& sa, hls::stream<ap_uint_1 >& sb,
ap_uint<32> & sa_count, ap_uint_1 & sb_level, ap_uint_1 & overflow);
int main(){
using namespace std;
hls::stream<ap_uint_1> sa;
hls::stream<ap_uint_1> sb;
ap_uint<32> sa_count;
ap_uint_1 sb_level;
ap_uint_1 overflow;
ap_uint_1 pwm_out;
ap_uint_1 dir_out;
for (int i=0; i<PWM_ALL_CLOCKS; i++){
if (i%SASB_PULSE_WIDTH <= SASB_PULSE_WIDTH/4)
sa << (ap_uint_1)1;
else if (i%SASB_PULSE_WIDTH > SASB_PULSE_WIDTH/4 && i%SASB_PULSE_WIDTH <= SASB_PULSE_WIDTH/4*3)
sa << (ap_uint_1)0;
else
sa << (ap_uint_1)1;
if (i%SASB_PULSE_WIDTH < SASB_PULSE_WIDTH/2)
sb << (ap_uint_1)0;
else
sb << (ap_uint_1)1;
}
PmodHB5_inf(0, 0, pwm_out, dir_out,
sa, sb, sa_count, sb_level, overflow);
PmodHB5_inf(50, 1, pwm_out, dir_out,
sa, sb, sa_count, sb_level, overflow);
PmodHB5_inf(100, 0, pwm_out, dir_out,
sa, sb, sa_count, sb_level, overflow);
printf("*sa_count = %d, *sb_level = %d, overflow = %d\n",
(unsigned int)sa_count, (unsigned int)sb_level, (unsigned int)overflow);
return 0;
}
void pwm(ap_uint<7> sw_late, ap_uint<1> dir,
volatile ap_uint<1> & pwm_out, ap_uint<1> & dir_out){
dir_out = dir;
for (int i=1; i<=PWM_MAX_VALUE; i++){
for (int n=0; n<PWM_WAIT_CLOCK; n++){
#pragma HLS PIPELINE II=1 rewind
if (sw_late == 0){
pwm_out = 0;
} else if(i==1){
pwm_out = 1;
} else if (sw_late < i){
pwm_out = 0;
}
}
}
}
これで、C コードの合成、C/RTLコシミュレーションを行った。C/RTLコシミュレーション波形を示す。void pwm(ap_uint<7> sw_late, ap_uint<1> dir,
volatile ap_uint<1> & pwm_out, ap_uint<1> & dir_out){
dir_out = dir;
for (int i=1; i<=PWM_MAX_VALUE; i++){
for (int n=0; n<PWM_WAIT_CLOCK; n++){
#pragma HLS PIPELINE II=1 rewind
if (sw_late == 0){
pwm_out = 0;
} else if(i>=1 && sw_late >= i){
pwm_out = 1;
} else if (sw_late < i){
pwm_out = 0;
}
}
}
}
ということです。volatile キーワー ド を使用する と 、 C コンパイラ (および Vivado HLS) でポインター アクセスに関する仮定がされないので、 データが揮発性であ り 変化する可能性があ る と解釈 されます。
#include <ap_int.h>
void volatile_test(volatile ap_uint<16> multi_in0, volatile ap_uint<16> multi_in1,
volatile ap_uint<16> *multi_out){
#pragma HLS INTERFACE ap_none register port=multi_out
#pragma HLS INTERFACE ap_none register port=multi_in1
#pragma HLS INTERFACE ap_none register port=multi_in0
for(int i=0; i<10; i++){
#pragma HLS PIPELINE II=1
ap_uint<16> temp = (ap_uint<16>)multi_in0 * (ap_uint<16>)multi_in1;
*multi_out = temp;
}
}
`default_nettype none
`timescale 100 ps / 1ps
module volatile_test_tb;
wire ap_clk;
wire ap_rst;
wire ap_start;
wire ap_done;
wire ap_idle;
wire ap_ready;
reg [15:0] multi_in0_V;
reg [15:0] multi_in1_V;
wire [15:0] multi_out_V;
volatile_test volatile_test_i (
.ap_clk(ap_clk),
.ap_rst(ap_rst),
.ap_start(ap_start),
.ap_done(ap_done),
.ap_idle(ap_idle),
.ap_ready(ap_ready),
.multi_in0_V(multi_in0_V),
.multi_in1_V(multi_in1_V),
.multi_out_V(multi_out_V)
);
assign ap_start = 1'b1;
always @(posedge ap_clk) begin
if (ap_rst) begin
multi_in0_V <= 0;
multi_in1_V <= 1;
end else begin
multi_in0_V <= multi_in0_V + 1;
multi_in1_V <= multi_in1_V + 1;
end
end
// ap_clk
clk_gen #(
.CLK_PERIOD(100), // 10.0nsec, 100MHz
.CLK_DUTY_CYCLE(0.5),
.CLK_OFFSET(0),
.START_STATE(1'b0)
) sys_clock_i (
.clk_out(ap_clk)
);
// ap_rst
reset_gen #(
.RESET_STATE(1'b1),
.RESET_TIME(1000) // 100nsec
) RESET2i (
.reset_out(ap_rst)
);
endmodule
module clk_gen #(
parameter CLK_PERIOD = 100,
parameter real CLK_DUTY_CYCLE = 0.5,
parameter CLK_OFFSET = 0,
parameter START_STATE = 1'b0 )
(
output reg clk_out
);
begin
initial begin
#CLK_OFFSET;
forever
begin
clk_out = START_STATE;
#(CLK_PERIOD-(CLK_PERIOD*CLK_DUTY_CYCLE)) clk_out = ~START_STATE;
#(CLK_PERIOD*CLK_DUTY_CYCLE);
end
end
end
endmodule
module reset_gen #(
parameter RESET_STATE = 1'b1,
parameter RESET_TIME = 100 )
(
output reg reset_out
);
begin
initial begin
reset_out = RESET_STATE;
#RESET_TIME;
reset_out = ~RESET_STATE;
end
end
endmodule
`default_nettype wire
#include <ap_int.h>
void volatile_test(volatile ap_uint<16> multi_in0, volatile ap_uint<16> multi_in1,
volatile ap_uint<16> *multi_out){
#pragma HLS INTERFACE ap_none register port=multi_out
#pragma HLS INTERFACE ap_none register port=multi_in1
#pragma HLS INTERFACE ap_none register port=multi_in0
for(int i=0; i<10; i++){
//#pragma HLS PIPELINE II=1
ap_uint<16> temp = (ap_uint<16>)multi_in0 * (ap_uint<16>)multi_in1;
*multi_out = temp;
}
}
#include <ap_int.h>
void volatile_test(volatile ap_uint<16> multi_in0, volatile ap_uint<16> multi_in1,
volatile ap_uint<16> *multi_out){
#pragma HLS INTERFACE ap_none port=multi_out
#pragma HLS INTERFACE ap_none register port=multi_in1
#pragma HLS INTERFACE ap_none register port=multi_in0
for(int i=0; i<10; i++){
//#pragma HLS PIPELINE II=1
ap_uint<16> temp = (ap_uint<16>)multi_in0 * (ap_uint<16>)multi_in1;
*multi_out = temp;
}
}
#include <ap_int.h>
void volatile_test(volatile ap_uint<16> *multi_in0, volatile ap_uint<16> *multi_in1,
volatile ap_uint<16> *multi_out){
#pragma HLS INTERFACE ap_none port=multi_out
#pragma HLS INTERFACE ap_none register port=multi_in1
#pragma HLS INTERFACE ap_none register port=multi_in0
for(int i=0; i<10; i++){
//#pragma HLS PIPELINE II=1
*multi_out = (ap_uint<16>)*multi_in0 * (ap_uint<16>)*multi_in1;
}
}
#include <ap_int.h>
void volatile_test(volatile ap_uint<16> *multi_in0, volatile ap_uint<16> *multi_in1,
volatile ap_uint<16> *multi_out){
#pragma HLS INTERFACE ap_none register port=multi_out
#pragma HLS INTERFACE ap_none register port=multi_in1
#pragma HLS INTERFACE ap_none register port=multi_in0
for(int i=0; i<10; i++){
//#pragma HLS PIPELINE II=1
*multi_out = (ap_uint<16>)*multi_in0 * (ap_uint<16>)*multi_in1;
}
}
#include <ap_int.h>
void volatile_test(volatile ap_uint<16> *multi_in0, volatile ap_uint<16> *multi_in1,
volatile ap_uint<16> *multi_out){
#pragma HLS INTERFACE ap_none register port=multi_out
#pragma HLS INTERFACE ap_none register port=multi_in1
#pragma HLS INTERFACE ap_none register port=multi_in0
for(int i=0; i<10; i++){
#pragma HLS PIPELINE II=1
*multi_out = (ap_uint<16>)*multi_in0 * (ap_uint<16>)*multi_in1;
}
}
#include <ap_int.h>
void volatile_test(ap_uint<16> *multi_in0, ap_uint<16> *multi_in1,
ap_uint<16> *multi_out){
#pragma HLS INTERFACE ap_none register port=multi_out
#pragma HLS INTERFACE ap_none register port=multi_in1
#pragma HLS INTERFACE ap_none register port=multi_in0
for(int i=0; i<10; i++){
#pragma HLS PIPELINE II=1
*multi_out = (ap_uint<16>)*multi_in0 * (ap_uint<16>)*multi_in1;
}
}
// motor_monitor.h
// 2016/06/16 by marsee
//
#ifndef __MOTOR_MONITOR___
#define __MOTOR_MONITOR___
#include <ap_int.h>
typedef ap_uint<1> ap_uint_1;
#endif
// motor_monitor.cpp
// 2016/06/15 by marsee
//
#include <ap_int.h>
#include <hls_stream.h>
#include "motor_monitor.h"
int motor_monitor(hls::stream<ap_uint_1 >& sa, hls::stream<ap_uint_1 >& sb,
ap_uint<32> & sa_count, ap_uint_1 & sb_level, ap_uint_1 & overflow){
#pragma HLS INTERFACE s_axilite port=overflow
#pragma HLS INTERFACE s_axilite port=return
#pragma HLS INTERFACE s_axilite port=sb_level
#pragma HLS INTERFACE s_axilite port=sa_count
#pragma HLS INTERFACE ap_hs port=sb
#pragma HLS INTERFACE ap_hs port=sa
ap_uint_1 sad;
ap_uint_1 sbd;
overflow = 0;
for (sa_count=0; sa_count!=0xffffffff; sa_count++){ // sa=1の間はループ
#pragma HLS PIPELINE II=1
sa >> sad;
sb >> sbd;
if (sa_count == 0xfffffffe) // overflow
overflow = 1;
if (!sad)
break;
}
for (sa_count=1; sa_count!=0xffffffff; sa_count++){ // sa=0の間はループ
#pragma HLS PIPELINE II=1
sa >> sad;
sb >> sbd;
if (sa_count == 0xfffffffe) // overflow
overflow = 1;
if (sad)
break;
}
sb_level = sbd; // saが立ち上がった時のsbの値
for (sa_count++; sa_count!=0xffffffff; sa_count++){ // sa=1の間はループ
#pragma HLS PIPELINE II=1
sa >> sad;
sb >> sbd;
if (sa_count == 0xfffffffe) // overflow
overflow = 1;
if (!sad)
break;
}
return 0;
}
// motor_monitor_tb.cpp
// 2016/06/15 by marsee
//
#include <ap_int.h>
#include <hls_stream.h>
#include "motor_monitor.h"
#define DATASIZE 20
int motor_monitor(hls::stream<ap_uint_1 >& sa, hls::stream<ap_uint_1 >& sb,
ap_uint<32> & sa_count, ap_uint_1 & sb_level, ap_uint_1 & overflow);
int main(){
using namespace std;
ap_uint_1 saa[DATASIZE] = {1,1,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,1,1,1};
ap_uint_1 sba[DATASIZE] = {0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1};
hls::stream<ap_uint_1> sa;
hls::stream<ap_uint_1> sb;
ap_uint<32> sa_count;
ap_uint_1 sb_level;
ap_uint_1 overflow;
for (int i=0; i<DATASIZE; i++){
sa << saa[i];
sb << sba[i];
}
motor_monitor(sa, sb, sa_count, sb_level, overflow);
printf("*sa_count = %d, *sb_level = %d, overflow = %d\n",
(unsigned int)sa_count, (unsigned int)sb_level, (unsigned int)overflow);
return 0;
}
0 0 0x44A00010 0x32
0 0 0x44A00000 0x1
0 5 0x44A00000 0x80
0 0x20 0x44A00010 0xA
0 0xFFFFFFFF 0 0
signal addr0_tmp : std_logic_vector(awidth-1 downto 0);
type mem_array is array (0 to mem_size-1) of std_logic_vector (dwidth-1 downto 0);
signal mem : mem_array := (
0 => "00000000000000000000000000000000",
1 => "00000000000000000000000000010100",
2 => "00000000000000000000000000001010",
3 => "10001111111111111111111111111111",
4 => "01001111111111111111111111110000",
5 => "11111111111111111111111111111111",
6 to 255=> "00000000000000000000000000000000" );
0 0 0x44A00010 0x32
0 0 0x44A00000 0x1
0 5 0x44A00000 0x80
0 0xFFFFFFFF 0 0
// reg_addr_data フォーマット、
// 第1フィールド(reg_ad[x][0]):Write - 0, Read - 1
// 第2フィールド(reg_ad[x][1]):Delay、単位はクロック数
// 第3フィールド(reg_ad[x][2]):アドレス、16進数
// 第4フィールド(reg_ad[x][3]):データ、16進数
`default_nettype none
`timescale 100 ps / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 2016/06/13 15:14:23
// Design Name:
// Module Name: PWMmodule_test_tb
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module PWMmodule_test_tb;
wire [31:0]dummy_out;
wire pwm_out_V;
wire reset_rtl_n;
wire sys_clock;
PWMmodule_test_wrapper PWMmodule_test_wrapper_i (
.dummy_out(dummy_out),
.pwm_out_V(pwm_out_V),
.reset_rtl_n(reset_rtl_n),
.sys_clock(sys_clock)
);
// sys_clock
clk_gen #(
.CLK_PERIOD(100), // 10.0nsec, 100MHz
.CLK_DUTY_CYCLE(0.5),
.CLK_OFFSET(0),
.START_STATE(1'b0)
) sys_clock_i (
.clk_out(sys_clock)
);
// reset_rtl_n
reset_gen #(
.RESET_STATE(1'b0),
.RESET_TIME(1000) // 100nsec
) RESET2i (
.reset_out(reset_rtl_n)
);
endmodule
module clk_gen #(
parameter CLK_PERIOD = 100,
parameter real CLK_DUTY_CYCLE = 0.5,
parameter CLK_OFFSET = 0,
parameter START_STATE = 1'b0 )
(
output reg clk_out
);
begin
initial begin
#CLK_OFFSET;
forever
begin
clk_out = START_STATE;
#(CLK_PERIOD-(CLK_PERIOD*CLK_DUTY_CYCLE)) clk_out = ~START_STATE;
#(CLK_PERIOD*CLK_DUTY_CYCLE);
end
end
end
endmodule
module reset_gen #(
parameter RESET_STATE = 1'b1,
parameter RESET_TIME = 100 )
(
output reg reset_out
);
begin
initial begin
reset_out = RESET_STATE;
#RESET_TIME;
reset_out = ~RESET_STATE;
end
end
endmodule
`default_nettype wire
const unsigned int reg_ad[AD_ARRAY_LIMIT][4]={
{0, 0, 0x100, 1},
{1, 20, 0x100, 0},
{0, 10, 0x104, 2},
{0, 0x8fffffff, 0xAffffff0, 0x8fffffff},
{1, 0x4ffffff0, 0xCfffffff, 0x5fffffff},
{0, 0xffffffff, 0, 0},
// reg_addr_data フォーマット、
// 第1フィールド(reg_ad[x][0]):Write - 0, Read - 1
// 第2フィールド(reg_ad[x][1]):Delay、単位はクロック数
// 第3フィールド(reg_ad[x][2]):アドレス、16進数
// 第4フィールド(reg_ad[x][3]):データ、16進数
//
// 終了は第2フィールド:Delayに 0xffffffff が書いてあったとき
// reg_write_read.h
// 2016/06/10 by marsee
//
// reg_addr_data フォーマット、
// 第1フィールド(reg_ad[x][0]):Write - 0, Read - 1
// 第2フィールド(reg_ad[x][1]):Delay、単位はクロック数
// 第3フィールド(reg_ad[x][2]):アドレス、16進数
// 第4フィールド(reg_ad[x][3]):データ、16進数
//
// 終了は第2フィールド:Delayに 0xffffffff が書いてあったとき
#define AD_ARRAY_LIMIT 256
#define REG_WRITE 0
#define REG_READ 1
#define R_W_FIELD 0
#define DELAY_FIELD 1
#define ADDRESS_FIELD 2
#define DATA_FIELD 3
const unsigned int reg_ad[AD_ARRAY_LIMIT][4]={
{0, 0, 0x100, 1},
{1, 20, 0x100, 0},
{0, 10, 0x104, 2},
{0, 0xffffffff, 0, 0},
{1, 0, 0, 0},
{0, 0, 0, 0},
{1, 0, 0, 0},
{0, 0, 0, 0},
{1, 0, 0, 0},
{0, 0, 0, 0},
{1, 0, 0, 0},
{0, 0, 0, 0},
// reg_write_read.cpp
// 2016/06/11 by marsee
//
// レジスタにWrite or Read する
//
#include "reg_write_read.h"
int reg_write_read(volatile int *axi4m, volatile int *dummy_out){
#pragma HLS INTERFACE ap_none port=dummy_out
#pragma HLS INTERFACE ap_ctrl_hs port=return
#pragma HLS INTERFACE m_axi depth=1024 port=axi4m offset=off
int ret;
for(int i=0; i<255; i++){
if(reg_ad[i][DELAY_FIELD] == 0xffffffff) // end
break;
for(unsigned int n=0; n<reg_ad[i][DELAY_FIELD]; n++){ // Delay count
#pragma HLS PIPELINE II=1
*dummy_out = n;
}
int index = reg_ad[i][ADDRESS_FIELD]/sizeof(unsigned int);
if(reg_ad[i][R_W_FIELD] == REG_WRITE){
axi4m[index] = reg_ad[i][DATA_FIELD];
} else { // read
*dummy_out = axi4m[index];
}
}
}
// reg_write_read_tb.cpp
// 2016/06/12 by marsee
//
int reg_write_read(volatile int *axi4m, volatile int *dummy_out);
int main(){
int axi4m[512];
int dm_out;
reg_write_read(axi4m, &dm_out);
return 0;
}
// PWMmodule.cpp
// 2016/06/08 by marsee
// PmodHB5のPWM用モジュール
// 100MHzのクロックで2KHz(500us)のPWM出力(最初に500分周する)
#include <ap_int.h>
void pwm(ap_uint<7> sw_late, volatile ap_uint<1> *pwm_out){
#pragma HLS INTERFACE ap_none register port=pwm_out
#pragma HLS INTERFACE s_axilite port=sw_late
#pragma HLS INTERFACE s_axilite port=return
for (int i=1; i<=100; i++){
for (int n=0; n<500; n++){
#pragma HLS PIPELINE II=1 rewind
if (sw_late == 0){
*pwm_out = 0;
} else if(i==1){
*pwm_out = 1;
} else if (sw_late < i){
*pwm_out = 0;
}
}
}
}
// PWMmodule_tb.cpp
// 2016/06/08 by marsee
// PWMmodule用テストベンチ
//
#include <ap_int.h>
void pwm(ap_uint<7> sw_late, volatile ap_uint<1> *pwm_out);
int main(){
ap_uint<1> pwmo, *pwm_out;
pwm_out = &pwmo;
pwm(0, pwm_out);
pwm(50, pwm_out);
pwm(100, pwm_out);
return 0;
}
だそうだ。単一の電源でモータに加える電圧の向きを変えられる回路として考案されたのが、「Hブリッジ回路」
Canny Edge Detectionのアルゴリズムは次の手順。
STEP1:ガウシアンフィルタで平滑化
STEP2:エッジ強度と勾配方向(4方向に量子化)を計算
STEP3:細線化処理(Non-maximum Suppression)
STEP4:ヒステリシス閾処理(Hysteresis Threshold)
void lap_filter(AXI_STREAM& input, AXI_STREAM& output, int rows, int cols, int threshold_low, int threshold_high) {
#pragma HLS INTERFACE s_axilite port=return
#pragma HLS DATAFLOW
#pragma HLS INTERFACE s_axilite port=threshold_high
#pragma HLS INTERFACE s_axilite port=threshold_low
#pragma HLS INTERFACE s_axilite port=cols
#pragma HLS INTERFACE s_axilite port=rows
#pragma HLS INTERFACE axis port=output
#pragma HLS INTERFACE axis port=input
#pragma HLS INTERFACE ap_stable port=rows
#pragma HLS INTERFACE ap_stable port=cols
RGB_IMAGE src(rows, cols);
RGBSINGLE_IMAGE src_bw(rows, cols);
RGBSINGLE_IMAGE src_blur(rows, cols);
RGBSINGLE_IMAGE lap_fil(rows, cols);
RGB_IMAGE lap_fil_color(rows, cols);
RGB_IMAGE lap_edges(rows, cols);
//#pragma HLS dataflow
// AXI to RGB_IMAGE stream
hls::AXIvideo2Mat( input, src );
// Grayscaling
hls::CvtColor<HLS_RGB2GRAY>( src, src_bw );
// Gaussian Blur Noise Reduction
hls::GaussianBlur<5,5>( src_bw, src_blur );
//hls::GaussianBlur<3,3>( src_bw, src_blur);
// Calculate laplacian filter
const int lap_weight[3][3] = {{-1, -1, -1},{-1, 8, -1},{-1, -1, -1}};
hls::Window<3, 3, int> kernel;
hls::Point_<int> anchor;
for (int i=0; i<3; i++){
for (int j=0; j<3; j++){
kernel.val[i][j] = lap_weight[i][j];
}
}
anchor.x = -1;
anchor.y = -1;
hls::Filter2D(src_blur, lap_fil, kernel, anchor);
// gray to color
hls::CvtColor<HLS_GRAY2BGR>( lap_fil, lap_fil_color );
// Perform hysteresis thresholding for edge tracing
hysteresis( lap_fil_color, lap_edges, threshold_low, threshold_high );
hls::Mat2AXIvideo(lap_edges, output );
}
// Lane-Detecting_tb.cpp
// 2016/05/22 by marsee
// OpenCV 2 の Mat を使用したバージョン
// Vivado HLSでは Canny フィルタのみハードウェア化した。OpenCV で処理したCannyフィルタとHough変換を行って比較する。
#include <iostream>
#include "hls_opencv.h"
#include "lap_filter.h"
using namespace cv;
void lap_filter(AXI_STREAM& input, AXI_STREAM& output, int rows, int cols, int threshold_low, int threshold_high);
void opencv_lap_filter(Mat& src, Mat& dst, int threshold_low, int threshold_high, int sobel_size);
int main (int argc, char** argv) {
//const int threshold_low = 50;
//const int threshold_high = 200;
const int threshold_low = 40;
const int threshold_high = 50;
const int sobel_size = 3;
// OpenCV で 画像を読み込む
Mat src = imread(INPUT_IMAGE);
AXI_STREAM src_axi, dst_axi;
// Mat フォーマットから AXI4 Stream へ変換
cvMat2AXIvideo(src, src_axi);
// image_filter() 関数をコール
lap_filter(src_axi, dst_axi, src.rows, src.cols, threshold_low, threshold_high);
// AXI4 Stream から Mat フォーマットへ変換
// dst は宣言時にサイズとカラー・フォーマットを定義する必要がある
Mat dst(src.rows, src.cols, CV_8UC3);
AXIvideo2cvMat(dst_axi, dst);
imshow("Vivado HLS lap_filter", dst);
// opencv_image_filter() をコール
Mat dst_cv(src.rows, src.cols, CV_8UC3);
opencv_lap_filter(src, dst_cv, 200, 300, sobel_size);
imshow("OpenCV Canny filter", dst_cv);
// Vivado HLS の Canny filter の Hough変換
// detect lines
vector<Vec2f> lines;
Mat gray_dst;
cvtColor(dst, gray_dst, CV_BGR2GRAY);
HoughLines(gray_dst, lines, 1, CV_PI/180, 120, 0, 0);
// draw lines
for( size_t i = 0; i < lines.size(); i++ )
{
float rho = lines[i][0], theta = lines[i][1];
Point pt1, pt2;
double a = cos(theta), b = sin(theta);
double x0 = a*rho, y0 = b*rho;
pt1.x = cvRound(x0 + 1000*(-b));
pt1.y = cvRound(y0 + 1000*(a));
pt2.x = cvRound(x0 - 1000*(-b));
pt2.y = cvRound(y0 - 1000*(a));
line( dst, pt1, pt2, Scalar(0,0,255), 3, CV_AA);
}
imwrite(OUTPUT_IMAGE, dst);
// OpenCV の Canny filter の Hough変換
// detect lines
Mat cdst_cv;
cvtColor(dst_cv, cdst_cv, CV_GRAY2BGR);
HoughLines(dst_cv, lines, 1, CV_PI/180, 150, 0, 0);
// draw lines
for( size_t i = 0; i < lines.size(); i++ )
{
float rho = lines[i][0], theta = lines[i][1];
Point pt1, pt2;
double a = cos(theta), b = sin(theta);
double x0 = a*rho, y0 = b*rho;
pt1.x = cvRound(x0 + 1000*(-b));
pt1.y = cvRound(y0 + 1000*(a));
pt2.x = cvRound(x0 - 1000*(-b));
pt2.y = cvRound(y0 - 1000*(a));
line( cdst_cv, pt1, pt2, Scalar(0,0,255), 3, CV_AA);
}
imwrite(OUTPUT_IMAGE_GOLDEN, cdst_cv);
printf("Test with 0 errors.\n");
imshow("Detect lines of Vivado HLS lap_filter", dst);
imshow("Detect lines of OpenCV", cdst_cv);
waitKey();
return 0;
}
void opencv_lap_filter(Mat& src, Mat& dst, int threshold_low, int threshold_high, int sobel_size){
Canny(src, dst, (double)threshold_low, (double)threshold_high, sobel_size);
}
日 | 月 | 火 | 水 | 木 | 金 | 土 |
---|---|---|---|---|---|---|
- | - | - | 1 | 2 | 3 | 4 |
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | - | - |