0%

网卡驱动安装

Macbook Air 2015年 13英寸版所使用的的网卡是 博通的 BCM94360CS2

可以从 关于本机 --> 系统报告 --> Wi-Fi 中查看到硬件固件版本。

image-20220128154108052

安装完Linux之后,暂时无法联网,需要使用有线网络进行上网,可以使用 iPhone 接 lighting-USBA 的转接线进行上网,然后使用 apt 命令下载安装 bcmwl-kernel-source

如果使用 pkgs.org 官网上下载的 bcmwl-kernel-source.dpkg 则会提示缺少很多依赖,无法直接一步安装到位。

image-20220128154312606

APFS 硬盘内容读取

https://github.com/sgan81/apfs-fuse/

REFERENCE

  1. 在linux访问macos下的分区

本博文并不提供全面的教学指导,详细手册请查阅 Git-Reference开发

Git 是一个开放源代码的版本控制系统,专用于处理分布在多个代码库上的大型项目。

Repo 是 google android 以 Git 为基础构建的代码库管理工具,依赖于 python2 脚本调用 Git,主要用来下载、管理android项目的软件仓库。

Repo 简化了跨多个代码库运行的流程,与 Git 相辅相成。Repo 可以在必要时 整合多个 Git 代码库,将相关内容上传到我们的修订版本控制系统,借助单个 Repo 命令,可以将文件从多个代码库下载到本地工作目录。使用 Repo 执行基本的跨网络操作可大大简化文件管理工作。

GIT

对git的使用会分为 基础概念部分(即相关概念介绍)、指令语法使用场景 三部分。

INTRODUCTION

DAG: Directed Acyclic Graph,有向无环图。

DVCS: Distributed Version Control System,分布式版本控制系统。

DVCS

节点:在DVCS中,每个节点代表项目的一个修订(一个版本),这些对象通常被称为提交。

有向边: 在DVCS中,每条边是基于两个修订之间的关系生成的。箭头是从父修订指向子修订的,代表他们之间的从属关系。 修订DAG中的箭头并不一定会形成闭环。通常修订的DAG是从左向右的结构(根节点在左,叶节点在右)或者自上而下结构(最新的版本在上面)。

BRANCH / TAG / REFS / HASH-CODE

分支(branch)和 标签 (tag)有时候也统称为 引用(refs),它们在修订 DAG 中的含义是样的,都是修订结构图表中的外部引用(指针)。

image-20220226205719300

上图中,包含两个分支,当前的分支 Master 和另一分支 maint 。其中 34ac2 分支有一个 v0.9 的标签,另一个 3fb00 标签是合并提交的。

标签(tag),即 给定版本的符号名称,如 v1.3-rc3其永远指向相同对象,且不会变更

这就是一个允许开发人员快速查询和浏览的信息,且该信息必须对所有人来说都是具有相同意义的。

分支(branch),即 一系列开发工作的符号名称

本地分支的引用信息都存放在 .git/refs/heads/ 路径下,如 master 分支信息存放于 .git/refs/heads/master 中,而 refs/heads/ 为该 master 的命名空间。

image-20220226211442066

目前Git在硬盘中采用了两种截然不同的方式来表示分支:松散格式压缩格式

例如master分支(该分支是Git采用的默认分支名,用户在创建新的版本库时默认的分支名就是它)。

  • 采用 松散格式 时,它是 .git/refs/heads/master 中的一行文本,其中指代分支的 内容是十六进制的SHA-1码
  • 采用 压缩格式 时,它是 .git/packed-refs 中的一行文本,使用 最顶部修订的SHA-1码分支全名一起 表示该分支。

Configuration

可以通过 git config --global user.email ""git config --global user.name "" 进行配置,相关信息存储在 ~/.gitconfig 文件中。

image-20220226203128964

Branch Name

分支 命名 说明
主分支 master 主分支,所有提供给用户使用的正式版本
开发分支 dev 开发分支,永远是功能最新最全的版本
功能分支 feature-* 新功能分支,某个功能点正在开发的分支
发布分支 release-* 发布定期要上线的功能
修复分支 bug-* 修复代码bug的分支

Master

代码库应该有且仅有一个主分支。所有提供给用户使用的正式版本,都在这个主分支上发布。Git主分支的名字,默认称为 MasterMaster 主分支是自动建立的,版本库初始化以后,默认就是在主分支在进行开发。

主分支只用来分布重大版本,日常开发应该在另一条分支上完成。我们把开发用的分支,叫做 Dev 这个分支可以用来生成代码的最新隔夜版本(nightly)。如果想正式对外发布,就在 Master 分支上,对 Dev 分支进行”合并”(merge)。

git 中的分支 本质上是个指向 commit 对象的可变指针。

而在每一个使用 git 的 .git/ 路径下,还保存着一个名为 HEAD 的特别指针,一般来说,它是指向正在工作中的本地分支的指针。

HEAD 的指向是可以改变的,比如在 commit / checkout / branch / tag / retest / restore 等操作之后。

有的时候 HEAD 会指向一个没有分支名字的修订版本,这种情况叫 detached HEAD

image-20220226203838866

在最底层实现中,Git 历史版本识别是通过一个 SHA-1 哈希码实现的,例如 2b953b4380

Git 支持多种形式的版本查询,其中就包括使用哈希码的精确匹配(最少提供4个字符)。

GIT COMMAND GRAMMER

  1. 使用 git <command> -h 可以获得该命令的所有参数用法帮助(简略的)。然后可以针对性地去搜索该指令和参数的用法。
  2. 下方会列出一些较为常见的(自己会使用得到的)命令及其参数。个别较常见的命令会贴上一张官方的参数用法图片。

git add

<file name>

使用本命令参数可以直接确认某个文件的变动记录。

git add readme.md 确认了 readme.md 文件的修改,git add . 确认了当前路径下包含的所有子路径和子文件的修改。

git blame

<file name>

本参数可以查看文件内部每一行内容的变动,例如新增一行,文件的编辑者等。

image-20220226202721363

git diff 不同的是,本命令是真的打开文件然后一行一行地给你修改和提示信息,包括每一行是谁写的

git branch

image-20220226213748945
1
2
git branch -D origin/xxxxxx
git branch -D xxxxxx

-a

使用本命令标志可以显示 本地 (local) 所有分支远程 (remote) 所有分支。 其中,带 * 的为当前所在分支。

image-20220226200020105

-d <branch name>

使用本命令标志可以删除 某个分支。

image-20220226211322680

-v

使用命令标志可以展示分支的哈希函数和commit信息,-v--verbose ,表示 "冗长的"。

例如: 下方,从 master 主分支刚创建出新分支 SWV 时,两者的哈希函数和commit信息是一样的。

image-20220226214736094

但修改了 SWV 分支的内容并确认提交之后,其哈希函数和commit信息就发生了改变。

image-20220226214912676

git checkout

image-20220226213843563

<branch>

单独使用此参数可以用于切换分支(也有新的实验性语句 switch 可以使用,但是 checkout 更稳定)或恢复工作树文件。使用方式如:

1
2
3
git checkout dev
git checkout origin/dev
git checkout xxxxxx

-b

使用本标志 + <new branch name> 可以创建一个新分支并切换至该分支,等同于 先使用 git branch <new branch name>git checkout <new branch name>

--orphan <branch name>

使用本命令标志可以创建一个与主分支没有联系的孤儿分支。

git commit

-a/-all

使用本标志指 接受被追踪文件的所有变更,可以在暂存区创建一个注释来实现操作隔离。

-m ""

本标志和参数可以支持在 "" 内实现对合并的快速注释。

git clone

使用本命令可以直接从某个库中拷贝某个路径下的 repository,如:

1
git clone git@git.islet.space:srv/led_blink.git

当然,拷贝不公开的repository时,需要确保已经将自己的 SSH-key 加入到该网站的 /home/git/.ssh/authorized_keys 文件中。公开的 repository 可以随便拷贝。

git diff

本命令可以简要地查看距离上次 commit 操作到底修改什么信息。

image-20220226202625977

git log

注意:所有的 git log 命令只会显示如下格式的 log 记录。

image-20220226202114879

-<num>

如输入 git log -2,可以查看当前项目最近两条的提交记录。

--author 或 --committer

本标志支持查看提交者信息,使用方法如:

1
git log --author=Linus

--merges 或 --no-merges

本标志支持查看已合并和提交或非合并提交的信息。

<path / file name>

本参数可以

git merge

默认情况下,Git执行 快进式合并(fast-forward merge),会直接将 Master 分支指向 Dev 分支。 使用 –no–ff 参数后,会执行正常合并,在 Master 分支上生成一个新节点。为了保证版本演进的清晰,我们希望采用这种做法。即:

1
git merge -no-ff dev

git pull

执行本命令后,Git系统会将服务器版本库中的变更下载到本机。自动将 remote 版本和 local 版本进行合并,然后把合并后的变更提交到本机 版本库中。

git push

--set-upstream

设置本地(新)分支的远程上游分支,一些在网上可以查找到的信息如下:

  • set upstream branches to work properly
  • closely associated with remote branches
  • define the branch tracked on the remote branches (also called as remote tracking branch)
  • --set-upstream is the same as -u

在本地创建的新分支如果希望在远程版本库中添加对应的上游分支,使用此命令和标志可以使得此分支推送至远程分支的目标更加明确。

1
git push --set-upstream origin better-random

git rebase

rebase是将自己的分支重新基于别人的分支之上,即,在别人的基础上再添加什么东西。

git reset

image-20220226223239807
1
git reset --hard HEAD^

git remote

本命令可以进行如下操作:

  1. 对远程repository进行 添加(add)、删除(remove)、重命名(rename)等操作。
image-20220226223823738

git status

直接使用本命令可以查看当前路径下所有文件的修改记录。

image-20220226223119337

GIT SITUATION

远程git clone一个master分支为空的仓库时

要么整个仓库都为空,要么肯定还有分支,使用 git branch -a 查看远程仓库分支,一般如下:

1
2
3
4
5
* dev
remotes/origin/xxxxxxxxxx
remotes/origin/HEAD -> origin/dev
remotes/origin/dev
remotes/origin/master

而正好 xxxxxxxxxx 可能就是真正存放现有文件的分支,使用 git checkout origin/xxxxxxxxxx 进行分支切换。

conflict

当文件冲突时,Git系统无法自动合并它们,因为可能这些代码块不是独立的。

image-20220225214016189
image-20220225211850394

git pull 也 pull 不下来。

image-20220225212102034

REPO

repo 部分将分为 安装repo命令语法使用场景 三部分。

INSTALL REPO

