rt-thread 下,配置 stm32 的 adc

步骤

修改 board/Kconfig,添加 adc 相关部分,以下为参考

1
2
3
4
5
6
7
8
9
menuconfig BSP_USING_ADC
bool "enable ADC"
default n
select RT_USING_ADC
if BSP_USING_ADC
config BSP_USING_ADC1
bool "enable ADC1"
default n
endif

如果启用的 adc 不自带,需要手工修改

修改libraries/HAL_Drivers/config/f4/adc_config.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#ifdef BSP_USING_ADC1
#ifndef ADC1_CONFIG
#define ADC1_CONFIG \
{ \
.Instance = ADC1, \
.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4, \
.Init.Resolution = ADC_RESOLUTION_12B, \
.Init.DataAlign = ADC_DATAALIGN_RIGHT, \
.Init.ScanConvMode = DISABLE, \
.Init.EOCSelection = DISABLE, \
.Init.ContinuousConvMode = DISABLE, \
.Init.NbrOfConversion = 1, \
.Init.DiscontinuousConvMode = DISABLE, \
.Init.NbrOfDiscConversion = 0, \
.Init.ExternalTrigConv = ADC_SOFTWARE_START, \
.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE, \
.Init.DMAContinuousRequests = DISABLE, \
}
#endif
#endif
1
2
scons --menuconfig 启用 adc
stm32XXxx_hal_conf.h 需要启用 HAL_ADC_MODULE_ENABLED

stm32 对于 rt-thread 的 bsp 移植

参考链接

STM32 系列 BSP 制作教程

STM32 系列外设驱动添加指南

步骤

bsp 模板

复制 bsp/stm32/libraries/templates 下面复制你的型号的模板 到 bsp/stm32/下,改成你喜欢的名字

配置 gcc

rtconfig.py, 配置编译器

1
2
3
4
5
if CROSS_TOOL == "gcc":
PLATFORM = "gcc"
EXEC_PATH = (
os.getenv("HOME") + "/dev/embedded/rt-thread/gcc-arm-none-eabi-6_2-2016q4/bin/"
)
1
scons -c; scons --dist

生成 cubeMX 项目

创建跟你 mcu 一样的项目,修改配置,生成代码。

复制 Inc 和 Src 目录到 board/CubeMX_Config 下覆盖

从 board/CubeMX_Config 里面找到 main.c,复制 SystemClock_Config() 到 board/board.c 里面,这是唯一需要手工复制的函数,如果不复制,可能会出现烧录以后失去响应的问题

时钟配置

强烈建议看一下原理图,里面 mcu 相关的晶振部分的频率,在 cubeMX 的时钟部分的 HSE 和 LSE 的频率,一定要和原理图里面的一致

串口引脚配置

注意看原理图里面的串口引脚,是否有重新映射的引脚,不然无法通信

配置 Kconfig

修改 board/Kconfig,搜索 config SOC_STM32, 改为相应的芯片型号

如果需要 i2c 等配置,而当前的 Kconfig 里面没有的话,可以从别的 bsp 里面借鉴一下

flash 和 ram 大小相关

bsp_helper.py

注意真实的大小

mcu 具体的 flash 和 ram 大小,最好看一下芯片手册,比如 f407igt6 里面,有 64k 的内存是保留不能使用的

可以使用 segger 公司的 JFlashLiteExe 查看具体芯片的 flash 和 ram 大小, v6.86g 这个版本是最后一个能看内存大小的版本,推荐使用

SConscript

修改 board/SConscript, 看看芯片等信息有没有错误

搜索 CPPDEFINES, 改成你的芯片对应的型号,具体写法参考 CPPDEFINES 上面的内容里面改

根据你的芯片型号,修改下面对应的汇编启动文件 xxxxxx.s, 如果不知道用哪个,可以用 cubeMX 生成项目以后找,看用的是哪个文件

1
2
3
4
5
6
if rtconfig.CROSS_TOOL == 'gcc':
src += [startup_path_prefix + '/STM32F1xx_HAL/CMSIS/Device/ST/STM32F1xx/Source/Templates/gcc/startup_stm32f103xb.s']
elif rtconfig.CROSS_TOOL == 'keil':
src += [startup_path_prefix + '/STM32F1xx_HAL/CMSIS/Device/ST/STM32F1xx/Source/Templates/arm/startup_stm32f103xb.s']
elif rtconfig.CROSS_TOOL == 'iar':
src += [startup_path_prefix + '/STM32F1xx_HAL/CMSIS/Device/ST/STM32F1xx/Source/Templates/iar/startup_stm32f103xb.s']

