part=xczu1cg-sbva484-1-e
[hls]
flow_target=vivado
package.output.format=ip_catalog
package.output.syn=false
clock=10ns
clock_uncertainty=27%
{
"name": "HSVConverter",
"type": "HLS",
"configuration": {
"componentType": "HLS",
"configFiles": [
"hls_config.cfg"
],
"work_dir": "HSVConverter"
},
"previousBuildStatusMap": {}
}
// HSVConverter.h
// 2023/10/21 by marsee
//
#ifndef __HSVCONVERTER_H__
#define __HSVCONVERTER_H__
#define ORG_IMGwAxiVdma 0
#define HSV_CONVwAxiVdma 1
#define ORG_IMGwAxiDma 2
#define HSV_CONVwAxiDma 3
#endif
// HSVConverter.cpp
// 2023/10/21 by marsee
//
#include <stdint.h>
#include <ap_int.h>
#include <hls_stream.h>
#include <ap_axi_sdata.h>
#include <ap_fixed.h>
#include "HSVConverter.h"
int hsv_conv(ap_uint<32> data, ap_uint<32> &val, int32_t h_add,
ap_ufixed<16, 8, AP_TRN_ZERO, AP_SAT> s_mult, int32_t s_add,
ap_ufixed<16, 8, AP_TRN_ZERO, AP_SAT> v_mult, int32_t v_ad);
int separate_hsv(ap_uint<25> hsv, ap_uint<9> &h, ap_uint<8> &s, ap_uint<8> &v);
int HSVConverter(hls::stream<ap_axiu<32,1,1,1> >& ins,
hls::stream<ap_axiu<32,1,1,1> >& outs, int32_t function,
int32_t row_size, int32_t col_size,
int32_t h_add,
ap_ufixed<16, 8, AP_TRN_ZERO, AP_SAT> s_mult, int32_t s_add,
ap_ufixed<16, 8, AP_TRN_ZERO, AP_SAT> v_mult, int32_t v_add){
#pragma HLS INTERFACE mode=s_axilite port=return
#pragma HLS INTERFACE mode=axis register_mode=both port=ins register
#pragma HLS INTERFACE mode=axis register_mode=both port=outs register
#pragma HLS INTERFACE mode=s_axilite port=function
#pragma HLS INTERFACE mode=s_axilite port=row_size
#pragma HLS INTERFACE mode=s_axilite port=col_size
#pragma HLS INTERFACE mode=s_axilite port=h_add
#pragma HLS INTERFACE mode=s_axilite port=s_mult
#pragma HLS INTERFACE mode=s_axilite port=s_add
#pragma HLS INTERFACE mode=s_axilite port=v_mult
#pragma HLS INTERFACE mode=s_axilite port=v_add
ap_axiu<32,1,1,1> pix;
ap_axiu<32,1,1,1> hsvd;
ap_uint<32> val;
LOOP_WAIT_USER : do { // user が 1になった時にフレームがスタートする
#pragma HLS LOOP_TRIPCOUNT min=1 max=1 avg=1
ins >> pix;
if(function==ORG_IMGwAxiDma || function==HSV_CONVwAxiDma)
break;
} while(pix.user == 0);
LOOP_Y: for(int y=0; y<row_size; y++){
#pragma HLS LOOP_TRIPCOUNT avg=600 max=1080 min=48
LOOP_X: for(int x=0; x<col_size; x++){
#pragma HLS LOOP_TRIPCOUNT avg=800 max=1920 min=64
#pragma HLS PIPELINE II=1
if (!(x==0 && y==0)) // 最初の入力はすでに入力されている
ins >> pix; // AXI4-Stream からの入力
hsv_conv(pix.data, val, h_add, s_mult, s_add, v_mult, v_add);
hsvd.data = val;
if(function==ORG_IMGwAxiVdma || function == HSV_CONVwAxiVdma){
if(x==0 && y==0) // 最初のピクセル
hsvd.user = 1;
else
hsvd.user = 0;
if(x == (col_size-1)) // 行の最後
hsvd.last = 1;
else
hsvd.last = 0;
}else{
hsvd.user = 0;
hsvd.last = pix.last;
}
hsvd.keep = 0x7;
hsvd.strb = 0x7;
if(function==HSV_CONVwAxiVdma || function==HSV_CONVwAxiDma)
outs << hsvd;
else
outs << pix;
}
}
return(0);
}
// hsv_converter
// h に h_add を加算する
// s に
int hsv_conv(ap_uint<32> data, ap_uint<32> &val, int32_t h_add,
ap_ufixed<16, 8, AP_TRN_ZERO, AP_SAT> s_mult, int32_t s_add,
ap_ufixed<16, 8, AP_TRN_ZERO, AP_SAT> v_mult, int32_t v_add){
ap_uint<9> h;
ap_uint<8> s , v;
int32_t calc_h;
ap_ufixed<16, 8, AP_TRN_ZERO, AP_SAT> calc_st, calc_vt, ap_05;
int32_t calc_s, calc_v;
ap_uint<9> ht;
ap_uint<8> st, vt;
ap_05 = (ap_ufixed<16, 8, AP_TRN_ZERO, AP_SAT>)0.5;
separate_hsv(data, h, s, v);
calc_h = (h + h_add)%360;
if(calc_h < 0)
calc_h = 360 + calc_h;
calc_st = (ap_ufixed<16, 8, AP_TRN_ZERO, AP_SAT>)s * s_mult;
calc_s = (uint32_t)(calc_st + ap_05) + s_add;
calc_vt = (ap_ufixed<16, 8, AP_TRN_ZERO, AP_SAT>)v * v_mult;
calc_v = (uint32_t)(calc_vt + ap_05) + v_add;
if(calc_s < 0)
calc_s = 0;
else if(calc_s > 255)
calc_s = 255;
if(calc_v < 0)
calc_v = 0;
else if(calc_v > 255)
calc_v = 255;
ht = (ap_uint<9>)calc_h;
st = (ap_uint<8>)calc_s;
vt = (ap_uint<8>)calc_v;
val = ((ap_uint<32>)ht << 16)+((ap_uint<32>)st << 8)+(ap_uint<32>)vt;
return(0);
}
// separate_hsv
// HSVを分離する
// HSVのフォーマットは、{H(9bits), S(8bits), V(8bits)}, 1pixel = 32bits
//
int separate_hsv(ap_uint<25> hsv, ap_uint<9> &h, ap_uint<8> &s, ap_uint<8> &v){
v = (ap_uint<8>)(hsv & 0x1ff);
s = (ap_uint<8>)((hsv>>8) & 0xff);
h = (ap_uint<9>)((hsv>>16) & 0x1ff);
return(0);
}
// HSVConverter_tb.cpp
// 2023/10/21 by marsee
//
// HSVCwXilinxVideoStandard を define すると axi_vdma 用となり、コメントアウトすると axi_dma 用になる
//
#include <stdio.h>
#include <stdint.h>
#include <ap_int.h>
#include <hls_stream.h>
#include <ap_axi_sdata.h>
#include "opencv2/opencv.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgcodecs/imgcodecs.hpp"
#include "HSVConverter.h"
#define HSVCwXilinxVideoStandard
constexpr int size = 3;
int HSVConverter(hls::stream<ap_axiu<32,1,1,1> >& ins,
hls::stream<ap_axiu<32,1,1,1> >& outs, int32_t function,
int32_t row_size, int32_t col_size,
int32_t h_add,
ap_ufixed<16, 8, AP_TRN_ZERO, AP_SAT> s_mult, int32_t s_add,
ap_ufixed<16, 8, AP_TRN_ZERO, AP_SAT> v_mult, int32_t v_add);
int HSVConverter_soft(hls::stream<ap_axiu<32,1,1,1> >& ins,
hls::stream<ap_axiu<32,1,1,1> >& outs, int32_t function,
int32_t row_size, int32_t col_size,
int32_t h_add,
ap_ufixed<16, 8, AP_TRN_ZERO, AP_SAT> s_mult, int32_t s_add,
ap_ufixed<16, 8, AP_TRN_ZERO, AP_SAT> v_mult, int32_t v_add);
int hsv_conv_soft(ap_uint<32> data, ap_uint<32> &val, int32_t h_add,
ap_ufixed<16, 8, AP_TRN_ZERO, AP_SAT> s_mult, int32_t s_add,
ap_ufixed<16, 8, AP_TRN_ZERO, AP_SAT> v_mult, int32_t v_ad);
int separate_hsv_soft(ap_uint<25> hsv, ap_uint<9> &h, ap_uint<8> &s, ap_uint<8> &v);
int32_t RGB2HSV(int32_t rgb);
int32_t HSV2RGB(int32_t hsv);
const char INPUT_JPG_FILE[] = "test2.jpg";
const char OUTPUT_JPG_FILE[] = "hsv_converter.jpg";
const char ORG_OUT_JPG_FILE[] = "hsv_converter2.jpg";
int main(){
hls::stream<ap_axiu<32,1,1,1> > ins, ins2;
hls::stream<ap_axiu<32,1,1,1> > ins_soft;
hls::stream<ap_axiu<32,1,1,1> > outs, outs2;
hls::stream<ap_axiu<32,1,1,1> > outs_soft;
ap_axiu<32,1,1,1> pix;
ap_axiu<32,1,1,1> vals, vals_soft;
// JPG ファイルをMat に読み込む
cv::Mat img = cv::imread(INPUT_JPG_FILE);
// ピクセルを入れる領域の確保
std::vector<int32_t> rd_bmp(sizeof(int32_t)*img.cols*img.rows);
std::vector<int32_t> hw_hsv_conv(sizeof(int32_t)*(img.cols)*(img.rows));
std::vector<int32_t> sw_hsv_conv(sizeof(int32_t)*(img.cols)*(img.rows));
// rd_bmp にJPGのピクセルを代入
cv::Mat_<cv::Vec3b> dst_vec3b = cv::Mat_<cv::Vec3b>(img);
for (int y=0; y<img.rows; y++){
for (int x=0; x<img.cols; x++){
cv::Vec3b pixel;
pixel = dst_vec3b(y,x);
rd_bmp[y*img.cols+x] = (pixel[0] & 0xff) | ((pixel[1] & 0xff)<<8) | ((pixel[2] & 0xff)<<16); // RGB 8 bits
// blue - pixel[0]; green - pixel[1]; red - pixel[2];
}
}
#ifdef HSVCwXilinxVideoStandard
// ins に入力データを用意する
for(int i=0; i<5; i++){ // dummy data
pix.user = 0;
pix.data = i;
pix.last = 0;
pix.user = 0;
pix.keep = 0x7;
pix.strb = 0x7;
ins << pix;
}
#endif
for(int j=0; j < img.rows; j++){
for(int i=0; i < img.cols; i++){
pix.data = RGB2HSV((int32_t)rd_bmp[(j*img.cols)+i]);
#ifdef HSVCwXilinxVideoStandard
if (j==0 && i==0) // 最初のデータの時に TUSER を 1 にする
pix.user = 1;
else
pix.user = 0;
if (i == img.cols-1) // 行の最後でTLASTをアサートする
pix.last = 1;
else
pix.last = 0;
#else
if(j==img.rows-1 && i==img.cols-1)
pix.last = 1;
else
pix.last = 0;
pix.user = 0;
#endif
pix.keep = 0x7;
pix.strb = 0x7;
ins << pix;
ins2 << pix;
ins_soft << pix;
}
}
// Hに180を加えて、SとVは2倍する
#ifdef HSVCwXilinxVideoStandard
HSVConverter(ins, outs, HSV_CONVwAxiVdma, img.rows, img.cols, 180, 2.0, 0, 2.0, 0); // ハードウェア
HSVConverter_soft(ins_soft, outs_soft, HSV_CONVwAxiVdma, img.rows, img.cols, 180, 2.0, 0, 2.0, 0); // ソフトウェア
#else
HSVConverter(ins, outs, HSV_CONVwAxiDma, img.rows, img.cols, 180, 2.0, 0, 2.0, 0); // ハードウェアのメディアンフィルタ
HSVConverter_soft(ins_soft, outs_soft, HSV_CONVwAxiDma, img.rows, img.cols, 180, 2.0, 0, 2.0, 0); // ソフトウェアのメディアンフィルタ
#endif
// ハードウェアとソフトウェアのメディアンフィルタの値のチェック
for (int y=0; y<img.rows; y++){ // 結果の画像サイズはx-2, y-2
for (int x=0; x<img.cols; x++){
outs >> vals;
outs_soft >> vals_soft;
ap_uint<32> val = vals.data;
hw_hsv_conv[y*img.cols+x] = (int32_t)val;
if (val != vals_soft.data){
printf("ERROR HW and SW results mismatch x = %ld, y = %ld, HW = %x, SW = %x\n",
x, y, val, vals_soft.data);
return(1);
}
}
}
printf("Success HW and SW results match\n");
const int hsv_conv_row = img.rows;
const int hsv_conv_cols = img.cols;
cv::Mat wbmpf(hsv_conv_row, hsv_conv_cols, CV_8UC3);
// wbmpf に色変換後の画像を入力
cv::Mat_<cv::Vec3b> sob_vec3b = cv::Mat_<cv::Vec3b>(wbmpf);
for (int y=0; y<wbmpf.rows; y++){
for (int x=0; x<wbmpf.cols; x++){
cv::Vec3b pixel;
pixel = sob_vec3b(y,x);
int32_t rbg = HSV2RGB(hw_hsv_conv[y*wbmpf.cols+x]);
pixel[0] = (rbg & 0xff); // blue
pixel[1] = ((rbg >> 8) & 0xff); // green
pixel[2] = ((rbg >> 16) & 0xff); // red
sob_vec3b(y,x) = pixel;
}
}
// ハードウェアのメディアンフィルタの結果を jpg ファイルへ出力する
cv::imwrite(OUTPUT_JPG_FILE, wbmpf);
#ifdef HSVCwXilinxVideoStandard
HSVConverter(ins2, outs2, HSV_CONVwAxiVdma, img.rows, img.cols, 0, 1.0, 32, 1.0, 32);
#else
HSVConverter(ins2, outs2, HSV_CONVwAxiDma, img.rows, img.cols, 0, 1.0, 32, 1.0, 32);
#endif
cv::Mat wbmpf2(hsv_conv_row, hsv_conv_cols, CV_8UC3);
// wbmpf2 に元画像を入力
sob_vec3b = cv::Mat_<cv::Vec3b>(wbmpf2);
for (int y=0; y<wbmpf.rows; y++){
for (int x=0; x<wbmpf.cols; x++){
cv::Vec3b pixel;
pixel = sob_vec3b(y,x);
outs2 >> vals;
int32_t val = HSV2RGB(vals.data);
pixel[0] = (val & 0xff); // blue
pixel[1] = ((val >> 8) & 0xff); // green
pixel[2] = ((val >> 16) & 0xff); // red
sob_vec3b(y,x) = pixel;
}
}
// 元画像を jpg ファイルへ出力する
cv::imwrite(ORG_OUT_JPG_FILE, wbmpf2);
return(0);
}
int HSVConverter_soft(hls::stream<ap_axiu<32,1,1,1> >& ins,
hls::stream<ap_axiu<32,1,1,1> >& outs, int32_t function,
int32_t row_size, int32_t col_size,
int32_t h_add,
ap_ufixed<16, 8, AP_TRN_ZERO, AP_SAT> s_mult, int32_t s_add,
ap_ufixed<16, 8, AP_TRN_ZERO, AP_SAT> v_mult, int32_t v_add){
ap_axiu<32,1,1,1> pix;
ap_axiu<32,1,1,1> hsvd;
ap_uint<32> val;
do { // user が 1になった時にフレームがスタートする
ins >> pix;
if(function==ORG_IMGwAxiDma || function==HSV_CONVwAxiDma)
break;
} while(pix.user == 0);
for(int y=0; y<row_size; y++){
for(int x=0; x<col_size; x++){
if (!(x==0 && y==0)) // 最初の入力はすでに入力されている
ins >> pix; // AXI4-Stream からの入力
hsv_conv_soft(pix.data, val, h_add, s_mult, s_add, v_mult, v_add);
hsvd.data = val;
if(function==ORG_IMGwAxiVdma || function == HSV_CONVwAxiVdma){
if(x==0 && y==0) // 最初のピクセル
hsvd.user = 1;
else
hsvd.user = 0;
if(x == (col_size-1)) // 行の最後
hsvd.last = 1;
else
hsvd.last = 0;
}else{
hsvd.user = 0;
hsvd.last = pix.last;
}
hsvd.keep = 0x7;
hsvd.strb = 0x7;
if(function==HSV_CONVwAxiVdma || function==HSV_CONVwAxiDma)
outs << hsvd;
else
outs << pix;
}
}
return(0);
}
// hsv_converter
// h に h_add を加算する
// s に
int hsv_conv_soft(ap_uint<32> data, ap_uint<32> &val, int32_t h_add,
ap_ufixed<16, 8, AP_TRN_ZERO, AP_SAT> s_mult, int32_t s_add,
ap_ufixed<16, 8, AP_TRN_ZERO, AP_SAT> v_mult, int32_t v_add){
ap_uint<9> h;
ap_uint<8> s , v;
int32_t calc_h;
ap_ufixed<16, 8, AP_TRN_ZERO, AP_SAT> calc_st, calc_vt, ap_05;
int32_t calc_s, calc_v;
ap_uint<9> ht;
ap_uint<8> st, vt;
ap_05 = (ap_ufixed<16, 8, AP_TRN_ZERO, AP_SAT>)0.5;
separate_hsv_soft(data, h, s, v);
calc_h = (h + h_add)%360;
if(calc_h < 0)
calc_h = 360 + calc_h;
calc_st = (ap_ufixed<16, 8, AP_TRN_ZERO, AP_SAT>)s * s_mult;
calc_s = (uint32_t)(calc_st + ap_05) + s_add;
calc_vt = (ap_ufixed<16, 8, AP_TRN_ZERO, AP_SAT>)v * v_mult;
calc_v = (uint32_t)(calc_vt + ap_05) + v_add;
if(calc_s < 0)
calc_s = 0;
else if(calc_s > 255)
calc_s = 255;
if(calc_v < 0)
calc_v = 0;
else if(calc_v > 255)
calc_v = 255;
ht = (ap_uint<9>)calc_h;
st = (ap_uint<8>)calc_s;
vt = (ap_uint<8>)calc_v;
val = ((ap_uint<32>)ht << 16)+((ap_uint<32>)st << 8)+(ap_uint<32>)vt;
return(0);
}
// separate_hsv
// HSVを分離する
// HSVのフォーマットは、{H(9bits), S(8bits), V(8bits)}, 1pixel = 32bits
//
int separate_hsv_soft(ap_uint<25> hsv, ap_uint<9> &h, ap_uint<8> &s, ap_uint<8> &v){
v = (ap_uint<8>)(hsv & 0x1ff);
s = (ap_uint<8>)((hsv>>8) & 0xff);
h = (ap_uint<9>)((hsv>>16) & 0x1ff);
return(0);
}
// RGBからHSVに変換
int32_t RGB2HSV(int32_t rgb){
int32_t r, g, b;
int32_t h, s, v;
float ht, st;
float max, min;
int32_t hsv;
b = rgb & 0xff;
g = (rgb>>8) & 0xff;
r = (rgb>>16) & 0xff;
// h と max, min を求める
if(r==g && g==b && r==b){
max = (float)r; // 8倍
min = (float)r;
}else if(r>=g && r>=b){ // r が最大
max = (float)r;
if(g>=b)
min = (float)b;
else
min = (float)g;
}else if(g>=r && g>=b){ // g が最大
max = (float)g;
if(r>=b)
min = (float)b;
else
min = (float)r;
}else{ // b が最大
max = (float)b;
if(r>=g)
min = (float)g;
else
min = (float)r;
}
if(max-min == 0.0)
ht = 0.0;
else if(max == (float)r)
ht = 60.0 * (((float)g-(float)b)/(max-min));
else if(max == (float)g)
ht = 60.0 * (((float)b-(float)r)/(max-min)) + 120.0; // MAGビットシフトして精度を確保
else // if(max == b)
ht = 60.0 * (((float)r-(float)g)/(max-min)) + 240.0; // MAGビットシフトして精度を確保
if(ht < 0)
ht += 360.0;
h = (uint32_t)(ht + 0.5);
if(max == 0.0)
st = 0.0;
else
st = ((max - min)/max) * 255.0; // MAGビットシフトして精度を確保
s = (uint32_t)(st + 0.5);
v = (uint32_t)max;
hsv = ((h&0x1ff)<<16) + ((s&0xff)<<8) + (v&0xff);
return(hsv);
}
// HSVからRGBに変換
int32_t HSV2RGB(int32_t hsv){
int32_t h, s, v;
float max, min;
uint8_t r, g, b;
int32_t rgb;
h = (hsv >> 16) & 0x1ff;
s = (hsv >> 8) & 0xff;
v = hsv & 0xff;
max = (float)v;
min = max - ((float)s / 255.0) * max;
if(h>=0 && h<60){
r = (uint8_t)max;
g = (uint8_t)(((float)h / 60.0) * (max - min) + min + 0.5);
b = (uint8_t)(min + 0.5);
}else if(h>=60 && h<120){
r = (uint8_t)(((120.0 - (float)h) / 60.0) * (max - min) + min + 0.5);
g = (uint8_t)max;
b = (uint8_t)(min + 0.5);
}else if(h>=120 && h<180){
r = (uint8_t)(min + 0.5);
g = (uint8_t)max;
b = (uint8_t)((((float)h - 120.0) / 60.0) * (max - min) + min + 0.5);
}else if(h>=180 && h<240){
r = (uint8_t)(min + 0.5);
g = (uint8_t)(((240.0 - (float)h) / 60.0) * (max - min) + min + 0.5);
b = (uint8_t)max;
}else if(h>=240 && h<300){
r = (uint8_t)((((float)h - 240.0) / 60.0) * (max - min) + min + 0.5);
g = (uint8_t)(min + 0.5);
b = (uint8_t)max;
}else{ // h>=300 && h<=360
r = (uint8_t)max;
g = (uint8_t)(min + 0.5);
b = (uint8_t)(((360.0 - (float)h) / 60.0) * (max - min) + min + 0.5);
}
rgb = (r << 16) + (g << 8) + b;
return(rgb);
}
を設定した。-I/usr/local/include
を設定した。-L/usr/local/lib -lopencv_core -lopencv_imgcodecs -lopencv_imgproc
int HSVConverter(hls::stream<ap_axiu<32,1,1,1> >& ins,
hls::stream<ap_axiu<32,1,1,1> >& outs, int32_t function,
int32_t row_size, int32_t col_size,
int32_t h_add,
ap_ufixed<16, 8, AP_TRN_ZERO, AP_SAT> s_mult, int32_t s_add,
ap_ufixed<16, 8, AP_TRN_ZERO, AP_SAT> v_mult, int32_t v_add);
// RGB24toHSV.cpp
// 2023/10/09 by marsee
// 2023/10/15 : バグを修正
// 2023/10/17 : MAG を 8 ビットから 16 ビットに変更
//
// 入力フォーマット:23ビット〜16ビットーRED、15ビット〜8ビットーGREEN、7ビット〜0ビットーBLUE
// 出力フォーマット:24ビット〜16ビットー H、15ビット〜8ビットーS、7ビット〜0ビットーV
// ”RGBとHSV・HSBの相互変換ツールと変換計算式”を参考にしています (https://www.peko-step.com/tool/hsvrgb.html)
#include <stdint.h>
#include <ap_int.h>
#include <hls_stream.h>
#include <ap_axi_sdata.h>
#define MAG 16 // 小数点以下のビット幅
#define ForAXIVdma 0
#define ForAXIDma 1
int RGB24toHSV(hls::stream<ap_axiu<24,1,1,1> >& ins, hls::stream<ap_axiu<32,1,1,1> >& outs,
int32_t function, int32_t row_size, int32_t col_size){
#pragma HLS INTERFACE mode=s_axilite port=function
#pragma HLS INTERFACE mode=s_axilite port=col_size
#pragma HLS INTERFACE mode=s_axilite port=row_size
#pragma HLS INTERFACE mode=s_axilite port=return
#pragma HLS INTERFACE mode=axis register_mode=both port=outs register
#pragma HLS INTERFACE mode=axis register_mode=both port=ins register
ap_axiu<24,1,1,1> pix;
ap_axiu<32,1,1,1> hsvst;
int32_t r, g, b;
int32_t h, s, v;
int32_t max, min;
int32_t hsv;
do{
#pragma HLS LOOP_TRIPCOUNT min=1 max=1 avg=1
ins >> pix;
if(function == ForAXIDma)
break;
}while(pix.user == 0);
loop_y: for(int y=0; y<row_size; y++){
#pragma HLS LOOP_TRIPCOUNT avg=600 max=1080 min=48
loop_x: for(int x=0; x<col_size; x++){
#pragma HLS LOOP_TRIPCOUNT avg=800 max=1920 min=64
if(!(x==0 && y==0)) // 最初の入力はすでに入力されている
ins >> pix; // AXI4-Stream からの入力
b = pix.data & 0xff;
g = (pix.data>>8) & 0xff;
r = (pix.data>>16) & 0xff;
// h と max, min を求める
if(r==g && g==b && r==b){
max = r; // 8倍
min = r;
}else if(r>=g && r>=b){ // r が最大
max = r;
if(g>=b)
min = b;
else
min = g;
}else if(g>=r && g>=b){ // g が最大
max = g;
if(r>=b)
min = b;
else
min = r;
}else{ // b が最大
max = b;
if(r>=g)
min = g;
else
min = r;
}
if(max-min == 0)
h = 0;
else if(max == r)
h = 60 * (((g-b)<<MAG)/(max-min)); // MAGビットシフトして精度を確保
else if(max == g)
h = 60 * (((b-r)<<MAG)/(max-min)) + (120<<MAG); // MAGビットシフトして精度を確保
else // if(max == b)
h = 60 * (((r-g)<<MAG)/(max-min)) + (240<<MAG); // MAGビットシフトして精度を確保
if(h < 0)
h += 360<<MAG;
h += 1<<(MAG-1); // +0.5、四捨五入
h >>= MAG; // 桁を戻す
if(max == 0)
s = 0;
else
s = (((max - min)<<MAG)/max) * 255; // MAGビットシフトして精度を確保
s += 1<<(MAG-1); // +0.5、四捨五入
s >>= MAG; // 桁を戻す
v = max;
hsv = ((h&0x1ff)<<16) + ((s&0xff)<<8) + (v&0xff);
hsvst.data = hsv;
if(function == ForAXIVdma){
if (x==0 && y==0) // 最初のデータでは、TUSERをアサートする
hsvst.user = 1;
else
hsvst.user = 0;
if (x == (col_size-1)) // 行の最後で TLAST をアサートする
hsvst.last = 1;
else
hsvst.last = 0;
} else {
hsvst.user = 0;
hsvst.last = pix.last;
}
hsvst.keep = 0xf;
hsvst.strb = 0xf;
outs << hsvst;
}
}
return(0);
}
// RGB24toHSV_tb.cpp
// 2023/10/09 by marsee
// 2023/10/15 : バグを修正、RGB値、HSV値をテキスト・ファイルに出力した。
// 2023/10/17 : MAG を 8 ビットから 16 ビットに変更、RGB24toHSV_soft() を浮動小数点数で実装
//
// ”RGBとHSV・HSBの相互変換ツールと変換計算式”を参考にしています (https://www.peko-step.com/tool/hsvrgb.html)
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <ap_int.h>
#include <hls_stream.h>
#include <iostream>
#include <fstream>
#include <math.h>
#include <ap_axi_sdata.h>
#include "bmp_header.h"
#define ForAXIVdma 0
#define ForAXIDma 1
#define BMP_FILE_NAME "test2.bmp"
#define SQUARE_ERROR_LIMIT 1 // 2乗誤差のエラー限界、この数より上はエラーとする
#define H 0
#define S 1
#define V 2
#define HSV_TEXT 0
#define RGB_TEXT 1
int RGB24toHSV(hls::stream<ap_axiu<24,1,1,1> >& ins, hls::stream<ap_axiu<32,1,1,1> >& outs,
int32_t function, int32_t row_size, int32_t col_size);
int RGB24toHSV_soft(hls::stream<ap_axiu<24,1,1,1> >& ins, hls::stream<ap_axiu<32,1,1,1> >& outs,
int32_t function, int32_t row_size, int32_t col_size);
void WriteBmpFile(FILE *fbmpw, BITMAPFILEHEADER &bmpfhr, BITMAPINFOHEADER &bmpihr, uint32_t *pixel_buf, uint32_t select_hsv);
int WriteTextFile(FILE *fbmpw, BITMAPFILEHEADER &bmpfhr, BITMAPINFOHEADER &bmpihr, uint32_t *pixel_buf, uint32_t HSVorRGB);
int main(){
using namespace std;
hls::stream<ap_axiu<24,1,1,1> > ins;
hls::stream<ap_axiu<24,1,1,1> > ins_soft;
hls::stream<ap_axiu<32,1,1,1> > outs;
hls::stream<ap_axiu<32,1,1,1> > outs_soft;
ap_axiu<24,1,1,1> pix;
ap_axiu<32,1,1,1> vals;
ap_axiu<32,1,1,1> vals_soft;
BITMAPFILEHEADER bmpfhr; // BMPファイルのファイルヘッダ(for Read)
BITMAPINFOHEADER bmpihr; // BMPファイルのINFOヘッダ(for Read)
FILE *fbmpr, *fbmpw, *fbmpwf;
uint32_t *rd_bmp, *hw_hsv, *sw_hsv;
uint32_t blue, green, red;
if ((fbmpr = fopen(BMP_FILE_NAME, "rb")) == NULL){ // BMP ファイル をオープン
fprintf(stderr, "Can't open test2.bmp by binary read mode\n");
exit(1);
}
// bmpヘッダの読み出し
fread(&bmpfhr.bfType, sizeof(uint16_t), 1, fbmpr);
fread(&bmpfhr.bfSize, sizeof(uint32_t), 1, fbmpr);
fread(&bmpfhr.bfReserved1, sizeof(uint16_t), 1, fbmpr);
fread(&bmpfhr.bfReserved2, sizeof(uint16_t), 1, fbmpr);
fread(&bmpfhr.bfOffBits, sizeof(uint32_t), 1, fbmpr);
fread(&bmpihr, sizeof(BITMAPINFOHEADER), 1, fbmpr);
// ピクセルを入れるメモリをアロケートする
if ((rd_bmp =(uint32_t *)malloc(sizeof(uint32_t) * (bmpihr.biWidth * bmpihr.biHeight))) == NULL){
fprintf(stderr, "Can't allocate rd_bmp memory\n");
exit(1);
}
if ((hw_hsv =(uint32_t *)malloc(sizeof(uint32_t) * (bmpihr.biWidth * bmpihr.biHeight))) == NULL){
fprintf(stderr, "Can't allocate hw_hsv memory\n");
exit(1);
}
if ((sw_hsv =(uint32_t *)malloc(sizeof(uint32_t) * (bmpihr.biWidth * bmpihr.biHeight))) == NULL){
fprintf(stderr, "Can't allocate sw_hsv memory\n");
exit(1);
}
// rd_bmp にBMPのピクセルを代入。その際に、行を逆転する必要がある
for (int y=0; y<bmpihr.biHeight; y++){
for (int x=0; x<bmpihr.biWidth; x++){
blue = fgetc(fbmpr);
green = fgetc(fbmpr);
red = fgetc(fbmpr);
rd_bmp[((bmpihr.biHeight-1)-y)*bmpihr.biWidth+x] = (blue & 0xff) | ((green & 0xff)<<8) | ((red & 0xff)<<16);
}
}
fclose(fbmpr);
// ins に入力データを用意する
for(int i=0; i<5; i++){ // dummy data
pix.user = 0;
pix.data = i;
ins << pix;
ins_soft << pix;
}
for(int j=0; j < bmpihr.biHeight; j++){
for(int i=0; i < bmpihr.biWidth; i++){
pix.data = (ap_int<32>)rd_bmp[(j*bmpihr.biWidth)+i];
if (j==0 && i==0) // 最初のデータの時に TUSER を 1 にする
pix.user = 1;
else
pix.user = 0;
if (i == bmpihr.biWidth-1) // 行の最後でTLASTをアサートする
pix.last = 1;
else
pix.last = 0;
ins << pix;
ins_soft << pix;
}
}
RGB24toHSV(ins, outs, ForAXIVdma, bmpihr.biHeight, bmpihr.biWidth);
RGB24toHSV_soft(ins_soft, outs_soft, ForAXIVdma, bmpihr.biHeight, bmpihr.biWidth);
// ハードウェアとソフトウェアのラプラシアン・フィルタの値のチェック
cout << endl;
cout << "outs" << endl;
for(int j=0; j < bmpihr.biHeight; j++){
for(int i=0; i < bmpihr.biWidth; i++){
outs >> vals;
outs_soft >> vals_soft;
ap_int<32> val = vals.data;
ap_int<32> val_soft = vals_soft.data;
hw_hsv[(j*bmpihr.biWidth)+i] = (int)val;
sw_hsv[(j*bmpihr.biWidth)+i] = (int)val_soft;
red = (rd_bmp[(j*bmpihr.biWidth)+i]>>16) & 0xff;
green = (rd_bmp[(j*bmpihr.biWidth)+i]>>8) & 0xff;
blue = rd_bmp[(j*bmpihr.biWidth)+i] & 0xff;
if ((double)pow((double)(val&0xff)-(val_soft&0xff),(double)2) > SQUARE_ERROR_LIMIT || // v の2乗誤差が4よりも大きい
(double)pow((double)((val>>8)&0xff)-((val_soft>>8)&0xff),(double)2) > SQUARE_ERROR_LIMIT || // s の2乗誤差が4よりも大きい
(double)pow((double)((val>>16)&0x1ff)-((val_soft>>16)&0x1ff),(double)2) > SQUARE_ERROR_LIMIT){ // h の2乗誤差が4よりも大きい
printf("ERROR HW and SW results mismatch i = %ld, j = %ld, Red = %d, Green = %d, Blue = %d, "
"HW_h = %d, HW_s = %d, HW_v = %d, SW_h = %d, SW_s = %d, SW_v = %d\n",
i, j, red, green, blue, (int)(val>>16)&0xff, (int)(val>>8)&0xff, (int)val&0xff,
(int)(val_soft>>16)&0xff, (int)(val_soft>>8)&0xff, (int)val_soft&0xff);
//return(1);
}
//if (vals.last)
//cout << "AXI-Stream is end" << endl;
}
}
cout << "Success HW and SW results match" << endl;
cout << endl;
if ((fbmpw=fopen("h_hw.bmp", "wb")) == NULL){
fprintf(stderr, "Can't open h_hw.bmp by binary write mode\n");
exit(1);
}
WriteBmpFile(fbmpw, bmpfhr, bmpihr, hw_hsv, H);
if ((fbmpw=fopen("s_hw.bmp", "wb")) == NULL){
fprintf(stderr, "Can't open s_hw.bmp by binary write mode\n");
exit(1);
}
WriteBmpFile(fbmpw, bmpfhr, bmpihr, hw_hsv, S);
if ((fbmpw=fopen("v_hw.bmp", "wb")) == NULL){
fprintf(stderr, "Can't open v_hw.bmp by binary write mode\n");
exit(1);
}
WriteBmpFile(fbmpw, bmpfhr, bmpihr, hw_hsv, V);
if ((fbmpw=fopen("h_sw.bmp", "wb")) == NULL){
fprintf(stderr, "Can't open h_sw.bmp by binary write mode\n");
exit(1);
}
WriteBmpFile(fbmpw, bmpfhr, bmpihr, sw_hsv, H);
if ((fbmpw=fopen("s_sw.bmp", "wb")) == NULL){
fprintf(stderr, "Can't open s_sw.bmp by binary write mode\n");
exit(1);
}
WriteBmpFile(fbmpw, bmpfhr, bmpihr, sw_hsv, S);
if ((fbmpw=fopen("v_sw.bmp", "wb")) == NULL){
fprintf(stderr, "Can't open v_sw.bmp by binary write mode\n");
exit(1);
}
WriteBmpFile(fbmpw, bmpfhr, bmpihr, sw_hsv, V);
if ((fbmpw=fopen("rgb_text.txt", "wt")) == NULL){
fprintf(stderr, "Can't open rgb_text.txt by binary write mode\n");
exit(1);
}
WriteTextFile(fbmpw, bmpfhr, bmpihr, rd_bmp, RGB_TEXT);
if ((fbmpw=fopen("hsv_text.txt", "wt")) == NULL){
fprintf(stderr, "Can't open hsv_text.txt by binary write mode\n");
exit(1);
}
WriteTextFile(fbmpw, bmpfhr, bmpihr, hw_hsv, HSV_TEXT);
free(rd_bmp);
free(hw_hsv);
free(sw_hsv);
}
// float で計算を行う
int RGB24toHSV_soft(hls::stream<ap_axiu<24,1,1,1> >& ins, hls::stream<ap_axiu<32,1,1,1> >& outs,
int32_t function, int32_t row_size, int32_t col_size){
ap_axiu<24,1,1,1> pix;
ap_axiu<32,1,1,1> hsvst;
int32_t r, g, b;
int32_t h, s, v;
float ht, st;
float max, min;
int32_t hsv;
do{
ins >> pix;
if(function == ForAXIDma)
break;
}while(pix.user == 0);
for(int y=0; y<row_size; y++){
for(int x=0; x<col_size; x++){
if(!(x==0 && y==0)) // 最初の入力はすでに入力されている
ins >> pix; // AXI4-Stream からの入力
b = pix.data & 0xff;
g = (pix.data>>8) & 0xff;
r = (pix.data>>16) & 0xff;
// h と max, min を求める
if(r==g && g==b && r==b){
max = (float)r; // 8倍
min = (float)r;
}else if(r>=g && r>=b){ // r が最大
max = (float)r;
if(g>=b)
min = (float)b;
else
min = (float)g;
}else if(g>=r && g>=b){ // g が最大
max = (float)g;
if(r>=b)
min = (float)b;
else
min = (float)r;
}else{ // b が最大
max = (float)b;
if(r>=g)
min = (float)g;
else
min = (float)r;
}
if(max-min == 0.0)
ht = 0.0;
else if(max == (float)r)
ht = 60.0 * (((float)g-(float)b)/(max-min));
else if(max == (float)g)
ht = 60.0 * (((float)b-(float)r)/(max-min)) + 120.0; // MAGビットシフトして精度を確保
else // if(max == b)
ht = 60.0 * (((float)r-(float)g)/(max-min)) + 240.0; // MAGビットシフトして精度を確保
if(ht < 0)
ht += 360.0;
h = (uint32_t)(ht + 0.5);
if(max == 0.0)
st = 0.0;
else
st = ((max - min)/max) * 255.0; // MAGビットシフトして精度を確保
s = (uint32_t)(st + 0.5);
v = (uint32_t)max;
hsv = ((h&0x1ff)<<16) + ((s&0xff)<<8) + (v&0xff);
hsvst.data = hsv;
if(function == ForAXIVdma){
if (x==0 && y==0) // 最初のデータでは、TUSERをアサートする
hsvst.user = 1;
else
hsvst.user = 0;
if (x == (col_size-1)) // 行の最後で TLAST をアサートする
hsvst.last = 1;
else
hsvst.last = 0;
} else {
hsvst.user = 0;
hsvst.last = pix.last;
}
hsvst.keep = 0xf;
hsvst.strb = 0xf;
outs << hsvst;
}
}
return(0);
}
// SV のうちの1つをblue, green, redの値として同じ値をBMPファイルに書く
// H は S,V の値を255とした時の H の値に対する RGB の値を計算する
void WriteBmpFile(FILE *fbmpw, BITMAPFILEHEADER &bmpfhr, BITMAPINFOHEADER &bmpihr, uint32_t *pixel_buf, uint32_t select_hsv){
uint32_t h;
uint32_t sv;
uint32_t r, g, b;
// BMPファイルヘッダの書き込み
fwrite(&bmpfhr.bfType, sizeof(uint16_t), 1, fbmpw);
fwrite(&bmpfhr.bfSize, sizeof(uint32_t), 1, fbmpw);
fwrite(&bmpfhr.bfReserved1, sizeof(uint16_t), 1, fbmpw);
fwrite(&bmpfhr.bfReserved2, sizeof(uint16_t), 1, fbmpw);
fwrite(&bmpfhr.bfOffBits, sizeof(uint32_t), 1, fbmpw);
fwrite(&bmpihr, sizeof(BITMAPINFOHEADER), 1, fbmpw);
// RGB データの書き込み、逆順にする
for (int y=0; y<bmpihr.biHeight; y++){
for (int x=0; x<bmpihr.biWidth; x++){
switch(select_hsv){
case H:
h = (pixel_buf[((bmpihr.biHeight-1)-y)*bmpihr.biWidth+x]>>16) & 0x1ff;
if(h>=0 && h<60){
r = 255;
g = (int)(((float)h/60.0)*255.0+0.5);
b = 0;
}else if(h>=60 && h<120){
r = (int)(((120.0-(float)h)/60.0)*255+0.5);
g = 255;
b = 0;
}else if(h>=120 && h<180){
r = 0;
g = 255;
b = (int)((((float)h-120.0)/60.0)*255+0.5);
}else if(h>=180 && h<240){
r = 0;
g = (int)(((240.0-(float)h)/60.0)*255+0.5);
b = 255;
}else if(h>=240 && h<300){
r = (int)((((float)h-240.0)/60.0)*255+0.5);
g = 0;
b = 255;
}else{ // h>=300 && h<=360
r = 255;
g = 0;
b = (int)(((360.0-(float)h)/60.0)*255+0.5);
}
break;
case S:
sv = (pixel_buf[((bmpihr.biHeight-1)-y)*bmpihr.biWidth+x] >> 8) & 0xff;
break;
default: // case V:
sv = pixel_buf[((bmpihr.biHeight-1)-y)*bmpihr.biWidth+x] & 0xff;
break;
}
if(select_hsv==S || select_hsv==V){
fputc(sv, fbmpw);
fputc(sv, fbmpw);
fputc(sv, fbmpw);
}else{
fputc(b, fbmpw);
fputc(g, fbmpw);
fputc(r, fbmpw);
}
}
}
fclose(fbmpw);
}
// rgb, hsv をテキストファイルに書き込む
int WriteTextFile(FILE *fbmpw, BITMAPFILEHEADER &bmpfhr, BITMAPINFOHEADER &bmpihr, uint32_t *pixel_buf, uint32_t HSVorRGB){
uint32_t hr, sg, vb;
for (int y=0; y<bmpihr.biHeight; y++){
for (int x=0; x<bmpihr.biWidth; x++){
if (HSVorRGB == HSV_TEXT)
hr = (pixel_buf[y*bmpihr.biWidth+x]>>16) & 0x1ff;
else
hr = (pixel_buf[y*bmpihr.biWidth+x]>>16) & 0xff;
sg = (pixel_buf[y*bmpihr.biWidth+x] >> 8) & 0xff;
vb = pixel_buf[y*bmpihr.biWidth+x] & 0xff;
fprintf(fbmpw, "%d, %d, %d\n",hr, sg, vb);
}
}
fclose(fbmpw);
return(0);
}
// HSVtoRGB24.cpp
// 2023/10/12 by marsee
// 2023/10/16 : バグをフィックスした
//
// 入力フォーマット:24ビット〜16ビットー H、15ビット〜8ビットーS、7ビット〜0ビットーV
// 出力フォーマット:23ビット〜16ビットーRED、15ビット〜8ビットーGREEN、7ビット〜0ビットーBLUE
// ”RGBとHSV・HSBの相互変換ツールと変換計算式”を参考にしています (https://www.peko-step.com/tool/hsvrgb.html)
#include <stdint.h>
#include <ap_int.h>
#include <hls_stream.h>
#include <ap_axi_sdata.h>
#define ForAXIVdma 0
#define ForAXIDma 1
int HSVtoRGB24(hls::stream<ap_axiu<32,1,1,1> >& ins, hls::stream<ap_axiu<24,1,1,1> >& outs,
int32_t function, int32_t row_size, int32_t col_size){
#pragma HLS INTERFACE mode=s_axilite port=return
#pragma HLS INTERFACE mode=s_axilite port=col_size register
#pragma HLS INTERFACE mode=s_axilite port=row_size register
#pragma HLS INTERFACE mode=s_axilite port=function
#pragma HLS INTERFACE mode=axis register_mode=both port=outs register
#pragma HLS INTERFACE mode=axis register_mode=both port=ins register
ap_ufixed<32,16, AP_TRN_ZERO, AP_SAT> ht, st, vt;
ap_ufixed<32,16, AP_TRN_ZERO, AP_SAT> max, min;
uint8_t r, g, b;
uint32_t h, s, v;
ap_axiu<32,1,1,1> hsve;
ap_axiu<24,1,1,1> rgbe;
ap_ufixed<32, 16, AP_TRN_ZERO, AP_SAT> ap_0_5, ap_60, ap_120, ap_240, ap_360;
ap_0_5 = (ap_ufixed<32,16, AP_TRN_ZERO, AP_SAT>)0.5;
ap_60 = (ap_ufixed<32,16, AP_TRN_ZERO, AP_SAT>)60;
ap_120 = (ap_ufixed<32,16, AP_TRN_ZERO, AP_SAT>)120;
ap_240 = (ap_ufixed<32,16, AP_TRN_ZERO, AP_SAT>)240;
ap_360 = (ap_ufixed<32,16, AP_TRN_ZERO, AP_SAT>)360;
do{
#pragma HLS LOOP_TRIPCOUNT min=1 max=1 avg=1
ins >> hsve;
if(function == ForAXIDma)
break;
}while(hsve.user == 0);
loop_y: for(int y=0; y<row_size; y++){
#pragma HLS LOOP_TRIPCOUNT avg=600 max=1080 min=48
loop_x: for(int x=0; x<col_size; x++){
#pragma HLS LOOP_TRIPCOUNT avg=800 max=1920 min=64
if(!(x==0 && y==0)) // 最初の入力はすでに入力されている
ins >> hsve; // AXI4-Stream からの入力
h = (hsve.data >> 16) & 0x1ff;
s = (hsve.data >> 8) & 0xff;
v = hsve.data & 0xff;
ht = (ap_ufixed<32,16, AP_TRN_ZERO, AP_SAT>)h;
st = (ap_ufixed<32,16, AP_TRN_ZERO, AP_SAT>)s;
vt = (ap_ufixed<32,16, AP_TRN_ZERO, AP_SAT>)v;
max = vt;
min = max - (st / (ap_ufixed<32,16, AP_TRN_ZERO, AP_SAT>)255) * max;
if(h>=0 && h<60){
r = (uint8_t)max;
g = (uint8_t)((ht / ap_60) * (max - min) + min + ap_0_5);
b = (uint8_t)(min + ap_0_5);
}else if(h>=60 && h<120){
r = (uint8_t)(((ap_120 - ht) / ap_60) * (max - min) + min + ap_0_5);
g = (uint8_t)max;
b = (uint8_t)(min + ap_0_5);
}else if(h>=120 && h<180){
r = (uint8_t)(min + ap_0_5);
g = (uint8_t)max;
b = (uint8_t)(((ht - ap_120) / ap_60) * (max - min) + min + ap_0_5);
}else if(h>=180 && h<240){
r = (uint8_t)(min + ap_0_5);
g = (uint8_t)(((ap_240 - ht) / ap_60) * (max - min) + min + ap_0_5);
b = (uint8_t)max;
}else if(h>=240 && h<300){
r = (uint8_t)(((ht - ap_240) / ap_60) * (max - min) + min + ap_0_5);
g = (uint8_t)(min + ap_0_5);
b = (uint8_t)max;
}else{ // h>=300 && h<=360
r = (uint8_t)max;
g = (uint8_t)(min + ap_0_5);
b = (uint8_t)(((ap_360 - ht) / ap_60) * (max - min) + min + ap_0_5);
}
rgbe.data = (r << 16) + (g << 8) + b;
if(function == ForAXIVdma){
if (x==0 && y==0) // 最初のデータでは、TUSERをアサートする
rgbe.user = 1;
else
rgbe.user = 0;
if (x == (col_size-1)) // 行の最後で TLAST をアサートする
rgbe.last = 1;
else
rgbe.last = 0;
} else {
rgbe.user = 0;
rgbe.last = hsve.last;
}
rgbe.keep = 0xf;
rgbe.strb = 0xf;
outs << rgbe;
}
}
return(0);
}
// HSVtoRGB24_tb.cpp
// 2023/10/12 by marsee
// 2023/10/16 : バグをフィックスした。原画像のデータのテキストとRGB-HSV 、HSV-RGB 変換の結果をテキストで表示
//
// HSVのフォーマット:24ビット〜16ビットー H、15ビット〜8ビットーS、7ビット〜0ビットーV
// RGBのフォーマット:23ビット〜16ビットーRED、15ビット〜8ビットーGREEN、7ビット〜0ビットーBLUE
// ”RGBとHSV・HSBの相互変換ツールと変換計算式”を参考にしています (https://www.peko-step.com/tool/hsvrgb.html)
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <ap_int.h>
#include <hls_stream.h>
#include <iostream>
#include <fstream>
#include <math.h>
#include <ap_axi_sdata.h>
#include <ap_fixed.h>
#include "bmp_header.h"
#define ForAXIVdma 0
#define ForAXIDma 1
#define MAG 16 // 小数点以下のビット幅
#define BMP_FILE_NAME "test2.bmp"
#define HS_SQUARE_ERROR_LIMIT 4 // 2乗誤差のエラー限界、この数以上はエラーとする
#define ORG_SQUARE_ERROR_LIMIT 4
// 2乗誤差のエラー限界、この数以上はエラーとする
#define HSV_TEXT 0
#define RGB_TEXT 1
int RGB24toHSV(hls::stream<ap_axiu<24,1,1,1> >& ins, hls::stream<ap_axiu<32,1,1,1> >& outs,
int32_t function, int32_t row_size, int32_t col_size);
int RGB24toHSV_soft(hls::stream<ap_axiu<24,1,1,1> >& ins, hls::stream<ap_axiu<32,1,1,1> >& outs,
int32_t function, int32_t row_size, int32_t col_size);
void WriteBmpFile(FILE *fbmpw, BITMAPFILEHEADER &bmpfhr, BITMAPINFOHEADER &bmpihr, uint32_t *pixel_buf);
int HSVtoRGB24(hls::stream<ap_axiu<32,1,1,1> >& ins, hls::stream<ap_axiu<24,1,1,1> >& outs,
int32_t function, int32_t row_size, int32_t col_size);
int HSVtoRGB24_soft(hls::stream<ap_axiu<32,1,1,1> >& ins, hls::stream<ap_axiu<24,1,1,1> >& outs,
int32_t function, int32_t row_size, int32_t col_size);
int WriteTextFile(FILE *fbmpw, BITMAPFILEHEADER &bmpfhr, BITMAPINFOHEADER &bmpihr, uint32_t *pixel_buf, uint32_t HSVorRGB);
int main(){
using namespace std;
hls::stream<ap_axiu<24,1,1,1> > ins;
hls::stream<ap_axiu<24,1,1,1> > ins_soft;
hls::stream<ap_axiu<32,1,1,1> > hsvs;
hls::stream<ap_axiu<32,1,1,1> > hsvs_soft;
hls::stream<ap_axiu<24,1,1,1> > outs;
hls::stream<ap_axiu<24,1,1,1> > outs_soft;
ap_axiu<24,1,1,1> pix;
ap_axiu<24,1,1,1> vals;
ap_axiu<24,1,1,1> vals_soft;
BITMAPFILEHEADER bmpfhr; // BMPファイルのファイルヘッダ(for Read)
BITMAPINFOHEADER bmpihr; // BMPファイルのINFOヘッダ(for Read)
FILE *fbmpr, *fbmpw, *fbmpwf;
uint32_t *rd_bmp, *hw_rgb, *sw_rgb;
uint32_t blue, green, red;
if ((fbmpr = fopen(BMP_FILE_NAME, "rb")) == NULL){ // BMP ファイル をオープン
fprintf(stderr, "Can't open test2.bmp by binary read mode\n");
exit(1);
}
// bmpヘッダの読み出し
fread(&bmpfhr.bfType, sizeof(uint16_t), 1, fbmpr);
fread(&bmpfhr.bfSize, sizeof(uint32_t), 1, fbmpr);
fread(&bmpfhr.bfReserved1, sizeof(uint16_t), 1, fbmpr);
fread(&bmpfhr.bfReserved2, sizeof(uint16_t), 1, fbmpr);
fread(&bmpfhr.bfOffBits, sizeof(uint32_t), 1, fbmpr);
fread(&bmpihr, sizeof(BITMAPINFOHEADER), 1, fbmpr);
// ピクセルを入れるメモリをアロケートする
if ((rd_bmp =(uint32_t *)malloc(sizeof(uint32_t) * (bmpihr.biWidth * bmpihr.biHeight))) == NULL){
fprintf(stderr, "Can't allocate rd_bmp memory\n");
exit(1);
}
if ((hw_rgb =(uint32_t *)malloc(sizeof(uint32_t) * (bmpihr.biWidth * bmpihr.biHeight))) == NULL){
fprintf(stderr, "Can't allocate hw_rgb memory\n");
exit(1);
}
if ((sw_rgb =(uint32_t *)malloc(sizeof(uint32_t) * (bmpihr.biWidth * bmpihr.biHeight))) == NULL){
fprintf(stderr, "Can't allocate sw_rgb memory\n");
exit(1);
}
// rd_bmp にBMPのピクセルを代入。その際に、行を逆転する必要がある
for (int y=0; y<bmpihr.biHeight; y++){
for (int x=0; x<bmpihr.biWidth; x++){
blue = fgetc(fbmpr);
green = fgetc(fbmpr);
red = fgetc(fbmpr);
rd_bmp[((bmpihr.biHeight-1)-y)*bmpihr.biWidth+x] = (blue & 0xff) | ((green & 0xff)<<8) | ((red & 0xff)<<16);
}
}
fclose(fbmpr);
// ins に入力データを用意する
for(int i=0; i<5; i++){ // dummy data
pix.user = 0;
pix.data = i;
ins << pix;
ins_soft << pix;
}
for(int j=0; j < bmpihr.biHeight; j++){
for(int i=0; i < bmpihr.biWidth; i++){
pix.data = (ap_int<32>)rd_bmp[(j*bmpihr.biWidth)+i];
if (j==0 && i==0) // 最初のデータの時に TUSER を 1 にする
pix.user = 1;
else
pix.user = 0;
if (i == bmpihr.biWidth-1) // 行の最後でTLASTをアサートする
pix.last = 1;
else
pix.last = 0;
ins << pix;
ins_soft << pix;
}
}
RGB24toHSV_soft(ins, hsvs, ForAXIVdma, bmpihr.biHeight, bmpihr.biWidth);
RGB24toHSV_soft(ins_soft, hsvs_soft, ForAXIVdma, bmpihr.biHeight, bmpihr.biWidth);
HSVtoRGB24(hsvs, outs, ForAXIVdma, bmpihr.biHeight, bmpihr.biWidth);
HSVtoRGB24_soft(hsvs_soft, outs_soft, ForAXIVdma, bmpihr.biHeight, bmpihr.biWidth);
// ハードウェアとソフトウェアの RGB - HSV - RGB の値を比較する
for(int j=0; j < bmpihr.biHeight; j++){
for(int i=0; i < bmpihr.biWidth; i++){
outs >> vals;
outs_soft >> vals_soft;
ap_int<24> val = vals.data;
ap_int<24> val_soft = vals_soft.data;
hw_rgb[(j*bmpihr.biWidth)+i] = (int)val;
sw_rgb[(j*bmpihr.biWidth)+i] = (int)val_soft;
red = (rd_bmp[(j*bmpihr.biWidth)+i]>>16) & 0xff;
green = (rd_bmp[(j*bmpihr.biWidth)+i]>>8) & 0xff;
blue = rd_bmp[(j*bmpihr.biWidth)+i] & 0xff;
if ((double)pow((double)(val&0xff)-(val_soft&0xff),(double)2) > HS_SQUARE_ERROR_LIMIT || // B の2乗誤差がSQUARE_ERROR_LIMITよりも大きい
(double)pow((double)((val>>8)&0xff)-((val_soft>>8)&0xff),(double)2) > HS_SQUARE_ERROR_LIMIT || // G の2乗誤差がSQUARE_ERROR_LIMITよりも大きい
(double)pow((double)((val>>16)&0xff)-((val_soft>>16)&0xff),(double)2) > HS_SQUARE_ERROR_LIMIT){ // R の2乗誤差が4よりも大きい
printf("ERROR HW and SW results mismatch i = %ld, j = %ld, Red = %d, Green = %d, Blue = %d, "
"HW_r = %d, HW_g = %d, HW_b = %d, SW_r = %d, SW_g = %d, SW_b = %d\n",
i, j, red, green, blue, (int)(val>>16)&0xff, (int)(val>>8)&0xff, (int)val&0xff,
(int)(val_soft>>16)&0xff, (int)(val_soft>>8)&0xff, (int)val_soft&0xff);
//return(1);
}
if ((double)pow((double)(val&0xff)-blue,(double)2) > ORG_SQUARE_ERROR_LIMIT || // B の2乗誤差がSQUARE_ERROR_LIMITよりも大きい
(double)pow((double)((val>>8)&0xff)-green,(double)2) > ORG_SQUARE_ERROR_LIMIT || // G の2乗誤差がSQUARE_ERROR_LIMITよりも大きい
(double)pow((double)((val>>16)&0xff)-red,(double)2) > ORG_SQUARE_ERROR_LIMIT){ // R の2乗誤差がSQUARE_ERROR_LIMITよりも大きい
printf("ERROR original BMP data and RGB-HSV-RGB data mismatch i = %ld, j = %ld, Red = %d, Green = %d, Blue = %d, "
"HW_r = %d, HW_g = %d, HW_b = %d\n",
i, j, red, green, blue, (int)(val>>16)&0xff, (int)(val>>8)&0xff, (int)val&0xff);
}
//if (vals.last)
//cout << "AXI-Stream is end" << endl;
}
}
cout << "Success HW and SW results match" << endl;
cout << endl;
if ((fbmpw=fopen("hw_rgb.bmp", "wb")) == NULL){
fprintf(stderr, "Can't open hw_rgb.bmp by binary write mode\n");
exit(1);
}
WriteBmpFile(fbmpw, bmpfhr, bmpihr, hw_rgb);
if ((fbmpw=fopen("sw_rgb.bmp", "wb")) == NULL){
fprintf(stderr, "Can't open sw_rgb.bmp by binary write mode\n");
exit(1);
}
WriteBmpFile(fbmpw, bmpfhr, bmpihr, sw_rgb);
if ((fbmpw=fopen("org_rgb.txt", "wt")) == NULL){
fprintf(stderr, "Can't open org_rgb.txt by binary write mode\n");
exit(1);
}
WriteTextFile(fbmpw, bmpfhr, bmpihr, rd_bmp, RGB_TEXT);
if ((fbmpw=fopen("rgb_text.txt", "wt")) == NULL){
fprintf(stderr, "Can't open rgb_text.txt by binary write mode\n");
exit(1);
}
WriteTextFile(fbmpw, bmpfhr, bmpihr, hw_rgb, RGB_TEXT);
free(rd_bmp);
free(hw_rgb);
free(sw_rgb);
}
int RGB24toHSV_soft(hls::stream<ap_axiu<24,1,1,1> >& ins, hls::stream<ap_axiu<32,1,1,1> >& outs,
int32_t function, int32_t row_size, int32_t col_size){
ap_axiu<24,1,1,1> pix;
ap_axiu<32,1,1,1> hsvst;
int32_t r, g, b;
int32_t h, s, v;
int32_t max, min;
int32_t hsv;
do{
ins >> pix;
if(function == ForAXIDma)
break;
}while(pix.user == 0);
for(int y=0; y<row_size; y++){
for(int x=0; x<col_size; x++){
if(!(x==0 && y==0)) // 最初の入力はすでに入力されている
ins >> pix; // AXI4-Stream からの入力
b = pix.data & 0xff;
g = (pix.data>>8) & 0xff;
r = (pix.data>>16) & 0xff;
// h と max, min を求める
if(r==g && g==b && r==b){
max = r; // 8倍
min = r;
}else if(r>=g && r>=b){ // r が最大
max = r;
if(g>=b)
min = b;
else
min = g;
}else if(g>=r && g>=b){ // g が最大
max = g;
if(r>=b)
min = b;
else
min = r;
}else{ // b が最大
max = b;
if(r>=g)
min = g;
else
min = r;
}
if(max-min == 0)
h = 0;
else if(max == r)
h = 60 * (((g-b)<<MAG)/(max-min)); // MAGビットシフトして精度を確保
else if(max == g)
h = 60 * (((b-r)<<MAG)/(max-min)) + (120<<MAG); // MAGビットシフトして精度を確保
else // if(max == b)
h = 60 * (((r-g)<<MAG)/(max-min)) + (240<<MAG); // MAGビットシフトして精度を確保
if(h < 0)
h += 360<<MAG;
h += 1<<(MAG-1); // +0.5、四捨五入
h >>= MAG; // 桁を戻す
if(max == 0)
s = 0;
else
s = (((max - min)<<MAG)/max) * 255; // MAGビットシフトして精度を確保
s += 1<<(MAG-1); // +0.5、四捨五入
s >>= MAG; // 桁を戻す
v = max;
hsv = ((h&0x1ff)<<16) + ((s&0xff)<<8) + (v&0xff);
hsvst.data = hsv;
if(function == ForAXIVdma){
if (x==0 && y==0) // 最初のデータでは、TUSERをアサートする
hsvst.user = 1;
else
hsvst.user = 0;
if (x == (col_size-1)) // 行の最後で TLAST をアサートする
hsvst.last = 1;
else
hsvst.last = 0;
} else {
hsvst.user = 0;
hsvst.last = pix.last;
}
hsvst.keep = 0xf;
hsvst.strb = 0xf;
outs << hsvst;
}
}
return(0);
}
// pixel_buf の画像をファイルに書き込む
void WriteBmpFile(FILE *fbmpw, BITMAPFILEHEADER &bmpfhr, BITMAPINFOHEADER &bmpihr, uint32_t *pixel_buf){
uint32_t h;
uint32_t sv;
uint32_t r, g, b;
// BMPファイルヘッダの書き込み
fwrite(&bmpfhr.bfType, sizeof(uint16_t), 1, fbmpw);
fwrite(&bmpfhr.bfSize, sizeof(uint32_t), 1, fbmpw);
fwrite(&bmpfhr.bfReserved1, sizeof(uint16_t), 1, fbmpw);
fwrite(&bmpfhr.bfReserved2, sizeof(uint16_t), 1, fbmpw);
fwrite(&bmpfhr.bfOffBits, sizeof(uint32_t), 1, fbmpw);
fwrite(&bmpihr, sizeof(BITMAPINFOHEADER), 1, fbmpw);
// RGB データの書き込み、逆順にする
for (int y=0; y<bmpihr.biHeight; y++){
for (int x=0; x<bmpihr.biWidth; x++){
uint32_t rgb_data = pixel_buf[((bmpihr.biHeight-1)-y)*bmpihr.biWidth+x];
fputc(rgb_data & 0xff, fbmpw); // blue;
fputc((rgb_data >> 8) & 0xff, fbmpw); // green
fputc((rgb_data >> 16) & 0xff, fbmpw); // red
}
}
fclose(fbmpw);
}
int HSVtoRGB24_soft(hls::stream<ap_axiu<32,1,1,1> >& ins, hls::stream<ap_axiu<24,1,1,1> >& outs,
int32_t function, int32_t row_size, int32_t col_size){
ap_ufixed<32, 16, AP_TRN_ZERO, AP_SAT> ht, st, vt;
ap_ufixed<32, 16, AP_TRN_ZERO, AP_SAT> max, min;
uint8_t r, g, b;
uint32_t h;
ap_axiu<32,1,1,1> hsve;
ap_axiu<24,1,1,1> rgbe;
ap_ufixed<32, 16, AP_TRN_ZERO, AP_SAT> ap_0_5, ap_60, ap_120, ap_240, ap_360;
ap_0_5 = (ap_ufixed<32, 16, AP_TRN_ZERO, AP_SAT>)0.5;
ap_60 = (ap_ufixed<32, 16, AP_TRN_ZERO, AP_SAT>)60;
ap_120 = (ap_ufixed<32, 16, AP_TRN_ZERO, AP_SAT>)120;
ap_240 = (ap_ufixed<32, 16, AP_TRN_ZERO, AP_SAT>)240;
ap_360 = (ap_ufixed<32, 16, AP_TRN_ZERO, AP_SAT>)360;
do{
ins >> hsve;
if(function == ForAXIDma)
break;
}while(hsve.user == 0);
for(int y=0; y<row_size; y++){
for(int x=0; x<col_size; x++){
if(!(x==0 && y==0)) // 最初の入力はすでに入力されている
ins >> hsve; // AXI4-Stream からの入力
h = (hsve.data >> 16) & 0x1ff;
ht = (ap_ufixed<32, 16, AP_TRN_ZERO, AP_SAT>)((hsve.data >> 16) & 0x1ff);
st = (ap_ufixed<32, 16, AP_TRN_ZERO, AP_SAT>)((hsve.data >> 8) & 0xff);
vt = (ap_ufixed<32, 16, AP_TRN_ZERO, AP_SAT>)(hsve.data & 0xff);
max = vt;
min = max - (st / (ap_ufixed<32, 16, AP_TRN_ZERO, AP_SAT>)255) * max;
if(h>=0 && h<60){
r = (uint8_t)max;
g = (uint8_t)((ht / ap_60) * (max - min) + min + ap_0_5);
b = (uint8_t)(min + ap_0_5);
}else if(h>=60 && h<120){
r = (uint8_t)(((ap_120 - ht) / ap_60) * (max - min) + min + ap_0_5);
g = (uint8_t)max;
b = (uint8_t)(min + ap_0_5);
}else if(h>=120 && h<180){
r = (uint8_t)(min + ap_0_5);
g = (uint8_t)max;
b = (uint8_t)(((ht - ap_120) / ap_60) * (max - min) + min + ap_0_5);
}else if(h>=180 && h<240){
r = (uint8_t)(min + ap_0_5);
g = (uint8_t)(((ap_240 - ht) / ap_60) * (max - min) + min + ap_0_5);
b = (uint8_t)max;
}else if(h>=240 && h<300){
r = (uint8_t)(((ht - ap_240) / ap_60) * (max - min) + min + ap_0_5);
g = (uint8_t)(min + ap_0_5);
b = (uint8_t)max;
}else{ // h>=300 && h<=360
r = (uint8_t)max;
g = (uint8_t)(min + ap_0_5);
b = (uint8_t)(((ap_360 - ht) / ap_60) * (max - min) + min + ap_0_5);
}
rgbe.data = (r << 16) + (g << 8) + b;
if(function == ForAXIVdma){
if (x==0 && y==0) // 最初のデータでは、TUSERをアサートする
rgbe.user = 1;
else
rgbe.user = 0;
if (x == (col_size-1)) // 行の最後で TLAST をアサートする
rgbe.last = 1;
else
rgbe.last = 0;
} else {
rgbe.user = 0;
rgbe.last = hsve.last;
}
rgbe.keep = 0xf;
rgbe.strb = 0xf;
outs << rgbe;
}
}
return(0);
}
// rgb, hsv をテキストファイルに書き込む
int WriteTextFile(FILE *fbmpw, BITMAPFILEHEADER &bmpfhr, BITMAPINFOHEADER &bmpihr, uint32_t *pixel_buf, uint32_t HSVorRGB){
uint32_t hr, sg, vb;
for (int y=0; y<bmpihr.biHeight; y++){
for (int x=0; x<bmpihr.biWidth; x++){
if (HSVorRGB == HSV_TEXT)
hr = (pixel_buf[y*bmpihr.biWidth+x]>>16) & 0x1ff;
else
hr = (pixel_buf[y*bmpihr.biWidth+x]>>16) & 0xff;
sg = (pixel_buf[y*bmpihr.biWidth+x] >> 8) & 0xff;
vb = pixel_buf[y*bmpihr.biWidth+x] & 0xff;
fprintf(fbmpw, "%d, %d, %d\n",hr, sg, vb);
}
}
fclose(fbmpw);
return(0);
}
// RGB24toHSV.cpp
// 2023/10/09 by marsee
// 2023/10/15 : バグを修正
//
// 入力フォーマット:23ビット〜16ビットーRED、15ビット〜8ビットーGREEN、7ビット〜0ビットーBLUE
// 出力フォーマット:24ビット〜16ビットー H、15ビット〜8ビットーS、7ビット〜0ビットーV
// ”RGBとHSV・HSBの相互変換ツールと変換計算式”を参考にしています (https://www.peko-step.com/tool/hsvrgb.html)
#include <stdint.h>
#include <ap_int.h>
#include <hls_stream.h>
#include <ap_axi_sdata.h>
#define MAG 8 // 小数点以下のビット幅
#define ForAXIVdma 0
#define ForAXIDma 1
int RGB24toHSV(hls::stream<ap_axiu<24,1,1,1> >& ins, hls::stream<ap_axiu<32,1,1,1> >& outs,
int32_t function, int32_t row_size, int32_t col_size){
#pragma HLS INTERFACE mode=s_axilite port=function
#pragma HLS INTERFACE mode=s_axilite port=col_size
#pragma HLS INTERFACE mode=s_axilite port=row_size
#pragma HLS INTERFACE mode=s_axilite port=return
#pragma HLS INTERFACE mode=axis register_mode=both port=outs register
#pragma HLS INTERFACE mode=axis register_mode=both port=ins register
ap_axiu<24,1,1,1> pix;
ap_axiu<32,1,1,1> hsvst;
int32_t r, g, b;
int32_t h, s, v;
int32_t max, min;
int32_t hsv;
do{
#pragma HLS LOOP_TRIPCOUNT min=1 max=1 avg=1
ins >> pix;
if(function == ForAXIDma)
break;
}while(pix.user == 0);
loop_y: for(int y=0; y<row_size; y++){
#pragma HLS LOOP_TRIPCOUNT avg=600 max=1080 min=48
loop_x: for(int x=0; x<col_size; x++){
#pragma HLS LOOP_TRIPCOUNT avg=800 max=1920 min=64
if(!(x==0 && y==0)) // 最初の入力はすでに入力されている
ins >> pix; // AXI4-Stream からの入力
b = pix.data & 0xff;
g = (pix.data>>8) & 0xff;
r = (pix.data>>16) & 0xff;
// h と max, min を求める
if(r==g && g==b && r==b){
max = r; // 8倍
min = r;
}else if(r>=g && r>=b){ // r が最大
max = r;
if(g>=b)
min = b;
else
min = g;
}else if(g>=r && g>=b){ // g が最大
max = g;
if(r>=b)
min = b;
else
min = r;
}else{ // b が最大
max = b;
if(r>=g)
min = g;
else
min = r;
}
if(max-min == 0)
h = 0;
else if(max == r)
h = 60 * (((g-b)<<MAG)/(max-min)); // MAGビットシフトして精度を確保
else if(max == g)
h = 60 * (((b-r)<<MAG)/(max-min)) + (120<<MAG); // MAGビットシフトして精度を確保
else // if(max == b)
h = 60 * (((r-g)<<MAG)/(max-min)) + (240<<MAG); // MAGビットシフトして精度を確保
if(h < 0)
h += 360<<MAG;
h += 1<<(MAG-1); // +0.5、四捨五入
h >>= MAG; // 桁を戻す
if(max == 0)
s = 0;
else
s = (((max - min)<<MAG)/max) * 255; // MAGビットシフトして精度を確保
s += 1<<(MAG-1); // +0.5、四捨五入
s >>= MAG; // 桁を戻す
v = max;
hsv = ((h&0x1ff)<<16) + ((s&0xff)<<8) + (v&0xff);
hsvst.data = hsv;
if(function == ForAXIVdma){
if (x==0 && y==0) // 最初のデータでは、TUSERをアサートする
hsvst.user = 1;
else
hsvst.user = 0;
if (x == (col_size-1)) // 行の最後で TLAST をアサートする
hsvst.last = 1;
else
hsvst.last = 0;
} else {
hsvst.user = 0;
hsvst.last = pix.last;
}
hsvst.keep = 0xf;
hsvst.strb = 0xf;
outs << hsvst;
}
}
return(0);
}
// RGB24toHSV_tb.cpp
// 2023/10/09 by marsee
// 2023/10/15 : バグを修正、RGB値、HSV値をテキスト・ファイルに出力した。
//
// ”RGBとHSV・HSBの相互変換ツールと変換計算式”を参考にしています (https://www.peko-step.com/tool/hsvrgb.html)
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <ap_int.h>
#include <hls_stream.h>
#include <iostream>
#include <fstream>
#include <math.h>
#include <ap_axi_sdata.h>
#include "bmp_header.h"
#define ForAXIVdma 0
#define ForAXIDma 1
#define MAG 8 // 小数点以下のビット幅
#define BMP_FILE_NAME "test2.bmp"
#define SQUARE_ERROR_LIMIT 4 // 2乗誤差のエラー限界、この数以上はエラーとする
#define H 0
#define S 1
#define V 2
#define HSV_TEXT 0
#define RGB_TEXT 1
int RGB24toHSV(hls::stream<ap_axiu<24,1,1,1> >& ins, hls::stream<ap_axiu<32,1,1,1> >& outs,
int32_t function, int32_t row_size, int32_t col_size);
int RGB24toHSV_soft(hls::stream<ap_axiu<24,1,1,1> >& ins, hls::stream<ap_axiu<32,1,1,1> >& outs,
int32_t function, int32_t row_size, int32_t col_size);
void WriteBmpFile(FILE *fbmpw, BITMAPFILEHEADER &bmpfhr, BITMAPINFOHEADER &bmpihr, uint32_t *pixel_buf, uint32_t select_hsv);
int WriteTextFile(FILE *fbmpw, BITMAPFILEHEADER &bmpfhr, BITMAPINFOHEADER &bmpihr, uint32_t *pixel_buf, uint32_t HSVorRGB);
int main(){
using namespace std;
hls::stream<ap_axiu<24,1,1,1> > ins;
hls::stream<ap_axiu<24,1,1,1> > ins_soft;
hls::stream<ap_axiu<32,1,1,1> > outs;
hls::stream<ap_axiu<32,1,1,1> > outs_soft;
ap_axiu<24,1,1,1> pix;
ap_axiu<32,1,1,1> vals;
ap_axiu<32,1,1,1> vals_soft;
BITMAPFILEHEADER bmpfhr; // BMPファイルのファイルヘッダ(for Read)
BITMAPINFOHEADER bmpihr; // BMPファイルのINFOヘッダ(for Read)
FILE *fbmpr, *fbmpw, *fbmpwf;
uint32_t *rd_bmp, *hw_hsv, *sw_hsv;
uint32_t blue, green, red;
if ((fbmpr = fopen(BMP_FILE_NAME, "rb")) == NULL){ // BMP ファイル をオープン
fprintf(stderr, "Can't open test2.bmp by binary read mode\n");
exit(1);
}
// bmpヘッダの読み出し
fread(&bmpfhr.bfType, sizeof(uint16_t), 1, fbmpr);
fread(&bmpfhr.bfSize, sizeof(uint32_t), 1, fbmpr);
fread(&bmpfhr.bfReserved1, sizeof(uint16_t), 1, fbmpr);
fread(&bmpfhr.bfReserved2, sizeof(uint16_t), 1, fbmpr);
fread(&bmpfhr.bfOffBits, sizeof(uint32_t), 1, fbmpr);
fread(&bmpihr, sizeof(BITMAPINFOHEADER), 1, fbmpr);
// ピクセルを入れるメモリをアロケートする
if ((rd_bmp =(uint32_t *)malloc(sizeof(uint32_t) * (bmpihr.biWidth * bmpihr.biHeight))) == NULL){
fprintf(stderr, "Can't allocate rd_bmp memory\n");
exit(1);
}
if ((hw_hsv =(uint32_t *)malloc(sizeof(uint32_t) * (bmpihr.biWidth * bmpihr.biHeight))) == NULL){
fprintf(stderr, "Can't allocate hw_hsv memory\n");
exit(1);
}
if ((sw_hsv =(uint32_t *)malloc(sizeof(uint32_t) * (bmpihr.biWidth * bmpihr.biHeight))) == NULL){
fprintf(stderr, "Can't allocate sw_hsv memory\n");
exit(1);
}
// rd_bmp にBMPのピクセルを代入。その際に、行を逆転する必要がある
for (int y=0; y<bmpihr.biHeight; y++){
for (int x=0; x<bmpihr.biWidth; x++){
blue = fgetc(fbmpr);
green = fgetc(fbmpr);
red = fgetc(fbmpr);
rd_bmp[((bmpihr.biHeight-1)-y)*bmpihr.biWidth+x] = (blue & 0xff) | ((green & 0xff)<<8) | ((red & 0xff)<<16);
}
}
fclose(fbmpr);
// ins に入力データを用意する
for(int i=0; i<5; i++){ // dummy data
pix.user = 0;
pix.data = i;
ins << pix;
ins_soft << pix;
}
for(int j=0; j < bmpihr.biHeight; j++){
for(int i=0; i < bmpihr.biWidth; i++){
pix.data = (ap_int<32>)rd_bmp[(j*bmpihr.biWidth)+i];
if (j==0 && i==0) // 最初のデータの時に TUSER を 1 にする
pix.user = 1;
else
pix.user = 0;
if (i == bmpihr.biWidth-1) // 行の最後でTLASTをアサートする
pix.last = 1;
else
pix.last = 0;
ins << pix;
ins_soft << pix;
}
}
RGB24toHSV(ins, outs, ForAXIVdma, bmpihr.biHeight, bmpihr.biWidth);
RGB24toHSV_soft(ins_soft, outs_soft, ForAXIVdma, bmpihr.biHeight, bmpihr.biWidth);
// ハードウェアとソフトウェアのラプラシアン・フィルタの値のチェック
cout << endl;
cout << "outs" << endl;
for(int j=0; j < bmpihr.biHeight; j++){
for(int i=0; i < bmpihr.biWidth; i++){
outs >> vals;
outs_soft >> vals_soft;
ap_int<32> val = vals.data;
ap_int<32> val_soft = vals_soft.data;
hw_hsv[(j*bmpihr.biWidth)+i] = (int)val;
sw_hsv[(j*bmpihr.biWidth)+i] = (int)val_soft;
red = (rd_bmp[(j*bmpihr.biWidth)+i]>>16) & 0xff;
green = (rd_bmp[(j*bmpihr.biWidth)+i]>>8) & 0xff;
blue = rd_bmp[(j*bmpihr.biWidth)+i] & 0xff;
if ((double)pow((double)(val&0xff)-(val_soft&0xff),(double)2) > SQUARE_ERROR_LIMIT || // v の2乗誤差が4よりも大きい
(double)pow((double)((val>>8)&0xff)-((val_soft>>8)&0xff),(double)2) > SQUARE_ERROR_LIMIT || // s の2乗誤差が4よりも大きい
(double)pow((double)((val>>16)&0x1ff)-((val_soft>>16)&0x1ff),(double)2) > SQUARE_ERROR_LIMIT){ // h の2乗誤差が4よりも大きい
printf("ERROR HW and SW results mismatch i = %ld, j = %ld, Red = %d, Green = %d, Blue = %d, "
"HW_h = %d, HW_s = %d, HW_v = %d, SW_h = %d, SW_s = %d, SW_v = %d\n",
i, j, red, green, blue, (int)(val>>16)&0xff, (int)(val>>8)&0xff, (int)val&0xff,
(int)(val_soft>>16)&0xff, (int)(val_soft>>8)&0xff, (int)val_soft&0xff);
//return(1);
}
//if (vals.last)
//cout << "AXI-Stream is end" << endl;
}
}
cout << "Success HW and SW results match" << endl;
cout << endl;
if ((fbmpw=fopen("h_hw.bmp", "wb")) == NULL){
fprintf(stderr, "Can't open h_hw.bmp by binary write mode\n");
exit(1);
}
WriteBmpFile(fbmpw, bmpfhr, bmpihr, hw_hsv, H);
if ((fbmpw=fopen("s_hw.bmp", "wb")) == NULL){
fprintf(stderr, "Can't open s_hw.bmp by binary write mode\n");
exit(1);
}
WriteBmpFile(fbmpw, bmpfhr, bmpihr, hw_hsv, S);
if ((fbmpw=fopen("v_hw.bmp", "wb")) == NULL){
fprintf(stderr, "Can't open v_hw.bmp by binary write mode\n");
exit(1);
}
WriteBmpFile(fbmpw, bmpfhr, bmpihr, hw_hsv, V);
if ((fbmpw=fopen("h_sw.bmp", "wb")) == NULL){
fprintf(stderr, "Can't open h_sw.bmp by binary write mode\n");
exit(1);
}
WriteBmpFile(fbmpw, bmpfhr, bmpihr, sw_hsv, H);
if ((fbmpw=fopen("s_sw.bmp", "wb")) == NULL){
fprintf(stderr, "Can't open s_sw.bmp by binary write mode\n");
exit(1);
}
WriteBmpFile(fbmpw, bmpfhr, bmpihr, sw_hsv, S);
if ((fbmpw=fopen("v_sw.bmp", "wb")) == NULL){
fprintf(stderr, "Can't open v_sw.bmp by binary write mode\n");
exit(1);
}
WriteBmpFile(fbmpw, bmpfhr, bmpihr, sw_hsv, V);
if ((fbmpw=fopen("rgb_text.txt", "wt")) == NULL){
fprintf(stderr, "Can't open rgb_text.txt by binary write mode\n");
exit(1);
}
WriteTextFile(fbmpw, bmpfhr, bmpihr, rd_bmp, RGB_TEXT);
if ((fbmpw=fopen("hsv_text.txt", "wt")) == NULL){
fprintf(stderr, "Can't open hsv_text.txt by binary write mode\n");
exit(1);
}
WriteTextFile(fbmpw, bmpfhr, bmpihr, hw_hsv, HSV_TEXT);
free(rd_bmp);
free(hw_hsv);
free(sw_hsv);
}
int RGB24toHSV_soft(hls::stream<ap_axiu<24,1,1,1> >& ins, hls::stream<ap_axiu<32,1,1,1> >& outs,
int32_t function, int32_t row_size, int32_t col_size){
ap_axiu<24,1,1,1> pix;
ap_axiu<32,1,1,1> hsvst;
int32_t r, g, b;
int32_t h, s, v;
int32_t max, min;
int32_t hsv;
do{
ins >> pix;
if(function == ForAXIDma)
break;
}while(pix.user == 0);
for(int y=0; y<row_size; y++){
for(int x=0; x<col_size; x++){
if(!(x==0 && y==0)) // 最初の入力はすでに入力されている
ins >> pix; // AXI4-Stream からの入力
b = pix.data & 0xff;
g = (pix.data>>8) & 0xff;
r = (pix.data>>16) & 0xff;
// h と max, min を求める
if(r==g && g==b && r==b){
max = r; // 8倍
min = r;
}else if(r>=g && r>=b){ // r が最大
max = r;
if(g>=b)
min = b;
else
min = g;
}else if(g>=r && g>=b){ // g が最大
max = g;
if(r>=b)
min = b;
else
min = r;
}else{ // b が最大
max = b;
if(r>=g)
min = g;
else
min = r;
}
if(max-min == 0)
h = 0;
else if(max == r)
h = 60 * (((g-b)<<MAG)/(max-min)); // MAGビットシフトして精度を確保
else if(max == g)
h = 60 * (((b-r)<<MAG)/(max-min)) + (120<<MAG); // MAGビットシフトして精度を確保
else // if(max == b)
h = 60 * (((r-g)<<MAG)/(max-min)) + (240<<MAG); // MAGビットシフトして精度を確保
if(h < 0)
h += 360<<MAG;
h += 1<<(MAG-1); // +0.5、四捨五入
h >>= MAG; // 桁を戻す
if(max == 0)
s = 0;
else
s = (((max - min)<<MAG)/max) * 255; // MAGビットシフトして精度を確保
s += 1<<(MAG-1); // +0.5、四捨五入
s >>= MAG; // 桁を戻す
v = max;
hsv = ((h&0x1ff)<<16) + ((s&0xff)<<8) + (v&0xff);
hsvst.data = hsv;
if(function == ForAXIVdma){
if (x==0 && y==0) // 最初のデータでは、TUSERをアサートする
hsvst.user = 1;
else
hsvst.user = 0;
if (x == (col_size-1)) // 行の最後で TLAST をアサートする
hsvst.last = 1;
else
hsvst.last = 0;
} else {
hsvst.user = 0;
hsvst.last = pix.last;
}
hsvst.keep = 0xf;
hsvst.strb = 0xf;
outs << hsvst;
}
}
return(0);
}
// SV のうちの1つをblue, green, redの値として同じ値をBMPファイルに書く
// H は S,V の値を255とした時の H の値に対する RGB の値を計算する
void WriteBmpFile(FILE *fbmpw, BITMAPFILEHEADER &bmpfhr, BITMAPINFOHEADER &bmpihr, uint32_t *pixel_buf, uint32_t select_hsv){
uint32_t h;
uint32_t sv;
uint32_t r, g, b;
// BMPファイルヘッダの書き込み
fwrite(&bmpfhr.bfType, sizeof(uint16_t), 1, fbmpw);
fwrite(&bmpfhr.bfSize, sizeof(uint32_t), 1, fbmpw);
fwrite(&bmpfhr.bfReserved1, sizeof(uint16_t), 1, fbmpw);
fwrite(&bmpfhr.bfReserved2, sizeof(uint16_t), 1, fbmpw);
fwrite(&bmpfhr.bfOffBits, sizeof(uint32_t), 1, fbmpw);
fwrite(&bmpihr, sizeof(BITMAPINFOHEADER), 1, fbmpw);
// RGB データの書き込み、逆順にする
for (int y=0; y<bmpihr.biHeight; y++){
for (int x=0; x<bmpihr.biWidth; x++){
switch(select_hsv){
case H:
h = (pixel_buf[((bmpihr.biHeight-1)-y)*bmpihr.biWidth+x]>>16) & 0x1ff;
if(h>=0 && h<60){
r = 255;
g = (int)(((float)h/60.0)*255.0+0.5);
b = 0;
}else if(h>=60 && h<120){
r = (int)(((120.0-(float)h)/60.0)*255+0.5);
g = 255;
b = 0;
}else if(h>=120 && h<180){
r = 0;
g = 255;
b = (int)((((float)h-120.0)/60.0)*255+0.5);
}else if(h>=180 && h<240){
r = 0;
g = (int)(((240.0-(float)h)/60.0)*255+0.5);
b = 255;
}else if(h>=240 && h<300){
r = (int)((((float)h-240.0)/60.0)*255+0.5);
g = 0;
b = 255;
}else{ // h>=300 && h<=360
r = 255;
g = 0;
b = (int)(((360.0-(float)h)/60.0)*255+0.5);
}
break;
case S:
sv = (pixel_buf[((bmpihr.biHeight-1)-y)*bmpihr.biWidth+x] >> 8) & 0xff;
break;
default: // case V:
sv = pixel_buf[((bmpihr.biHeight-1)-y)*bmpihr.biWidth+x] & 0xff;
break;
}
if(select_hsv==S || select_hsv==V){
fputc(sv, fbmpw);
fputc(sv, fbmpw);
fputc(sv, fbmpw);
}else{
fputc(b, fbmpw);
fputc(g, fbmpw);
fputc(r, fbmpw);
}
}
}
fclose(fbmpw);
}
// rgb, hsv をテキストファイルに書き込む
int WriteTextFile(FILE *fbmpw, BITMAPFILEHEADER &bmpfhr, BITMAPINFOHEADER &bmpihr, uint32_t *pixel_buf, uint32_t HSVorRGB){
uint32_t hr, sg, vb;
for (int y=0; y<bmpihr.biHeight; y++){
for (int x=0; x<bmpihr.biWidth; x++){
if (HSVorRGB == HSV_TEXT)
hr = (pixel_buf[y*bmpihr.biWidth+x]>>16) & 0x1ff;
else
hr = (pixel_buf[y*bmpihr.biWidth+x]>>16) & 0xff;
sg = (pixel_buf[y*bmpihr.biWidth+x] >> 8) & 0xff;
vb = pixel_buf[y*bmpihr.biWidth+x] & 0xff;
fprintf(fbmpw, "%d, %d, %d\n",hr, sg, vb);
}
}
fclose(fbmpw);
return(0);
}
// bmp_header.h
// BMP ファイルフォーマットから引用させて頂きました
// http://www.kk.iij4u.or.jp/~kondo/bmp/
//
// 2017/05/04 : takseiさんのご指摘によりintX_tを使った宣言に変更。takseiさんありがとうございました
// 変数の型のサイズの違いによってLinuxの64ビット版では動作しなかったためです
// http://marsee101.blog19.fc2.com/blog-entry-3354.html#comment2808
//
#include <stdio.h>
#include <stdint.h>
// BITMAPFILEHEADER 14bytes
typedef struct tagBITMAPFILEHEADER {
uint16_t bfType;
uint32_t bfSize;
uint16_t bfReserved1;
uint16_t bfReserved2;
uint32_t bfOffBits;
} BITMAPFILEHEADER;
// BITMAPINFOHEADER 40bytes
typedef struct tagBITMAPINFOHEADER{
uint32_t biSize;
int32_t biWidth;
int32_t biHeight;
uint16_t biPlanes;
uint16_t biBitCount;
uint32_t biCompression;
uint32_t biSizeImage;
int32_t biXPixPerMeter;
int32_t biYPixPerMeter;
uint32_t biClrUsed;
uint32_t biClrImporant;
} BITMAPINFOHEADER;
typedef struct BMP24bitsFORMAT {
uint8_t blue;
uint8_t green;
uint8_t red;
} BMP24FORMAT;
// HSVtoRGB24.cpp
// 2023/10/12 by marsee
//
// 入力フォーマット:24ビット〜16ビットー H、15ビット〜8ビットーS、7ビット〜0ビットーV
// 出力フォーマット:23ビット〜16ビットーRED、15ビット〜8ビットーGREEN、7ビット〜0ビットーBLUE
// ”RGBとHSV・HSBの相互変換ツールと変換計算式”を参考にしています (https://www.peko-step.com/tool/hsvrgb.html)
#include <stdint.h>
#include <ap_int.h>
#include <hls_stream.h>
#include <ap_axi_sdata.h>
#define MAG 8 // 小数点以下のビット幅
#define ForAXIVdma 0
#define ForAXIDma 1
int HSVtoRGB24(hls::stream<ap_axiu<32,1,1,1> >& ins, hls::stream<ap_axiu<24,1,1,1> >& outs,
int32_t function, int32_t row_size, int32_t col_size){
#pragma HLS INTERFACE mode=s_axilite port=return
#pragma HLS INTERFACE mode=axis register_mode=both port=col_size register
#pragma HLS INTERFACE mode=s_axilite port=row_size register
#pragma HLS INTERFACE mode=s_axilite port=function
#pragma HLS INTERFACE mode=axis register_mode=both port=outs register
#pragma HLS INTERFACE mode=axis register_mode=both port=ins register
ap_ufixed<16, 8, AP_TRN_ZERO, AP_SAT> ht, st, vt;
ap_ufixed<16, 8, AP_TRN_ZERO, AP_SAT> max, min;
uint8_t r, g, b;
uint32_t h;
ap_axiu<32,1,1,1> hsve;
ap_axiu<24,1,1,1> rgbe;
ap_ufixed<16, 8, AP_TRN_ZERO, AP_SAT> ap_0_5, ap_60, ap_120, ap_240, ap_360;
ap_0_5 = (ap_ufixed<16, 8, AP_TRN_ZERO, AP_SAT>)0.5;
ap_60 = (ap_ufixed<16, 8, AP_TRN_ZERO, AP_SAT>)60;
ap_120 = (ap_ufixed<16, 8, AP_TRN_ZERO, AP_SAT>)120;
ap_240 = (ap_ufixed<16, 8, AP_TRN_ZERO, AP_SAT>)240;
ap_360 = (ap_ufixed<16, 8, AP_TRN_ZERO, AP_SAT>)360;
do{
#pragma HLS LOOP_TRIPCOUNT min=1 max=1 avg=1
ins >> hsve;
if(function == ForAXIDma)
break;
}while(hsve.user == 0);
loop_y: for(int y=0; y<row_size; y++){
#pragma HLS LOOP_TRIPCOUNT avg=600 max=1080 min=48
loop_x: for(int x=0; x<col_size; x++){
#pragma HLS LOOP_TRIPCOUNT avg=800 max=1920 min=64
if(!(x==0 && y==0)) // 最初の入力はすでに入力されている
ins >> hsve; // AXI4-Stream からの入力
h = (hsve.data >> 16) & 0x1ff;
ht = (ap_ufixed<16, 8, AP_TRN_ZERO, AP_SAT>)((hsve.data >> 16) & 0x1ff);
st = (ap_ufixed<16, 8, AP_TRN_ZERO, AP_SAT>)((hsve.data >> 8) & 0xff);
vt = (ap_ufixed<16, 8, AP_TRN_ZERO, AP_SAT>)(hsve.data & 0xff);
max = vt;
min = max - (st / (ap_ufixed<16, 8, AP_TRN_ZERO, AP_SAT>)255) * max;
if(h>=0 && h<60){
r = (uint8_t)(max + ap_0_5);
g = (uint8_t)(ht * (max - min) + min + ap_0_5);
b = (uint8_t)(min + ap_0_5);
}else if(h>=60 && h<120){
r = (uint8_t)(((ap_120 - ht) / ap_60) * (max - min) + min + ap_0_5);
g = (uint8_t)(max + ap_0_5);
b = (uint8_t)(min + ap_0_5);
}else if(h>=120 && h<180){
r = (uint8_t)(min + ap_0_5);
g = (uint8_t)(max + ap_0_5);
b = (uint8_t)((ht - ap_120) * (max - min) + min + ap_0_5);
}else if(h>=180 && h<240){
r = (uint8_t)(min + ap_0_5);
g = (uint8_t)(((ap_240 - ht) / ap_60) * (max - min) + min + ap_0_5);
b = (uint8_t)(max + ap_0_5);
}else if(h>=240 && h<300){
r = (uint8_t)(((ht - ap_240) / ap_60) * (max - min) + min + ap_0_5);
g = (uint8_t)(min + ap_0_5);
b = (uint8_t)(max + ap_0_5);
}else{ // h>=300 && h<=360
r = (uint8_t)(max + ap_0_5);
g = (uint8_t)(min + ap_0_5);
b = (uint8_t)(((ap_360 - ht) / ap_60) * (max - min) + min + ap_0_5);
}
rgbe.data = (r << 16) + (g << 8) + b;
if(function == ForAXIVdma){
if (x==0 && y==0) // 最初のデータでは、TUSERをアサートする
rgbe.user = 1;
else
rgbe.user = 0;
if (x == (col_size-1)) // 行の最後で TLAST をアサートする
rgbe.last = 1;
else
rgbe.last = 0;
} else {
rgbe.user = 0;
rgbe.last = hsve.last;
}
rgbe.keep = 0xf;
rgbe.strb = 0xf;
outs << rgbe;
}
}
return(0);
}
// HSVtoRGB24_tb.cpp
// 2023/10/12 by marsee
//
// HSVのフォーマット:24ビット〜16ビットー H、15ビット〜8ビットーS、7ビット〜0ビットーV
// RGBのフォーマット:23ビット〜16ビットーRED、15ビット〜8ビットーGREEN、7ビット〜0ビットーBLUE
// ”RGBとHSV・HSBの相互変換ツールと変換計算式”を参考にしています (https://www.peko-step.com/tool/hsvrgb.html)
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <ap_int.h>
#include <hls_stream.h>
#include <iostream>
#include <fstream>
#include <math.h>
#include <ap_axi_sdata.h>
#include <ap_fixed.h>
#include "bmp_header.h"
#define ForAXIVdma 0
#define ForAXIDma 1
#define MAG 8 // 小数点以下のビット幅
#define BMP_FILE_NAME "test2.bmp"
#define SQUARE_ERROR_LIMIT 4 // 2乗誤差のエラー限界、この数以上はエラーとする
#define H 0
#define S 1
#define V 2
int RGB24toHSV(hls::stream<ap_axiu<24,1,1,1> >& ins, hls::stream<ap_axiu<32,1,1,1> >& outs,
int32_t function, int32_t row_size, int32_t col_size);
int RGB24toHSV_soft(hls::stream<ap_axiu<24,1,1,1> >& ins, hls::stream<ap_axiu<32,1,1,1> >& outs,
int32_t function, int32_t row_size, int32_t col_size);
void WriteBmpFile(FILE *fbmpw, BITMAPFILEHEADER &bmpfhr, BITMAPINFOHEADER &bmpihr, uint32_t *pixel_buf);
int HSVtoRGB24(hls::stream<ap_axiu<32,1,1,1> >& ins, hls::stream<ap_axiu<24,1,1,1> >& outs,
int32_t function, int32_t row_size, int32_t col_size);
int HSVtoRGB24_soft(hls::stream<ap_axiu<32,1,1,1> >& ins, hls::stream<ap_axiu<24,1,1,1> >& outs,
int32_t function, int32_t row_size, int32_t col_size);
int main(){
using namespace std;
hls::stream<ap_axiu<24,1,1,1> > ins;
hls::stream<ap_axiu<24,1,1,1> > ins_soft;
hls::stream<ap_axiu<32,1,1,1> > hsvs;
hls::stream<ap_axiu<32,1,1,1> > hsvs_soft;
hls::stream<ap_axiu<24,1,1,1> > outs;
hls::stream<ap_axiu<24,1,1,1> > outs_soft;
ap_axiu<24,1,1,1> pix;
ap_axiu<24,1,1,1> vals;
ap_axiu<24,1,1,1> vals_soft;
BITMAPFILEHEADER bmpfhr; // BMPファイルのファイルヘッダ(for Read)
BITMAPINFOHEADER bmpihr; // BMPファイルのINFOヘッダ(for Read)
FILE *fbmpr, *fbmpw, *fbmpwf;
uint32_t *rd_bmp, *hw_rgb, *sw_rgb;
uint32_t blue, green, red;
if ((fbmpr = fopen(BMP_FILE_NAME, "rb")) == NULL){ // BMP ファイル をオープン
fprintf(stderr, "Can't open test2.bmp by binary read mode\n");
exit(1);
}
// bmpヘッダの読み出し
fread(&bmpfhr.bfType, sizeof(uint16_t), 1, fbmpr);
fread(&bmpfhr.bfSize, sizeof(uint32_t), 1, fbmpr);
fread(&bmpfhr.bfReserved1, sizeof(uint16_t), 1, fbmpr);
fread(&bmpfhr.bfReserved2, sizeof(uint16_t), 1, fbmpr);
fread(&bmpfhr.bfOffBits, sizeof(uint32_t), 1, fbmpr);
fread(&bmpihr, sizeof(BITMAPINFOHEADER), 1, fbmpr);
// ピクセルを入れるメモリをアロケートする
if ((rd_bmp =(uint32_t *)malloc(sizeof(uint32_t) * (bmpihr.biWidth * bmpihr.biHeight))) == NULL){
fprintf(stderr, "Can't allocate rd_bmp memory\n");
exit(1);
}
if ((hw_rgb =(uint32_t *)malloc(sizeof(uint32_t) * (bmpihr.biWidth * bmpihr.biHeight))) == NULL){
fprintf(stderr, "Can't allocate hw_rgb memory\n");
exit(1);
}
if ((sw_rgb =(uint32_t *)malloc(sizeof(uint32_t) * (bmpihr.biWidth * bmpihr.biHeight))) == NULL){
fprintf(stderr, "Can't allocate sw_rgb memory\n");
exit(1);
}
// rd_bmp にBMPのピクセルを代入。その際に、行を逆転する必要がある
for (int y=0; y<bmpihr.biHeight; y++){
for (int x=0; x<bmpihr.biWidth; x++){
blue = fgetc(fbmpr);
green = fgetc(fbmpr);
red = fgetc(fbmpr);
rd_bmp[((bmpihr.biHeight-1)-y)*bmpihr.biWidth+x] = (blue & 0xff) | ((green & 0xff)<<8) | ((red & 0xff)<<16);
}
}
fclose(fbmpr);
// ins に入力データを用意する
for(int i=0; i<5; i++){ // dummy data
pix.user = 0;
pix.data = i;
ins << pix;
ins_soft << pix;
}
for(int j=0; j < bmpihr.biHeight; j++){
for(int i=0; i < bmpihr.biWidth; i++){
pix.data = (ap_int<32>)rd_bmp[(j*bmpihr.biWidth)+i];
if (j==0 && i==0) // 最初のデータの時に TUSER を 1 にする
pix.user = 1;
else
pix.user = 0;
if (i == bmpihr.biWidth-1) // 行の最後でTLASTをアサートする
pix.last = 1;
else
pix.last = 0;
ins << pix;
ins_soft << pix;
}
}
RGB24toHSV_soft(ins, hsvs, ForAXIVdma, bmpihr.biHeight, bmpihr.biWidth);
RGB24toHSV_soft(ins_soft, hsvs_soft, ForAXIVdma, bmpihr.biHeight, bmpihr.biWidth);
HSVtoRGB24(hsvs, outs, ForAXIVdma, bmpihr.biHeight, bmpihr.biWidth);
HSVtoRGB24_soft(hsvs_soft, outs_soft, ForAXIVdma, bmpihr.biHeight, bmpihr.biWidth);
// ハードウェアとソフトウェアの RGB - HSV - RGB の値を比較する
for(int j=0; j < bmpihr.biHeight; j++){
for(int i=0; i < bmpihr.biWidth; i++){
outs >> vals;
outs_soft >> vals_soft;
ap_int<24> val = vals.data;
ap_int<24> val_soft = vals_soft.data;
hw_rgb[(j*bmpihr.biWidth)+i] = (int)val;
sw_rgb[(j*bmpihr.biWidth)+i] = (int)val_soft;
red = (rd_bmp[(j*bmpihr.biWidth)+i]>>16) & 0xff;
green = (rd_bmp[(j*bmpihr.biWidth)+i]>>8) & 0xff;
blue = rd_bmp[(j*bmpihr.biWidth)+i] & 0xff;
if ((double)pow((double)(val&0xff)-(val_soft&0xff),(double)2) > SQUARE_ERROR_LIMIT || // B の2乗誤差が4よりも大きい
(double)pow((double)((val>>8)&0xff)-((val_soft>>8)&0xff),(double)2) > SQUARE_ERROR_LIMIT || // G の2乗誤差が4よりも大きい
(double)pow((double)((val>>16)&0xff)-((val_soft>>16)&0xff),(double)2) > SQUARE_ERROR_LIMIT){ // R の2乗誤差が4よりも大きい
printf("ERROR HW and SW results mismatch i = %ld, j = %ld, Red = %d, Green = %d, Blue = %d, "
"HW_h = %d, HW_s = %d, HW_v = %d, SW_h = %d, SW_s = %d, SW_v = %d\n",
i, j, red, green, blue, (int)(val>>16)&0xff, (int)(val>>8)&0xff, (int)val&0xff,
(int)(val_soft>>16)&0xff, (int)(val_soft>>8)&0xff, (int)val_soft&0xff);
//return(1);
}
//if (vals.last)
//cout << "AXI-Stream is end" << endl;
}
}
cout << "Success HW and SW results match" << endl;
cout << endl;
if ((fbmpw=fopen("hw_rgb.bmp", "wb")) == NULL){
fprintf(stderr, "Can't open hw_rgb.bmp by binary write mode\n");
exit(1);
}
WriteBmpFile(fbmpw, bmpfhr, bmpihr, hw_rgb);
if ((fbmpw=fopen("sw_rgb.bmp", "wb")) == NULL){
fprintf(stderr, "Can't open sw_rgb.bmp by binary write mode\n");
exit(1);
}
WriteBmpFile(fbmpw, bmpfhr, bmpihr, sw_rgb);
free(rd_bmp);
free(hw_rgb);
free(sw_rgb);
}
int RGB24toHSV_soft(hls::stream<ap_axiu<24,1,1,1> >& ins, hls::stream<ap_axiu<32,1,1,1> >& outs,
int32_t function, int32_t row_size, int32_t col_size){
ap_axiu<24,1,1,1> pix;
ap_axiu<32,1,1,1> hsvst;
uint32_t r, g, b;
uint32_t h, s, v;
uint32_t max, min;
uint32_t hsv;
do{
ins >> pix;
if(function == ForAXIDma)
break;
}while(pix.user == 0);
for(int y=0; y<row_size; y++){
for(int x=0; x<col_size; x++){
if(!(x==0 && y==0)) // 最初の入力はすでに入力されている
ins >> pix; // AXI4-Stream からの入力
b = pix.data & 0xff;
g = (pix.data>>8) & 0xff;
r = (pix.data>>16) & 0xff;
// h と max, min を求める
if(r==g && g==b && r==b){
max = r; // 8倍
min = r;
}else if(r>=g && r>=b){ // r が最大
max = r;
if(g>=b)
min = b;
else
min = g;
}else if(g>=r && g>=b){ // g が最大
max = g;
if(r>=b)
min = b;
else
min = r;
}else{ // b が最大
max = b;
if(r>=g)
min = g;
else
min = r;
}
if(max-min == 0)
h = 0;
else if(max == r)
h = 60 * (((g-b)<<MAG)/(max-min)); // MAGビットシフトして精度を確保
else if(max == g)
h = 60 * (((b-r)<<MAG)/(max-min)) + (120<<MAG); // MAGビットシフトして精度を確保
else // if(max == b)
h = 60 * (((r-g)<<MAG)/(max-min)) + (240<<MAG); // MAGビットシフトして精度を確保
if(h < 0)
h += 360<<MAG;
h += 1<<(MAG-1); // +0.5、四捨五入
h >>= MAG; // 桁を戻す
if(max == 0)
s = 0;
else
s = (((max - min)<<MAG)/max) * 255; // MAGビットシフトして精度を確保
s += 1<<(MAG-1); // +0.5、四捨五入
s >>= MAG; // 桁を戻す
v = max;
hsv = ((h&0x1ff)<<16) + ((s&0xff)<<8) + (v&0xff);
hsvst.data = hsv;
if(function == ForAXIVdma){
if (x==0 && y==0) // 最初のデータでは、TUSERをアサートする
hsvst.user = 1;
else
hsvst.user = 0;
if (x == (col_size-1)) // 行の最後で TLAST をアサートする
hsvst.last = 1;
else
hsvst.last = 0;
} else {
hsvst.user = 0;
hsvst.last = pix.last;
}
hsvst.keep = 0xf;
hsvst.strb = 0xf;
outs << hsvst;
}
}
return(0);
}
// pixel_buf の画像をファイルに書き込む
void WriteBmpFile(FILE *fbmpw, BITMAPFILEHEADER &bmpfhr, BITMAPINFOHEADER &bmpihr, uint32_t *pixel_buf){
uint32_t h;
uint32_t sv;
uint32_t r, g, b;
// BMPファイルヘッダの書き込み
fwrite(&bmpfhr.bfType, sizeof(uint16_t), 1, fbmpw);
fwrite(&bmpfhr.bfSize, sizeof(uint32_t), 1, fbmpw);
fwrite(&bmpfhr.bfReserved1, sizeof(uint16_t), 1, fbmpw);
fwrite(&bmpfhr.bfReserved2, sizeof(uint16_t), 1, fbmpw);
fwrite(&bmpfhr.bfOffBits, sizeof(uint32_t), 1, fbmpw);
fwrite(&bmpihr, sizeof(BITMAPINFOHEADER), 1, fbmpw);
// RGB データの書き込み、逆順にする
for (int y=0; y<bmpihr.biHeight; y++){
for (int x=0; x<bmpihr.biWidth; x++){
uint32_t rgb_data = pixel_buf[((bmpihr.biHeight-1)-y)*bmpihr.biWidth+x];
fputc(rgb_data & 0xff, fbmpw); // blue;
fputc((rgb_data >> 8) & 0xff, fbmpw); // green
fputc((rgb_data >> 16) & 0xff, fbmpw); // red
}
}
fclose(fbmpw);
}
int HSVtoRGB24_soft(hls::stream<ap_axiu<32,1,1,1> >& ins, hls::stream<ap_axiu<24,1,1,1> >& outs,
int32_t function, int32_t row_size, int32_t col_size){
ap_ufixed<16, 8, AP_TRN_ZERO, AP_SAT> ht, st, vt;
ap_ufixed<16, 8, AP_TRN_ZERO, AP_SAT> max, min;
uint8_t r, g, b;
uint32_t h;
ap_axiu<32,1,1,1> hsve;
ap_axiu<24,1,1,1> rgbe;
ap_ufixed<16, 8, AP_TRN_ZERO, AP_SAT> ap_0_5, ap_60, ap_120, ap_240, ap_360;
ap_0_5 = (ap_ufixed<16, 8, AP_TRN_ZERO, AP_SAT>)0.5;
ap_60 = (ap_ufixed<16, 8, AP_TRN_ZERO, AP_SAT>)60;
ap_120 = (ap_ufixed<16, 8, AP_TRN_ZERO, AP_SAT>)120;
ap_240 = (ap_ufixed<16, 8, AP_TRN_ZERO, AP_SAT>)240;
ap_360 = (ap_ufixed<16, 8, AP_TRN_ZERO, AP_SAT>)360;
do{
ins >> hsve;
if(function == ForAXIDma)
break;
}while(hsve.user == 0);
for(int y=0; y<row_size; y++){
for(int x=0; x<col_size; x++){
if(!(x==0 && y==0)) // 最初の入力はすでに入力されている
ins >> hsve; // AXI4-Stream からの入力
h = (hsve.data >> 16) & 0x1ff;
ht = (ap_ufixed<16, 8, AP_TRN_ZERO, AP_SAT>)((hsve.data >> 16) & 0x1ff);
st = (ap_ufixed<16, 8, AP_TRN_ZERO, AP_SAT>)((hsve.data >> 8) & 0xff);
vt = (ap_ufixed<16, 8, AP_TRN_ZERO, AP_SAT>)(hsve.data & 0xff);
max = vt;
min = max - (st / (ap_ufixed<16, 8, AP_TRN_ZERO, AP_SAT>)255) * max;
if(h>=0 && h<60){
r = (uint8_t)(max + ap_0_5);
g = (uint8_t)(ht * (max - min) + min + ap_0_5);
b = (uint8_t)(min + ap_0_5);
}else if(h>=60 && h<120){
r = (uint8_t)(((ap_120 - ht) / ap_60) * (max - min) + min + ap_0_5);
g = (uint8_t)(max + ap_0_5);
b = (uint8_t)(min + ap_0_5);
}else if(h>=120 && h<180){
r = (uint8_t)(min + ap_0_5);
g = (uint8_t)(max + ap_0_5);
b = (uint8_t)((ht - ap_120) * (max - min) + min + ap_0_5);
}else if(h>=180 && h<240){
r = (uint8_t)(min + ap_0_5);
g = (uint8_t)(((ap_240 - ht) / ap_60) * (max - min) + min + ap_0_5);
b = (uint8_t)(max + ap_0_5);
}else if(h>=240 && h<300){
r = (uint8_t)(((ht - ap_240) / ap_60) * (max - min) + min + ap_0_5);
g = (uint8_t)(min + ap_0_5);
b = (uint8_t)(max + ap_0_5);
}else{ // h>=300 && h<=360
r = (uint8_t)(max + ap_0_5);
g = (uint8_t)(min + ap_0_5);
b = (uint8_t)(((ap_360 - ht) / ap_60) * (max - min) + min + ap_0_5);
}
rgbe.data = (r << 16) + (g << 8) + b;
if(function == ForAXIVdma){
if (x==0 && y==0) // 最初のデータでは、TUSERをアサートする
rgbe.user = 1;
else
rgbe.user = 0;
if (x == (col_size-1)) // 行の最後で TLAST をアサートする
rgbe.last = 1;
else
rgbe.last = 0;
} else {
rgbe.user = 0;
rgbe.last = hsve.last;
}
rgbe.keep = 0xf;
rgbe.strb = 0xf;
outs << rgbe;
}
}
return(0);
}
// bmp_header.h
// BMP ファイルフォーマットから引用させて頂きました
// http://www.kk.iij4u.or.jp/~kondo/bmp/
//
// 2017/05/04 : takseiさんのご指摘によりintX_tを使った宣言に変更。takseiさんありがとうございました
// 変数の型のサイズの違いによってLinuxの64ビット版では動作しなかったためです
// http://marsee101.blog19.fc2.com/blog-entry-3354.html#comment2808
//
#include <stdio.h>
#include <stdint.h>
// BITMAPFILEHEADER 14bytes
typedef struct tagBITMAPFILEHEADER {
uint16_t bfType;
uint32_t bfSize;
uint16_t bfReserved1;
uint16_t bfReserved2;
uint32_t bfOffBits;
} BITMAPFILEHEADER;
// BITMAPINFOHEADER 40bytes
typedef struct tagBITMAPINFOHEADER{
uint32_t biSize;
int32_t biWidth;
int32_t biHeight;
uint16_t biPlanes;
uint16_t biBitCount;
uint32_t biCompression;
uint32_t biSizeImage;
int32_t biXPixPerMeter;
int32_t biYPixPerMeter;
uint32_t biClrUsed;
uint32_t biClrImporant;
} BITMAPINFOHEADER;
typedef struct BMP24bitsFORMAT {
uint8_t blue;
uint8_t green;
uint8_t red;
} BMP24FORMAT;
// RGB24toHSV.cpp
// 2023/10/09 by marsee
//
// 入力フォーマット:23ビット〜16ビットーRED、15ビット〜8ビットーGREEN、7ビット〜0ビットーBLUE
// 出力フォーマット:24ビット〜16ビットー H、15ビット〜8ビットーS、7ビット〜0ビットーV
// ”RGBとHSV・HSBの相互変換ツールと変換計算式”を参考にしています (https://www.peko-step.com/tool/hsvrgb.html)
#include <stdint.h>
#include <ap_int.h>
#include <hls_stream.h>
#include <ap_axi_sdata.h>
#define MAG 8 // 小数点以下のビット幅
#define ForAXIVdma 0
#define ForAXIDma 1
int RGB24toHSV(hls::stream<ap_axiu<24,1,1,1> >& ins, hls::stream<ap_axiu<32,1,1,1> >& outs,
int32_t function, int32_t row_size, int32_t col_size){
#pragma HLS INTERFACE mode=s_axilite port=function
#pragma HLS INTERFACE mode=s_axilite port=col_size
#pragma HLS INTERFACE mode=s_axilite port=row_size
#pragma HLS INTERFACE mode=s_axilite port=return
#pragma HLS INTERFACE mode=axis register_mode=both port=outs register
#pragma HLS INTERFACE mode=axis register_mode=both port=ins register
ap_axiu<24,1,1,1> pix;
ap_axiu<32,1,1,1> hsvst;
uint32_t r, g, b;
uint32_t h, s, v;
uint32_t max, min;
uint32_t hsv;
do{
#pragma HLS LOOP_TRIPCOUNT min=1 max=1 avg=1
ins >> pix;
if(function == ForAXIDma)
break;
}while(pix.user == 0);
loop_y: for(int y=0; y<row_size; y++){
#pragma HLS LOOP_TRIPCOUNT avg=600 max=1080 min=48
loop_x: for(int x=0; x<col_size; x++){
#pragma HLS LOOP_TRIPCOUNT avg=800 max=1920 min=64
if(!(x==0 && y==0)) // 最初の入力はすでに入力されている
ins >> pix; // AXI4-Stream からの入力
b = pix.data & 0xff;
g = (pix.data>>8) & 0xff;
r = (pix.data>>16) & 0xff;
// h と max, min を求める
if(r==g && g==b && r==b){
max = r; // 8倍
min = r;
}else if(r>=g && r>=b){ // r が最大
max = r;
if(g>=b)
min = b;
else
min = g;
}else if(g>=r && g>=b){ // g が最大
max = g;
if(r>=b)
min = b;
else
min = r;
}else{ // b が最大
max = b;
if(r>=g)
min = g;
else
min = r;
}
if(max-min == 0)
h = 0;
else if(max == r)
h = 60 * (((g-b)<<MAG)/(max-min)); // MAGビットシフトして精度を確保
else if(max == g)
h = 60 * (((b-r)<<MAG)/(max-min)) + (120<<MAG); // MAGビットシフトして精度を確保
else // if(max == b)
h = 60 * (((r-g)<<MAG)/(max-min)) + (240<<MAG); // MAGビットシフトして精度を確保
if(h < 0)
h += 360<<MAG;
h += 1<<(MAG-1); // +0.5、四捨五入
h >>= MAG; // 桁を戻す
if(max == 0)
s = 0;
else
s = (((max - min)<<MAG)/max) * 255; // MAGビットシフトして精度を確保
s += 1<<(MAG-1); // +0.5、四捨五入
s >>= MAG; // 桁を戻す
v = max;
hsv = ((h&0x1ff)<<16) + ((s&0xff)<<8) + (v&0xff);
hsvst.data = hsv;
if(function == ForAXIVdma){
if (x==0 && y==0) // 最初のデータでは、TUSERをアサートする
hsvst.user = 1;
else
hsvst.user = 0;
if (x == (col_size-1)) // 行の最後で TLAST をアサートする
hsvst.last = 1;
else
hsvst.last = 0;
} else {
hsvst.user = 0;
hsvst.last = pix.last;
}
hsvst.keep = 0xf;
hsvst.strb = 0xf;
outs << hsvst;
}
}
return(0);
}
// RGB24toHSV_tb.cpp
// 2023/10/09 by marsee
// ”RGBとHSV・HSBの相互変換ツールと変換計算式”を参考にしています (https://www.peko-step.com/tool/hsvrgb.html)
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <ap_int.h>
#include <hls_stream.h>
#include <iostream>
#include <fstream>
#include <math.h>
#include <ap_axi_sdata.h>
#include "bmp_header.h"
#define ForAXIVdma 0
#define ForAXIDma 1
#define MAG 8 // 小数点以下のビット幅
#define BMP_FILE_NAME "test2.bmp"
#define SQUARE_ERROR_LIMIT 4 // 2乗誤差のエラー限界、この数以上はエラーとする
#define H 0
#define S 1
#define V 2
int RGB24toHSV(hls::stream<ap_axiu<24,1,1,1> >& ins, hls::stream<ap_axiu<32,1,1,1> >& outs,
int32_t function, int32_t row_size, int32_t col_size);
int RGB24toHSV_soft(hls::stream<ap_axiu<24,1,1,1> >& ins, hls::stream<ap_axiu<32,1,1,1> >& outs,
int32_t function, int32_t row_size, int32_t col_size);
void WriteBmpFile(FILE *fbmpw, BITMAPFILEHEADER &bmpfhr, BITMAPINFOHEADER &bmpihr, uint32_t *pixel_buf, uint32_t select_hsv);
int main(){
using namespace std;
hls::stream<ap_axiu<24,1,1,1> > ins;
hls::stream<ap_axiu<24,1,1,1> > ins_soft;
hls::stream<ap_axiu<32,1,1,1> > outs;
hls::stream<ap_axiu<32,1,1,1> > outs_soft;
ap_axiu<24,1,1,1> pix;
ap_axiu<32,1,1,1> vals;
ap_axiu<32,1,1,1> vals_soft;
BITMAPFILEHEADER bmpfhr; // BMPファイルのファイルヘッダ(for Read)
BITMAPINFOHEADER bmpihr; // BMPファイルのINFOヘッダ(for Read)
FILE *fbmpr, *fbmpw, *fbmpwf;
uint32_t *rd_bmp, *hw_hsv, *sw_hsv;
uint32_t blue, green, red;
if ((fbmpr = fopen(BMP_FILE_NAME, "rb")) == NULL){ // BMP ファイル をオープン
fprintf(stderr, "Can't open test2.bmp by binary read mode\n");
exit(1);
}
// bmpヘッダの読み出し
fread(&bmpfhr.bfType, sizeof(uint16_t), 1, fbmpr);
fread(&bmpfhr.bfSize, sizeof(uint32_t), 1, fbmpr);
fread(&bmpfhr.bfReserved1, sizeof(uint16_t), 1, fbmpr);
fread(&bmpfhr.bfReserved2, sizeof(uint16_t), 1, fbmpr);
fread(&bmpfhr.bfOffBits, sizeof(uint32_t), 1, fbmpr);
fread(&bmpihr, sizeof(BITMAPINFOHEADER), 1, fbmpr);
// ピクセルを入れるメモリをアロケートする
if ((rd_bmp =(uint32_t *)malloc(sizeof(uint32_t) * (bmpihr.biWidth * bmpihr.biHeight))) == NULL){
fprintf(stderr, "Can't allocate rd_bmp memory\n");
exit(1);
}
if ((hw_hsv =(uint32_t *)malloc(sizeof(uint32_t) * (bmpihr.biWidth * bmpihr.biHeight))) == NULL){
fprintf(stderr, "Can't allocate hw_hsv memory\n");
exit(1);
}
if ((sw_hsv =(uint32_t *)malloc(sizeof(uint32_t) * (bmpihr.biWidth * bmpihr.biHeight))) == NULL){
fprintf(stderr, "Can't allocate sw_hsv memory\n");
exit(1);
}
// rd_bmp にBMPのピクセルを代入。その際に、行を逆転する必要がある
for (int y=0; y<bmpihr.biHeight; y++){
for (int x=0; x<bmpihr.biWidth; x++){
blue = fgetc(fbmpr);
green = fgetc(fbmpr);
red = fgetc(fbmpr);
rd_bmp[((bmpihr.biHeight-1)-y)*bmpihr.biWidth+x] = (blue & 0xff) | ((green & 0xff)<<8) | ((red & 0xff)<<16);
}
}
fclose(fbmpr);
// ins に入力データを用意する
for(int i=0; i<5; i++){ // dummy data
pix.user = 0;
pix.data = i;
ins << pix;
ins_soft << pix;
}
for(int j=0; j < bmpihr.biHeight; j++){
for(int i=0; i < bmpihr.biWidth; i++){
pix.data = (ap_int<32>)rd_bmp[(j*bmpihr.biWidth)+i];
if (j==0 && i==0) // 最初のデータの時に TUSER を 1 にする
pix.user = 1;
else
pix.user = 0;
if (i == bmpihr.biWidth-1) // 行の最後でTLASTをアサートする
pix.last = 1;
else
pix.last = 0;
ins << pix;
ins_soft << pix;
}
}
RGB24toHSV(ins, outs, ForAXIVdma, bmpihr.biHeight, bmpihr.biWidth);
RGB24toHSV_soft(ins_soft, outs_soft, ForAXIVdma, bmpihr.biHeight, bmpihr.biWidth);
// ハードウェアとソフトウェアのラプラシアン・フィルタの値のチェック
cout << endl;
cout << "outs" << endl;
for(int j=0; j < bmpihr.biHeight; j++){
for(int i=0; i < bmpihr.biWidth; i++){
outs >> vals;
outs_soft >> vals_soft;
ap_int<32> val = vals.data;
ap_int<32> val_soft = vals_soft.data;
hw_hsv[(j*bmpihr.biWidth)+i] = (int)val;
sw_hsv[(j*bmpihr.biWidth)+i] = (int)val_soft;
red = (rd_bmp[(j*bmpihr.biWidth)+i]>>16) & 0xff;
green = (rd_bmp[(j*bmpihr.biWidth)+i]>>8) & 0xff;
blue = rd_bmp[(j*bmpihr.biWidth)+i] & 0xff;
if ((double)pow((double)(val&0xff)-(val_soft&0xff),(double)2) > SQUARE_ERROR_LIMIT || // v の2乗誤差が4よりも大きい
(double)pow((double)((val>>8)&0xff)-((val_soft>>8)&0xff),(double)2) > SQUARE_ERROR_LIMIT || // s の2乗誤差が4よりも大きい
(double)pow((double)((val>>16)&0x1ff)-((val_soft>>16)&0x1ff),(double)2) > SQUARE_ERROR_LIMIT){ // h の2乗誤差が4よりも大きい
printf("ERROR HW and SW results mismatch i = %ld, j = %ld, Red = %d, Green = %d, Blue = %d, "
"HW_h = %d, HW_s = %d, HW_v = %d, SW_h = %d, SW_s = %d, SW_v = %d\n",
i, j, red, green, blue, (int)(val>>16)&0xff, (int)(val>>8)&0xff, (int)val&0xff,
(int)(val_soft>>16)&0xff, (int)(val_soft>>8)&0xff, (int)val_soft&0xff);
//return(1);
}
//if (vals.last)
//cout << "AXI-Stream is end" << endl;
}
}
cout << "Success HW and SW results match" << endl;
cout << endl;
if ((fbmpw=fopen("h_hw.bmp", "wb")) == NULL){
fprintf(stderr, "Can't open h_hw.bmp by binary write mode\n");
exit(1);
}
WriteBmpFile(fbmpw, bmpfhr, bmpihr, hw_hsv, H);
if ((fbmpw=fopen("s_hw.bmp", "wb")) == NULL){
fprintf(stderr, "Can't open s_hw.bmp by binary write mode\n");
exit(1);
}
WriteBmpFile(fbmpw, bmpfhr, bmpihr, hw_hsv, S);
if ((fbmpw=fopen("v_hw.bmp", "wb")) == NULL){
fprintf(stderr, "Can't open v_hw.bmp by binary write mode\n");
exit(1);
}
WriteBmpFile(fbmpw, bmpfhr, bmpihr, hw_hsv, V);
if ((fbmpw=fopen("h_sw.bmp", "wb")) == NULL){
fprintf(stderr, "Can't open h_sw.bmp by binary write mode\n");
exit(1);
}
WriteBmpFile(fbmpw, bmpfhr, bmpihr, sw_hsv, H);
if ((fbmpw=fopen("s_sw.bmp", "wb")) == NULL){
fprintf(stderr, "Can't open s_sw.bmp by binary write mode\n");
exit(1);
}
WriteBmpFile(fbmpw, bmpfhr, bmpihr, sw_hsv, S);
if ((fbmpw=fopen("v_sw.bmp", "wb")) == NULL){
fprintf(stderr, "Can't open v_sw.bmp by binary write mode\n");
exit(1);
}
WriteBmpFile(fbmpw, bmpfhr, bmpihr, sw_hsv, V);
free(rd_bmp);
free(hw_hsv);
free(sw_hsv);
}
int RGB24toHSV_soft(hls::stream<ap_axiu<24,1,1,1> >& ins, hls::stream<ap_axiu<32,1,1,1> >& outs,
int32_t function, int32_t row_size, int32_t col_size){
ap_axiu<24,1,1,1> pix;
ap_axiu<32,1,1,1> hsvst;
uint32_t r, g, b;
uint32_t h, s, v;
uint32_t max, min;
uint32_t hsv;
do{
ins >> pix;
if(function == ForAXIDma)
break;
}while(pix.user == 0);
for(int y=0; y<row_size; y++){
for(int x=0; x<col_size; x++){
if(!(x==0 && y==0)) // 最初の入力はすでに入力されている
ins >> pix; // AXI4-Stream からの入力
b = pix.data & 0xff;
g = (pix.data>>8) & 0xff;
r = (pix.data>>16) & 0xff;
// h と max, min を求める
if(r==g && g==b && r==b){
max = r; // 8倍
min = r;
}else if(r>=g && r>=b){ // r が最大
max = r;
if(g>=b)
min = b;
else
min = g;
}else if(g>=r && g>=b){ // g が最大
max = g;
if(r>=b)
min = b;
else
min = r;
}else{ // b が最大
max = b;
if(r>=g)
min = g;
else
min = r;
}
if(max-min == 0)
h = 0;
else if(max == r)
h = 60 * (((g-b)<<MAG)/(max-min)); // MAGビットシフトして精度を確保
else if(max == g)
h = 60 * (((b-r)<<MAG)/(max-min)) + (120<<MAG); // MAGビットシフトして精度を確保
else // if(max == b)
h = 60 * (((r-g)<<MAG)/(max-min)) + (240<<MAG); // MAGビットシフトして精度を確保
if(h < 0)
h += 360<<MAG;
h += 1<<(MAG-1); // +0.5、四捨五入
h >>= MAG; // 桁を戻す
if(max == 0)
s = 0;
else
s = (((max - min)<<MAG)/max) * 255; // MAGビットシフトして精度を確保
s += 1<<(MAG-1); // +0.5、四捨五入
s >>= MAG; // 桁を戻す
v = max;
hsv = ((h&0x1ff)<<16) + ((s&0xff)<<8) + (v&0xff);
hsvst.data = hsv;
if(function == ForAXIVdma){
if (x==0 && y==0) // 最初のデータでは、TUSERをアサートする
hsvst.user = 1;
else
hsvst.user = 0;
if (x == (col_size-1)) // 行の最後で TLAST をアサートする
hsvst.last = 1;
else
hsvst.last = 0;
} else {
hsvst.user = 0;
hsvst.last = pix.last;
}
hsvst.keep = 0xf;
hsvst.strb = 0xf;
outs << hsvst;
}
}
return(0);
}
// SV のうちの1つをblue, green, redの値として同じ値をBMPファイルに書く
// H は S,V の値を255とした時の H の値に対する RGB の値を計算する
void WriteBmpFile(FILE *fbmpw, BITMAPFILEHEADER &bmpfhr, BITMAPINFOHEADER &bmpihr, uint32_t *pixel_buf, uint32_t select_hsv){
uint32_t h;
uint32_t sv;
uint32_t r, g, b;
// BMPファイルヘッダの書き込み
fwrite(&bmpfhr.bfType, sizeof(uint16_t), 1, fbmpw);
fwrite(&bmpfhr.bfSize, sizeof(uint32_t), 1, fbmpw);
fwrite(&bmpfhr.bfReserved1, sizeof(uint16_t), 1, fbmpw);
fwrite(&bmpfhr.bfReserved2, sizeof(uint16_t), 1, fbmpw);
fwrite(&bmpfhr.bfOffBits, sizeof(uint32_t), 1, fbmpw);
fwrite(&bmpihr, sizeof(BITMAPINFOHEADER), 1, fbmpw);
// RGB データの書き込み、逆順にする
for (int y=0; y<bmpihr.biHeight; y++){
for (int x=0; x<bmpihr.biWidth; x++){
switch(select_hsv){
case H:
h = (pixel_buf[((bmpihr.biHeight-1)-y)*bmpihr.biWidth+x]>>16) & 0x1ff;
if(h>=0 && h<60){
r = 255;
g = (int)(((float)h/60.0)*255.0+0.5);
b = 0;
}else if(h>=60 && h<120){
r = (int)(((120.0-(float)h)/60.0)*255+0.5);
g = 255;
b = 0;
}else if(h>=120 && h<180){
r = 0;
g = 255;
b = (int)((((float)h-120.0)/60.0)*255+0.5);
}else if(h>=180 && h<240){
r = 0;
g = (int)(((240.0-(float)h)/60.0)*255+0.5);
b = 255;
}else if(h>=240 && h<300){
r = (int)((((float)h-240.0)/60.0)*255+0.5);
g = 0;
b = 255;
}else{ // h>=300 && h<=360
r = 255;
g = 0;
b = (int)(((360.0-(float)h)/60.0)*255+0.5);
}
break;
case S:
sv = (pixel_buf[((bmpihr.biHeight-1)-y)*bmpihr.biWidth+x] >> 8) & 0xff;
break;
default: // case V:
sv = pixel_buf[((bmpihr.biHeight-1)-y)*bmpihr.biWidth+x] & 0xff;
break;
}
if(select_hsv==S || select_hsv==V){
fputc(sv, fbmpw);
fputc(sv, fbmpw);
fputc(sv, fbmpw);
}else{
fputc(b, fbmpw);
fputc(g, fbmpw);
fputc(r, fbmpw);
}
}
}
fclose(fbmpw);
}
// zub1cg_i4filters.c
// 2023/10/04 by marsee
//
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <assert.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <string.h>
#include "bmp_header.h"
char INPUT_IMG_FILE[] = "test2.bmp";
char OUTPUT_IMG_FILE[] = "output_img.bmp";
#define BLOCK_SIZE 4096
#define IMAGE_WIDTH 800
#define IMAGE_HEIGHT 600
#define IMAGE_CHANNEL 3
#define MAT_IMGAGE_BUF (IMAGE_WIDTH*IMAGE_HEIGHT*IMAGE_CHANNEL)
#define MM2S_CONTROL_REG 0x00
#define MM2S_STATUS_REG (0x4 >> 2)
#define MM2S_START_ADDR (0x18 >> 2)
#define MM2S_LENGTH_REG (0x28 >> 2)
#define S2MM_CONTROL_REG (0x30 >> 2)
#define S2MM_STATUS_REG (0x34 >> 2)
#define S2MM_DESTINATION_ADDR (0x48 >> 2)
#define S2MM_LENGTH_REG (0x58 >> 2)
// bits 1 - idle
#define MM2S_IDLE_MASK 0x2
#define S2MM_IDLE_MASK 0x2
#define GUSSIAN_CONTROL 0x00
#define GUSSIAN_FUNCTON_R (0x18 >> 2)
#define GUSSIAN_ROW_SIZE (0x20 >> 2)
#define GUSSIAN_COL_SIZE (0x28 >> 2)
#define MEDIAN_CONTROL 0x00
#define MEDIAN_FUNCTION_R (0x18 >> 2)
#define MEDIAN_ROW_SIZE (0x20 >> 2)
#define MEDIAN_COL_SIZE (0x28 >> 2)
#define COLOR_CONVERTER_CONTROL 0x00
#define COLOR_CONVERTER_FUNCTION_R (0x18 >> 2)
#define COLOR_CONVERTER_ROW_SIZE (0x20 >> 2)
#define COLOR_CONVERTER_COL_SIZE (0x28 >> 2)
#define COLOR_CONVERTER_RED_MAG (0x30 >> 2)
#define COLOR_CONVERTER_GREEN_MAG (0x38 >> 2)
#define COLOR_CONVERTER_BLUE_MAG (0x40 >> 2)
#define SOBEL_CONTROL 0x00
#define SOBEL_FUNCTION_R (0x18 >> 2)
#define SOBEL_ROW_SIZE (0x20 >> 2)
#define SOBEL_COL_SIZE (0x28 >> 2)
volatile uint32_t *reg;
int main(){
BITMAPFILEHEADER bmpfhr; // BMPファイルのファイルヘッダ(for Read)
BITMAPINFOHEADER bmpihr; // BMPファイルのINFOヘッダ(for Read)
FILE *fbmpr, *fbmpw;
volatile uint8_t *rd_bmp, *wr_bmp;
uint32_t blue, green, red;
int fd4, fd5, fd6, fd7, fd8, fd9;
volatile uint32_t *axi_dma;
volatile uint32_t *color_converter_RGB24;
volatile uint32_t *gaussian_axis_RGB24;
volatile uint32_t *median_axis_RGB24;
volatile uint32_t *sobel_axis_RGB24;
volatile uint8_t *image_buf;
u_int32_t fd_paddr;
unsigned char attr[1024];
unsigned long phys_addr;
// Image file open
if ((fbmpr = fopen(INPUT_IMG_FILE, "rb")) == NULL){ // test.bmp をオープン
fprintf(stderr, "Can't open %s by binary read mode\n", INPUT_IMG_FILE);
exit(1);
}
// bmpヘッダの読み出し
fread(&bmpfhr.bfType, sizeof(uint16_t), 1, fbmpr);
fread(&bmpfhr.bfSize, sizeof(uint32_t), 1, fbmpr);
fread(&bmpfhr.bfReserved1, sizeof(uint16_t), 1, fbmpr);
fread(&bmpfhr.bfReserved2, sizeof(uint16_t), 1, fbmpr);
fread(&bmpfhr.bfOffBits, sizeof(uint32_t), 1, fbmpr);
fread(&bmpihr, sizeof(BITMAPINFOHEADER), 1, fbmpr);
uint32_t image_all_pixels = bmpihr.biHeight * bmpihr.biWidth;
uint32_t image_all_bytes = image_all_pixels * IMAGE_CHANNEL;
// udmabuf0
fd9 = open("/dev/udmabuf0", O_RDWR | O_SYNC); // frame_buffer, The chache is disabled.
if (fd9 == -1){
fprintf(stderr, "/dev/udmabuf0 open error\n");
exit(-1);
}
image_buf = (volatile uint8_t *)mmap(NULL, 2*image_all_bytes, PROT_READ|PROT_WRITE, MAP_SHARED, fd9, 0);
if (image_buf == -1){
fprintf(stderr, "frame_buffer_bmdc mmap error\n");
exit(-1);
}
// phys_addr of udmabuf0
fd_paddr = open("/sys/class/u-dma-buf/udmabuf0/phys_addr", O_RDONLY);
if (fd_paddr == -1){
fprintf(stderr, "/sys/class/u-dma-buf/udmabuf0/phys_addr open errorn");
exit(-1);
}
read(fd_paddr, (void *)attr, 1024);
sscanf((const char *)attr, "%lx", &phys_addr);
close(fd_paddr);
printf("phys_addr = %x\n", (unsigned int)phys_addr);
// ピクセルを入れるメモリを定義する
rd_bmp = image_buf;
wr_bmp = & image_buf[image_all_bytes];
// rd_bmp にBMPのピクセルを代入。その際に、行を逆転する必要がある
for (int y=0; y<bmpihr.biHeight; y++){
for (int x=0; x<bmpihr.biWidth; x++){
blue = fgetc(fbmpr);
green = fgetc(fbmpr);
red = fgetc(fbmpr);
uint32_t index = (((bmpihr.biHeight-1)-y)*bmpihr.biWidth+x)*IMAGE_CHANNEL;
rd_bmp[index] = blue;
rd_bmp[index+1] = green;
rd_bmp[index+2] = red;
}
}
fclose(fbmpr);
// uio のオープン
// axi_dma (UIO 4)
fd4 = open("/dev/uio4", O_RDWR); // axi_dma interface AXI4 Lite Slave
if (fd4 < 1){
fprintf(stderr, "/dev/uio4 (axi_dma) open error\n");
exit(-1);
}
axi_dma = (volatile unsigned *)mmap(NULL, 0x10000, PROT_READ|PROT_WRITE, MAP_SHARED, fd4, 0);
if (!axi_dma){
fprintf(stderr, "axi_dma mmap error\n");
exit(-1);
}
// color_converter_RGB24 (UIO 5)
fd5 = open("/dev/uio5", O_RDWR); // color_converter_RGB24 interface AXI4 Lite Slave
if (fd5 < 1){
fprintf(stderr, "/dev/uio5 (color_converter_RGB24) open error\n");
exit(-1);
}
color_converter_RGB24 = (volatile unsigned *)mmap(NULL, 0x10000, PROT_READ|PROT_WRITE, MAP_SHARED, fd5, 0);
if (!color_converter_RGB24){
fprintf(stderr, "color_converter_RGB24 mmap error\n");
exit(-1);
}
// gaussian_axis_RGB24 (UIO 6)
fd6 = open("/dev/uio6", O_RDWR); // gaussian_axis_RGB24 interface AXI4 Lite Slave
if (fd6 < 1){
fprintf(stderr, "/dev/uio6 (gaussian_axis_RGB24) open error\n");
exit(-1);
}
gaussian_axis_RGB24 = (volatile unsigned *)mmap(NULL, 0x10000, PROT_READ|PROT_WRITE, MAP_SHARED, fd6, 0);
if (!gaussian_axis_RGB24){
fprintf(stderr, "gaussian_axis_RGB24 mmap error\n");
exit(-1);
}
// median_axis_RGB24 (UIO 7)
fd7 = open("/dev/uio7", O_RDWR); // median_axis_RGB24 interface AXI4 Lite Slave
if (fd7 < 1){
fprintf(stderr, "/dev/uio7 (median_axis_RGB24) open error\n");
exit(-1);
}
median_axis_RGB24 = (volatile unsigned *)mmap(NULL, 0x10000, PROT_READ|PROT_WRITE, MAP_SHARED, fd7, 0);
if (!median_axis_RGB24){
fprintf(stderr, "median_axis_RGB24 mmap error\n");
exit(-1);
}
// sobel_axis_RGB24 (UIO 8)
fd8 = open("/dev/uio8", O_RDWR); // sobel_axis_RGB24 interface AXI4 Lite Slave
if (fd8 < 1){
fprintf(stderr, "/dev/uio8 (sobel_axis_RGB24) open error\n");
exit(-1);
}
sobel_axis_RGB24 = (volatile unsigned *)mmap(NULL, 0x10000, PROT_READ|PROT_WRITE, MAP_SHARED, fd8, 0);
if (!sobel_axis_RGB24){
fprintf(stderr, "sobel_axis_RGB24 mmap error\n");
exit(-1);
}
// gaussian_axis_RGB24
gaussian_axis_RGB24[GUSSIAN_ROW_SIZE] = bmpihr.biHeight; // row_size
gaussian_axis_RGB24[GUSSIAN_COL_SIZE] = bmpihr.biWidth; // col_size
gaussian_axis_RGB24[GUSSIAN_FUNCTON_R] = 2; // function_r, ORG_IMGwAxiDma
//gaussian_axis_RGB24[GUSSIAN_FUNCTON_R] = 3; // function_r, GAUSSIANwAxiDma
// median_axis_RGB24
median_axis_RGB24[MEDIAN_ROW_SIZE] = bmpihr.biHeight; // row_size
median_axis_RGB24[MEDIAN_COL_SIZE] = bmpihr.biWidth; // col_size
//median_axis_RGB24[MEDIAN_FUNCTION_R] = 2; // function_r, ORG_IMGwAxiDma
median_axis_RGB24[MEDIAN_FUNCTION_R] = 3; // function_r, MEDIANwAxiDma
// color_converter_RGB24
color_converter_RGB24[COLOR_CONVERTER_ROW_SIZE] = bmpihr.biHeight; // row_size
color_converter_RGB24[COLOR_CONVERTER_COL_SIZE] = bmpihr.biWidth; // col_size
color_converter_RGB24[COLOR_CONVERTER_FUNCTION_R] = 2; // function_r, ORG_IMGwAxiDma
//color_converter_RGB24[COLOR_CONVERTER_FUNCTION_R] = 3; // function_r, COLOR_CONVwAxiDma
color_converter_RGB24[COLOR_CONVERTER_RED_MAG] = 0x2000; // 32.0, ap_ufixed<16, 8, AP_TRN_ZERO, AP_SAT>
color_converter_RGB24[COLOR_CONVERTER_GREEN_MAG] = 0x0100; // 1.0, ap_ufixed<16, 8, AP_TRN_ZERO, AP_SAT>
color_converter_RGB24[COLOR_CONVERTER_BLUE_MAG] = 0x0100; // 1.0, ap_ufixed<16, 8, AP_TRN_ZERO, AP_SAT>
// sobel_axis_RGB24
sobel_axis_RGB24[SOBEL_ROW_SIZE] = bmpihr.biHeight; // row_size
sobel_axis_RGB24[SOBEL_COL_SIZE] = bmpihr.biWidth; // col_size
//sobel_axis_RGB24[SOBEL_FUNCTION_R] = 2; // function_r, ORG_IMGwAxiDma
sobel_axis_RGB24[SOBEL_FUNCTION_R] = 3; // function_r, MEDIANwAxiDma
// DMA Start
// MM2S Channel
axi_dma[MM2S_CONTROL_REG] = 1; // MM2S_DMACR, Run/Stop bit(bit 0) = 1
axi_dma[MM2S_START_ADDR] = phys_addr; // MM2S_SA
axi_dma[MM2S_LENGTH_REG] = image_all_bytes; // MM2S_LENGTH(bytes), Start
// S2MM Channel
axi_dma[S2MM_CONTROL_REG] = 1; // S2MM_DMACR, Run/Stop bit(bit 0) = 1
axi_dma[S2MM_DESTINATION_ADDR] = phys_addr + image_all_bytes; // S2MM_SA
axi_dma[S2MM_LENGTH_REG] = image_all_bytes; // S2MM_LENGTH(bytes), Start
// Image IPs start
gaussian_axis_RGB24[GUSSIAN_CONTROL] = 1; // start
median_axis_RGB24[MEDIAN_CONTROL] = 1; // start
color_converter_RGB24[COLOR_CONVERTER_CONTROL] = 1; // start
sobel_axis_RGB24[SOBEL_CONTROL] = 1; // start
// Waiting for DMA to finish
while(!(axi_dma[S2MM_STATUS_REG] & S2MM_IDLE_MASK)) ; // Waiting Idle bit (S2MM_DMASR, bit 1)
// Write filtered image file
if ((fbmpw=fopen(OUTPUT_IMG_FILE, "wb")) == NULL){
fprintf(stderr, "Can't open %s by binary write mode\n", OUTPUT_IMG_FILE);
exit(1);
}
// BMPファイルヘッダの書き込み
fwrite(&bmpfhr.bfType, sizeof(uint16_t), 1, fbmpw);
fwrite(&bmpfhr.bfSize, sizeof(uint32_t), 1, fbmpw);
fwrite(&bmpfhr.bfReserved1, sizeof(uint16_t), 1, fbmpw);
fwrite(&bmpfhr.bfReserved2, sizeof(uint16_t), 1, fbmpw);
fwrite(&bmpfhr.bfOffBits, sizeof(uint32_t), 1, fbmpw);
fwrite(&bmpihr, sizeof(BITMAPINFOHEADER), 1, fbmpw);
// RGB データの書き込み、逆順にする
for (int y=0; y<bmpihr.biHeight; y++){
for (int x=0; x<bmpihr.biWidth; x++){
uint32_t index = (((bmpihr.biHeight-1)-y)*bmpihr.biWidth+x)*IMAGE_CHANNEL;
blue = wr_bmp[index];
green = wr_bmp[index+1];
red = wr_bmp[index+2];
fputc(blue, fbmpw);
fputc(green, fbmpw);
fputc(red, fbmpw);
}
}
fclose(fbmpw);
munmap((void *)image_buf, 2*image_all_bytes);
munmap((void *)axi_dma, 0x10000);
munmap((void *)gaussian_axis_RGB24, 0x10000);
munmap((void *)median_axis_RGB24, 0x10000);
munmap((void *)color_converter_RGB24, 0x10000);
munmap((void *)sobel_axis_RGB24, 0x10000);
close(fd4);
close(fd5);
close(fd6);
close(fd7);
close(fd8);
close(fd9);
return(0);
}
rd_bmp[((bmpihr.biHeight-1)-y)*bmpihr.biWidth+x] = (blue & 0xff) | ((green & 0xff)<<8) | ((red & 0xff)<<16);
// bmp_header.h
// BMP ファイルフォーマットから引用させて頂きました
// http://www.kk.iij4u.or.jp/~kondo/bmp/
//
// 2017/05/04 : takseiさんのご指摘によりintX_tを使った宣言に変更。takseiさんありがとうございました
// 変数の型のサイズの違いによってLinuxの64ビット版では動作しなかったためです
// http://marsee101.blog19.fc2.com/blog-entry-3354.html#comment2808
//
#include <stdio.h>
#include <stdint.h>
// BITMAPFILEHEADER 14bytes
typedef struct tagBITMAPFILEHEADER {
uint16_t bfType;
uint32_t bfSize;
uint16_t bfReserved1;
uint16_t bfReserved2;
uint32_t bfOffBits;
} BITMAPFILEHEADER;
// BITMAPINFOHEADER 40bytes
typedef struct tagBITMAPINFOHEADER{
uint32_t biSize;
int32_t biWidth;
int32_t biHeight;
uint16_t biPlanes;
uint16_t biBitCount;
uint32_t biCompression;
uint32_t biSizeImage;
int32_t biXPixPerMeter;
int32_t biYPixPerMeter;
uint32_t biClrUsed;
uint32_t biClrImporant;
} BITMAPINFOHEADER;
typedef struct BMP24bitsFORMAT {
uint8_t blue;
uint8_t green;
uint8_t red;
} BMP24FORMAT;
// zub1cg_i4filters_peta.c
// 2023/10/04 by marsee
//
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <assert.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <string.h>
#include "bmp_header.h"
char INPUT_IMG_FILE[] = "test2.bmp";
char OUTPUT_IMG_FILE[] = "output_img.bmp";
int main(){
BITMAPFILEHEADER bmpfhr; // BMPファイルのファイルヘッダ(for Read)
BITMAPINFOHEADER bmpihr; // BMPファイルのINFOヘッダ(for Read)
FILE *fbmpr, *fbmpw;
volatile uint32_t *rd_bmp, *wr_bmp;
int blue, green, red;
int fd4, fd5, fd6, fd7, fd8, fd9;
volatile uint32_t *axi_dma;
volatile uint32_t *color_converter_RGB24;
volatile uint32_t *gaussian_axis_RGB24;
volatile uint32_t *median_axis_RGB24;
volatile uint32_t *sobel_axis_RGB24;
volatile uint32_t *image_buf;
u_int32_t fd_paddr;
unsigned char attr[1024];
unsigned long phys_addr;
// Image file open
if ((fbmpr = fopen(INPUT_IMG_FILE, "rb")) == NULL){ // test.bmp をオープン
fprintf(stderr, "Can't open %s by binary read mode\n", INPUT_IMG_FILE);
exit(1);
}
// bmpヘッダの読み出し
fread(&bmpfhr.bfType, sizeof(uint16_t), 1, fbmpr);
fread(&bmpfhr.bfSize, sizeof(uint32_t), 1, fbmpr);
fread(&bmpfhr.bfReserved1, sizeof(uint16_t), 1, fbmpr);
fread(&bmpfhr.bfReserved2, sizeof(uint16_t), 1, fbmpr);
fread(&bmpfhr.bfOffBits, sizeof(uint32_t), 1, fbmpr);
fread(&bmpihr, sizeof(BITMAPINFOHEADER), 1, fbmpr);
uint32_t image_all_pixels = bmpihr.biHeight * bmpihr.biWidth;
uint32_t image_all_bytes = image_all_pixels * sizeof(uint32_t);
// udmabuf0
fd9 = open("/dev/udmabuf0", O_RDWR | O_SYNC); // frame_buffer, The chache is disabled.
if (fd9 == -1){
fprintf(stderr, "/dev/udmabuf0 open error\n");
exit(-1);
}
image_buf = (volatile uint32_t *)mmap(NULL, 2*image_all_bytes, PROT_READ|PROT_WRITE, MAP_SHARED, fd9, 0);
if (image_buf == -1){
fprintf(stderr, "frame_buffer_bmdc mmap error\n");
exit(-1);
}
// phys_addr of udmabuf0
fd_paddr = open("/sys/class/u-dma-buf/udmabuf0/phys_addr", O_RDONLY);
if (fd_paddr == -1){
fprintf(stderr, "/sys/class/u-dma-buf/udmabuf0/phys_addr open errorn");
exit(-1);
}
read(fd_paddr, (void *)attr, 1024);
sscanf((const char *)attr, "%lx", &phys_addr);
close(fd_paddr);
printf("phys_addr = %x\n", (unsigned int)phys_addr);
// ピクセルを入れるメモリを定義する
rd_bmp = image_buf;
wr_bmp = & image_buf[image_all_pixels];
// rd_bmp にBMPのピクセルを代入。その際に、行を逆転する必要がある
for (int y=0; y<bmpihr.biHeight; y++){
for (int x=0; x<bmpihr.biWidth; x++){
blue = fgetc(fbmpr);
green = fgetc(fbmpr);
red = fgetc(fbmpr);
rd_bmp[((bmpihr.biHeight-1)-y)*bmpihr.biWidth+x] = (blue & 0xff) | ((green & 0xff)<<8) | ((red & 0xff)<<16);
}
}
fclose(fbmpr);
// uio のオープン
// axi_dma (UIO 4)
fd4 = open("/dev/uio4", O_RDWR); // axi_dma interface AXI4 Lite Slave
if (fd4 < 1){
fprintf(stderr, "/dev/uio4 (axi_dma) open error\n");
exit(-1);
}
axi_dma = (volatile unsigned *)mmap(NULL, 0x10000, PROT_READ|PROT_WRITE, MAP_SHARED, fd4, 0);
if (!axi_dma){
fprintf(stderr, "axi_dma mmap error\n");
exit(-1);
}
// color_converter_RGB24 (UIO 5)
fd5 = open("/dev/uio5", O_RDWR); // color_converter_RGB24 interface AXI4 Lite Slave
if (fd5 < 1){
fprintf(stderr, "/dev/uio5 (color_converter_RGB24) open error\n");
exit(-1);
}
color_converter_RGB24 = (volatile unsigned *)mmap(NULL, 0x10000, PROT_READ|PROT_WRITE, MAP_SHARED, fd5, 0);
if (!color_converter_RGB24){
fprintf(stderr, "color_converter_RGB24 mmap error\n");
exit(-1);
}
// gaussian_axis_RGB24 (UIO 6)
fd6 = open("/dev/uio6", O_RDWR); // gaussian_axis_RGB24 interface AXI4 Lite Slave
if (fd6 < 1){
fprintf(stderr, "/dev/uio6 (gaussian_axis_RGB24) open error\n");
exit(-1);
}
gaussian_axis_RGB24 = (volatile unsigned *)mmap(NULL, 0x10000, PROT_READ|PROT_WRITE, MAP_SHARED, fd6, 0);
if (!gaussian_axis_RGB24){
fprintf(stderr, "gaussian_axis_RGB24 mmap error\n");
exit(-1);
}
// median_axis_RGB24 (UIO 7)
fd7 = open("/dev/uio7", O_RDWR); // median_axis_RGB24 interface AXI4 Lite Slave
if (fd7 < 1){
fprintf(stderr, "/dev/uio7 (median_axis_RGB24) open error\n");
exit(-1);
}
median_axis_RGB24 = (volatile unsigned *)mmap(NULL, 0x10000, PROT_READ|PROT_WRITE, MAP_SHARED, fd7, 0);
if (!median_axis_RGB24){
fprintf(stderr, "median_axis_RGB24 mmap error\n");
exit(-1);
}
// sobel_axis_RGB24 (UIO 8)
fd8 = open("/dev/uio8", O_RDWR); // sobel_axis_RGB24 interface AXI4 Lite Slave
if (fd8 < 1){
fprintf(stderr, "/dev/uio8 (sobel_axis_RGB24) open error\n");
exit(-1);
}
sobel_axis_RGB24 = (volatile unsigned *)mmap(NULL, 0x10000, PROT_READ|PROT_WRITE, MAP_SHARED, fd8, 0);
if (!sobel_axis_RGB24){
fprintf(stderr, "sobel_axis_RGB24 mmap error\n");
exit(-1);
}
// gaussian_axis_RGB24
gaussian_axis_RGB24[8] = bmpihr.biHeight; // row_size
gaussian_axis_RGB24[10] = bmpihr.biWidth; // col_size
gaussian_axis_RGB24[6] = 2; // function_r, ORG_IMGwAxiDma
//gaussian_axis_RGB24[6] = 3; // function_r, GAUSSIANwAxiDma
// median_axis_RGB24
median_axis_RGB24[8] = bmpihr.biHeight; // row_size
median_axis_RGB24[10] = bmpihr.biWidth; // col_size
//median_axis_RGB24[6] = 2; // function_r, ORG_IMGwAxiDma
median_axis_RGB24[6] = 3; // function_r, MEDIANwAxiDma
// color_converter_RGB24
color_converter_RGB24[8] = bmpihr.biHeight; // row_size
color_converter_RGB24[10] = bmpihr.biWidth; // col_size
color_converter_RGB24[6] = 2; // function_r, ORG_IMGwAxiDma
//color_converter_RGB24[6] = 3; // function_r, COLOR_CONVwAxiDma
color_converter_RGB24[12] = 0x2000; // 32.0, ap_ufixed<16, 8, AP_TRN_ZERO, AP_SAT>
color_converter_RGB24[14] = 0x0100; // 1.0, ap_ufixed<16, 8, AP_TRN_ZERO, AP_SAT>
color_converter_RGB24[16] = 0x0100; // 1.0, ap_ufixed<16, 8, AP_TRN_ZERO, AP_SAT>
// sobel_axis_RGB24
sobel_axis_RGB24[8] = bmpihr.biHeight; // row_size
sobel_axis_RGB24[10] = bmpihr.biWidth; // col_size
//sobel_axis_RGB24[6] = 2; // function_r, ORG_IMGwAxiDma
sobel_axis_RGB24[6] = 3; // function_r, MEDIANwAxiDma
// DMA Start
// MM2S Channel
axi_dma[0] = 1; // MM2S_DMACR, Run/Stop bit(bit 0) = 1
axi_dma[6] = phys_addr; // MM2S_SA
axi_dma[10] = image_all_bytes; // MM2S_LENGTH(bytes), Start
// S2MM Channel
axi_dma[12] = 1; // S2MM_DMACR, Run/Stop bit(bit 0) = 1
axi_dma[18] = phys_addr + image_all_bytes; // S2MM_SA
axi_dma[22] = image_all_bytes; // S2MM_LENGTH(bytes), Start
// Image IPs start
gaussian_axis_RGB24[0] = 1; // start
median_axis_RGB24[0] = 1; // start
color_converter_RGB24[0] = 1; // start
sobel_axis_RGB24[0] = 1; // start
// Waiting for DMA to finish
while(!(axi_dma[13] & 2)) ; // Waiting Idle bit (S2MM_DMASR, bit 1)
// Write filtered image file
if ((fbmpw=fopen(OUTPUT_IMG_FILE, "wb")) == NULL){
fprintf(stderr, "Can't open %s by binary write mode\n", OUTPUT_IMG_FILE);
exit(1);
}
// BMPファイルヘッダの書き込み
fwrite(&bmpfhr.bfType, sizeof(uint16_t), 1, fbmpw);
fwrite(&bmpfhr.bfSize, sizeof(uint32_t), 1, fbmpw);
fwrite(&bmpfhr.bfReserved1, sizeof(uint16_t), 1, fbmpw);
fwrite(&bmpfhr.bfReserved2, sizeof(uint16_t), 1, fbmpw);
fwrite(&bmpfhr.bfOffBits, sizeof(uint32_t), 1, fbmpw);
fwrite(&bmpihr, sizeof(BITMAPINFOHEADER), 1, fbmpw);
// RGB データの書き込み、逆順にする
for (int y=0; y<bmpihr.biHeight; y++){
for (int x=0; x<bmpihr.biWidth; x++){
uint32_t pixel = wr_bmp[((bmpihr.biHeight-1)-y)*bmpihr.biWidth+x];
blue = pixel & 0xff;
green = (pixel >> 8) & 0xff;
red = (pixel >> 16) & 0xff;
fputc(blue, fbmpw);
fputc(green, fbmpw);
fputc(red, fbmpw);
}
}
fclose(fbmpw);
munmap((void *)image_buf, 2*image_all_bytes);
munmap((void *)axi_dma, 0x10000);
munmap((void *)gaussian_axis_RGB24, 0x10000);
munmap((void *)median_axis_RGB24, 0x10000);
munmap((void *)color_converter_RGB24, 0x10000);
munmap((void *)sobel_axis_RGB24, 0x10000);
close(fd4);
close(fd5);
close(fd6);
close(fd7);
close(fd8);
close(fd9);
return(0);
}
uio4: dma 0xa0000000
uio5: color_converter_RGB24 0xa0040000
uio6: gaussian_axis_RGB24 0xa0030000
uio7: median_axis_RGB24 0xa0020000
uio8: sobel_axis_RGB24 0xa0010000
/include/ "system-conf.dtsi"
/ {
chosen {
bootargs = "uio_pdrv_genirq.of_id=generic-uio";
};
};
&axi_dma_0{
compatible = "generic-uio";
};
&color_converter_RGB24_0{
compatible = "generic-uio";
};
&gaussian_axis_RGB24_0{
compatible = "generic-uio";
};
&median_axis_RGB24_0{
compatible = "generic-uio";
};
&sobel_axis_RGB24_0{
compatible = "generic-uio";
};
&sdhci1 {
status = "okay";
no-1-8-v;
disable-wp;
};
NOTICE: BL31: v2.6(release):xlnx_rebase_v2.6_2022.1_update3-18-g0897efd45
NOTICE: BL31: Built : 03:55:03, Sep 9 2022
U-Boot 2022.01 (Sep 20 2022 - 06:35:33 +0000)
CPU: ZynqMP
Silicon: v3
Board: Xilinx ZynqMP
DRAM: 1023 MiB
PMUFW: v1.1
PMUFW no permission to change config object
EL Level: EL2
Chip ID: zu1eg
NAND: 0 MiB
MMC: mmc@ff170000: 0
Loading Environment from FAT... *** Error - No Valid Environment Area found
*** Warning - bad env area, using default environment
In: serial
Out: serial
Err: serial
Bootmode: SD_MODE1
Reset reason: EXTERNAL
Net: FEC: can't find phy-handle
ZYNQ GEM: ff0d0000, mdio bus ff0d0000, phyaddr 7, interface rgmii-id
Warning: ethernet@ff0d0000 (eth0) using random MAC address - aa:f8:2c:57:0c:03
eth0: ethernet@ff0d0000
scanning bus for devices...
starting USB...
No working controllers found
Hit any key to stop autoboot: 0
switch to partitions #0, OK
mmc0 is current device
Scanning mmc 0:1...
Found U-Boot script /boot.scr
2777 bytes read in 13 ms (208 KiB/s)
## Executing script at 20000000
Trying to load boot images from mmc0
86728516 bytes read in 6164 ms (13.4 MiB/s)
## Loading kernel from FIT Image at 10000000 ...
Using 'conf-system-top.dtb' configuration
Trying 'kernel-1' kernel subimage
Description: Linux kernel
Created: 2022-10-03 7:50:07 UTC
Type: Kernel Image
Compression: gzip compressed
Data Start: 0x100000fc
Data Size: 9268952 Bytes = 8.8 MiB
Architecture: AArch64
OS: Linux
Load Address: 0x00200000
Entry Point: 0x00200000
Hash algo: sha256
Hash value: 0a45931a185d9da44b6d5e41c6b7e68412ab963794be99aef85124f428fb76a2
Verifying Hash Integrity ... sha256+ OK
## Loading ramdisk from FIT Image at 10000000 ...
Using 'conf-system-top.dtb' configuration
Trying 'ramdisk-1' ramdisk subimage
Description: petalinux-image-minimal
Created: 2022-10-03 7:50:07 UTC
Type: RAMDisk Image
Compression: uncompressed
Data Start: 0x108e0aec
Data Size: 77418206 Bytes = 73.8 MiB
Architecture: AArch64
OS: Linux
Load Address: unavailable
Entry Point: unavailable
Hash algo: sha256
Hash value: ff1d7c1578de26fece5d4358eaac333164748fce77c8d75ec131848af5ba36bc
Verifying Hash Integrity ... sha256+ OK
## Loading fdt from FIT Image at 10000000 ...
Using 'conf-system-top.dtb' configuration
Trying 'fdt-system-top.dtb' fdt subimage
Description: Flattened Device Tree blob
Created: 2022-10-03 7:50:07 UTC
Type: Flat Device Tree
Compression: uncompressed
Data Start: 0x108d70e4
Data Size: 39223 Bytes = 38.3 KiB
Architecture: AArch64
Hash algo: sha256
Hash value: f7c8b5875bb51734ec5d4e2c015badfb626df1ed3bc97442d824c6f34b44ae08
Verifying Hash Integrity ... sha256+ OK
Booting using the fdt blob at 0x108d70e4
Uncompressing Kernel Image
Loading Ramdisk to 37226000, end 3bbfaede ... OK
Loading Device Tree to 0000000037219000, end 0000000037225936 ... OK
Starting kernel ...
[ 0.000000] Booting Linux on physical CPU 0x0000000000 [0x410fd034]
[ 0.000000] Linux version 5.15.36-xilinx-v2022.2 (oe-user@oe-host) (aarch64-xilinx-linux-gcc (GCC) 11.2.0, GNU ld (GNU Binutils) 2.37.20210721) #1 SMP Mon Oct 3 07:50:07 UTC 2022
[ 0.000000] Machine model: xlnx,zynqmp
[ 0.000000] efi: UEFI not found.
[ 0.000000] Zone ranges:
[ 0.000000] DMA32 [mem 0x0000000000000000-0x000000003fefffff]
[ 0.000000] Normal empty
[ 0.000000] Movable zone start for each node
[ 0.000000] Early memory node ranges
[ 0.000000] node 0: [mem 0x0000000000000000-0x000000003fefffff]
[ 0.000000] Initmem setup node 0 [mem 0x0000000000000000-0x000000003fefffff]
[ 0.000000] On node 0, zone DMA32: 256 pages in unavailable ranges
[ 0.000000] cma: Reserved 256 MiB at 0x0000000027000000
[ 0.000000] psci: probing for conduit method from DT.
[ 0.000000] psci: PSCIv1.1 detected in firmware.
[ 0.000000] psci: Using standard PSCI v0.2 function IDs
[ 0.000000] psci: MIGRATE_INFO_TYPE not supported.
[ 0.000000] psci: SMC Calling Convention v1.2
[ 0.000000] percpu: Embedded 18 pages/cpu s34776 r8192 d30760 u73728
[ 0.000000] Detected VIPT I-cache on CPU0
[ 0.000000] CPU features: detected: ARM erratum 845719
[ 0.000000] Built 1 zonelists, mobility grouping on. Total pages: 257796
[ 0.000000] Kernel command line: uio_pdrv_genirq.of_id=generic-uio
[ 0.000000] Dentry cache hash table entries: 131072 (order: 8, 1048576 bytes, linear)
[ 0.000000] Inode-cache hash table entries: 65536 (order: 7, 524288 bytes, linear)
[ 0.000000] mem auto-init: stack:off, heap alloc:off, heap free:off
[ 0.000000] Memory: 667776K/1047552K available (13888K kernel code, 990K rwdata, 3916K rodata, 2176K init, 573K bss, 117632K reserved, 262144K cma-reserved)
[ 0.000000] rcu: Hierarchical RCU implementation.
[ 0.000000] rcu: RCU event tracing is enabled.
[ 0.000000] rcu: RCU restricting CPUs from NR_CPUS=16 to nr_cpu_ids=2.
[ 0.000000] rcu: RCU calculated value of scheduler-enlistment delay is 25 jiffies.
[ 0.000000] rcu: Adjusting geometry for rcu_fanout_leaf=16, nr_cpu_ids=2
[ 0.000000] NR_IRQS: 64, nr_irqs: 64, preallocated irqs: 0
[ 0.000000] GIC: Adjusting CPU interface base to 0x00000000f902f000
[ 0.000000] Root IRQ handler: gic_handle_irq
[ 0.000000] GIC: Using split EOI/Deactivate mode
[ 0.000000] random: get_random_bytes called from start_kernel+0x474/0x6d8 with crng_init=0
[ 0.000000] arch_timer: cp15 timer(s) running at 100.00MHz (phys).
[ 0.000000] clocksource: arch_sys_counter: mask: 0xffffffffffffff max_cycles: 0x171024e7e0, max_idle_ns: 440795205315 ns
[ 0.000000] sched_clock: 56 bits at 100MHz, resolution 10ns, wraps every 4398046511100ns
[ 0.000364] Console: colour dummy device 80x25
[ 0.000603] printk: console [tty0] enabled
[ 0.000639] Calibrating delay loop (skipped), value calculated using timer frequency.. 200.00 BogoMIPS (lpj=400000)
[ 0.000660] pid_max: default: 32768 minimum: 301
[ 0.000929] Mount-cache hash table entries: 2048 (order: 2, 16384 bytes, linear)
[ 0.000952] Mountpoint-cache hash table entries: 2048 (order: 2, 16384 bytes, linear)
[ 0.002344] rcu: Hierarchical SRCU implementation.
[ 0.002594] EFI services will not be available.
[ 0.002711] smp: Bringing up secondary CPUs ...
[ 0.003160] Detected VIPT I-cache on CPU1
[ 0.003216] CPU1: Booted secondary processor 0x0000000001 [0x410fd034]
[ 0.003304] smp: Brought up 1 node, 2 CPUs
[ 0.003329] SMP: Total of 2 processors activated.
[ 0.003339] CPU features: detected: 32-bit EL0 Support
[ 0.003349] CPU features: detected: CRC32 instructions
[ 0.003400] CPU: All CPU(s) started at EL2
[ 0.003420] alternatives: patching kernel code
[ 0.004504] devtmpfs: initialized
[ 0.008888] clocksource: jiffies: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 7645041785100000 ns
[ 0.008917] futex hash table entries: 512 (order: 3, 32768 bytes, linear)
[ 0.018620] pinctrl core: initialized pinctrl subsystem
[ 0.019275] DMI not present or invalid.
[ 0.019582] NET: Registered PF_NETLINK/PF_ROUTE protocol family
[ 0.020843] DMA: preallocated 128 KiB GFP_KERNEL pool for atomic allocations
[ 0.020934] DMA: preallocated 128 KiB GFP_KERNEL|GFP_DMA32 pool for atomic allocations
[ 0.020995] audit: initializing netlink subsys (disabled)
[ 0.021101] audit: type=2000 audit(0.020:1): state=initialized audit_enabled=0 res=1
[ 0.021512] hw-breakpoint: found 6 breakpoint and 4 watchpoint registers.
[ 0.021563] ASID allocator initialised with 65536 entries
[ 0.021692] Serial: AMBA PL011 UART driver
[ 0.039601] HugeTLB registered 1.00 GiB page size, pre-allocated 0 pages
[ 0.039635] HugeTLB registered 32.0 MiB page size, pre-allocated 0 pages
[ 0.039646] HugeTLB registered 2.00 MiB page size, pre-allocated 0 pages
[ 0.039657] HugeTLB registered 64.0 KiB page size, pre-allocated 0 pages
[ 1.109434] cryptd: max_cpu_qlen set to 1000
[ 1.134814] DRBG: Continuing without Jitter RNG
[ 1.237095] raid6: neonx8 gen() 2140 MB/s
[ 1.305150] raid6: neonx8 xor() 1586 MB/s
[ 1.373216] raid6: neonx4 gen() 2182 MB/s
[ 1.441272] raid6: neonx4 xor() 1555 MB/s
[ 1.509343] raid6: neonx2 gen() 2066 MB/s
[ 1.577396] raid6: neonx2 xor() 1430 MB/s
[ 1.645472] raid6: neonx1 gen() 1762 MB/s
[ 1.713522] raid6: neonx1 xor() 1212 MB/s
[ 1.781591] raid6: int64x8 gen() 1366 MB/s
[ 1.849647] raid6: int64x8 xor() 773 MB/s
[ 1.917708] raid6: int64x4 gen() 1599 MB/s
[ 1.985778] raid6: int64x4 xor() 851 MB/s
[ 2.053853] raid6: int64x2 gen() 1396 MB/s
[ 2.121911] raid6: int64x2 xor() 749 MB/s
[ 2.189980] raid6: int64x1 gen() 1033 MB/s
[ 2.258034] raid6: int64x1 xor() 517 MB/s
[ 2.258045] raid6: using algorithm neonx4 gen() 2182 MB/s
[ 2.258054] raid6: .... xor() 1555 MB/s, rmw enabled
[ 2.258063] raid6: using neon recovery algorithm
[ 2.258675] iommu: Default domain type: Translated
[ 2.258688] iommu: DMA domain TLB invalidation policy: strict mode
[ 2.258955] SCSI subsystem initialized
[ 2.259142] usbcore: registered new interface driver usbfs
[ 2.259182] usbcore: registered new interface driver hub
[ 2.259211] usbcore: registered new device driver usb
[ 2.259291] mc: Linux media interface: v0.10
[ 2.259318] videodev: Linux video capture interface: v2.00
[ 2.259365] pps_core: LinuxPPS API ver. 1 registered
[ 2.259375] pps_core: Software ver. 5.3.6 - Copyright 2005-2007 Rodolfo Giometti <giometti@linux.it>
[ 2.259397] PTP clock support registered
[ 2.259431] EDAC MC: Ver: 3.0.0
[ 2.259778] zynqmp-ipi-mbox mailbox@ff990400: Registered ZynqMP IPI mbox with TX/RX channels.
[ 2.260028] FPGA manager framework
[ 2.260171] Advanced Linux Sound Architecture Driver Initialized.
[ 2.260578] Bluetooth: Core ver 2.22
[ 2.260609] NET: Registered PF_BLUETOOTH protocol family
[ 2.260619] Bluetooth: HCI device and connection manager initialized
[ 2.260635] Bluetooth: HCI socket layer initialized
[ 2.260646] Bluetooth: L2CAP socket layer initialized
[ 2.260663] Bluetooth: SCO socket layer initialized
[ 2.261096] clocksource: Switched to clocksource arch_sys_counter
[ 2.261265] VFS: Disk quotas dquot_6.6.0
[ 2.261319] VFS: Dquot-cache hash table entries: 512 (order 0, 4096 bytes)
[ 2.265902] NET: Registered PF_INET protocol family
[ 2.266022] IP idents hash table entries: 16384 (order: 5, 131072 bytes, linear)
[ 2.266662] tcp_listen_portaddr_hash hash table entries: 512 (order: 1, 8192 bytes, linear)
[ 2.266693] TCP established hash table entries: 8192 (order: 4, 65536 bytes, linear)
[ 2.266760] TCP bind hash table entries: 8192 (order: 5, 131072 bytes, linear)
[ 2.266930] TCP: Hash tables configured (established 8192 bind 8192)
[ 2.267045] UDP hash table entries: 512 (order: 2, 16384 bytes, linear)
[ 2.267078] UDP-Lite hash table entries: 512 (order: 2, 16384 bytes, linear)
[ 2.267180] NET: Registered PF_UNIX/PF_LOCAL protocol family
[ 2.267533] RPC: Registered named UNIX socket transport module.
[ 2.267545] RPC: Registered udp transport module.
[ 2.267554] RPC: Registered tcp transport module.
[ 2.267562] RPC: Registered tcp NFSv4.1 backchannel transport module.
[ 2.267578] PCI: CLS 0 bytes, default 64
[ 2.267746] Trying to unpack rootfs image as initramfs...
[ 2.274014] armv8-pmu pmu: hw perfevents: no interrupt-affinity property, guessing.
[ 2.274653] hw perfevents: enabled with armv8_pmuv3 PMU driver, 7 counters available
[ 6.035995] Freeing initrd memory: 75600K
[ 6.099817] Initialise system trusted keyrings
[ 6.099982] workingset: timestamp_bits=46 max_order=18 bucket_order=0
[ 6.100835] NFS: Registering the id_resolver key type
[ 6.100857] Key type id_resolver registered
[ 6.100866] Key type id_legacy registered
[ 6.100892] nfs4filelayout_init: NFSv4 File Layout Driver Registering...
[ 6.100904] nfs4flexfilelayout_init: NFSv4 Flexfile Layout Driver Registering...
[ 6.100934] jffs2: version 2.2. (NAND) (SUMMARY) © 2001-2006 Red Hat, Inc.
[ 6.137025] NET: Registered PF_ALG protocol family
[ 6.137043] xor: measuring software checksum speed
[ 6.141235] 8regs : 2363 MB/sec
[ 6.144760] 32regs : 2799 MB/sec
[ 6.149038] arm64_neon : 2307 MB/sec
[ 6.149048] xor: using function: 32regs (2799 MB/sec)
[ 6.149060] Key type asymmetric registered
[ 6.149070] Asymmetric key parser 'x509' registered
[ 6.149128] Block layer SCSI generic (bsg) driver version 0.4 loaded (major 244)
[ 6.149143] io scheduler mq-deadline registered
[ 6.149154] io scheduler kyber registered
[ 6.178215] Serial: 8250/16550 driver, 4 ports, IRQ sharing disabled
[ 6.179540] Serial: AMBA driver
[ 6.180377] cacheinfo: Unable to detect cache hierarchy for CPU 0
[ 6.185394] brd: module loaded
[ 6.189002] loop: module loaded
[ 6.189985] mtdoops: mtd device (mtddev=name/number) must be supplied
[ 6.193139] tun: Universal TUN/TAP device driver, 1.6
[ 6.193235] CAN device driver interface
[ 6.193884] usbcore: registered new interface driver asix
[ 6.193950] usbcore: registered new interface driver ax88179_178a
[ 6.193980] usbcore: registered new interface driver cdc_ether
[ 6.194012] usbcore: registered new interface driver net1080
[ 6.194046] usbcore: registered new interface driver cdc_subset
[ 6.194076] usbcore: registered new interface driver zaurus
[ 6.194119] usbcore: registered new interface driver cdc_ncm
[ 6.194883] usbcore: registered new interface driver uas
[ 6.194926] usbcore: registered new interface driver usb-storage
[ 6.195724] rtc_zynqmp ffa60000.rtc: registered as rtc0
[ 6.195751] rtc_zynqmp ffa60000.rtc: setting system clock to 1970-01-01T00:00:11 UTC (11)
[ 6.195822] i2c_dev: i2c /dev entries driver
[ 6.197547] usbcore: registered new interface driver uvcvideo
[ 6.198003] Bluetooth: HCI UART driver ver 2.3
[ 6.198016] Bluetooth: HCI UART protocol H4 registered
[ 6.198026] Bluetooth: HCI UART protocol BCSP registered
[ 6.198052] Bluetooth: HCI UART protocol LL registered
[ 6.198062] Bluetooth: HCI UART protocol ATH3K registered
[ 6.198084] Bluetooth: HCI UART protocol Three-wire (H5) registered
[ 6.198130] Bluetooth: HCI UART protocol Intel registered
[ 6.198154] Bluetooth: HCI UART protocol QCA registered
[ 6.198188] usbcore: registered new interface driver bcm203x
[ 6.198221] usbcore: registered new interface driver bpa10x
[ 6.198256] usbcore: registered new interface driver bfusb
[ 6.198291] usbcore: registered new interface driver btusb
[ 6.198340] usbcore: registered new interface driver ath3k
[ 6.198434] EDAC MC: ECC not enabled
[ 6.198589] EDAC DEVICE0: Giving out device to module edac controller cache_err: DEV edac (POLLED)
[ 6.198765] EDAC DEVICE1: Giving out device to module zynqmp-ocm-edac controller zynqmp_ocm: DEV ff960000.memory-controller (INTERRUPT)
[ 6.199251] sdhci: Secure Digital Host Controller Interface driver
[ 6.199262] sdhci: Copyright(c) Pierre Ossman
[ 6.199270] sdhci-pltfm: SDHCI platform and OF driver helper
[ 6.199567] ledtrig-cpu: registered to indicate activity on CPUs
[ 6.199700] SMCCC: SOC_ID: ARCH_SOC_ID not implemented, skipping ....
[ 6.199786] zynqmp_firmware_probe Platform Management API v1.1
[ 6.199801] zynqmp_firmware_probe Trustzone version v1.0
[ 6.228028] securefw securefw: securefw probed
[ 6.228143] zynqmp_aes firmware:zynqmp-firmware:zynqmp-aes: The zynqmp-aes driver shall be deprecated in 2022.2 and removed in 2023.1
[ 6.228441] alg: No test for xilinx-zynqmp-aes (zynqmp-aes)
[ 6.228473] zynqmp_aes firmware:zynqmp-firmware:zynqmp-aes: AES Successfully Registered
[ 6.228604] zynqmp-keccak-384 firmware:zynqmp-firmware:sha384: The zynqmp-sha-deprecated driver shall be deprecated in 2022.2 and removed in 2023.1 release
[ 6.228704] alg: No test for xilinx-keccak-384 (zynqmp-keccak-384)
[ 6.228904] alg: No test for xilinx-zynqmp-rsa (zynqmp-rsa)
[ 6.229124] usbcore: registered new interface driver usbhid
[ 6.229136] usbhid: USB HID core driver
[ 6.232367] ARM CCI_400_r1 PMU driver probed
[ 6.233025] fpga_manager fpga0: Xilinx ZynqMP FPGA Manager registered
[ 6.233486] usbcore: registered new interface driver snd-usb-audio
[ 6.234326] pktgen: Packet Generator for packet performance testing. Version: 2.75
[ 6.234910] Initializing XFRM netlink socket
[ 6.235006] NET: Registered PF_INET6 protocol family
[ 6.235635] Segment Routing with IPv6
[ 6.235660] In-situ OAM (IOAM) with IPv6
[ 6.235749] sit: IPv6, IPv4 and MPLS over IPv4 tunneling driver
[ 6.236153] NET: Registered PF_PACKET protocol family
[ 6.236176] NET: Registered PF_KEY protocol family
[ 6.236202] can: controller area network core
[ 6.236246] NET: Registered PF_CAN protocol family
[ 6.236257] can: raw protocol
[ 6.236268] can: broadcast manager protocol
[ 6.236280] can: netlink gateway - max_hops=1
[ 6.236384] Bluetooth: RFCOMM TTY layer initialized
[ 6.236401] Bluetooth: RFCOMM socket layer initialized
[ 6.236431] Bluetooth: RFCOMM ver 1.11
[ 6.236446] Bluetooth: BNEP (Ethernet Emulation) ver 1.3
[ 6.236456] Bluetooth: BNEP filters: protocol multicast
[ 6.236469] Bluetooth: BNEP socket layer initialized
[ 6.236478] Bluetooth: HIDP (Human Interface Emulation) ver 1.2
[ 6.236491] Bluetooth: HIDP socket layer initialized
[ 6.236535] 8021q: 802.1Q VLAN Support v1.8
[ 6.236659] 9pnet: Installing 9P2000 support
[ 6.236696] Key type dns_resolver registered
[ 6.236826] registered taskstats version 1
[ 6.236837] Loading compiled-in X.509 certificates
[ 6.238323] Btrfs loaded, crc32c=crc32c-generic, zoned=no, fsverity=no
[ 6.249544] ff000000.serial: ttyPS0 at MMIO 0xff000000 (irq = 59, base_baud = 6249999) is a xuartps
[ 7.585577] printk: console [ttyPS0] enabled
[ 7.590315] of-fpga-region fpga-full: FPGA Region probed
[ 7.597630] xilinx-zynqmp-dma fd500000.dma-controller: ZynqMP DMA driver Probe success
[ 7.605735] xilinx-zynqmp-dma fd510000.dma-controller: ZynqMP DMA driver Probe success
[ 7.613837] xilinx-zynqmp-dma fd520000.dma-controller: ZynqMP DMA driver Probe success
[ 7.621943] xilinx-zynqmp-dma fd530000.dma-controller: ZynqMP DMA driver Probe success
[ 7.630051] xilinx-zynqmp-dma fd540000.dma-controller: ZynqMP DMA driver Probe success
[ 7.638164] xilinx-zynqmp-dma fd550000.dma-controller: ZynqMP DMA driver Probe success
[ 7.646264] xilinx-zynqmp-dma fd560000.dma-controller: ZynqMP DMA driver Probe success
[ 7.654365] xilinx-zynqmp-dma fd570000.dma-controller: ZynqMP DMA driver Probe success
[ 7.662539] xilinx-zynqmp-dma ffa80000.dma-controller: ZynqMP DMA driver Probe success
[ 7.670638] xilinx-zynqmp-dma ffa90000.dma-controller: ZynqMP DMA driver Probe success
[ 7.678735] xilinx-zynqmp-dma ffaa0000.dma-controller: ZynqMP DMA driver Probe success
[ 7.686835] xilinx-zynqmp-dma ffab0000.dma-controller: ZynqMP DMA driver Probe success
[ 7.694948] xilinx-zynqmp-dma ffac0000.dma-controller: ZynqMP DMA driver Probe success
[ 7.703048] xilinx-zynqmp-dma ffad0000.dma-controller: ZynqMP DMA driver Probe success
[ 7.711150] xilinx-zynqmp-dma ffae0000.dma-controller: ZynqMP DMA driver Probe success
[ 7.719257] xilinx-zynqmp-dma ffaf0000.dma-controller: ZynqMP DMA driver Probe success
[ 7.727977] zynqmp-qspi ff0f0000.spi: rx bus width not found
[ 7.733641] zynqmp-qspi ff0f0000.spi: tx bus width not found
[ 7.739408] spi_master spi0: cannot find modalias for /axi/spi@ff0f0000/flash@0
[ 7.746729] spi_master spi0: Failed to create SPI device for /axi/spi@ff0f0000/flash@0
[ 7.755005] macb ff0d0000.ethernet: Not enabling partial store and forward
[ 7.767977] macb ff0d0000.ethernet eth0: Cadence GEM rev 0x50070106 at 0xff0d0000 irq 37 (aa:f8:2c:57:0c:03)
[ 7.778354] zynqmp_pll_disable() clock disable failed for apll_int, ret = -13
[ 7.785647] xilinx-axipmon ffa00000.perf-monitor: Probed Xilinx APM
[ 7.792231] xilinx-axipmon fd0b0000.perf-monitor: Probed Xilinx APM
[ 7.798739] xilinx-axipmon fd490000.perf-monitor: Probed Xilinx APM
[ 7.805279] xilinx-axipmon ffa10000.perf-monitor: Probed Xilinx APM
[ 7.814272] cdns-i2c ff030000.i2c: 400 kHz mmio ff030000 irq 39
[ 7.820647] cdns-wdt fd4d0000.watchdog: Xilinx Watchdog Timer with timeout 60s
[ 7.828126] cdns-wdt ff150000.watchdog: Xilinx Watchdog Timer with timeout 10s
[ 7.839660] of_cfs_init
[ 7.842186] of_cfs_init: OK
[ 7.846261] ALSA device list:
[ 7.849226] No soundcards found.
[ 7.869485] mmc0: SDHCI controller on ff170000.mmc [ff170000.mmc] using ADMA 64-bit
[ 7.878260] Freeing unused kernel memory: 2176K
[ 7.883100] Run /init as init process
[ 7.900455] systemd[1]: System time before build time, advancing clock.
[ 7.911456] systemd[1]: systemd 249.7+ running in system mode (+PAM -AUDIT -SELINUX -APPARMOR +IMA -SMACK +SECCOMP -GCRYPT -GNUTLS -OPENSSL +ACL +BLKID -CURL -ELFUTILS -FIDO2 -IDN2 -IDN -IPTC +KMOD -LIBCRYPTSETUP +LIBFDISK -PCRE2 -PWQUALITY -P11KIT -QRENCODE -BZIP2 -LZ4 -XZ -ZLIB +ZSTD +XKBCOMMON +UTMP +SYSVINIT default-hierarchy=hybrid)
[ 7.941801] systemd[1]: Detected architecture arm64.
[ 7.952839] mmc0: Problem switching card into high-speed mode!
[ 7.961308] mmc0: new SDHC card at address 0001
Welcome to PetaLinux 2022.2_update1_04022314 (honister)[ 7.966557] mmcblk0: mmc0:0001 SPCC 29.0 GiB
!
[ 7.976923] systemd[1]: Hostname set to <zub1cgi4filterspeta>.
[ 7.982986] random: systemd: uninitialized urandom read (16 bytes read)
[ 7.990275] systemd[1]: Initializing machine ID from random generator.
[ 7.996879] mmcblk0: p1 p2
[ 8.056096] systemd-sysv-generator[217]: SysV service '/etc/init.d/watchdog-init' lacks a native systemd unit file. Automatically generating a unit file for compatibility. Please update package to include a native systemd unit file, in order to make it more safe and robust.
[ 8.083557] systemd-sysv-generator[217]: SysV service '/etc/init.d/nfsserver' lacks a native systemd unit file. Automatically generating a unit file for compatibility. Please update package to include a native systemd unit file, in order to make it more safe and robust.
[ 8.107617] systemd-sysv-generator[217]: SysV service '/etc/init.d/nfscommon' lacks a native systemd unit file. Automatically generating a unit file for compatibility. Please update package to include a native systemd unit file, in order to make it more safe and robust.
[ 8.131944] systemd-sysv-generator[217]: SysV service '/etc/init.d/inetd.busybox' lacks a native systemd unit file. Automatically generating a unit file for compatibility. Please update package to include a native systemd unit file, in order to make it more safe and robust.
[ 8.157054] systemd-sysv-generator[217]: SysV service '/etc/init.d/dropbear' lacks a native systemd unit file. Automatically generating a unit file for compatibility. Please update package to include a native systemd unit file, in order to make it more safe and robust.
[ 8.381723] systemd[1]: Queued start job for default target Graphical Interface.
[ 8.390287] random: systemd: uninitialized urandom read (16 bytes read)
[ 8.419745] systemd[1]: Created slice Slice /system/getty.
[ OK ] Created slice Slice /system/getty.
[ 8.441261] random: systemd: uninitialized urandom read (16 bytes read)
[ 8.449378] systemd[1]: Created slice Slice /system/modprobe.
[ OK ] Created slice Slice /system/modprobe.
[ 8.470455] systemd[1]: Created slice Slice /system/serial-getty.
[ OK ] Created slice Slice /system/serial-getty.
[ 8.494282] systemd[1]: Created slice User and Session Slice.
[ OK ] Created slice User and Session Slice.
[ 8.517401] systemd[1]: Started Dispatch Password Requests to Console Directory Watch.
[ OK ] Started Dispatch Password …ts to Console Directory Watch.
[ 8.541301] systemd[1]: Started Forward Password Requests to Wall Directory Watch.
[ OK ] Started Forward Password R…uests to Wall Directory Watch.
[ 8.565358] systemd[1]: Reached target Path Units.
[ OK ] Reached target Path Units.
[ 8.581196] systemd[1]: Reached target Remote File Systems.
[ OK ] Reached target Remote File Systems.
[ 8.601191] systemd[1]: Reached target Slice Units.
[ OK ] Reached target Slice Units.
[ 8.617203] systemd[1]: Reached target Swaps.
[ OK ] Reached target Swaps.
[ 8.633749] systemd[1]: Listening on RPCbind Server Activation Socket.
[ OK ] Listening on RPCbind Server Activation Socket.
[ 8.657185] systemd[1]: Reached target RPC Port Mapper.
[ OK ] Reached target RPC Port Mapper.
[ 8.677463] systemd[1]: Listening on Syslog Socket.
[ OK ] Listening on Syslog Socket.
[ 8.693367] systemd[1]: Listening on initctl Compatibility Named Pipe.
[ OK ] Listening on initctl Compatibility Named Pipe.
[ 8.717709] systemd[1]: Listening on Journal Audit Socket.
[ OK ] Listening on Journal Audit Socket.
[ 8.737407] systemd[1]: Listening on Journal Socket (/dev/log).
[ OK ] Listening on Journal Socket (/dev/log).
[ 8.761491] systemd[1]: Listening on Journal Socket.
[ OK ] Listening on Journal Socket.
[ 8.777641] systemd[1]: Listening on Network Service Netlink Socket.
[ OK ] Listening on Network Service Netlink Socket.
[ 8.801485] systemd[1]: Listening on udev Control Socket.
[ OK ] Listening on udev Control Socket.
[ 8.821392] systemd[1]: Listening on udev Kernel Socket.
[ OK ] Listening on udev Kernel Socket.
[ 8.841420] systemd[1]: Listening on User Database Manager Socket.
[ OK ] Listening on User Database Manager Socket.
[ 8.868215] systemd[1]: Mounting Huge Pages File System...
Mounting Huge Pages File System...
[ 8.888500] systemd[1]: Mounting POSIX Message Queue File System...
Mounting POSIX Message Queue File System...
[ 8.912583] systemd[1]: Mounting Kernel Debug File System...
Mounting Kernel Debug File System...
[ 8.929603] systemd[1]: Condition check resulted in Kernel Trace File System being skipped.
[ 8.941495] systemd[1]: Mounting Temporary Directory /tmp...
Mounting Temporary Directory /tmp...
[ 8.957564] systemd[1]: Condition check resulted in Create List of Static Device Nodes being skipped.
[ 8.970602] systemd[1]: Starting Load Kernel Module configfs...
Starting Load Kernel Module configfs...
[ 8.993269] systemd[1]: Starting Load Kernel Module drm...
Starting Load Kernel Module drm...
[ 9.012835] systemd[1]: Starting Load Kernel Module fuse...
Starting Load Kernel Module fuse...
[ 9.032899] systemd[1]: Starting RPC Bind...
Starting RPC Bind...
[ 9.049367] systemd[1]: Condition check resulted in File System Check on Root Device being skipped.
[ 9.059226] systemd[1]: Condition check resulted in Load Kernel Modules being skipped.
[ 9.070200] systemd[1]: Mounting NFSD configuration filesystem...
Mounting NFSD configuration filesystem...
[ 9.088793] systemd[1]: Starting Remount Root and Kernel File Systems...
Starting Remount Root and Kernel File Systems...
[ 9.117007] systemd[1]: Starting Apply Kernel Variables...
Starting Apply Kernel Variables...
[ 9.136921] systemd[1]: Starting Coldplug All udev Devices...
Starting Coldplug All udev Devices...
[ 9.158380] systemd[1]: Started RPC Bind.
[ OK ] Started RPC Bind.
[ 9.173929] systemd[1]: Mounted Huge Pages File System.
[ OK ] Mounted Huge Pages File System.
[ 9.197913] systemd[1]: Mounted POSIX Message Queue File System.
[ OK ] Mounted POSIX Message Queue File System.
[ 9.225913] systemd[1]: Mounted Kernel Debug File System.
[ OK ] Mounted Kernel Debug File System.
[ 9.254010] systemd[1]: Mounted Temporary Directory /tmp.
[ OK ] Mounted Temporary Directory /tmp.
[ 9.278498] systemd[1]: modprobe@configfs.service: Deactivated successfully.
[ 9.287039] systemd[1]: Finished Load Kernel Module configfs.
[ OK ] Finished Load Kernel Module configfs.
[ 9.309983] systemd[1]: modprobe@drm.service: Deactivated successfully.
[ 9.317828] systemd[1]: Finished Load Kernel Module drm.
[ OK ] Finished Load Kernel Module drm.
[ 9.337899] systemd[1]: modprobe@fuse.service: Deactivated successfully.
[ 9.345816] systemd[1]: Finished Load Kernel Module fuse.
[ OK ] Finished Load Kernel Module fuse.
[ 9.369526] systemd[1]: proc-fs-nfsd.mount: Mount process exited, code=exited, status=32/n/a
[ 9.377991] systemd[1]: proc-fs-nfsd.mount: Failed with result 'exit-code'.
[ 9.386381] systemd[1]: Failed to mount NFSD configuration filesystem.
[FAILED] Failed to mount NFSD configuration filesystem.
See 'systemctl status proc-fs-nfsd.mount' for details.
[ 9.421132] systemd[1]: Dependency failed for NFS server and services.
[DEPEND] Dependency failed for NFS server and services.
[ 9.445149] systemd[1]: Dependency failed for NFS Mount Daemon.
[DEPEND] Dependency failed for NFS Mount Daemon.
[ 9.465131] systemd[1]: nfs-mountd.service: Job nfs-mountd.service/start failed with result 'dependency'.
[ 9.474740] systemd[1]: nfs-server.service: Job nfs-server.service/start failed with result 'dependency'.
[ 9.486055] systemd[1]: Finished Remount Root and Kernel File Systems.
[ OK ] Finished Remount Root and Kernel File Systems.
[ 9.510800] systemd[1]: Finished Apply Kernel Variables.
[ OK ] Finished Apply Kernel Variables.
[ 9.536707] systemd[1]: Condition check resulted in FUSE Control File System being skipped.
[ 9.548695] systemd[1]: Mounting Kernel Configuration File System...
Mounting Kernel Configuration File System...
[ 9.577816] systemd[1]: Condition check resulted in Rebuild Hardware Database being skipped.
[ 9.586596] systemd[1]: Condition check resulted in Platform Persistent Storage Archival being skipped.
[ 9.600088] systemd[1]: Starting Create System Users...
Starting Create System Users...
[ 9.621795] systemd[1]: Mounted Kernel Configuration File System.
[ OK ] Mounted Kernel Configuration File System.
[ 9.655677] systemd[1]: Finished Create System Users.
[ OK ] Finished Create System Users.
[ 9.681711] systemd[1]: Starting Create Static Device Nodes in /dev...
Starting Create Static Device Nodes in /dev...
[ 9.712112] systemd[1]: Finished Create Static Device Nodes in /dev.
[ OK ] Finished Create Static Device Nodes in /dev.
[ 9.733771] systemd[1]: Reached target Preparation for Local File Systems.
[ OK ] Reached target Preparation for Local File Systems.
[ 9.764949] systemd[1]: Mounting /var/volatile...
Mounting /var/volatile...
[ 9.785912] systemd[1]: Started Entropy Daemon based on the HAVEGE algorithm.
[ OK ] Started Entropy Daemon based on the HAVEGE algorithm.
[ 9.814289] systemd[1]: systemd-journald.service: unit configures an IP firewall, but the local system does not support BPF/cgroup firewalling.
[ 9.841192] systemd[1]: (This warning is only shown for the first unit using IP firewalling.)
[ 9.861766] systemd[1]: Starting Journal Service...
Starting Journal Service...
[ 9.890224] systemd[1]: Starting Rule-based Manager for Device Events and Files...
Starting Rule-based Manage…for Device Events and Files...
[ 9.925454] systemd[1]: Finished Coldplug All udev Devices.
[ OK ] Finished Coldplug All udev Devices.
[ 9.950013] systemd[1]: Mounted /var/volatile.
[ OK ] Mounted /var/volatile.
[ 9.965729] systemd[1]: Condition check resulted in Bind mount volatile /var/cache being skipped.
[ 9.981239] systemd[1]: Condition check resulted in Bind mount volatile /var/lib being skipped.
[ 10.005771] systemd[1]: Starting Load/Save Random Seed...
Starting Load/Save Random Seed...
[ 10.037477] systemd[1]: Condition check resulted in Bind mount volatile /var/spool being skipped.
[ 10.054190] systemd[1]: Condition check resulted in Bind mount volatile /srv being skipped.
[ 10.077468] systemd[1]: Reached target Local File Systems.
[ OK ] Reached target Local File Systems.
[ 10.137487] systemd[1]: Starting Rebuild Dynamic Linker Cache...
Starting Rebuild Dynamic Linker Cache...
[ 10.166829] systemd[1]: Started Rule-based Manager for Device Events and Files.
[ OK ] Started Rule-based Manager for Device Events and Files.
[ 10.194282] systemd[1]: Started Journal Service.
[ OK ] Started Journal Service.
Starting Flush Journal to Persistent Storage...
Starting Network Configuration...
[ 10.298514] systemd-journald[245]: Received client request to flush runtime journal.
[ OK ] Finished Rebuild Dynamic Linker Cache.
[ OK ] Finished Flush Journal to Persistent Storage.
Starting Create Volatile Files and Directories...
[ OK ] Finished Create Volatile Files and Directories.
Starting Run pending postinsts...
Starting Rebuild Journal Catalog...
Starting Network Time Synchronization...
Starting Record System Boot/Shutdown in UTMP...
[ 11.062558] random: fast init done
[ OK ] Finished Rebuild Journal Catalog.
[ OK ] Finished Record System Boot/Shutdown in UTMP.
[ OK ] Reached target Hardware activated USB gadget.
Starting Update is Completed...
[ 11.286242] update-alternatives: Linking /usr/lib/libMali.so.9.0 to /usr/lib/x11/libMali.so.9.0
[ OK ] Finished Update is Completed.
[ OK ] Started Network Configuration.
[ 11.771453] macb ff0d0000.ethernet eth0: PHY [ff0d0000.ethernet-ffffffff:07] driver [Microchip KSZ9131 Gigabit PHY] (irq=POLL)
[ 11.783012] macb ff0d0000.ethernet eth0: configuring for phy/rgmii-id link mode
[ 11.800307] update-alternatives: Linking /usr/lib/libMali.so.9.0 to /usr/lib/x11/libMali.so.9.0
Starting Network Name Resolution...
[ OK ] Listening on Load/Save RF …itch Status /dev/rfkill Watch.
[ 11.933919] pps pps0: new PPS source ptp0
[ 11.965025] macb ff0d0000.ethernet: gem-ptp-timer ptp clock registered.
[ 12.007617] Warn: update-alternatives: libmali-xlnx has multiple providers with the same priority, please check /usr/lib/opkg/alternatives/libmali-xlnx for details
[ 12.207522] update-alternatives: Linking /usr/lib/libMali.so.9.0 to /usr/lib/x11/libMali.so.9.0
[ OK ] Created slice Slice /system/systemd-fsck.
Starting File System Check on /dev/mmcblk0p1...
[ OK ] Found device /dev/mmcblk0p2.
[ OK ] Finished File System Check on /dev/mmcblk0p1.
Mounting /run/media/mmcblk0p1...
Starting File System Check on /dev/mmcblk0p2...
[ 12.706527] update-alternatives: Linking /usr/lib/libMali.so.9.0 to /usr/lib/x11/libMali.so.9.0
[ 12.809168] random: crng init done
[ 12.812598] random: 7 urandom warning(s) missed due to ratelimiting
[ OK ] Finished Load/Save Random Seed.
[ OK ] Mounted /run/media/mmcblk0p1.
[ OK ] Finished File System Check on /dev/mmcblk0p2.
[ OK ] Started Network Time Synchronization.
[ OK ] Finished Run pending postinsts.
[ OK ] Started Network Name Resolution.
[ OK ] Reached target Network.
[ OK ] Reached target Host and Network Name Lookups.
[ OK ] Reached target System Initialization.
[ OK ] Started Daily Cleanup of Temporary Directories.
[ OK ] Reached target System Time Set.
[ OK ] Reached target Timer Units.
[ OK ] Listening on D-Bus System Message Bus Socket.
[ OK ] Listening on dropbear.socket.
[ OK ] Reached target Socket Units.
[ OK ] Reached target Basic System.
Mounting /run/media/mmcblk0p2...
[ OK ] Started Kernel Logging Service.
[ OK ] Started System Logging Service.
[ OK ] Started D-Bus System Message Bus.
[ OK ] Started NFS status monitor for NFSv2/3 locking..
Starting LSB: NFS support for both client and server...
Starting User Login Management...
Starting Permit User Sessions...
Starting Target Communication Framework agent...
[ OK ] Started Xserver startup without a display manager.
[ OK ] Started LSB: NFS support for both client and server.
[ 14.385380] EXT4-fs (mmcblk0p2): mounted filesystem with ordered data mode. Opts: (null). Quota mode: none.
[ OK ] Finished Permit User Sessions.
[ OK ] Mounted /run/media/mmcblk0p2.
[ OK ] Started Target Communication Framework agent.
[ OK ] Started Getty on tty1.
Starting inetd.busybox.service...
Starting LSB: Kernel NFS server support...
[ OK ] Started Serial Getty on ttyPS0.
[ OK ] Reached target Login Prompts.
[ OK ] Started inetd.busybox.service.
[FAILED] Failed to start LSB: Kernel NFS server support.
See 'systemctl status nfsserver.service' for details.
[ OK ] Started User Login Management.
[ OK ] Reached target Multi-User System.
[ OK ] Reached target Graphical Interface.
Starting Record Runlevel Change in UTMP...
[ OK ] Finished Record Runlevel Change in UTMP.
[ 14.977155] xhci-hcd xhci-hcd.1.auto: xHCI Host Controller
[ 14.982710] xhci-hcd xhci-hcd.1.auto: new USB bus registered, assigned bus number 1
[ 14.990565] xhci-hcd xhci-hcd.1.auto: hcc params 0x0238f625 hci version 0x100 quirks 0x0000000002010090
[ 15.000056] xhci-hcd xhci-hcd.1.auto: irq 63, io mem 0xfe300000
[ 15.006284] usb usb1: New USB device found, idVendor=1d6b, idProduct=0002, bcdDevice= 5.15
[ 15.014585] usb usb1: New USB device strings: Mfr=3, Product=2, SerialNumber=1
[ 15.021828] usb usb1: Product: xHCI Host Controller
[ 15.026714] usb usb1: Manufacturer: Linux 5.15.36-xilinx-v2022.2 xhci-hcd
[ 15.033500] usb usb1: SerialNumber: xhci-hcd.1.auto
[ 15.039013] hub 1-0:1.0: USB hub found
[ 15.042804] hub 1-0:1.0: 1 port detected
[ 15.047045] xhci-hcd xhci-hcd.1.auto: xHCI Host Controller
[ 15.052579] xhci-hcd xhci-hcd.1.auto: new USB bus registered, assigned bus number 2
[ 15.060291] xhci-hcd xhci-hcd.1.auto: Host supports USB 3.0 SuperSpeed
[ 15.066981] usb usb2: We don't know the algorithms for LPM for this host, disabling LPM.
[ 15.075294] usb usb2: New USB device found, idVendor=1d6b, idProduct=0003, bcdDevice= 5.15
[ 15.083574] usb usb2: New USB device strings: Mfr=3, Product=2, SerialNumber=1
[ 15.090800] usb usb2: Product: xHCI Host Controller
[ 15.095683] usb usb2: Manufacturer: Linux 5.15.36-xilinx-v2022.2 xhci-hcd
[ 15.102477] usb usb2: SerialNumber: xhci-hcd.1.auto
[ 15.107844] hub 2-0:1.0: USB hub found
[ 15.111637] hub 2-0:1.0: 1 port detected
PetaLinux 2022.2_update1_04022314 zub1cgi4filterspeta ttyPS0
zub1cgi4filterspeta login: [ 16.039529] macb ff0d0000.ethernet eth0: Link is Up - 1Gbps/Full - flow control off
[ 16.047274] IPv6: ADDRCONF(NETDEV_CHANGE): eth0: link becomes ready
日 | 月 | 火 | 水 | 木 | 金 | 土 |
---|---|---|---|---|---|---|
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 | 31 | - | - | - | - |