repo 的安装有 自动手动 两种,类 UNIX 系统都可以通过对应的包管理工具进行安装,但如果没有手动修改源,使用效果可能也不尽如人意。

安装完毕之后还需要进行 版本验证,可能还需要 对python版本进行更改

SETUP AUTOMATICALLY

根据 google android installing repo 指示,可以从 apt 包管理库中下载和安装 repo,也可以使用 google源、清华源或其他源进行手动下载。

Debian 系 Linux 的安装:

1
2
sudo apt-get update
sudo apt-get install repo

Mac 安装:

1
sudo port install repo

1
sudo brew install repo

SETUP MANUALLY

手动安装 repo 的大概思路如下:

  1. 在用户根目录 ~ 下新建 bin 文件夹,即把 $HOME/bin~/bin 当做 repo 的执行文件路径。
  2. 将该路径加入系统变量 PATH 中,可以通过写入 ~/.profile 或对应的 shell 配置文件(如zsh的 ~/.zshrc )中并更新该配置文件来实现。
  3. 然后在该路径下载 repo的执行程序,主要是将某个 url 中(如下方所示为清华源的repo)的信息写入 ~/bin/repo 中。
  4. 为所有用户 a 附加 ~/bin/repo 的可执行 x 权限。
  5. export REPO_URL='https://mirrors.tuna.tsinghua.edu.cn/git/git-repo' 加入到配置文件中,使其一直生效(也可以在 terminal 中临时输入此命令,使其在设备重启前生效)。如果未写入 shell 的配置文件,则重启后该变量就会消失。

下方代码以安装了 zsh shell 的 linux 或 debian 系系统为例,可以拷贝粘贴保存至脚本以运行。

1
2
3
4
5
6
7
8
9
10
11
12
13
# 手动安装repo
mkdir ~/bin
PATH=~/bin:$PATH
curl https://mirrors.tuna.tsinghua.edu.cn/git/git-repo > ~/bin/repo
chmod a+x ~/bin/repo

# 将源添加到shell配置文件并使其生效
echo "export REPO_URL='https://mirrors.tuna.tsinghua.edu.cn/git/git-repo'" >> ~/.zshrc
source ~/.zshrc

# 验证信息
repo version
echo $REPO

注意:google android用的是 https://storage.googleapis.com/git-repo-downloads/repo 的链接,但不是很方便下载,所以就更换成了清华源的。

VERIFICATION

安装完毕之后,可以对手动安装的 repo 进行版本验证,输入 repo versionecho $REPO_URL 即可,结果如下:

此处提示的 <repo not installed> 是正常的,因为在 ~ 目录下的确没有安装 repo .

image-20220226193048479

PYTHON NOT FOUND

如果出现以下提示,则说明你的系统中没有为 python 添加 软连接

1
/usr/bin/env: ‘python’: No such file or directory

解决方法

  1. 验证是否已经安装了 python2 :输入命令 python2 --version,如果提示对应的版本信息则跳到 第3步,否则进行 第2步。
  2. 下载 python2:debian 系用户输入命令 sudo apt install python2 进行安装。mac系用户输入 sudo port install python2 进行安装。
  3. /usr/bin/ 目录下为 python2 创建软链:sudo ln -s /usr/bin/python2 /usr/bin/python
  4. 再次运行 repo init 即可正常。

如,在 Kali Linux 绑定 python2python 之后,可以输入 whereis pythonpython --version 进行验证:

image-20220125143434000

REPO COMMAND GRAMMER

  1. 参考 Repo 命令参考资料
  2. 使用 repo <command> -h 可以获取相应命令的帮助。
  3. 在初始化过 repo 的路径下使用 repo help 可以获得以下信息:
image-20220226220906805

repo init

执行下方的命令会在当前目录中创建一个 .repo/ 目录并初始化 Repo 的版本控制,其中包含存放 Repo 源代码,以及从 URL(对应下方 -u 参数) 中同步下来的 Git 代码库 的某个分支 (对应下方 -b 参数)。

1
repo init -u <git@xxxx.com:xxxx/manifest> -b <oneOfTheBranch>
  • -u:即URL,指定从中检索清单代码库的网址。
  • -m:选择代码库中的清单文件。如果未选择清单名称,则默认为 default.xml
  • -b:指定修订版本,即特定的 manifest-branch,可以是 dev 分支,也可以是特定分支,拉下来之后参照 REPO SWITCH BRANCH 进行分支切换。

注意:对于所有剩余的 Repo 命令,当前的工作目录必须是 .repo/ 的父目录或该父目录的子目录。

repo branch

使用本命令可以查看所有的 目前可用的主题分支(currently available topic branches)。

repo sync

manifest 源中往外拉取分支。下方的 -j<number> 是指创建多线程进行数据资源获取,如 -j4 是指创建四线程进行数据资源获取。

1
2
3
repo sync
repo sync -j4
repo sync -j8

但,bitbucket的网络资源极差,很多情况下都拉不下来代码。

repo help

在其他地方如果没有运行过 repo init 而直接输入 repo help ,则会出现以下信息,详见 REPO INIT

image-20220226220753429

REPO SITUATION

REPO SWITCH BRANCH

前文有说过 “借助单个 Repo 命令,可以将文件从多个代码库下载到本地工作目录”,即使用repo拉下来的是多个 git repository,且这个repo是通过 .xml 文件进行管理的,也就是它自身包含了一些版本和分支切换相关的信息。

如果要对repo拉下来的东西进行分支切换,就要参考一下步骤:

  1. .repo/manifest 路径中。
  2. 使用 git branch -a 查看分支信息。
  3. 使用 git checkout <branch name> 进行分支切换。
  4. 再次使用 repo sync 命令进行同步。
image-20220225211308567

下图是通过 repo 拉下来的多个git repository 之一中的隐藏文件,可以看到这个 .git 文件被使用指向上级 .repo/ 路径下的某个 .git 文件,也就是说,需要先通过 repo 去拉取信息,再使用 git 来切换分支。

image-20220225214801501

REFERENCE

  1. Git与Repo简单入门
  2. git rebase 命令
  3. git reference
  4. 《Git高手之路》,Jakub Narebski,人民邮电出版社

本文参考 《Mac 外接显示器色彩问题》和 《为 macOS 10.15 开启 HiDPI,让 2K 显示器更舒适》两篇文章。

刚买来新的 HUAWEI Mateview 无线版,显示器分辨率为 3840*2560 ,该死的 3:2 屏幕啊,我图啥......

外接2015年的Macbook Air的MiniDP口输出准4K分辨率。

但是,但是,但是~~Air只能输出 16:916:10 的分辨率,让我搞了整整一下午来调整这个分辨率,4个小时啊。

算了,总结一下吧。

关闭SIP