freebsd 开机启动脚本

说明

启动顺序

1
2
3
4
5
# 自己的启动脚本,需要 chmod a+x
/usr/local/etc/rc.d/

# 最后加载
/etc/rc.local

分类

rc 格式

需要符合 rc 格式

1
chmod a+x /usr/local/etc/rc.d/*

格式如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#!/bin/sh
#
# PROVIDE: myapp
# REQUIRE: DAEMON
# KEYWORD: shutdown
#

# 加载预定义变量和函数
. /etc/rc.subr

name="myapp"
rcvar="myapp_enable"
command="/usr/local/bin/myapp"

# 用于重启
procname="/usr/local/bin/myapp"
desc="my custom service"

load_rc_config $name
# 如果变量未定义,则为 NO
: ${myapp_enable:="NO"}

# $1 为启动参数
run_rc_command "$1"

自定义脚本

1
chmod a+x /etc/rc.local

标准 shell 格式

1
2
3
4
5
6
7
8
9
10
#!/bin/sh -e

. /etc/profile

# nohup xxx > /dev/null 2>&1 &
# screen -dm xxx

/opt/demo/_build/prod/rel/demo/bin/demo daemon

exit 0

freebsd 开机启动配置文件

说明

里面有一些 xxx_enable 字段

都可以用类似如下的方式修改

1
sysrc -f /etc/rc.conf kld_list="i915kms"

加载顺序如下

1
2
3
4
5
6
/etc/rc.conf

# 自己的全局配置,覆盖默认
/etc/rc.conf.local
# 拆分出来的配置
/usr/local/etc/rc.conf.d/

这些字段在如下两个目录内的脚本内搜索

1
2
/etc/rc.d/
/usr/local/etc/rc.d/

zfs 用法

每 1tb 的储存空间对应 1gb 的 ram

概念

1
2
3
pool
虚拟设备
磁盘设备

添加硬盘

查看磁盘

1
sudo bsdconfig

pool

如果创建带虚拟设备的 pool,每个虚拟设备的子设备数量需要一致

说明

创建成功,会自动 mount,如果修改了 mountpoint,开机以后也会自动 mount

类型 说明
stripe 1 块即可, 类似 raid0
mirror 至少 2 块, 允许坏掉一个硬盘,类似 raid1
raid10 至少 4 块
raidz1 至少 2+1 块,允许坏掉一个硬盘,类似 raid5
raidz2 至少 2+2 块,允许坏掉两个硬盘,类似 raid6
raidz3 至少 2+3 块,允许坏掉三个硬盘,类似 raid7

查看 pool

1
2
zpool list
zpool status -v demo

创建 pool

创建没有 mirror 的 pool

1
zpool create -m /mount_demo demo nvd0 nvd1 nvd2

带两组 mirror 的 pool, mirror 即为虚拟设备

1
zpool create demo mirror nvd0 nvd1 mirror nvd2 nvd3

创建 raidz 的 pool

1
zpool create demo raidz1 nvd0 nvd1 nvd2

删除 pool

1
zpool destroy demo

虚拟设备

增加虚拟设备

1
zpool add demo raidz nvd3 nvd4 nvd5

删除虚拟设备

1
只有log device, cache device 和 mirror device 支持删除, raidz不支持删除

添加/删除磁盘

添加磁盘

支持 mirror 虚拟设备和非虚拟设备的 pool

1
2
zpool create demo nvd0
zpool attach demo nvd0 nvd1

删除磁盘

1
zpool detach demo nvd1

在线替换

在线替换,支持 raidz, 新盘内不需要放东西

1
zpool replace demo nvd3 nvd4

添加修改 mount 盘

1
2
3
sudo zpool add demo ada2
sudo zpool remove demo ada1
sudo zpool replace demo nvd3 nvd4

修改挂载点

1
2
3
4
5
zfs mount
zfs umount -f /mount_demo
mkdir -p /mount_demo1
zfs set mountpoint=/mount_demo1 demo
zfs mount

快照

1
2
3
4
zfs snapshot -r demo@2019-1-6
zfs list -t snapshot
zfs rollback -r demo@2019-1-6
zfs destroy demo@2019-1-6

备份恢复

到文件

1
zfs send demo@aaa > xxxx

本机

1
zfs send demo1@aaa | zfs recv demo2@bbb

远程

1
2
nc -w 120 -l 8023 | zfs receive -F demo2
zfs send demo1@aaa | nc -w 120 127.0.0.1 8023

freebsd 下 jail 用法

目前使用 qjail

安装

1
2
3
sudo pkg install -y qjail
axel -o /tmp/ http://mirrors.ustc.edu.cn/freebsd/releases/amd64/13.0-RELEASE/base.txz
sudo qjail install -f /tmp/base.txz

常规用法

创建

1
sudo qjail create -4 192.168.88.123 xxx
1
2
3
4
sudo qjail list
sudo qjail start xxx
sudo qjail console xxx
sudo qjail stop xxx

修改 ip

1
sudo qjail config -4 192.168.88.222 xxx

允许使用主机网络

1
sudo qjail config -k xxx

改名字

1
sudo qjail config -n demo xxx

备份恢复

1
2
3
sudo qjail archive xxx
sudo qjail delete xxx
sudo qjail restore xxx

文件复制

具体虚拟机路径

1
/usr/jails/xxx

模板路径

1
/usr/jails/template

任务管理

1
2
jls 查看任务列表
sudo jexec 1 csh

erlang 下 genserver 的 exit

本质和普通进程一样

总结

  • 内部 crash
  • 设置 trap_exit, 并且 gen_server 内部处理 {'EXIT', From , Reason} 消息
gen_server 退出原因 trap_exit terminate 备注
内部 crash true/false 执行 普通业务情况下,保证都能被捕获
exit(Pid,kill) true/false 不执行 kill 杀进程是 vm 的保留手段
exit(Pid,Reason) true 如果内部处理了{'EXIT', From , Reason}消息,则执行 转换为 handle_info 消息
exit(Pid,Reason) false 不执行 同普通 process 一样

演示代码

1
2
3
4
5
6
7
8
9
10
11
stop(Reason) ->
io:format("call bbb stop func ~p ~n", [Reason]),
gen_server:call(bbb, {stop, Reason}).

handle_call({stop, Reason}, _From, State) ->
io:format("on handle_call stop by ~p ~n", [Reason]),
{stop, Reason, ok, State};

handle_info({'EXIT', From , Reason}, State) ->
io:format("on handle_info 'EXIT' ~p ~p~n", [From, Reason]),
{stop, Reason, State};

erlang 的 trap_exit

说明

exit(Pid, Msg)

未设置 trap_exit

1
2
3
4
5
不给进程发 Exit 消息, 只执行默认的行为
normal 返回 true
shutdown 模式下,进程退出,返回 true
kill 模式下,进程退出,返回 true
其它模式下,进程退出,返回 true

设置 process_flag(trap_exit, true)

1
2
3
4
5
执行默认的行为的同时,给进程发 Exit 消息
normal 返回 true,发 {'EXIT', _From, normal} 消息, 进程是否退出,看消息处理部分
shutdown 返回 true,发 {'EXIT', _From, shutdown} 消息, 进程是否退出,看消息处理部分
其它模式下,返回 true, 发 {'EXIT', _From, _Msg} 消息, 进程是否退出,看消息处理部分
kill 模式下,返回 true, 不会收到消息,进程直接被系统杀死

演示代码

dist_proc.erl

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
-module(dist_proc).

-export([start/0]).
-export([init/0]).
-export([loop/0]).

start() ->
Pid = spawn(?MODULE,init,[]),
register(?MODULE, Pid),
{ok, Pid}.

init() ->
io:format("on ~p init ~n", [?MODULE]),
process_flag(trap_exit, true),
loop().

loop() ->
receive
{'EXIT', From, Reason} ->
io:format("~p got exit msg ~p ~p~n", [?MODULE, From, Reason]),
loop();
Msg ->
io:format("~p got other msg ~p~n", [?MODULE, Msg]),
loop()
end.

测试

1
2
3
4
5
6
7
8
9
10
11
12
dist_proc:start().

exit(whereis(dist_proc), normal).
exit(whereis(dist_proc), shutdown).
exit(whereis(dist_proc), xxx).
exit(whereis(dist_proc), kill).

whereis(dist_proc) ! {'EXIT', self(), normal}.
whereis(dist_proc) ! {'EXIT', self(), xxx}.
whereis(dist_proc) ! {'EXIT', self(), kill}.

whereis(dist_proc).

erlang 之进程监控 monitor

和 link 的区别,是单向的

演示代码

dist_proc.erl

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
-module(dist_proc).

-export([start/0]).
-export([init/0]).
-export([loop/0]).

start() ->
Pid = spawn(?MODULE,init,[]),
register(?MODULE, Pid),
{ok, Pid}.

init() ->
io:format("on ~p init ~n", [?MODULE]),
process_flag(trap_exit, true),
loop().

loop() ->
receive
{'EXIT', From, Reason} ->
io:format("~p got exit msg ~p ~p~n", [?MODULE, From, Reason]);
Msg ->
io:format("~p got other msg ~p~n", [?MODULE, Msg]),
loop()
end.

mon_proc.erl

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
-module(mon_proc).

-export([start/0]).
-export([init/0]).
-export([loop/0]).

start() ->
Pid = spawn(?MODULE,init,[]),
register(?MODULE, Pid),
{ok, Pid}.

init() ->
io:format("on ~p init ~n", [?MODULE]),
process_flag(trap_exit, true),
dist_proc:start(),
_Ref = erlang:monitor(process, dist_proc),
loop().

loop() ->
receive
{'DOWN', Ref, process, {Pid, Node}, Reason} ->
erlang:demonitor(Ref),
io:format("~p got pid down msg ~p ~p ~p ~n", [?MODULE, Pid, Node, Reason]),
loop();
{'EXIT', From, Reason} ->
io:format("~p got exit msg ~p ~p~n", [?MODULE, From, Reason]);
Msg ->
io:format("~p got other msg ~p~n", [?MODULE, Msg]),
loop()
end.

测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
spawn(fun() -> mon_proc:start() end).

exit(whereis(dist_proc), normal).
exit(whereis(dist_proc), shutdown).
exit(whereis(dist_proc), xxx).
exit(whereis(dist_proc), kill).

exit(whereis(mon_proc), shutdown).

whereis(dist_proc) ! {'EXIT', self(), normal}.
whereis(dist_proc) ! {'EXIT', self(), xxx}.
whereis(dist_proc) ! {'EXIT', self(), kill}.

whereis(dist_proc).
whereis(mon_proc).

erlang 的进程监控 link

说明

link 是双向的, 任何一个进程挂掉, 另外一个都会受影响

1
2
3
A 挂掉, B 会检查自己有没有设置 process_flag(trap_exit, true)
如果没有设置, 则也挂掉。
如果设置了, 则在消息循环里面检测 {'EXIT', _From, Msg} 消息, 就算 A 是被 kill 的, 在 B 这里也是收到消息, 不会直接挂掉

演示代码

dist_proc.erl

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
-module(dist_proc).

-export([start/0]).
-export([init/0]).
-export([loop/0]).

start() ->
Pid = spawn_link(?MODULE,init,[]),
register(?MODULE, Pid),
{ok, Pid}.

init() ->
io:format("on ~p init ~n", [?MODULE]),
process_flag(trap_exit, true),
loop().

loop() ->
receive
{'EXIT', From, Reason} ->
io:format("~p got exit msg ~p ~p~n", [?MODULE, From, Reason]),
loop();
Msg ->
io:format("~p got other msg ~p~n", [?MODULE, Msg]),
loop()
end.

mon_proc.erl

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
-module(mon_proc).

-export([start/0]).
-export([init/0]).
-export([loop/0]).

start() ->
Pid = spawn(?MODULE,init,[]),
register(?MODULE, Pid),
{ok, Pid}.

init() ->
io:format("on ~p init ~n", [?MODULE]),
process_flag(trap_exit, true),
dist_proc:start(),
loop().

loop() ->
receive
{'EXIT', From, Reason} ->
io:format("~p got exit msg ~p ~p~n", [?MODULE, From, Reason]),
loop();
Msg ->
io:format("~p got other msg ~p~n", [?MODULE, Msg]),
loop()
end.

测试

1
2
3
4
5
6
7
8
9
mon_proc:start().

exit(whereis(mon_proc), normal).
exit(whereis(mon_proc), shutdown).
exit(whereis(mon_proc), xxx).
exit(whereis(mon_proc), kill).

whereis(mon_proc).
whereis(dist_proc).