Arduino是一个比较好的平台,里面丰富的库,但是可惜没有在线调试功能。如果仅仅做教学和教育使用,Arduino的IDE环境是可以满足要求的。但是如果应用到项目中,没有在线调试功能显然是不可接受的。尝试在一个使用STM32F103的项目使用arduino平台,将如何进行调试进行了一下总结。目前看,还没有找到各方面都达到要求的环境,只能综合各个方案,根据问题选用。
即使Arduino没有没有在线调试功能,但是Arduino作为官方的环境,显然编译下载的兼容性是最好的。所以我们需要该环境做一下信息对比,以查找出在其他环境下的问题点。Arduino环境下,编译的时候会输出编译过程详细的命令行调用,这为我们脱离Arduino环境编译提供基础。 我使用的STM32芯片,我推荐使用stm32duino项目,将json文件地址添加到Preferences对话框的“Additional Boards Manager URLs”里面,Arduino会完成该STM32系列芯片的支持。该项目支持的板子和芯片及其丰富,基本上能ST官方的板子,都支持了。
在以前关于arduino的文章中(2019-02-27-stm32-arduino-f103),曾经使用过“Eclipse C++ IDE for Arduino”,但是这个项目已经不维护了,推荐使用“The Arduino Eclipse plugin named Sloeber V4”来替代,这个插件不依赖Arduino的IDE本身,其会下载自己的Arduino基本支持工具和库,安装比较费时间,安装完毕之后,还需要在“Arduino=>Preferences”对话框下,“Private hardware path”中添加额外的硬件支持库路径,一般是“C:\Users<User>\AppData\Local\Arduino15”,如果在Arduino下已经下载完毕,这里不需要重复下载。 依据插件的说明,在项目右键的“Properties”菜单下,在项目属性对话框中,在“Arduino”下,有硬件平台,板卡以及其他选项的设置,信息和Arduino环境很类似,正确选择即可,可惜这个方式编译STM32平台有问题,其调用的编译器是“/bin/arm-none-eabi-g++”,显然是不对的。其对于本身自带的基础板子,例如Arduino-DUE,是可以正确编译的,但可惜不是我们要的。由于我也没有AVR的在线调试器,也就没有测试AVR平台的在线调试。 虽然不能编译,但是代码跳转功能是没问题的,还不错。
既然插件编译有问题,那我们可以先脱离Arduino环境生成目标文件,再在eclipse中使用makefile项目来进行调试(期望可以提供调试和代码跳转),经过一番努力,终于搞定了的CMake文件,和Makefile文件,CMake文件有比较大的坑,如果将两大块,分别生成wrapper和cores库,会出现链接问题。CMake的缺省link调用也有问题,需要自己去手动指定link调用。这么一来,其实远远没有Makefile本身来得更方便。 然后用带有“GNU ARM eclipse”插件的eclipse环境,新建“GDB Hardware Debugging”目标来调试,就可以顺利调试了。gdbserver可以用“STM32CubeIDE”带的“ST-Link_gdbserver”。复制其一个tools下的小目录,就够了,总共也就2M多一点,找个项目附近的地方放就可以了。 似乎这还挺好,唯一遗憾是,没有代码跳转功能。
之后,无意中发现,VSCode+Arduino插件(均为微软出品),其实是更好的一个方案,该插件依赖Arduino环境本省,安装省事。代码跳转功能也好用强大,编译也顺利。可惜调试缺省用的是OpenOCD,而不是J-Link或者ST-Link,而我对OpenOCD不太熟悉,也不知道怎么设定去更换(README里面的相关设置项,似乎不管用)
这个是个不完全转载,仅仅转一下目录,值得广大嵌入式攻城狮去观摩一圈。
最有价值的,是里面有正确可以工作版本的文件提供下载,避免入手的时候,各种失败问题。
这个是个不完全转载,仅仅转一下目录,值得广大嵌入式攻城狮去观摩一圈。
今年开始接触更改产品的FPGA代码,感觉公司虽然搞了很多年了,但是FPGA这块缺乏一些“软件工程”上的概念导入。
如果对于Altera/Xilinx公司,如果做IP库,可能需要考虑各种编译器的兼容性,不能引入太多的“高级”语法,但是,对于一个公司而言,我认为代码的可维护性是放在第一位的,是在编译器兼容性之类之上的要求。
总体而言,VHDL提供了如下一些语法特性,用于简化代码:
例如对于KM1024i喷头控制,我们可以定义如下:
-- 喷头控制信号
type KM_HEAD_CTRL_TYPE is record
load : std_logic;
lat : std_logic;
gsclk : std_logic;
stb : std_logic;
plstm2 : std_logic;
plstm1 : std_logic;
end record;
type KM_HEADs_CTRL_TYPE is array (natural range <>) of KM_HEAD_CTRL_TYPE;
-- 喷头数据信号
type KM_HEAD_DATA_TYPE is record
sa : std_logic_vector(2 downto 0); -- sa(n)=sa_n,
dclk : std_logic;
end record;
type KM_HEADs_DATA_TYPE is array (natural range <>) of KM_HEAD_DATA_TYPE;
有了上面的定义之后,接口可以为如下的方式:
entity KM1024i_8head_v1 is
port (
......
hd_data : out KM_HEADs_DATA_TYPE(0 to MAX_HEAD_NUM*CHNL_PER_HEAD-1);
hd_ctrl : out KM_HEADs_CTRL_TYPE(0 to MAX_HEAD_NUM*CHNL_PER_HEAD-1);
......
);
end KM1024i_8head_v1;
接口简化了很多,原先的接口,非常长的一堆信号列表。
我们的FPGA主要在喷头控制上,典型特点就是一块板子上,驱动很多的喷头,典型的是4H和8H,但是甚至有16H的,原先的代码人肉重复,但是在引入generate语句之后,可以大幅度减少代码,甚至可以不同喷头数的板子,代码仅仅需要改几行即可。
PRINT_HEAD_GEN : for i in 0 to 7 generate
HEAD_OPR : opr_setting
port map (
sys_clk => sys_clk,
sys_rst => sys_rst,
reg => opr_hd(i),
ctrl => opr_op(i),
cmd_trig => opr_trig(i),
pon_trig => pon_trig
);
HEAD_CTRL : head_controller
port map (
sys_clk => sys_clk,
sys_rst => sys_rst,
head => i_hd_ctrl(i),
f_fire => f_fire,
gs_level => gs_level_hd(i),
fire_dis => fire_dis_any,
fire_skip => data_crc_err and fire_dis_on_err,
grp_select => grp_select_hd(i),
grp_seg_num => grp_seg_num_hd(i),
grp_seg_desc=> grp_seg_desc_hd(i)
);
end generate;
Verilog语言没有类似于于VHDL的record的定义,也没有C语言的struct。但是,SystemVerilog是支持这些的,所以我们把标准切到SystemVerilog,以支持这些语法特性。以下以Max5183芯片驱动为例:
// DAC MAX5183 的控制信号
typedef struct {
logic clk;
logic cs_n;
logic [9:0] data;
logic pwr_down;
logic ref_en_n;
logic da_en;
} max5183_t;
typedef enum logic[1:0] { ST_OUT_D1, ST_LAT_D1, ST_OUT_D2, ST_LAT_D2 } da_state_t;
这是控制信号接口和状态机状态定义。
这个是Verilog支持的,和VHDL的generate类似,例如,某个板子里面用到了6个fifo,可以这样定义:
genvar gi;
generate for (gi = 0; gi < 6; gi = gi+1) begin: fifo_inst_lp
data_fifo data_fifo_inst (
.clock (sys_clk ),
.data (fifo_inst_data[gi] ),
.rdreq (fifo_inst_rd[gi] ),
.aclr (fifo_aclr[gi[0]] ),
.wrreq (fifo_inst_wr[gi] ),
.empty (fifo_inst_empty[gi] ),
.full (fifo_inst_full[gi] ),
.q (fifo_inst_q[gi] ));
end endgenerate
虽然说,FPGA代码和一般的软件代码,有截然不同的内涵,但是,毕竟“硬件”已经“软件”化了。引入软件工程的一些概念,对于增加FPGA代码的可维护性和开发效率,是非常有必要,非常有意义的。
重装服务器真是一个耗精力的过程,尤其是用ghost做数据全盘备份,数据ghost恢复蜗牛一般的速度,再加上ghost居然人生第一次碰到了软件会异常问题,真的是让人痛苦不堪啊。从现在想来,可能不如用imagex来备份数据,imagex至少可以直接mount,省了我不断的恢复过程啊。回想起来,选ghost唯一的理由,应该是:全盘备份,可以必要时候全盘恢复。不过,这个不是这里的重点。这里主要讲服务安装时候,自动化脚本构建。当然,使用构建脚本的方法,可能真的不如直接手动操作,但是,万一需要第二台或第二次再来一遍呢。当然,程序员对于人肉方法,也是倾向于不屑一顾的。
公司转向了事业部制,大概的公司结构如下: 基本SVN设计是,每个事业部有一个SVN库,下面设一级目录,HW/FPGA/FW/SW,分别授权不同的工程师访问。
用户归属于事业部,需要创建事业部组,事业部下根据研发性质,在细分成HW/FPGA/FW/SW用户组,创建用户用命令“net user”,从Excel生成命令脚本使用Excel的VBA生成,代码如下:
Sub CreateScript()
Dim row As Integer, i As Integer
Dim tsUsr As TextStream, tsSmtp As TextStream
Dim usr As String, grp As String, cmt As String
Dim outFolder As String
Set fso = CreateObject("Scripting.FileSystemObject")
outFolder = "D:\BYHX\Server\"
Set tsUsr = fso.OpenTextFile(outFolder & "0.servadmin.cmd", ForWriting, True)
Set tsSmtp = fso.OpenTextFile(outFolder & "0.sendmail.ps1", ForWriting, True)
' PowerShell,需要先执行以下的语句,才能执行ps1脚本
tsSmtp.WriteLine "# Execute below command first, then ps1 script will allowed."
tsSmtp.WriteLine "# Set-ExecutionPolicy -ExecutionPolicy Unrestricted -Scope CurrentUser"
' 创建事业部和大的用户性质用户组
For row = 2 To 18
grp = Range("L" & row)
If Left(grp, 2) <> "RD" Then grp = "BU-" & grp
tsUsr.WriteLine "net localgroup " & grp & " /add /comment:""" & Range("M" & row) & """"
Next row
' 创建事业部下研发分类用户组,以及列出同类研发事业部组列表
For row = 2 To 13
grp = Range("L" & row)
cmt = Range("M" & row)
If Left(grp, 2) <> "RD" Then grp = "BU-" & grp
tsUsr.WriteLine "net localgroup " & grp & "-HW /add /comment:""" & cmt & " 硬件"""
tsUsr.WriteLine "net localgroup " & grp & "-FPGA /add /comment:""" & cmt & " FPGA"""
tsUsr.WriteLine "net localgroup " & grp & "-FW /add /comment:""" & cmt & " 嵌入"""
tsUsr.WriteLine "net localgroup " & grp & "-SW /add /comment:""" & cmt & " 软件"""
Next row
For row = 2 To 1000
usr = Trim(Range("A" & row).Text)
grp = Trim(Range("D" & row).Text)
' 行的A列为空,表示处理结束
If usr = "" Then Exit For
' 非RD的,添加BU前缀
If Left(grp, 2) <> "RD" Then grp = "BU-" & grp
' 添加用户
tsUsr.WriteLine "net user " & usr & " """ & Range("B" & row) & """ /add /active:yes /expires:never /fullname:" & Range("C" & row)
' 用户密码永不过期
tsUsr.WriteLine "wmic useraccount where name='" & usr & "' set passwordexpires=false"
' 把用户添加到事业部
tsUsr.WriteLine "net localgroup " & grp & " " & usr & " /add"
' 根据研发内容,添加用户到事业部研发组
If Range("E" & row).Text = "Y" Then tsUsr.WriteLine "net localgroup " & grp & "-HW " & usr & " /add" & vbCrLf & "net localgroup RD-AllHW " & usr & " /add"
If Range("F" & row).Text = "Y" Then tsUsr.WriteLine "net localgroup " & grp & "-FPGA " & usr & " /add" & vbCrLf & "net localgroup RD-AllFPGA " & usr & " /add"
If Range("G" & row).Text = "Y" Then tsUsr.WriteLine "net localgroup " & grp & "-FW " & usr & " /add" & vbCrLf & "net localgroup RD-AllFW " & usr & " /add"
If Range("H" & row).Text = "Y" Then tsUsr.WriteLine "net localgroup " & grp & "-SW " & usr & " /add" & vbCrLf & "net localgroup RD-AllSW " & usr & " /add"
If Range("I" & row).Text = "Y" Then tsUsr.WriteLine "net localgroup BU-Leader " & usr & " /add"
Next row
tsUsr.Close
tsSmtp.Close
MsgBox "OK"
End Sub
安装完毕之后,建立一个Demo库,手动添加管理账号的读写访问权限,拷贝出账号认证配置文件,再准备好需要的svn的hook文件。 准备好事业部列表文件“1.svn-repo.txt”,每行只有事业部的名称(从Excel拷贝出来即可),用批处理命令,生成SVN库,以及离线SVN配置。
for /f %%i in (1.svn-repo.txt) do (
svnadmin create E:\Repositories\%%i
mkdir %%i\conf\
mkdir %%i\hooks\
copy /y VisualSVN-WinAuthz.ini %%i\conf\
copy /y pre-commit.cmd %%i\hooks\
)
用svn命令,管理账号,创建各个库的一级目录:
for /f %%i in (1.svn-repo.txt) do (
svn mkdir https://BYHX-MasterServ:8443/svn/%%i/hw -m "Create hardware folder"
svn mkdir https://BYHX-MasterServ:8443/svn/%%i/fpga -m "Create FPGA folder"
svn mkdir https://BYHX-MasterServ:8443/svn/%%i/fw -m "Create firmware folder"
svn mkdir https://BYHX-MasterServ:8443/svn/%%i/sw -m "Create software folder"
)
用类似的循环,用“PsGetsid”工具,获取用户的SID信息文件,单个SID信息类似于
SID for my-co-server\whom:
S-1-5-21-316025195-1075053894-3005689260-1012
利用shell脚本,处理SID信息(注意先转换“sidresult.txt”为unix格式)
cat sidresult.txt | egrep "SID\ for|S\-1" | sed -e 'N;s/\n//g' | sed -e 's/^.*\\//g' > sidlist.txt
处理完信息类似于:
whom:S-1-5-21-316025195-1075053894-3005689260-1012
有了SID信息表之后,用Excel的VBA,处理权限信息:
Function GetSID(sName As String)
Dim sidFile As TextStream
Dim outFolder As String
Dim str As String, s1 As String
Dim pos As Integer
outFolder = "D:\BYHX\Server\"
Set sidFile = fso.OpenTextFile(outFolder & "sidlist.txt", ForReading)
Do While Not sidFile.AtEndOfStream
str = sidFile.ReadLine
pos = InStr(str, ":")
s1 = Left(str, pos - 1)
If s1 = sName Then
GetSID = mid(str, pos + 1)
Exit Do
End If
Loop
End Function
Sub ModiPrivilege()
Dim row As Integer, i As Integer
Dim outFolder As String
Dim authFile As TextStream
Dim str As String, s1 As String
Dim usr As String, grp As String
Set fso = CreateObject("Scripting.FileSystemObject")
outFolder = "D:\BYHX\Server\"
' 给负责人添加库的完全权限
For row = 2 To 1000
usr = Trim(Range("A" & row).Text)
grp = Trim(Range("D" & row).Text)
' 行的A列为空,表示处理结束
If usr = "" Then Exit For
' 非RD的,添加BU前缀
If Left(grp, 2) <> "RD" Then grp = "BU-" & grp
If Range("I" & row).Text = "Y" Then
str = outFolder & grp & "\conf\VisualSVN-WinAuthz.ini"
Set authFile = fso.OpenTextFile(str, ForAppending)
authFile.WriteLine GetSID(usr) & "=rw"
authFile.Close
End If
Next row
' 事业部下研发分类用户组,设置权限
For row = 2 To 13
grp = Range("L" & row)
If Left(grp, 2) <> "RD" Then grp = "BU-" & grp
Set authFile = fso.OpenTextFile(outFolder & grp & "\conf\VisualSVN-WinAuthz.ini", ForAppending)
authFile.WriteLine vbCrLf & "[/hw]"
authFile.WriteLine GetSID(grp & "-HW") & "=rw"
authFile.WriteLine vbCrLf & "[/fpga]"
authFile.WriteLine GetSID(grp & "-FPGA") & "=rw"
authFile.WriteLine vbCrLf & "[/fw]"
authFile.WriteLine GetSID(grp & "-FW") & "=rw"
authFile.WriteLine vbCrLf & "[/sw]"
authFile.WriteLine GetSID(grp & "-SW") & "=rw"
authFile.Close
Next row
MsgBox "OK"
End Sub
将离线的SVN配置文件,复制到SVN库目录,重启SVN服务,SVN配置完成。
需要把各个账户的密码,通知到各位同仁。将Excel的用户名和密码这两列,复制到文本文件。转为unix格式。发送邮件脚本如下:
#!/usr/bin/bash
input="mailaccount.txt"
while IFS= read -r line
do
_usr=`echo -n $line | gawk '{printf "%s",$1}'`
_pwd=`echo -n $line | gawk '{printf "%s",$2}' | ./htmlenc.exe`
cat SwithMailSettings.xml | sed -e "s/__to_person__/$_usr/g" -e "s/__password__/$_pwd/g" > account.xml
./SwithMail.exe /s /x account.xml
done < "$input"
命令行邮件工具选择了“SwithMail”,依据的是7 Command Line Utilities to Easily Send Email Using SMTP的推荐。当然,用PowerShell也可以,就是比较麻烦一点点。
这里记一下开始入手OpenCV碰到的一些问题以及解决办法。学习参考书是《OpenCV 4 计算机视觉项目实战(原书第2版)》,ISBN:978-7-111-63164-4。
构建安装原书最主要的两个命令和测试命令是:
$ cmake -D CMAKE_BUILD_TYPE=RELEASE -D CMAKE_INSTALL_PREFIX=/full/path/to/opencv-4.0.0/build -D INSTALL_C_EXAMPLES=ON -D BUILD_EXAMPLES=ON -D OPEN_EXTRA_MODULES_PATH=/full/path/to/opencv_contrib-4.0.0/modules ..
$ cp /full/path/to/opencv-4.0.0/build/lib/pkgconfig/opencv.pc /usr/local/lib/pkgconfig/opencv4.pc
$ cd /full/path/to/opencv-4.0.0/samples/cpp
$ g++ -ggdb `pkg-config --cflags --libs opencv4` opencv_version.cpp -o /tmp/opencv_version && /tmp/opencv_version
这里面会碰到几个问题:
ippicv_2019_lnx_intel64_general_20180723.tgz
会被卡住这个不算是国内问题,是cmake缺省不支持https的问题。有关于这个问题的说明。我只做了
$ sudo apt-get install libcurl4-openssl-dev
cmake就应该可以成功了
似乎opencv认为pkg-config
包管理器已经落伍,所以缺省是不会生成该文件的。要生成该命令,需要修改cmake命令,打开产生opencv.pc的选项:
$ cmake ... -D OPENCV_GENERATE_PKGCONFIG=ON ..
这里面有几个错误,1) 需要c++11; 2) 连接找不到cv::CommandLineParser
类的一些函数,解决方法是:
$ export LD_LIBRARY_PATH=/full/path/to/opencv-4.0.0/build/lib
$ g++ -std=c++11 -ggdb opencv_version.cpp `pkg-config --cflags --libs opencv4` -o /tmp/opencv_version && /tmp/opencv_version
在编译第二章的示例程序的时候,会发现cmake会失败,需要把CMakeLists.txt的寻找opencv包命令这句修改为:
FIND_PACKAGE( OpenCV 4.1.2 REQUIRED PATHS /home/opencv/4.1.2 )