Big sur 和之前版本不同,需要的操作如下:

  1. 关机
  2. 长按 Command 键 和 R 键(都不要松开),短按 开机电源键,直到出现进度条才能松开。
  3. 找到终端,然后输入 csrutil authenticated-root disable ,出现 successfully 字样就算是成功了。(之前的版本是 csrutil disable

查询设备号

  1. 先断开显示器,输入如下代码:
1
2
ioreg -l | grep "DisplayVendorID"
ioreg -l | grep "DisplayProductID"
  1. 再插上显示器,再次运行上方代码。
  2. 两次得出来的不同的设备号就可以区分哪个 VendorIDProductID 是外接显示器的。
image-20220123175000229
  1. 记下那串代码,并将外接显示器的两个ID转换成对应的十六进制数, 如 895022f6 , 2819466e2

生成配置参数

  1. 在用户目录 ,即 ~ 下,使用 DisplayVendorID-xxxxxxxx 即对应外接显示器 Vendor 号的16进制 )创建一个文件夹。
  2. 然后在对应文件夹下创建一个 使用 DisplayProductID-yyyy ( yyyy` 即对应外接显示器 Product 号的16进制 )创建一个无后缀名的文件。
  3. Scaled Resolution for your Mac 网站生成配置参数,在红色框中分别填入你外接显示器的对应参数,和你想使你的显示器所呈现的分辨率参数。
image-20220123175609151
  1. 复制右侧的 xml 代码至刚刚的 DisplayProductID-yyyy 文件中,并保存。

导入系统

在Big Sur系统下,根目录 / 是禁止写入的,需要稍微用点技巧(走点弯路)。

  1. 新建一个文件夹,将解除SIP之后的 / 挂载到某个地方,如下方所示:
1
2
mkdir ~/nvme
sudo mount -o nobrowse -t apfs /dev/disk1s5 ~/nvme/

其中,/dev/disk1s5 中的 /disk1s5 要通过 磁盘工具 各自查看自己的 设备 ,最后面的 s1 去掉不写。

image-20220123173550666
  1. 然后就可以 cd 进去查看对应目录下的文件内容,但是所有读写操作都需要加上 sudo 才可以。
1
2
cd ~/nvme/System/Library/Displays/Contents/Resources/Overrides
ls
image-20220123173806535
  1. ~/DisplayVendorID-xxxx 复制到 ~/nvme/System/Library/Displays/Contents/Resources/Overrides 里面:
1
sudo cp -r ~/DisplayVendorID-22f6 ~/nvme/System/Library/Displays/Contents/Resources/Overrides/DisplayVendorID-22f6

复制完毕之后可以再 ls 查看,就存在了。

  1. 但是这种复制只是一种暂时的,重启之后就会被镜像文件所覆盖,所以要重新 snapshot 一下。注意,这一步一定要做,否则重启就失效了。
1
sudo bless --folder ~/nvme/System/Library/Displays/Contents/Resources/Overrides --bootefi --create-snapshot

截止2022年1月23日,以下是ST公司的产品线,下图通过Flash大小和Nucleo类型对产品进行了一定划分。

img

NECLEO-L476RG DATA BRIEF

Necleo系列开发板下面有很多型号,且每个型号的板子(除开芯片以外)设计应该都是大同小异的,所以最底层板子也就有了自己的型号。

而 NecleoL476RG 开发板的底板型号为 MB1136 。且下方所有Necleo的产品都自带 ST-LINK/V2-1 调试器。

image-20220122193806691

ST-LINK/V2-1

支持USB软件 重新检查(re-enumeration) 、支持虚拟COM口、支持大容量储存、支持超过 100mA 电流的电源管理,但是不支持 SWIM 接口且最小输入电压为 3V

注意:一旦激活了 ST-LINK/V2-1 的目标读出保护功能,就会阻止目标应用运行事后运行(prevents the target application from running afterward.)目标读出保护必须被关闭(must be kept disabled on board)。

可以根据跳线帽的两种状态来使用 ST-LINK/V2-1:

  • 在线编程和调试STM32(Program/debug the on-board STM32),此时 CN2 的两个跳线帽都连接着,处于在线编程状态(默认)。
  • 使用连接到SWD连接器CN4的电缆对外部应用板中的MCU进行编程/调试,此时 CN2 的两个跳线帽都不连接,以允许 CN4 (即 SWD 接口)连接至外部连接器。
image-20220123183857115

LAYOUT

image-20220123182028068

image-20220123182139437

CHIP BREIEF

STM32 Nucleo L476RG 所使用的芯片是 STM32L476RGT6U,其中 L4 是系列号,76 是产线,R 是指64pin,C 是指 256Kbytes 的 Flash内存大小。

下方为《STM32 Nucleo-64 boards data brief》提供的 产品芯片命名方法

image-20220122195540612

REFERENCE

  1. NUCLEO-L476RG

INSTALL FONTS ON DEBIAN LINUX

We can install True Type or Open Type fonts(.ttf / .otf / .ttc) in DEBIAN LINUX, like ubuntu or kali.

DOWNLOAD FONT FROM WEBSITE

  1. Download Cascadia Code from https://github.com/microsoft/cascadia-code/releases and unzip it.
  2. We got 3 folders here: /otf/ , /ttf/ and woff2 , and we only need `ttf

COPY FILES TO SYSTEM FONT DIRECTORY

Font fils are generally installed in either the system font directory on the path /usr/share/fonts/ or in a user font directory that is frequently on one of the following paths:

  • ~/.local/share/fonts/
  • ~/usr/local/share/fonts/
  1. Execute the following command to copy the fonts to system path
1
sudo cp -r ttf /usr/share/fonts/CascadiaCode

GENERATE FONT CHACHE

We need to build font infomation caches for apps using fontconfig for their font handling.

1
2
cd /usr/share/fonts/CascadiaCode
fc-cache -f -v

NOTE

If you cannot execute fc-cache command , copy and execute the following command in terminal.

1
sudo apt install fontconfig

VERIFY THE FONT INSTALLATION

Confirm that the fonts are installed by displaying the paths and style definitions with fc-list command filtered on the font family name with grep .

1
fc-list | grep "Cascadia Code"

CUSTOMIZE VSCODE

  1. Get to Setting
image-20220122161611892
  1. Search font in the bar
image-20220122161750043
  1. Add 'Cascadia Code', to the Editor: Font Family .
  2. Restart vscode.

SPI Introdution

SPI, Serial Peripheral Interface, 即串行设备接口,微控制器和外围IC(如传感器、ADC、DAC、移位寄存器、SRAM等)之间使用最广泛的接口之一。

SPI是一种同步的主从式接口,支持全部通信制式(单工、半双工、全双工)。与I2C的 多主多从 模式不同,SPI协议为 一主多从 模式。SPI所消耗的接口数也有所提升。

接线

SPI 的物理线支持 三种类型

  • 片选线(NCS / CS / SS),某些数据手册会将 片选引脚 称为 NSS /NCS / SEL (Select) / CS (Chip Select) / STE (Slaver Transmit Enable)
  • 时钟线(CLK / SCK)
  • 数据线(DA 或 MOSI 和 MISO )

需要注意的是,SPI的通信线有太多的名称,需要自行对照芯片手册进行查询,避免混淆。下方为标准全双工四线SPI的通信接线示意图

image-20210819075248043

SPI 通过对硬件资源的使用修改(禁用片选、禁 / 复用数据线)可以达到 全双工半双工 通信的目的。标准SPI为 四线SPI (CS / CLK / MOSI / MISO);最低支持2根数据引脚(仅保留 CLK / DA,其中DA为分时复用数据线 )来达到半双工通信的目的,可以增加一 / 多根 CS 来达到拓展SPI从设备片选的目的;也可以利用四根独立的半双工数据线,来达到 标准四线SPI 四倍通信能力 的 六线SPI(一般被称为 Quad-IO SPI)。

分类

各芯片厂商对SPI的通信协议好像并没有一个较为正式的名称,但都可以从通信制式的类型进行区分,并不能仅从 x线SPI 的数量来判断SPI通信协议的类型。

较为推荐的称呼方式是:线数 + 有无片选 +通信制式。比如:

  • 两线无片选半双工SPI,即 CLK 和 SDIO 两线,SDIO 支持分时双工。
  • 三线无片选半双工SPI,即 CLK 和 两根 SDIO,两根SDIO 都是分时双工。
  • 三线有片选半双工SPI,即 CLK 、SDIO 和 CS,SDIO 支持分时双工。
  • 三线无片选全双工SPI,即 CLK、MOSI 和 MISO。
  • 四线有片选全双工SPI,即 CLK、MOSI、MISO 和 CS。
  • ......

例如,据STM32L476RG芯片手册《RM0351》第1450页所示,SPI外设可以被配置为以下三种模式,即 三线全双工两线半双工两线单工

  • Full-duplex synchronous transfers on three lines
  • Half-duplex synchronous transfer on two lines (with bidirectional data line)
  • Simplex synchronous transfers on two lines (with unidirectional data line)

SDR 和 DDR 模式

扩展的 SPI 协议还增加了 SDR 模式(单倍速率 Single Data Rate)和 DDR 模式(双倍 速率 Double Data Rate)。例如在标准 SPI 协议的 SDR 模式下,只在 SCK 的单边沿进行数据传输,即一个 SCK 时钟只传输一位数据;而在它的 DDR 模式下,会在 SCK 的上升沿和下降沿都进行数据传输,即一个 SCK 时钟能传输两位数据,传输速率提高一倍。

数据传输

下以四线有片选全双工SPI为例进行说明。

要开始SPI通信,主机必须发送时钟信号,并通过使能CS信号选择从机。

片选 通常 是 低电平有效(active-low) 信号。

主机须在 CS 信号上发送逻辑 0 以选择从机。主机和从机可以分别通过 MOSI 和 MISO 引脚同时发送数据。在SPI通信期间,数据的发送(串行移出到MOSI/SDO总线上)和接收(采样或读入总线(MISO/SDI)上的数据)同时进行。串行时钟沿同步数据的移位和采样。

SPI接口允许用户灵活选择时钟的 上升沿 或 下降沿 来采样和/或移位数据。

需要注意:SPI接口传输的 数据位数 仍需查阅器件数据手册。

时钟极性和时钟相位

在SPI中,主机可以选择 时钟极性(Clock Polarity,CPOL)和 时钟相位(Clock Phase,CPHA)。

在空闲状态期间,CPOL 控制 时钟极性。空闲状态是指传输开始时CS为高电平且在向低电平转变的期间,以及传输结束时CS为低电平且在向高电平转变的期间。

CPHA 控制 时钟相位。根据CPHA位的状态,使用时钟上升沿或下降沿来采样和/或移位数据。主机必须 根据从机的要求选择时钟极性和时钟相位。根据CPOL和CPHA位的选择,有四种SPI模式可用,如下表:

SPI 模式 CPOL CPHA 空闲状态下的时钟极性 用于采样和/或移位数据的时钟相应
0 0 0 逻辑低电平 数据在上升沿采样,在下降沿移出
1 0 1 逻辑低电平 数据在下降沿采样,在上升沿移出
2 1 1 逻辑低电平 数据在下降沿采样,在上升沿移出
3 1 0 逻辑低电平 数据在上升沿采样,在下降沿移出

下图为TI公司F280049芯片的SPI时钟模式:

image-20210819084200284

下图为ADI公司ADSP21479芯片的SPI时钟模式:

image-20210819084447672

后述 图2 至 图5 显示了四种SPI模式下的通信示例。

在这些示例中,数据显示在MOSI和MISO线上。传输的开始和结束用绿色虚线表示,采样边沿用橙色虚线表示,移位边沿用蓝色虚线表示。请注意,这些图形仅供参考。要成功进行SPI通信,用户须参阅产品数据手册并确保满足器件的时序规格。

图2. SPI模式0,CPOL = 0,CPHA = 0:CLK空闲状态 = 低电平,数据在上升沿采样,并在下降沿移出

图2. SPI模式0,CPOL = 0,CPHA = 0:CLK空闲状态 = 低电平,数据在上升沿采样,并在下降沿移出

图3给出了SPI模式1的时序图。在此模式下,时钟极性为0,表示时钟信号的空闲状态为低电平。此模式下的时钟相位为1,表示数据在下降沿采样(由橙色虚线显示),并且数据在时钟信号的上升沿移出(由蓝色虚线显示)。

图3. SPI模式1,CPOL = 0,CPHA = 1:CLK空闲状态 = 低电平,数据在下降沿采样,并在上升沿移出

图3. SPI模式1,CPOL = 0,CPHA = 1:CLK空闲状态 = 低电平,数据在下降沿采样,并在上升沿移出

图4给出了SPI模式2的时序图。在此模式下,时钟极性为1,表示时钟信号的空闲状态为高电平。此模式下的时钟相位为1,表示数据在下降沿采样(由橙色虚线显示),并且数据在时钟信号的上升沿移出(由蓝色虚线显示)。

图4. SPI模式2,CPOL = 1,CPHA = 1:CLK空闲状态 = 高电平,数据在下降沿采样,并在上升沿移出

图4. SPI模式2,CPOL = 1,CPHA = 1:CLK空闲状态 = 高电平,数据在下降沿采样,并在上升沿移出。

图5给出了SPI模式3的时序图。在此模式下,时钟极性为1,表示时钟信号的空闲状态为高电平。此模式下的时钟相位为0,表示数据在上升沿采样(由橙色虚线显示),并且数据在时钟信号的下降沿移出(由蓝色虚线显示)。

图5. SPI模式3,CPOL = 1,CPHA = 0:CLK空闲状态 = 高电平,数据在上升沿采样,并在下降沿移出

图5. SPI模式3,CPOL = 1,CPHA = 0:CLK空闲状态 = 高电平,数据在上升沿采样,并在下降沿移出

多从机配置

多个从机可与单个SPI主机一起使用。从机可以采用常规模式连接,或采用菊花链模式连接。

常规SPI模式

image-20210819075431419
图6. 多从机SPI配置

在常规模式下,主机需要为每个从机提供单独的片选信号。一旦主机使能(拉低)片选信号,MOSI/MISO线上的时钟和数据便可用于所选的从机。如果使能多个片选信号,则MISO线上的数据会被破坏,因为主机无法识别哪个从机正在传输数据。

从图6可以看出,随着从机数量的增加,来自主机的片选线的数量也增加。这会快速增加主机需要提供的输入和输出数量,并限制可以使用的从机数量。可以使用其他技术来增加常规模式下的从机数量,例如使用多路复用器产生片选信号。

菊花链模式

image-20210819075542602

图7. 多从机SPI菊花链配置

在菊花链模式下,所有从机的片选信号连接在一起,数据从一个从机传播到下一个从机。在此配置中,所有从机同时接收同一SPI时钟。来自主机的数据直接送到第一个从机,该从机将数据提供给下一个从机,依此类推。

使用该方法时,由于数据是从一个从机传播到下一个从机,所以传输数据所需的时钟周期数与菊花链中的从机位置成比例(成比例倍增)。

例如在图7所示的8位系统中,为使第3个从机能够获得数据,需要24个时钟脉冲,而常规SPI模式下只需8个时钟脉冲。图8显示了时钟周期和通过菊花链的数据传播。并非所有SPI器件都支持菊花链模式。请参阅产品数据手册以确认菊花链是否可用。

图8. 菊花链配置:数据传播

图8. 菊花链配置:数据传播

HALF DUPLEX SPI

半双工通信可以是 两线SPI 或 三线SPI,仅仅是有无片选线的差异而已。

PIN DEFINITION

NCS: SPI控制读写使能信号;使用时需要被拉低,否则SDIO会处在 HIGH-Z 态,而SCLK信号也会被无视。也可以被用于在通信错误发生时重置SPI 通信。两线SPI不需要这根线,但个别芯片可能需要这个引脚接地(不能悬空),具体看芯片手册。

SDIO: SPI的数据读写端口;半双工读写。只有在“从被控设备读出数据”的情况下,SDIO 才会由被控制设备控制。

SCLK: SPI接口时钟;总是由主控制器生成和控制。

TRANSMISSION PROTOCOL

跟其他通信类似,SPI 的 SDIO 需要在 时钟低电平时 进行电平跳变。

半双工SPI读写操作都包含两个字(byte),第一个字包含1 bit的 数据方向(或称 控制位) 和 7 bit的 地址,第二个字包含 数据

关于数据方向/控制位

通常定义是,当需要写入数据时,控制位写 1 。当需要读出数据时,控制位写 0

image-20220118135819247

但不一定所有支持半双工SPI的通信控制位都是在MSB,有可能是在 LSB 。

如,下方右侧 SL8541E 的安卓平台主控,支持半双工SPI,但是其控制位就在地址字符的LSB上。

image-20220419235450360

写操作

主控制器在SCLK下降沿时改变 SDIO的电平,被控设备在SCLK上升沿时读取SDIO的电平。

image-20220118140526017

读取操作

SDIO会在SCLK下降沿时修改,主控制器需要在SCLK的上升沿时读取SDIO的电平信息。

注意:发送完地址字 之后需要延长半个周期的时钟低电平。

image-20220118141033005

Timing Serial

因为芯片自带的时序图有些许错误,所以就自己画了一个。

时序图绘图工具(开源):WAVEDROM

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
32
33
34
35
36
37
38
39
40
41
{signal: [
['CPOL=1,CPHA=1',
['Read',
['Control',
{name: 'NCS', wave: 'hl................h'},
{name: 'SCLK', wave: 'hn.......lnn......h'},
],
{name: 'SDIO', wave: '102222222x222222221',data: ["A6","A5","A4","A3","A2","A1","A0","D7","D6","D5","D4","D3","D2","D1","D0",]},
],
{},
['Write',
['Control',
{name: 'NCS', wave: 'hl...............h'},
{name: 'SCLK', wave: 'hn...............h'},
],
{name: 'SDIO', wave: '1.2222222222222221',data: ["A6","A5","A4","A3","A2","A1","A0","D7","D6","D5","D4","D3","D2","D1","D0",]},
]
],
{},
['CPOL=1,CPHA=0',
['Read',
['Control',
{name: 'NCS', wave: 'hl................h'},
{name: 'SCLK', wave: 'hpp......lpp......h'},
],
{name: 'SDIO', wave: '102222222x222222221',data: ["A6","A5","A4","A3","A2","A1","A0","D7","D6","D5","D4","D3","D2","D1","D0",],phase: 0.25},
],
{},
['Write',
['Control',
{name: 'NCS', wave: 'hl...............h'},
{name: 'SCLK', wave: 'hpp..............h'},
],
{name: 'SDIO', wave: '1.2222222222222221',data: ["A6","A5","A4","A3","A2","A1","A0","D7","D6","D5","D4","D3","D2","D1","D0"],phase: 0.25},
]
],

],
config: { hscale: 1 }
}

image-20220423193121090

DEBUG RECORDS

下面这个时序图错误的坑是真的大,调了好就才折腾明白。

某些芯片下,SDIO 的闲置状态可能不能是 Hi-Z 态。

时序图错误

内部调试时发现,SDIO在读取数据前后必须是 输出模式,最好 强制拉高,而不是 Hi-Z 态。

image-20220419210753902

读写单个字符

以下这两个函数中的 for() 使用了 MSB 发送数据,最好不要自作聪明将 i 的数据类型改为 uint8_t 或其他非负型数据,以下这种循环写法会让程序陷入死循环的。

另外,SPI 和 I2C 不一样,读取和写入的时序有较大差异。比如,I2C会在时钟高电平时读取电平数据,在低电平时改写电平数据。而 CPOL = 1, CPHA = 1 的SPI 会在上升沿时读取和写入数据,而 CPOL = 1, CPHA = 0 的 SPI会在下降沿时读取和写入数据。

主从设备必须将SPI特性保持一致,才能确保读写的稳定性。

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
/**
* @brief 写入8bit数据
* @param {uint8_t} data
* @return {*}
*/
static void write_byte(uint8_t data)
{
for(int i = 7; i>= 0; i--)
{
if( (data >> i) & 0x01)
{
write_high_level();
}
else
{
write_low_level();
}
}
}

/**
* @brief 读取8bit数据
* @param {*}
* @return {uint8_t} data
*/
static uint8_t read_byte(void)
{
uint8_t data = 0;
for(int i = 7; i>= 0; i--)
{
#if (CPHA == 1)
SCLK_SET_LOW;
data |= HAL_GPIO_ReadPin(SPI_DATA_GPIO_Port, SPI_DATA_Pin) << i;
delay_nop(LEVEL_DELAY_SLICES);

SCLK_SET_HIGH;
delay_nop(LEVEL_DELAY_SLICES);
#else

SCLK_SET_HIGH;
delay_nop(LEVEL_DELAY_SLICES);
SCLK_SET_LOW;
data |= HAL_GPIO_ReadPin(SPI_DATA_GPIO_Port, SPI_DATA_Pin) << i;
delay_nop(LEVEL_DELAY_SLICES);
#endif
}
return data;
}

STM32 SPI 配置

image-20220824175804976

image-20220824175908055

由外设SPI控制的 SCLK / SDIO 波形与手动控制的 SNCS 波形之间的矛盾。

image-20220824175942791

write_register(0x09, 0xA5),对应应该输出数据为 0x89, 0xA5 ,而 SNCS 在两处地方产生了错误的波形。

image-20220824175951156

SOURCE CODE

以下是适用于 STM32 平台的 GPIO-模拟 半双工SPI 代码,利用 空指令进行延时控制,实现半双工(三线/两线)SPI 的通信。

需要软件适配以下几个功能:

  1. 控制精细度在 \([10^{-9}s:10^{-6}s]\) 之间的 精准延时(如果做不到,通信速率就上不去 1MHz )。
  2. 控制引脚电平的宏定义(可选)。
  3. 设置数据接口输出设置数据接口输入 的代码。
  4. 拉高电平拉低电平 的代码,这里需要根据从设备特性来控制时钟的相位,即 CPHA = 1 或者 CPHA = 0
  5. 对照着 正确的时序图 写一遍 读单字符写单字符 的代码,这里需要根据从设备特性来控制时钟的相位,即 CPHA = 1 或者 CPHA = 0
  6. 对照着 正确的时序图 写一遍 写寄存器读寄存器 的代码,这里需要根据从设备特性来控制时钟的极性,决定时钟在闲时为高电平还是低电平,即 CPOL = 1 或者 CPOL = 0

注意:都是按顺序来完成的,所有后面的功能都需要依托于前面的功能来实现。而且,需要用示波器(有条件)进行测量以校准通信速率,并使用正确的时序图进行编码(如果是错误的,浪费时间,尽快跟厂家确认)。

代码部分可以参考 gmi 中对 spi 的定义和使用。

REFERENCE

  1. 实例解析非标准SPI
  2. 扩展SPI协议
  3. SPI接口简介
  4. SPI通信协议详解(spi总线)
  5. 第23 章 串行外设接口(SPI)

基础技能

  1. ARM架构芯片的样例代码加载、编译、烧录、调试工作熟悉。
  2. bitbucket 如何使用(是否需要配置SSH、repository如何pull和push、add、commit等) √
  3. confluence 如何使用(任务的查看、提交、文章的发布、协作等等)

IDE for Realtek

VSCODE ARM

image-20220112105541195
image-20220112110410253
image-20220112110533598
image-20220112110507665
image-20220112105734831

KEIL ARM

将Realtek RTL8762D SDK中的项目单独摘出来,放到某个文件夹下进行管理时,需要单独更改好几处内容:

  1. C/C++的Include Path
  2. 源文件的Source Path
  3. APP Image(.bin 生成文件),即 after_build_common.bat 的路径和内容。

如下所示,把单独某个Project摘出来时会产生很多感叹号。

image-20220112111951120

头文件路径修改

此时需要进入设置中进行头文件路径修改

image-20220112133356533

选择 C/C++ 选项卡下的 Include Paths 进行修改。

image-20220112133505056

原来的路径设置都是使用相对路径进行的,此时需要将 sbee2-sdk-v1.0.0 文件夹放到与你项目文件同盘的某个文件夹下,最好不要相距太远。

image-20220112133731688

可以使用 VS Code将 .uvprojx 文件打开,使用搜索和替换工具对相关头文件的路径进行替换。

源文件路径修改

修改方法同头文件,

image-20220117094508419

bat文件路径修改

.bat 文件是用于在 .o 文件生成后的链接脚本。所以如果该脚本自身路径和脚本内的包含路径出错,可能会导致无法编译出对应的 app_MP_adk##### 文件。

image-20220117095506866

下方为样例代码原来的设置情况:

image-20220120134642405

Option-User 设置中,可以查看到 After Build/Rebuild 相关的设置,其中 Run #1 则是 Realtek MP Tools 需要烧录 EVB开发板相关的脚本文件。

image-20220117095438927

将单独摘放出来的项目文件夹 pixart_i2csbee2-sdk-v1.0.0sbee2_wristband_sdk_upperstack_img 放到同一个文件夹下。

image-20220117110446703

因此修改 .uvprojx 文件内容下 after_build_common.bat 的路径时,将该路径修改为如下的相对路径即可:

1
..\sbee2-sdk-v1.0.0\tool\after_build_common.bat $J #L @L
image-20220117104943624

保存修改后的 .uvprojx 文件,可以看到 Keil V5 自动更新了相关设置。如下:

image-20220117104955125

after_build_common.bat 控制着自动生成Realtek 的 MP Tool 需要使用的 APP Bin文件,如果该 Run #1 没有启用,则无法生产该文件。

image-20220117105247314

.bat 文件下所有的 ..\..\..\tool\ 都要修改成 ..\sbee2-sdk-v1.0.0\tool\,如果项目文件夹和SDK文件夹路径有异,则需要适当修改。

image-20220117105040885

启用完成之后即可生成对应 app_MP_adk##### 文件

image-20220117105414578

HARDWARES

ADAPTER

SPECIFICATION

A4芯片,即KA8G2芯片用的转接板需要接入5V电压,LDO会转换电压。

而PAT9126JA芯片则使用两个3.3V进行接入。

CHIP & BOARD

开发测试板为 Realtek RTL8762D EVB KIT。

型号: RTL8762DW

SENSOR - KA8G2

KAG2 is a high performance and ultra low power CMOS-processed optical image sensor with integrated digital image process circuits. It is based on an optical navigation technology which measures changes in position by optically acquiring sequential surface images(frames) and mathematically determining the speed, the direction and the magnitude of motion. The displacement delta_X and delta_Y information are available in registers which are accessible through SPI serial interface. A host controller reads and translates the data from the SPI serial interface into RF signals before sending them to the host PC.

SPECIFICATION

image-20220113150323525

HARDWARE LINKING

image-20220112172532934
企业微信截图_16391255852712

CHIP INITIATE

这个芯片启动时,需要对一些寄存器进行写入以初始化。下方为二维数组,sensor_init_regs[][0] 为寄存器地址,sensor_init_regs[][1] 为寄存器需要写入的数据。

1
2
3
4
5
6
7
8
9
uint8_t sensor_init_regs[7][2] = {
{0X09, 0XA5},
{0X26, 0X34},
{0X19, 0X04},
{0X6D, 0X39},
{0X0D, 0X20},
{0X0E, 0X20},
{0X09, 0X00}
};

初始化时,需要注意以下问题:

  1. 某些主控芯片在使用两线SPI进行数据写入时,会有要求使用 7bit 地址,且 MSB 为 1 。此时需要判断是否需要认为修改地址的 MSB为 1 ,例如 Realtek 的 RTL8762DW 芯片就不需要人为修改,人为修改会导致波形异常。而某些芯片需要人为写入MSB。
  2. 在每一次写入寄存器之后,强烈建议进行延时,可以使用 delay(0xFFFF),(尝试过 0xFF 太短,不能完成初始化写入)。

SENSOR - PAT9126JA

  1. 需要确定 ID_SEL 引脚的连接情况,是拉高、接地还是悬空。分别对应的 CHIP ID 都是不一样的,可能是0x73  0x75  0x79 三者之一。

transformer 上的 VCC3.3V

SPECIFICATION

这个芯片有两种电压要求,默认为高电压版本 3.3V ,可以通过SPI写入寄存器和硬件并线来达到降低至 1.8V 低电压的模式。

HADWARE LINKING

OpticalSensorTransfer_I2C

SDK & Tools

此处有 2个SDK包 和 3个tool包,分别是:

  1. sbee2-sdk-v1.0.0.zip
  2. sbee2_wristband_sdk_upperstack_img.zip
  3. MPPackTool_v2.0.5.2.zip
  4. 日志输出软件:DebugAnalyzer-v4.0.0.14.zip
  5. 代码烧录软件:BeeMPTool_kits_v1.0.5.0.zip

BUILD / FLASH / LOG

BUILD

点击 build 按钮即可进行代码构建。

image-20220113090856565

build 完毕之后可以看到下方的成功提示 0 Error(s), 0 Warning(s)

image-20220113091008941

FLASH

FLAHS需要经过 configuration 、 detect 和 download 三步

configuration

根据《RTL8762D SDK User Guide CN》文件,RTL8762D 的 EVB KIT 是可以支持 JLINK 的(如下图所示)。

image-20220113095321215

但这里并未使用 JLINK,而是使用 Realtek 专门的工具 BeeMPTool_kits, 通过 UART 进行烧录。

image-20220113095804076

打开 MPTool.exe ,并选中对应的芯片型号 RTL8762D

image-20220113095854784

在这里选择 调试 模式进行烧录

image-20220113095949881

Config Set 中选择 Confirm ,不需要修改什么东西。

image-20220113100100098

此处需要设置 Flash 地址映射文件 flash map.ini

image-20220113100324900
image-20220113101953154

下方为 《RTL8762D SDK User Guide CN》文件中,9.1章节对五个images文件进行了描述。

image-20220113102036834

FILE TYPE DESCRIPTION FILE PATH
System Config File - 来自 BeeMPTool_kits \BeeMPTool_kits_v1.0.5.0\BeeMPTool\ConfigFile\
Bank0 OTA Header File - 来自 sbee2_wristband_sdk_upperstack_img \sbee2_wristband_sdk_upperstack_img\src\app\wristband\firmware\
Bank0 Secure Boot Loader Image - 来自 sbee2_wristband_sdk_upperstack_img \sbee2_wristband_sdk_upperstack_img\src\app\wristband\firmware\
Bank0 ROM Patch Image - 来自 sbee2_wristband_sdk_upperstack_img \sbee2_wristband_sdk_upperstack_img\src\app\wristband\firmware\
Bank0 APP Image - 来自 sbee2-sdk-v1.0.0 sbee2-sdk-v1.0.0\board\evb\io_sample\SPI3WIRE\spi3wire_polling\bin

关于app image文件选择

在Build完成后,会生成三个 .bin 文件,如果选择错误,会提示 MD5 check error!Image type doesn't match IC type. ,选择正确的话会提示 File check OK

image-20220113111301561

detect

detect 的时候需要注意:

  1. 将 EVB kit上的 J15 LOG口接地,否则会检测失败
  2. 如果出现 Failed 字样,则按一下 EVB KIT 上的红色的 RESET 按钮进行复位后再尝试。
image-20220113111054035
image-20220113103853161

download

最后选择 download 下载即可。

image-20220113104047601

UPPERSTACK FLASH

自带的 \sbee2-sdk-v1.0.0\doc\ 路径下的教程是,都是有 Bank0 Upperstack Image 需要烧录的。

image-20220120140307997

步骤如下:

  1. 使用 \sbee2_wristband_sdk_upperstack_img\src\app\wristband\firmware\upperstack_img 路径下的 .ini 文件作为 layout 文件。(而之前使用的flash map.ini 地址为 \sbee2_wristband_sdk_upperstack_img\src\app\wristband\firmware\

  2. 指定 \sbee2_wristband_sdk_upperstack_img\src\app\wristband\firmware\upperstack_img 路径下的 .bin 文件作为 Upperstack Image 文件。

  3. \sbee2_wristband_sdk_upperstack_img\board\evb_stack_img\wristband\flash_map.h 文件作为项目工程里的唯一内存映射文件依赖。flash_map.h 被放在 mem_config.h 头文件下,间接被 syetem_rtl876x.h 引用。

LOG

RTL8762D 的 EVB KIT 不支持 JTAG 方式进行观察,(听说是)通信过程容易被打断。

这里使用 UART 和 EVB KIT 上的 J15 口来观察 LOG数据。

LOG软件

使用专用工具 DebugAnalyzer 进行日志输出。

  1. 选择合适的串口,即使用 FT232 的UART口,将该芯片口的 RX 连接至 RTL8762D 板子上的 J15 口。并在电脑中选中对应的 FT232 设备。
image-20220113093030488
  1. 需要设置 App Trace File
image-20220113093723962
  1. 观察日志输出
image-20220113104331739

COM SETTING

UART SETTING

image-20220113111953878

PERIPHERAL

3-WIRED SPI

以下是主控板 RTL8762D 的SDK对3线SPI的相关设置结构体。

1
2
3
4
5
6
7
8
9
10
11
12
13
typedef struct
{
uint32_t SPI3WIRE_SysClock; /*!< Specifies system clock */
uint32_t SPI3WIRE_Speed; /*!< Specifies SPI clock. */
uint32_t SPI3WIRE_Mode; /*!< Specifies SPI operation mode.
This parameter can be a value of @ref THREE_WIRE_SPI_mode */
uint32_t SPI3WIRE_ReadDelay; /*!< Specifies the delay time from the end of address phase to the start of read data phase.
This parameter can be a value of 0x0 to 0x1f, delay time = (SPI3WIRE_ReadDelay+1)/(2*SPI3WIRE_Speed) */
uint32_t SPI3WIRE_OutputDelay; /*!< Specifies SPI output delay 1T or not.
This parameter can be a value of @ref THREE_WIRE_SPI_OE_delay_config */

uint32_t SPI3WIRE_ExtMode; /*!< Specifies extended timing window for SPI output enable = 0. */
} SPI3WIRE_InitTypeDef;

WRITING-DELAY

\[ 1s = 1^3ms = 1^6us = 1^9ns\\ 1Hz = 1^{-3}KHz = 1^{-6}MHz = 1^{-9}GHz \]

在3线SPI的数据线读取过程中,在前一段地址帧结束且尚未开始读取数据前,会有一段延时。由 spiReadDelayspiWireSpeed 两个参数控制。 \[ DelayTime = (spiReadDelay +1) / (2* spiWireSpeed) \tag{延时计算公式} \] 例如, 当 spiWireSpeed = 8e5 时, 设置 spiReadDelay = 0x03 ,此时 可以在中间延时 2.5us

CLOCK_FREQ

将RTL8762D的SPI通信时钟频率从 2E7 更改为 1E6 后可以短时间正常通信,但是稍微过一段时间就出现了不稳定,度数全为 0 ,且复位后读取的 chipID 也为 0x00, 0x00

1
2
3
// the actual frequency of spi is set by `SPI3_WIRE_SysClock`
// `1E6` means 1MHz, and `2E7` means 20MHz.
SPI3WIRE_InitStruct.SPI3WIRE_SysClock = 1E6;
image-20220119152741283

TIMING

\[ Sysclk = 1e7 \\ wirespeek = 8e5 \]

2-WIRED SPI

To recover the correct communication of SPI, the host controller can de-assert the SCLK for at least tRESYNC (1us min), and then keep SCLK asserted for a certain time interval tWDT (1.7ms, min) as shown in below Figure . to force the SPI control circuits of the sensor to reset.

image-20220120154724619

DEBUG RECORDS

image-20220112163300158

0x05 // 0000 0101

// 1000 0101

DELTA_X & DELTA_Y UNREAD

Motion  DYOVF  DXOVF 并未读出,未检测到移动。

image-20220114110802052

Operation_Mode = 0xB8, cofiguration = 0x17 均为默认

image-20220114111325286
image-20220114111114776

0xB8 使 设备处于睡眠模式,configuration = 0x17 使设备未处于 sleep3powerDown 为正常模式,即未断电。

所以需要修改 Operation_Mode0x01

在设置了下方的语句之后,LOG记录传送回来的 OperationMode 对应的数据为 0xFC0xB81111 11001011 1000) 。

默认情况下 OperationMode0xB81011 1000

异常情况下 OperationMode0xFC1111 1100

即第 2 位和 第 6 位会变,查数据手册,只有第 2 位(Slp2mu_Enh)有影响,该位控制芯片强制进入 睡眠2 模式。

1
spi3wire_writebyte(REG_KA8G2_OPERATION_MODE, KA8G2_OM_RUN);  // edited by liew in 20211114
image-20220114135400211
image-20220114135647079

从《KA8G2 optical mouse sensor》中的 MOTION Pin Function 可以看出,Motion 寄存器即运动检测标志相关寄存器。

image-20220114142319440

主控板IO口数据异常

下方为利用SDK进行 读数据 的相关操作:

1
2
3
4
5
6
7
8
9
10
11
12
13
int main(void){
extern uint32_t random_seed_value;
srand(random_seed_value);
spi3wire_demo();
DBG_DIRECT("TEST_20220120");

while (1){
for(uint8_t i = 0; i< 0xFF; i++){
spi3wire_writebyte(0x7F, i);
delaySys(0xF);
}
}
}

并用逻辑分析仪进行捕获和分析,发现数据异常:

image-20220120151632286

经过检查,发现时序解码无误,所有波形的高低和解码结果一致。

image-20220120151645002

但是相连的数据之间数据差异较大。

image-20220120151638254

查看LOG也发现数据的确有按照预定的逻辑进行循环:

20220120

但是逻辑分析仪采出来的数据就是异常。

经过分析,是因为逻辑分析仪的采样率为 1MHz ,与SPI外设的频率 1e6 一致。

修改了逻辑分析仪的采样率为 2MHz ,提高了1倍,采样出来的逻辑就正常了。

image-20220120162227888

但是之前的项目只用了写数据的函数。示波器波形和逻辑分析仪都能正常。

改了项目主循环中的语句为读数据之后,就出现异常了。

问题推断

通过注释部分语句,进行间歇性测试和波形观察。

发现,spi读取语句 uint8_t spi3wire_readbyte(uint8_t address) 可能是波形不正常的原因。

硬件查找主控板和底板的引脚问题:

  1. 找到扩展板上的GPIO口对应核心板上的哪个口
  2. 使用示波器探头直接接触对应的GPIO口并查看波形,查看主控板和底板之间是否存在问题。

发现示波器探头从底板更换至主控板之后,示波器所显示波形并无差异。

GITEE: https://gitee.com/isletspace/esp32iot

本项目是使用 微信小程序+腾讯云+乐鑫开发板+5V-多路-继电器+220V-AC-电器 的模式对家庭中的硬件进行检测和控制,本项目涉及到 网络前端服务器后端网络通信物联网硬件控制 方面的相关知识。

需要实现的功能

  1. 开发板能够自动连接家庭WiFi
  2. 开发板能够通过MQTT协议与后台服务器取得联系
  3. 开发板能够定时自动获取时钟并校准
  4. 开发板能够根据MQTT协议控制外围电路
  5. 开发板能够根据已经设置的参数与实时的传感器参数比对,并在一定环境条件内开启/关闭相关电路
  6. 手机可以通过微信小程序发送MQTT数据至服务器

软件开发平台:Mac

硬件开发IDE:Arduino

硬件准备

  1. 4路5V红板(光耦/高低电平)继电器 *1
  2. DHT11温度模块 *2
  3. 加热器 *1
  4. ESP32-WROOM-32开发板 *1

其他:

  1. 杜邦线
  2. 电烙铁
  3. 锡丝
  4. 松香
  5. 面包板

芯片模组比对选型

ESP32-WROOM-32X(此处 X 代表不确定) 和 ESP32-WROVER-X(此处 X 代表不确定) 在性能上基本一模一样,包括核心数、最大时钟频率、Flash大小、支持的接口类型 和 特殊传感器等等。除了在 PSRAM、工作温度范围、天线、WiFi最高频率 和 模组尺寸上有所区别外。 ESP32-WROVER-X 则具有PSRAM 和 最大的面积(18mm × 31.4mm × 3.3mm)。

官方展示的ESP32模组性能参数对比

芯片选型

无脑选了ESP32-WROOM-32SE,反正自己用,而且便宜(¥21.5包邮)。

芯片基本信息

Arduino所展示的开发板可调参数

Arduino IDE准备

使用 Arduino IDE 进行开发,但开发配置相关的 .json 文件 及其安装包都在 github.com 上,但因为加速器的加速层级可能和IDE拉取资源包所用的数据层级不在同一个上面,无法代理,就白天基本上无法下载,凌晨(正经程序员谁tm熬夜)才有机会下载东西。

英文版下的 首选项Preferences

修改附加开发板管理网址

然后去 开发板管理器 中搜索 esp32 进行安装。

目录-开发板-开发板管理器
搜索关键词“esp32”

解决github问题

方法一

本来应该用如下链接进行配置的:

1
https://dl.espressif.com/dl/package_esp32_index.json 

自己扒拉了一遍该文件中可能包含的所有资源包(主要是 github.com 上的),然后修改了 .json 文件,放到自己的桶里,然后放出来使用,还好这个文件里有明确提到要哪些资源不然也没法扒拉。

1
https://code.islet.space/espressif/dl/package_esp32_index.json

注意:Mac系统下可能会因为曾经下载过的缓存文件无法生效(如果自行修改了网站上的 .json 文件的话),需要自行清除缓存,打开 ~/Library/ArduinoXX/cache/ 并对应删除该网站的文件夹即可,如 code.islet.space 。(这里的 ArduinoXX 中的 XX 需要自己去看自己的文件夹,应该是受版本控制的)

修改链接后可以正常下载

方法二

自己去github,用浏览器或者下载器下好了以后放到 用户目录--资源库--程序缓存--指定位置(如下)。

1
~/Library/ArduinoXX/staging/packages/

这个文件夹也就需要放这么多文件吧。

资源库缓存指定位置下的文件

亲测,第二种方法更好用。

提示安装成功

Visual Studio Code IDE准备

总的来说,VS Code的IDE配置会比Arduino更为复杂,VS Code下载毫无压力,且VS Code使用习惯之后更加方便。

至少前期配置工作来说,VS Code更为友好。

Espressif IDF插件安装

首先去插件市场搜索 Espressif IDF 插件进行安装,然后点击 查看 -> 命令面板

image-20211228182209737

到这里需要输入 configure esp-idf extension 以进入该插件的配置页面。

image-20211228182314161

必要工具安装

然后它就会提示你需要安装几个必要插件,有 Git / Python / CMake 和 Ninja。这些都可以从Espressif的 官方文档 中获取到安装步骤。

image-20211228182508965

下方为四个工具的官方下载链接,前三个都可以通过官方下载软件包进行安装,第四个 Ninja 我安装不成功,是通过 Mac Ports 进行安装的。

GIT : https://git-scm.com/

PYTHON : https://www.python.org/downloads/

CMAKE : https://cmake.org/download/

NINJA : https://github.com/ninja-build/ninja/releases

需要注意的是,CMAKE 和 Ninja 安装完还需要加入到系统环境变量 PATH 中去,Windows系统下的系统环境变量添加比较方便,下方为 Mac 系统下 CMake 的系统环境变量添加方法。

CMAKE命令行

打开Mac系统下的 CMake GUI,点击 Tools --> How to Install For Command Line Use ,可以查看到三种将 CMake 添加到命令行中去运行的方法。

点击“工具”菜单中的“如何为命令行使用进行安装”
可以查看到三种安装方法

使用的是第二种方法,向命令行输入 sudo "/Applications/CMake.app/Contents/bin/cmake-gui" --install 并输入管理员密码即可。

然后通过 cmake --version 可以查看到版本号说明安装成功,但需要注意的是 whereis cmake 还是没有用。

操作结果

工具安装验证

四个必须要安装的软件都已经安装完毕,通过 --version 可以查看版本号。

安装验证

配置继续

四个必要工具安装完毕之后,关闭 ESP-IDF Setup 页面,然后重新在 命令面板 输入 configure esp-idf extension 以进入该插件的配置页面。

再次进入配置页面

此处选择 EXPRESS 即可,里面会要求选择从哪个服务器下载(自己看情况选择Github / Espressif)、IDF版本(默认选最新)、IDF放置路径、工具路径、使用的Python3路径 等几个信息,选完了就进入下一界面,会自动下载安装 ESP-IDF。

详细配置页面

耐心等待下载完毕即可,我用 Espressif 服务器下载不下来,然后改用 Github 进行下载的。

image-20211228185748221

下载过程页面如下:

image-20211228190058612
image-20211228190027057

最后提示的安装成功:

image-20211228190438498

示例项目载入

命令面板 中输入 show examples projects

image-20211228190651117

即可调出 ESP-IDF的示例代码项目列表。

image-20211228190738993

选择 blink 作为测试代码。

image-20211228190839371

项目构建

这里可以用命令面板输入 esp build your project ,也可以点击GUI下方的 image-20211231124940242进行构建。

命令面板构建

构建完成后,会生成 build 文件夹,下次构建时CMake会查看变动的文件然后只编译变动过的代码。

也可以删除该 build 文件夹,使其全部重新构建,会比较费时。

build过程

点击下方的闪电按钮烧录按钮即可烧录,烧录成功提示如下:

烧录过程

连接WiFi

下图为使用示例代码更改的项目代码文件内容:

项目文件内容示例

利用ESP自带的示例代码station 进行调试和更改,需要注意以下几点:

  1. 不用去更改 isletSpaceIotMain.c 中的 SSIDPASS ,只需要在 sdkconfig 文件中进行更改即可(如下图)。

  2. 所有的 WiFi设置参数 都可以在 sdkconfig 文件中进行修改,如需要连接 AP 的 名称和密码,还有自身设备所显示的名称。

  3. 修改文件名之后,需要对两个 CMakeList.txt文件 和 一个Makefile 文件中的项目和文件名进行修改(如下图)。

如果修改代码名称需要修改main文件夹下的CMakeList文件
如果修改项目名称需要修改根目录下的CMakeList
如果修改项目名称需要修改根目录下的Makefile

MENUCONFIG 或者说 sdkconfig ,一个是图形界面的,一个是纯文本形式的。

用menuconfig的话只需要找到下方的齿轮按钮即可。

image-20211231130402110

可以找到WiFi相关的配置位置:

image-20211231130507316

sdkconfig 文件中的设备名称进行修改。

image-20211228223040901

修改完毕后可以在路由器 AP 的后台查看到已经连接的设备的名称,如下。

image-20211228223134009

MQTT协议

根据 Espressif 官网的 ESP-MQTT 开发文档可知,MQTT 协议支持以下几种形式:

  • MQTT over TCP

  • MQTT over SSL with mbedtls

  • MQTT over Websocket

  • MQTT over Websocket Secure.

各MQTT协议形式(与对应SDK里的 MQTT示例代码)及其所使用的端口号不同:

  • protocols/mqtt/tcp: MQTT over tcp, default port 1883
  • protocols/mqtt/ssl: MQTT over tcp, default port 8883
  • protocols/mqtt/ssl_psk: MQTT over tcp using pre-shared keys for authentication, default port 8883
  • protocols/mqtt/ws: MQTT over Websocket, default port 80
  • protocols/mqtt/wss: MQTT over Websocket Secure, default port 443

MQTT事件结构体

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/**
* MQTT event configuration structure
*/
typedef struct {
esp_mqtt_event_id_t event_id; /*!< MQTT event type */
esp_mqtt_client_handle_t client; /*!< MQTT client handle for this event */
void *user_context; /*!< User context passed from MQTT client config */
char *data; /*!< Data associated with this event */
int data_len; /*!< Length of the data for this event */
int total_data_len; /*!< Total length of the data (longer data are supplied with multiple events) */
int current_data_offset; /*!< Actual offset for the data associated with this event */
char *topic; /*!< Topic associated with this event */
int topic_len; /*!< Length of the topic for this event associated with this event */
int msg_id; /*!< MQTT messaged id of message */
int session_present; /*!< MQTT session_present flag for connection event */
esp_mqtt_error_codes_t *error_handle; /*!< esp-mqtt error handle including esp-tls errors as well as internal mqtt errors */
bool retain; /*!< Retained flag of the message associated with this event */
} esp_mqtt_event_t;

typedef esp_mqtt_event_t *esp_mqtt_event_handle_t;

MQTT相关示例代码

了解完官方开发文档中的信息,就可以知道MQTT示例代码里的这些文件夹命名含义,以及自己需要打开哪个示例代码了。

image-20211228223617579

MENUCONFIG 页面可以看到MQTT的相关配置信息。

image-20211229011902429

MQTT服务器开发

自行购买了腾讯云的服务器,然后完成了配置(步骤略),发现自测“主题订阅”不成功。

image-20211229033019004

然后刚好发现服务器的 Ubuntu 20 系统使用的防火墙是 iptables ,顺利打开 1883 端口。

1
sudo iptables -A INPUT -p tcp --dport 1883 -j ACCEPT

然后查看打开情况。

image-20211229032825212

顺便在服务器页面也打开相关配置。

image-20211229032753559

最后自测成功:

image-20211229032920902
image-20211229032953396

小程序开发(未完)

因为个人使用腾讯云注册了自己的域名 islet.space,且小程序也属于腾讯自家产品,为了后续开发的兼容性和便利性,就同步参阅了腾讯云的 物联网自主品牌小程序开发文档

image-20211227202550338

微信开发者工具

微信开发者工具下载页面:https://cloud.tencent.com/document/product/1081/47685

image-20211227202759080
image-20211227203058077

后台设置

物联网开发平台

DEBUG

烧录和调试过程报错

出现这种情况,可能是所选芯片不正确导致。

烧录错误提示

解决过程

重新选择了芯片,然后将烧录方法改为 UART ,重新烧录即可成功。

在插件中选择”扩展设置“
选择需要调试的设备类型
选择烧录方式
烧录成功提示

头文件查找错误

这个bug始终没有解决,之后再说吧。。。

提示无该文件

WIFI初始化出错

将WiFi-station的代码搬到 MQTT-TCP中,发现 wifiStationInit() 函数初始化错误,报错的行数是 117

wifi初始化函数出错

经检查,发现该函数示例代码的一部分,并未改动,且未添加其他自定义的 .h.c 文件进行编译,应该不存在人为修改错误。

检查函数定义

因为仅修改了本 isletSpaceIotMain.c 文件,就在本文件中搜索 esp_event_loop_create_default 关键字,发现在 app_main() 中也有该语句,初步判断可能是两次调用导致错误,就注释了 298 行 和 299 行进行重新编译和烧录,问题解决,设备可以正常连接到路由器。

注释重复语句

MQTT服务器连接错误

在设备成功接入WiFi后,发现MQTT客户端无法连接至服务器。给出的错误提示是 There are no transports valid ,大致意思即连接不可用。

Monitor提示无可用传输

经过检查,发现原来填写在 sdkconfig 文件中的 Broker URL 链接为 https://iot.islet.space ,而实际上,官网给出的配置方式如下:

查看官方URI定义

打开项目配置菜单,修改为 mqtt://iot.islet.space ,并重新 Build 和 Flash。

修改URL

可以发现错误已解决,设备已经正常连接至服务器。

Monitor提示成功

尝试在对应主题下发布信息进行测试:

尝试发布信息

通过终端Monitor可以观察到,设备正常接收到数据:

设备接收成功

eventHandler未进入

image-20211229182911935

参考

  1. Mac 安装 CMake 配置及环境配置
  2. Quick User Guide for the ESP-IDF VS Code Extension
  3. ESP-IDF 编程指南
  4. ESP-MQTT

请先确保电脑上已经安装了必须的软件,如 node.jsgit ,因为日常需要使用 代码数学公式流程图搜索 等工具,所以下方的插件安装也主要是与此相关的。

注意:以下仅适用于 hexo-next 主题。

插件安装

先放一个博客 islet.space 需要使用到的插件,都需要使用 npm 进行安装。

本博客使用到的一些插件

将下方这段脚本保存至 hexo_install.sh 文件中,并使用 chmod +x hexo_install.sh 命令为其添加执行权限,并使用 ./hexo_install.sh 进行执行即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# uninstall the unnecessary renderer,like marked and kramed
sudo npm uninstall hexo-renderer-marked --save
sudo npm uninstall hexo-renderer-kramed --save


# install the necessary plugins for hexo
sudo npm install @fancyapps/fancybox --save
sudo npm install @fortawesome/fontawesome-free --save
sudo npm install @next-theme/pjax --save
sudo npm install @next-theme/plugins --save
sudo npm install hexo-deployer-git --save
sudo npm install hexo-filter-mermaid-diagrams --save
sudo npm install hexo-generator-searchdb --save
sudo npm install hexo-math --save
sudo npm install hexo-renderer-ejs --save
sudo npm install hexo-renderer-pandoc --save
sudo npm install hexo-renderer-stylus --save

插件启用

pandoc

若要启用pandoc进行渲染,除了之前必须要卸载旧的渲染器(如 markedkramed 外),还需要去github页面下载一个pandoc的渲染器软件并进行安装。

pandoc下载链接:https://github.com/jgm/pandoc/releases

mermaid

mermaid需要显示的话也需要安装插件,需要在hexo-next主题文件夹下的 _config.yml 文件中进行启用,如下:

mermaid在主题配置文件中的启用

latex

latex数学公式可以由 pandoc 渲染器进行渲染,只需要在hexo-next主题文件夹下的 _config.yml 文件中启用 mathjax ,如下:

数学公式在主题配置文件中的启用

搜索功能功能不仅需要安装插件,还需要分别在博客文件夹根目录中的 _config.yml 和 hexo-next主题文件夹下的 _config.yml 文件中进行启用,如下:

博客根目录配置文件下的启用

注意:此处的 db.json 需要在 public 文件夹中也有一份的时候启用;如果 db.json 无法使用,则更换为 search.xml 。因为 db.jsonsearch.xml 是由插件生成的搜索数据库(可以这么看)。

hexo主题配置文件下的启用

因为也是人力资源管理专业出身,所以基于面试者(员工)角度来写这篇文章的时候,其实是左右手互博的感觉。

特殊性说明,本文所描述的岗位背景其实是 嵌入式DSP裸机软件(驱动)开发

注意:下面标灰色的部分都是跟HR工作相关的概念,如果看不太懂可以跳过。

面试流程

技术类岗位招聘通常会遇到 2~3轮面试 和一次 HR提供Offer 的环节,最经典的流程如下:

graph LR
简历投送 --> ID1((HR面)) --> ID2((项目面)) --> ID3((技术面)) --> 拿Offer

面试原则

面试者需要在面试过程中适当包装和美化一下自己的工作经历,但是还是需要秉承着相对诚实的原则。

为什么说是相对诚实的原则

你可以说“自己的工作很难但按时完成”,“自己独立完成”,“自主编写代码” 等等他人较难去鉴别的工作,这些都是一个人工作能力不错的表现。但假如把自己没做过的项目放进去,一旦被问技术面的时候问到细节就会露馅。即使面试时没有露馅,工作时露馅了,大概率也会被面试官知道的。

一个HR有可能是在一家公司专门从事招聘的专员,也有可能是为多家公司做招聘的猎头(专门从事招聘工作的人员,通常是成立一个猎头公司,专门帮其他公司找人才)。一旦技术面的时候夸大自己的工作经验,技术面也会跟HR反馈你的夸大情况,然后你就再也不能通过该猎头或者专员找到其他的工作了,相当于自己白白损失了一个资源口。

而,嵌入式开发之类的技术岗位(目前)是绝对的版本答案之一,企业通过猎头找人才已经是常态,因此绝对不能有这种作死行为。

HR面

由专门/兼职做人力资源的工作人员负责,主要有以下流程:

  1. 说明招聘信息(包括所招聘的岗位的基本要求和职责、企业背景、团队情况和项目情况)
  2. 在职情况(千万不能说自己已经离职,否则你就会很掉价,因为HR会觉得你急于找到新工作而压低你的价格——对,就是你的薪酬,你的卖身一个月的价格,当然也有其他方法可以来试着压低你的薪酬,后面再谈)
  3. 询问面试者的离职原因(以判断该员工是否足够稳定,因为薪酬给的更高的员工其离职后给企业造成的离职成本会更高,因此需要该员工足够稳定,后面详谈如何回答离职原因)
  4. 询问面试者当前的工作内容(以确定该员工与所招聘岗位的匹配度,就是说,面试者目前的工作内容如果和他招聘的岗位的工作内容差异太大,他就不会想要再继续去问了,这点应该比较容易懂吧。当然,面试者也不能明明不匹配就瞎说自己会该工作技能,不然就是坑自己也坑别人,这里尽量坦白一些比较好)
  5. 询问面试者的求职意向及工作意愿(就是会问面试者是否愿意从事本岗,一般到这里如果没有回答“愿意”,都没得聊了)
  6. 询问面试者期待的薪资及目前薪资(这一点在招聘网站看可以看到该企业所招聘的岗位能提供的薪资范围,通常也就是个薪酬区间,后面详谈如何回答这部分内容。询问目前薪资就是来确定你的人力成本,进而探寻能够压缩你人力成本空间的可能性的。)
  7. 约定下一步面试时间(这一点应该没什么好说,通常都是电话技术面或视频技术面,确认好双方有空闲的时间)
  8. 其他(会问是不是符合一些硬性条件,比如统招本科(就是学信网能够查到本科学历信息),毕业时间等等)

如何回答离职原因

这一部分看似回答很简单,其实会藏着很多坑。

首先,要明白为什么需要HR面,为什么面试第一个打来的都是HR,而不是技术员工直接打过来。

从企业运行的角度考虑,每一时刻的企业运作都是需要运行成本的,包括场地成本、设备成本(采购、折旧、损耗等等)、物料成本、人力成本(招聘成本、培训成本、薪酬成本等)等等,就特别多,专人专事这个大家都能理解。

如果一个员工匆忙从一家企业离职,该员工入职前的招聘成本、入职时的培训成本和所需要支付的薪酬成本就会拜拜支出,不能给企业带来盈利,但企业在招聘一个员工前后所支出的成本又是实实在在支出了的,就会造成巨大损失(绿厂就不是,就完全不担心这一点,因为给的太少了(通俗点就是成本不高),打着500强名号,韭菜一茬一茬就随便割,又不会特地挽留员工离职,而且全公司现状都是培训工作做得差,成本就不高)。

(个人觉得)企业当然不能实现所有人终身雇佣,没有新鲜血液是不行的,一定比例的人员流动可以给企业带来活力(这个原因我就不必讲了吧)。HR是学过这些东西的,需要站在企业角度去帮企业考虑招聘什么样子的人会让企业更加稳定,人员稳定(流失减少,并控制在一定范围内)就能帮助企业降低运行成本。

因此,面试者需要体现出自己的稳定性,证明自己是一个不太会轻易离职的人,并说明是一些客观的因素(并不是自己的原因)造成了面试者的离职。当然,面试者自己在一家企业就业时,也不应该轻易离职,如果是高校毕业者,最好在第一家企业从事1年及以上再离职(建议!)。以下列举了几个较为客观(不能说绝对客观)的原因:

  • 办公室氛围太过压抑,缺少团队活动
  • 团队协作性太差
  • 领导风格太过压迫和强势

一些员工的主观原因(或者说是令HR反感的原因),这些话是绝对不能说的,绝对禁区!

  • 自己不喜欢目前的工作
  • 工作太难了

一些员工可以说的话:

  • 自己不太挑工作,比较看重团队氛围和工作环境(一般有自信点的HR都会觉得这点没问题,“不太挑工作”的前提是,也得是自己觉得对口的才行,别不对口你不挑个啥。比如,做MCU/ARM/SOC/DSP的相通性较高,说自己不挑可以,但是跨行业太大也敢说自己不挑那就是找事儿)(另,不太挑工作其实对HR来说是个好品质,但自己也得好好掂量掂量自己)

如何回答目前薪资及期望薪资

HR之所以需要问你的目前薪资,不仅是了解本行业或者某个岗位在某个地区的大致薪酬情况(以对比公司招聘员工的薪酬竞争优势),也是在探寻面试者的薪酬上涨或可以压缩的空间。

面试者首先需要了解(或者说准备好)几点信息:

  1. 该行业该岗位在某个地区的 普遍薪资范围 是如何(当然不能拿最高薪资来当做普遍薪资,得看自己的能力和对应岗位的工作难度)
  2. 所面试的公司提供的薪酬范围
  3. 自己所期待的薪资底线
  4. 自己目前薪资

首先是,如果HR问目前薪资。面试者可以适当夸大自己目前的薪资,税后薪资可能都很低,可以说税前,多说几千没关系,不要与对方公司提供的薪酬底线相差太大即可。如果HR说自己公司有30%或者40%的涨薪幅度限制,那么可以放心,该HR觉得你岗位匹配度较高,只是想通过这个来压一压你的成本而已。

此时,你可以说自己期待在某个地区某个岗位的薪酬底线,低于这个就不行。HR态度一般都会更为委婉些。

如果你通过面试,到了拿offer的环节,HR还是会再跟你谈一遍。豪气的公司(一种薪酬策略,用高于行业平均水平的薪资招聘员工,但也要求更高)一般开价都会比你要求的更高,但这是后面的事情了。

HR面结束之后

(如果你对HR提供的岗位较为满意,接收了技术面/项目面的预约)需要记住一些最基础、关键、有用的信息。这些HR面时都已经说明了,最好是拿个小本本记好,这是对面试企业的一个尊重,也是为了防止后面出现的一些莫名其妙的(跟你面试岗位无关的)问题把你问倒。

  1. 岗位工作地点(很多大企业全国都有研究中心和技术中心,可以选择的,看对方给你提供的是哪个城市的就业岗位)
  2. 对方面试官的名字(至少记住姓啥)
  3. 对方的公司名称及背景(比如是帮别人做外包的还是做自研的,有没有上市或者有没有股权激励,成立多久了之类的)
  4. 岗位基本信息 (任职要求和工作职责等)

项目面和技术面

普遍情况下,二轮/三轮面试都会问你一些技术和项目上的东西,根据所闻内容的不同,将其分别称呼为 技术面项目面

有些公司会将这两轮分开,面试的先后顺序不一,总得占比是项目经历会问得更多一些,技术面的占比较少。

有些公司也会将项目面和技术面合在一起(就是同一次面试里就有技术面和项目面),夹杂交替着问。

项目面

主要是问你从事(主要负责或者协助负责)过的一些项目/经历,了解你对研发的产品、芯片、硬件、软件、工具、设备的认知。项目面会有三种类型的提问:

  1. 工具认知提问。了解面试者对工具使用的经验。
  2. 问题解决提问。了解面试者对一些解决问题的方法和经历。
  3. 情景假设提问。考验面试者解决问题的思路。

项目面的面试形式:一般都是电话提问和视频提问。

面试时长:单轮面试时间都是在15分钟以上,最长30分钟左右。

工具认知提问

就是会问你开发过程中遇到的一些工具模块是如何使用的,一些算法或者逻辑的原理。这部分比较简单,都是经验而已。

例如,面试官问我ADC的使用,我就如实回答我是如何用ADC的,以及我对ADC模块的认知。

问题解决提问

有很大概率(不一定是所有公司都会问的),会问你一些“发现问题解决问题”的经验。这里面试官主要是想知道以下几点情况:

  1. 面试者对工作问题的解决思路。是否足够清晰,有什么角度可以去考虑,需要面试者自己去总结,然后可以清晰地向他人阐述。
  2. 面试者在解决问题时的耐心。面试者需要介绍一个以上的案例,向面试官说明问题现象,自己的思考方式、检查方法、解决方法、过程 和 结果 等等。
  3. 面试者的经验。你能说出自己在遇到一些问题(比如调试问题)时的解决思路,或者看待问题(较为全面)的角度时,就说明了你已经具有足够经验了。

如果面试官问你“发现问题解决问题”的经验,你回答自己不知道,不太记得,忘记了这些话,就妥妥失败了。

因为这些工作问题的发现、解决和记录工作,在日常工作过程中其实都是可以稍微花点时间去完成的(这并不难,只是你有没有耐心而已),如果面试者自己没有做这部分 经验积累工作,那就很吃亏,大部分人都有相关的工作经验,自己不会去 总结 而已。

情景假设提问

面试官可能会抛出情景题,例如问你给你一个芯片,2周之内完成开发,你需要怎么准备,有什么计划。其实就是一个经验问题,或者思路问题。回答方法我就不详细说了。

技术面

技术面,就是会问一些项目之下的一些底层技术问题,一般来说都不会太难,也偶尔会有一些面试官问的问题比较偏门(开发过程中较难出现的问题)。例如,我经历过的偏门提问,会问C语言的野指针出现和排查,C++的继承概念等等(这些是我项目上比较难涉及到的)。

但大部分情况下,这些技术提问,都是提问一些你做过的东西,比如你做过某种通信协议的开发,请你表述以下该协议的相关内容(例如,时序、通信格式(通信起始和结束的变化)、电气特性(电平、电压范围)等)。这些其实也是经验的一部分,真的做过的话就应该自己做做笔记,一定会有点印象的,不应该去抱佛脚。

面试原则:问到你会的,你就自信回答。问到偏门的,开发过程中较少出现/遇到和使用的,你就如实回答就好了,不要不懂装懂。

技术面的面试形式:可能是让你线上答卷,现场答卷,也可以是电话提问、视频提问。

面试时长:同项目面,也可能夹杂着在项目面中间进行提问。

拿Offer

拿到Offer后,你可能需要向HR详细确认的信息:

  1. 每天上班时间,从几点到几点
  2. 每个月的薪资计算时间是从几号到几号
  3. 每个月的薪资发放日期、时间
  4. 是否双休、年假情况
  5. 每天的加班强度、每个月的加班强度、加班薪资等
  6. 每年发放多少个月的薪资(就是年终奖发放情况,好一点的是15薪以上,最基本的13薪)
  7. 每个(税前)月薪资是多少(可能需要关心一下社保和公积金的缴纳情况等)

基本信息了解完毕之后,需要自己有意识地去提问的一些问题:

  1. 近期可以签订合同的最晚时间(合同期限一般都是3年,这个就比较不用担心)
  2. 期望入职时间(自己期望什么时候入职,对方期望最晚什么时候入职,可否协调程度)
  3. 涨薪计划(入职后会有哪些涨薪激励计划,或之前其他股权发放啊、年终奖增长等等)
  4. 绩效计划(可能这时候不太愿意说,但是入职后可以去了解)