0%

blog.csdn.net

简介

每一个程序至少拥有一个线程,那就是执行 main() 函数的主线程,而多线程则是出现两个或两个以上的线程并行运行,即主线程和子线程在同一时间段同时运行。而在这个过程中会出现几种情况:

  1. 主线程先运行结束
  2. 子线程先运行结束
  3. 主子线程同时结束

在一些情况下需要在子线程结束后主线程才能结束,而一些情况则不需要等待,但需注意一点,并不是主线程结束了其他子线程就立即停止,其他子线程会进入后台运行

join()

join()函数是一个等待线程完成函数,主线程需要等待子线程运行结束了才可以结束

image-20210531223156398

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <iostream>
#include <thread>

using namespace std;

void func()
{
for(int i = -10; i > -20; i--)
{
cout << "from func():" << i << endl;
}
}

int main() //主线程
{
cout << "mian()" << endl;
cout << "mian()" << endl;
cout << "mian()" << endl;
thread t(func); //子线程
t.join(); //等待子线程结束后才进入主线程
return 0;
}
在这里插入图片描述
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <iostream>
#include <thread>

using namespace std;

void func()
{
for(int i = -10; i > -20; i--)
{
cout << "from func():" << i << endl;
}
}

int main() //主线程
{
thread t(func); //子线程
cout << "mian()" << endl;
cout << "mian()" << endl;
cout << "mian()" << endl;
t.join(); //等待子线程结束后才进入主线程
return 0;
}
在这里插入图片描述
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <iostream>
#include <thread>

using namespace std;

void func()
{
for(int i = -10; i > -20; i--)
{
cout << "from func():" << i << endl;
}
}

int main() //主线程
{
thread t(func); //子线程
t.join(); //等待子线程结束后才进入主线程
cout << "mian()" << endl;
cout << "mian()" << endl;
cout << "mian()" << endl;
return 0;
}
在这里插入图片描述

detach()

image-20210601222337419
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <iostream>
#include <thread>

using namespace std;

void func()
{
for(int i = -10; i > -20; i--)
{
cout << "from func():" << i << endl;
}
}

int main() //主线程
{
cout << "mian()" << endl;
cout << "mian()" << endl;
cout << "mian()" << endl;
thread t(func); //子线程
t.detach(); //分离子线程
return 0;
}
在这里插入图片描述

可以明显看到,主线程太快了,还没等子线程运行就结束了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <iostream>
#include <thread>

using namespace std;

void func()
{
for(int i = -10; i > -20; i--)
{
cout << "from func():" << i << endl;
}
}

int main() //主线程
{
thread t(func); //子线程
cout << "mian()" << endl;
cout << "mian()" << endl;
cout << "mian()" << endl;
t.detach(); //分离子线程
return 0;
}
在这里插入图片描述

同样没等子线程运行完就结束了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <iostream>
#include <thread>

using namespace std;

void func()
{
for(int i = -10; i > -20; i--)
{
cout << "from func():" << i << endl;
}
}

int main() //主线程
{
thread t(func); //子线程
cout << "mian()" << endl;
cout << "mian()" << endl;
cout << "mian()" << endl;
t.detach(); //分离子线程
return 0;
}
在这里插入图片描述

没等子线程运行完就结束

总结

  • 如果想要分离一个线程,可以在线程启动后,直接使用 detach() 进行分离。如果打算等待对应线程,则需要细心挑选调用 join() 的位置。当在线程运行之后产生异常,在 join() 调用之前抛出,就意味着很这次调用会被跳过。

  • join() 函数是一个等待线程函数,主线程需等待子线程运行结束后才可以结束(注意不是才可以运行,运行是并行的),如果打算等待对应线程,则需要细心挑选调用 join() 的位置

  • detach() 函数是子线程的分离函数,当调用该函数后,线程就被分离到后台运行,主线程不需要等待该线程结束才结束

c.biancheng.net

编译注意

注意:在clang上使用lambda表达式时可能会报错,编译时需要添加option -std=c++11

This is because clang++ by default compiles your code using ISO C++ 1998 standard (including the defects addressed in the ISO C++ 2003 standard) except for 'export' (which has been removed in C++11)

Lambdas are part of Clang's C++11 Language Extension, therefore you need to compile your code with -std=c++11 or -std=gnu++11

——STACKOVERFLOW

Lambda介绍

lambda 表达式是 C++11 最重要也最常用的一个特性之一,C# 3.5 和 Java 8 中就引入了 lambda 表达式。

lambda 来源于 函数式编程 的概念,也是现代编程语言的一个特点。C++11 这次终于把 lambda 加进来了。

lambda表达式有如下优点:

  • 声明式编程风格:就地匿名定义目标函数或函数对象,不需要额外写一个命名函数或者函数对象。以更直接的方式去写程序,好的可读性和可维护性。
  • 简洁:不需要额外再写一个函数或者函数对象,避免了代码膨胀和功能分散,让开发者更加集中精力在手边的问题,同时也获取了更高的生产率。
  • 在需要的时间和地点实现功能闭包,使程序更灵活。

下面,先从 lambda 表达式的基本功能开始介绍它。

Lambda 表达式的概念和基本用法

lambda 表达式定义了一个 匿名函数,并且可以 捕获一定范围内的变量。lambda 表达式的语法形式可简单归纳如下:

[ capture ] ( params ) opt -> ret { body; };

  • capture 是捕获列表
  • params 是参数表
  • opt 是函数选项
  • ret 是返回值类型
  • body是函数体。

因此,一个完整的 lambda 表达式看起来像这样:

1
auto f = [](int a) -> int { return a + 1; };std::cout << f(1) << std::endl;  

可以看到,上面通过一行代码定义了一个小小的功能闭包,用来将输入加 1 并返回。

在 C++11 中,lambda 表达式的返回值是通过前面介绍的《C++返回值类型后置》语法来定义的。

其实很多时候,lambda 表达式的返回值是非常明显的,比如这个例子。因此,C++11 中允许省略 lambda 表达式的返回值定义:

1
auto f = [](int a){ return a + 1; };

这样编译器就会根据 return 语句自动推导出返回值类型。

需要注意的是,初始化列表不能用于返回值的自动推导:

1
2
auto x1 = [](int i){ return i; }; // OK: return type is int
auto x2 = [](){ return { 1, 2 }; }; // error: 无法推导出返回值类型

这时我们需要显式给出具体的返回值类型。

另外,lambda 表达式在没有参数列表时,参数列表是可以省略的。因此像下面的写法都是正确的:

1
2
auto f1 = [](){ return 1; };
auto f2 = []{ return 1; }; // 省略空参数表

捕获列表

lambda 表达式还可以通过捕获列表捕获一定范围内的变量:

  • [] 不捕获任何变量。
  • [&] 捕获外部作用域中所有变量,并作为引用在函数体中使用(按引用捕获)。
  • [=] 捕获外部作用域中所有变量,并作为副本在函数体中使用(按值捕获)。
  • [=,&foo] 按值捕获外部作用域中所有变量,并按引用捕获 foo 变量。
  • [bar] 按值捕获 bar 变量,同时不捕获其他变量。
  • [this] 捕获当前类中的 this 指针,让 lambda 表达式拥有和当前类成员函数同样的访问权限。如果已经使用了 & 或者 =,就默认添加此选项。捕获 this 的目的是可以在 lamda 中使用当前类的成员函数和成员变量。

下面看一下它的具体用法,如下所示。

【实例】lambda 表达式的基本用法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class A{    
public:
int i_ = 0;
void func(int x, int y){
auto x1 = []{ return i_; };
auto x2 = [=]{ return i_ + x + y; };
auto x3 = [&]{ return i_ + x + y; };
auto x4 = [this]{ return i_; };
auto x5 = [this]{ return i_ + x + y; };
auto x6 = [this, x, y]{ return i_ + x + y; };
auto x7 = [this]{ return i_++; };
}
};

int a = 0, b = 1;
auto f1 = []{ return a; };
auto f2 = [&]{ return a++; };
auto f3 = [=]{ return a; };
auto f4 = [=]{ return a++; };
auto f5 = [a]{ return a + b; };
auto f6 = [a, &b]{ return a + (b++); };
auto f7 = [=, &b]{ return a + (b++); };

从上例中可以看到,lambda 表达式的捕获列表精细地控制了 lambda 表达式能够访问的外部变量,以及如何访问这些变量。

注意:默认状态下 lambda 表达式无法修改通过复制方式捕获的外部变量。如果希望修改这些变量的话,我们需要使用引用方式进行捕获。

一个容易出错的细节是关于 lambda 表达式的延迟调用的:

1
2
3
4
int a = 0;
auto f = [=]{ return a; };
a += 1;
std::cout << f() << std::endl;

在这个例子中,lambda 表达式按值捕获了所有外部变量。在捕获的一瞬间,a 的值就已经被复制到f中了。之后 a 被修改,但此时 f 中存储的 a 仍然还是捕获时的值,因此,最终输出结果是 0。

如果希望 lambda 表达式在调用时能够即时访问外部变量,我们应当使用引用方式捕获。

从上面的例子中我们知道,按值捕获得到的外部变量值是在 lambda 表达式定义时的值。此时所有外部变量均被复制了一份存储在 lambda 表达式变量中。此时虽然修改 lambda 表达式中的这些外部变量并不会真正影响到外部,我们却仍然无法修改它们。

那么如果希望去修改按值捕获的外部变量应当怎么办呢?这时,需要显式指明 lambda 表达式为 mutable:

1
2
3
int a = 0;
auto f1 = [=]{ return a++; };
auto f2 = [=]() mutable { return a++; };

需要注意的一点是,被 mutable 修饰的 lambda 表达式就算没有参数也要写明参数列表。

Lambda 表达式的类型

最后,介绍一下 lambda 表达式的类型。

lambda 表达式的类型在 C++11 中被称为“闭包类型(Closure Type)”。它是一个特殊的,匿名的非 nunion 的类类型。

因此,我们可以认为它是一个带有 operator() 的类,即仿函数。因此,我们可以使用 std::function 和 std::bind 来存储和操作 lambda 表达式:

1
std::function<int(int)>  f1 = [](int a){ return a; };std::function<int(void)> f2 = std::bind([](int a){ return a; }, 123);

另外,对于没有捕获任何变量的 lambda 表达式,还可以被转换成一个普通的函数指针:

1
2
3
using func_t = int(*)(int);
func_t f = [](int a){ return a; };
f(123);

lambda 表达式可以说是就地定义仿函数闭包的“语法糖”。它的捕获列表捕获住的任何外部变量,最终均会变为闭包类型的成员变量。而一个使用了成员变量的类的 operator(),如果能直接被转换为普通的函数指针,那么 lambda 表达式本身的 this 指针就丢失掉了。而没有捕获任何外部变量的 lambda 表达式则不存在这个问题。

这里也可以很自然地解释为何按值捕获无法修改捕获的外部变量。因为按照 C++ 标准,lambda 表达式的 operator() 默认是 const 的。一个 const 成员函数是无法修改成员变量的值的。而 mutable 的作用,就在于取消 operator() 的 const。

需要注意的是,没有捕获变量的 lambda 表达式可以直接转换为函数指针,而捕获变量的 lambda 表达式则不能转换为函数指针。看看下面的代码:

1
2
3
typedef void(*Ptr)(int*);
Ptr p = [](int* p){delete p;};
Ptr p1 = [&](int* p){delete p;};

上面第二行代码能编译通过,而第三行代码不能编译通过,因为第三行的代码捕获了变量,不能直接转换为函数指针。

声明式的编程风格,简洁的代码

就地定义匿名函数,不再需要定义函数对象,大大简化了标准库算法的调用。比如,在 C++11 之前,我们要调用 for_each 函数将 vector 中的偶数打印出来,如下所示。

【实例】lambda 表达式代替函数对象的示例。

1
2
3
4
5
class CountEven{    
int& count_;public:
CountEven(int& count) : count_(count) {} void operator()(int val) { if (!(val & 1)) { ++ count_; } }};
std::vector<int> v = { 1, 2, 3, 4, 5, 6 };
int even_count = 0;for_each(v.begin(), v.end(), CountEven(even_count));std::cout << "The number of even is " << even_count << std::endl;

这样写既烦琐又容易出错。有了 lambda 表达式以后,我们可以使用真正的闭包概念来替换掉这里的仿函数,代码如下:

1
2
3
4
std::vector<int> v = { 1, 2, 3, 4, 5, 6 };
int even_count = 0;
for_each( v.begin(), v.end(), [&even_count](int val) { if (!(val & 1)) { ++ even_count; } });
std::cout << "The number of even is " << even_count << std::endl;

lambda 表达式的价值在于,就地封装短小的功能闭包,可以极其方便地表达出我们希望执行的具体操作,并让上下文结合得更加紧密。

线程创建

C++中对线程的创建都需要使用到库函数 <thread> ,但是线程的启动和使用可以通过 函数带有函数调用操作符的类实例 来进行。

函数式启动

函数名启动

无论是从何处启用多线程,都需要从C++线程库 <thread> 来开始一个线程,通过构造一个 std::thread 对象来启动,以下为最常见的线程创建方法:

1
2
void threadHello(void);
std::thread thread1(threadHello);

threadHello() 就是需要执行线程的函数;

std::thread 就是创建线程对象的类型;

thread1 就是被创造的线程对象,而 () 中则填写着被这个对象调用的函数。

函数启动

不同于通过函数名启动,函数启动时会带上其括号 () , 多个线程可被同时被一个线程对象启动。

式1:

1
std::thread my_thread((background_task()));

其中,通过第二层外层 () 将函数及其 () 括起来避免被解释为函数声明,即 my_thread( ( f() ) )

式2:

1
std::thread my_thread{ background_task() };

通过将 background() 包括在 {} 中,同样是将 background() 声明为一个变量的方法。

Lambda表达式

lambda表达式是在C++11以后的新特性。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
```







## 类实例启动

`std::thread` 可以与任何 可调用(callable)类型一同工作,因此可以将一个带有函数调用操作符的类的实例传递给 `std::thread` 的构造函数来进行代替。

```c++
class background_task{
public:
void operator()() const{ //带有函数调用操作符
do_something();
do_something_else();
}
};

background_task threadF; //类实例

std::thread thread1(threadF); //线程调用该类实例

这种情况下,所提供的函数对象被赋值(copied)到属于新创建的执行线程的存储器中,并从那里调用。因此,副本与原版有着灯箱的行为,否则结果可能与预期不符。

函数调用操作符

1
2
3
4
5
struct AA{
void operator()(){
cout<<"aa";
}
}

AA()() 中,AA() 是构造函数,调用了() 操作符。

Core/Shell

首先,要理解Core / shell的概念,系统内核一般被称之为core,而unix及类unix(即与unix类似)系统(如linux)都继承了这一概念,都有其内核。

古早时期,都是一台电脑就是一台服务器,为了提高服务器的利用率,大家都在用很多客户端登录系统,系统分时(电脑高效处理任务,看起来像是同时进行,其实还是存在先后顺序的)为许多客户端提供服务,即“一点对多点”式的服务模式,客户端都通过小黑窗进行操作。

如今,独立PC都已经没了服务器这一概念,一台设备就只为一个客户服务(单点对单点),但是这个小黑窗的高效操作的理念却被保留了下来。

因为所有的客户端对主机的使用都没有进入到内核层面,仅仅停留在表面,所以这种小黑窗的操作层被称为shell层,即外壳。

逐渐衍生了终端的概念,即客户端即用户终端,即terminal;现在shell、terminal、command-line(命令行)这几个概念都可以被视为同一个概念。

但shell的流行,逐渐衍生除了很多个人制作的版本,流行的有bash shell、zsh等。

目录操作

cd

1
cd zplusplus

即Change directory,改变目录

类unix中没有路径这个概念,只有目录。

  • ~ 主目录,个人目录

  • / 根目录,硬盘目录

TIPS:

  • tabs键可以快速补全相符的目录名称

cd ../可以返回上一层文件目录

image-20210528002003445

mkdir

1
mkdir zplusplus

即make directory,创建目录

image-20210528001730316

mv

1
mv zplusplus

即move,移动或删除

  • -f force 强制

也可以用来改名,用法如下:

1
mv main.c test.c

其他类似的语句如 rm,可以参考手册

ls

1
ls

即List,(展现)列表

这个命令非常好用,学会了就基本忘不了,各别shell能够提供不同的色彩显示,对于文档类型识别来说非常高效。

image-20210528001701289

文件编辑

vim

1
vim main.c

注意:如果已经存在了main.c 他就不会新生成一个,否则就会新建。

操作方法

  1. 刚进去的时候需要按 i 进行插入(insert)操作
  2. 编辑完毕之后需要先按 ESC 键,在依次输入 : 及其他指令进行退出,具体参考下方,可以看手册。

: instructor 指令输入

w wirte

q quit

! 强制

编辑界面如下

image-20210528002252175

科普视频

自行科普:GUI,Graphic User Interface 图形用户界面

代码运行

gcc

1
gcc main.c 

GNU下的GCC编译器之一,c的编译器是gcc,c++的编译器是g++

  • -o main 参数
image-20210528002708689

编译完成之后使用 ls 可以查看已生成的文件 a.out(默认命名)。

image-20210528002757152

这个 a.out 文件是CPU能够直接识别和运行的文件,因此直接使用以下代码运行即可。

1
./a.out

运行效果如下:

image-20210528002900901

遇到问题可以再进行调试。

对GNU和开源的概念可以参考下方视频:

收藏转载自:zhuanlan.zhihu.com

前言

本篇还是USB-C 转接器指南贴,由于硬件上的不同,后续还会有一篇雷电专用的指南作为区分

这篇内容其实在2016年的时候就有写的意向了(笑),当时12寸 Macbook 刚推出,Macbook Pro 也刚更新为全Type-C模具。

当时对先进转接器需求最强烈的其实还是12英寸的用户,由于12英寸Macbook 只搭载了一个Type-C,还不是雷电(是的,Mac全系列唯一有Type-C却不是雷电的机型),导致接口丰富兼顾充电的雷电Dock产品无法正常使用,造成了外设和充电你死我活的尴尬境地

所幸戴尔WD15的推出缓解了这个尴尬局面,然而17年之后Macbook 产品线再次被放弃,于此同时市面上类似的单Type-C 模具笔记本极为稀少,后继的Macbook Pro和 Macbook Air 都可以通过 PD充电+DA300的方式满足便携扩展需求,因此 放弃了在便携扩展器领域的进一步探索

然而有趣的是从17年到20年,居然没有一个便携转接器能够在功能参数上全面追赶DA300,甚至有某品牌转接器烧毁Macbook 接口的负面新闻广为流传,抽了闲暇时间做了一定程度的调查,借此机会把目光重新放回了转接器领域

这篇文章依然会是按照我先前的风格,从IC层面对市面上绝大部分的产品进行分类和归纳,从IC层面做出指南

不会对具体的产品进行推荐,适合自己的才是最好的,没空一一了解消费能力和理念,请见谅

本文长达近 一万七千字,由于转接器硬件需求复杂,建议还是通读

目录

img

总结与指南

总的来说转接器产品有两大特点不同于 朴素认知

  • 作为转接器的核心部件PD控制器并不影响转接器的主要功能(视频转换和USB、扩展)
  • 转接器接口多寡并不和其 成本 呈正相关 (原本可以给的接口会被阉割,市场内的常见手段),将多种接口整合变少才是本事(就像你用来扩展的Type C口)

因此通过接口多寡来计算性价比(价格/接口)基本只能陷入坑货泥潭

下图是目前常见的 支持 DP Alt Mode的控制器总结,由于PD控制器门槛不高,陆续会有MCU厂家涉足该领域,但和主流硬件选用相比不足为提。

img

此外 新款芯片一般至少需要一年的周期才能真正被采用到新产品里面,因此盲目追新 方案大可不必


  • 推荐

尽管各头部厂商 由于历史原因或者其他的一些因素多少都有一些坑货,而下面的白莲花制造商也少之又少,即使是 Belkin 也能找出一些 智商税产品

但是原则上依然推荐 HP,Dell,苹果,微软的新品转接器,这些厂子的转接器不分高端低端,出手即是代表性产品,但也导致开发成本以及最终价格极高

这些头部厂商的产品也会有一个共性的缺点就是不会在自己的产品上集成读卡器功能

其余的,功能和做工就拉不开多少差距了,很难说有完美的,各方面都做的很优秀的产品

总结一下本文提到的带有拆解文章的产品,转接器功能需求复杂,产品或多或少存有不足,仅作参考,长期更新

依然不建议依赖该表,建议通读

img

  • 排雷

这个市场内显著的坑货有两大类

一类是长得像 Belkin 的 非Belkin 产品

img
img

这类产品一般都是VIA 的VL100系公模产品, 本来做的像样的也有,比如在我的专栏中拆过的Satechi

但由于对压缩成本的追求,VIA的公版设计被无限压缩,导致市面上一大批的公模VIA产品坑点奇多,下面的雷至少踩两个:

  • 质劣价高(物料成本20块左右,直接抄公版设计无需研发成本,防护全无的扩展坞可以卖到150以上,200,300 也是常见)
  • 供电稀烂,带不动一块移动机械硬盘的读写耗电
  • 屏蔽基本无,是一个巨大的2.4Ghz污染源,干扰附近的蓝牙,WIFI设备的正常工作
  • 工厂品控稀烂

涉及品牌包括 绿联,Orico,飞利浦(转接器业务已经被别家收购),Unitek,倍思

国内能叫的上名字的配件厂几乎全部中枪,同样是 VL100系主控,没一家的做工和防护能比得上Satechi(苹果合作款)

img
img

另一类是长得像苹果的非苹果产品

img

这类产品同样有VIA 阵营的VL100系产品牵涉其中

但在低端攻城掠地的 龙讯LT8711H ,安格 AG9321 同样也籍由这样的外型活得滋润(物料成本估计 10块左右,售价一般在30,40元水平)

此外 Fresco 的 FL5002 公版设计也是籍由这种 外形活得滋润,例如 小米ZJQ01TM[1] ,联想也是[2],尽管TVS防护尚可,但是绝对不会装配 屏蔽罩,另外FL5002 发热较大

还有一类较隐蔽坑货就是自己做标致的外壳,内藏稀烂的硬件

外形就请自行想象了,以下三款图内PCBA的售价都在10元内

img
img
img

Q&A扫盲

Q:为什么转接器标明的可以支持4K 60Hz显示输出,我买了以后不管怎么鼓捣都只能4K 30Hz?

A:这类问题基本是由于转接器 在DP1.4下支持4K 60Hz,在DP1.2 下支持到4K 30Hz,你的Type-C接口只支持到DP1.2 造成了跟描述不同的问题,下文会有详细的原理说明和计算来解释原理和区别

Q:为什么我的转接器插上东西之后,WIFI/蓝牙/无线接收器就卡的不行?

A:老生常谈的问题,由于转接器的电磁屏蔽差劲,导致USB3.0工作时辐射出来的2.4GHz 射频信号[3]干扰了处于相近频段的无线设备,2.4GHz WIFI,蓝牙,无线接收器都处于这一频道;总之建议更换配件一劳永逸;凑合的办法是用金属箔包住转接器可以减少干扰

Q:这些USB转接器不是都从USB转接而来的吗?据我所知USB3.0只有5Gbps速度,怎么做到输出4K@60Hz的?

A:那种纯靠USB转接视频输出的应用叫做Display Link,已经是比较有年岁的技术了。本篇涉及的主要技术是所谓的 Display Alt Mode,是将DP 信号直接跟USB一起塞到了 Type-C接口里,二者井水不犯河水。DP Alt Mode 借助 Power Delivery 报文[4]来对Type-C 接口进行具体的配置,平常时Type-C只是一个普通的USB接口,链接特殊的配件可以把 ”可选模式“唤醒, 即 ”Alternative Mode“ ,从而在Type-C中直接引入DP信号输出视频,而不是通过USB转接

Q:为什么要将USB-C 和雷电的转接器做区分呢,二者有什么区别?

A:雷电转接器仅能配合雷电接口正常工作,设备会印有雷电logo,而多功能 USB-C 适配范围要广泛的多,除了雷电接口以外,常规计算机搭载的 多功能Type-C 不仅在Windows或者Mac OS,在Chrome OS, Ubuntu, RHEL 8都能使用,甚至 苹果 安卓阵营的移动平台(比如iPad Pro 以及 一加7 Pro,三星S7手机等)以及 Switch(注意兼容稀烂),都可以使用相同的硬件设计来完成转接任务

目前最先进的单口Type-C 方案可以支持 单 8K@30Hz或者双4K@60Hz 输出,尽管比 JHL7440雷电方案 的40Gbps 输出能力还是逊色,但是满足日常的使用需求已经完全不成问题,因此这里先从 USB-C转接器进行归类介绍

Q:是否能传输视频信号能充电的Type-C接口就是多功能Type-C?

A:本文的多功能Type-C指狭义的,支持DP Alt Mode 的Type-C 接口(下文会有进阶介绍),包括雷电3雷电4接口也支持这个技术,本文介绍的所有配件都可以在雷电接口上使用。

然而这里有几个盲区,1.除了DP Alt Mode,HDMI Alt Mode[5]在技术层面上也是存在的,然而没有厂商支持该模式 。 2. 如上文提到过的Display Link 技术可以在通过常规的USB接口(无论Type-A,Type-B,Type-C)传输视频信号,但是需要额外的驱动,在Windows,Mac OS,Linux,Chrome OS,以及Android 都有广泛的支持,比如目前比较热门的VR头显 Oculus Quest2 用的串流技术即是 Display Link而非高端设备采用的 Alt Mode USB。

此外还有MHL技术以及支持MHL技术的 Alt Mode也可以通过USB 物理接口直接传输视频信号,但基本限于手机应用,而 MHL Alt Mode 同样也没厂商做,所以不提了

Q:那么DP Alt Mode 的 Type-C配件一般是什么样的呢?

A:本次的分类几乎涵盖了所有类别的 非雷电非DisplayLink产品(Display Link 有空也许会在后期也更新进来),Alt Mode 配件和 Display Link配件的区别在于,Display Link的配件可以在 Type-A接口上正常工作,在系统中需要安装Display Link 驱动(Chrome OS已集成) 才能输出视频信号,而 DP Alt Mode配件不需要驱动就可以外接显示器,但只能在支持的 Type-C 主机接口上运行正常。(咋一看Display Link 确实适用范围更广,但是性能缺陷是绕不开的问题)

涉及的产品主要形态如下:

1.Type C 转换为任意视频接口的单转单线缆

img

2.便携型适配器,无论有或没有PD Pass Through 功能,都可以无需外接电源使用

img
  1. 坞站,通常需要大型的外置DC电源支持才能使用
img

前置进阶科普

这里就不啰嗦接口和协议的区分问题了,直接进入正题

要先了解 全功能Type-C的大致机理,才能了解其配件的运作模式

更进一步地,了解配件功能上限/功能潜力,也能把握未来配件的发展方向

  • DP Alt Mode Type-C性能维度

Type-C 的DP Alt Mode 模式被激活后可以维持三大功能同时正常运作,分别是供电、DP传输以及USB 传输,因此本文中Type-C的的性能按照 供电能力、DP输出能力、USB传输能力 这三条作为三维来衡量性能,以下为三维分别的分级:

供电能力

由于桌面平台的 多功能Type-C/雷电 不支持电源输入,因此无法与移动平台比较,本文只会罗列参数而不会具体比较

USB 带宽

在先前的移动硬盘指南中提及过目前先进的USB协议类型,Type-C Alt Mode 中常见的USB 带宽模式有以下几种

USB3.2 Gen1 (5Gbps) 比如15~17年的12英寸 Macbook,比如华为Matebook 13,14 包括一加 7 Pro 等手机应用

USB3.2 Gen2 (10Gbps) 比如所有计算机搭载的雷电3及雷电4接口,桌面PC 可以使用的UPD2018 DP alt mode Type C扩展卡,Surface Laptop 3 等应用

理论上目前的技术是可以使Alt Mode支持 仅USB2.0 以及USB3.2 Gen2x2 模式的,但并没有实际产品可以参考

视频带宽

既然名为DP Alt Mode,那么在激活状态下输出的视频信号则为DP 信号

类似于USB协议,DP协议的迭代也可以提高相同接口下的传输速率

HBR2(DP1.2) 每Lane 5.4Gbps的理论传输速率,由于8b/10b编码,有效带宽为4.32Gbps

HBR3(DP1.3&DP1.4) 每Lane 8.1Gbps [6]的理论传输速率,由于8b/10b编码,有效带宽为6.48Gbps

常见显示分辨率所需带宽如下[7]

分辨率 所需的最小带宽
1 x FHD (1920 x 1080) 显示屏 @60 Hz 3.2 Gbps
1 x QHD (2560 x 1440) 显示屏 @60 Hz 5.6 Gbps
1 x 4K (3840 x 2160) 显示屏 @30 Hz 6.2 Gbps
1 x 4K (3840 x 2160) 显示屏 @60 Hz 12.5 Gbps

可以看到,4K@60Hz所需带宽仅需2 Lane 的 HBR3 DP 通道即可满足,而HBR2 则不行。这是买了 支持 4k@60Hz实际却只能30Hz 这个问题的核心所在

  • DP Alt mode 主机口构成

多功能Type-C 主机接口本质上只要把USB和DP的线路塞在一个Type-C插头里就可以。但是为了灵活调用和防止Type-C正反插酿成悲剧,在接口屁股上又加了multiplexer(多路复用器,以下简称MUX)[8]将USB和DP信号的物理线路随心所欲地排布在Type-C接口中,另外也增加了PD控制器用来控制MUX;同时这个控制器可以跟下游的PD控制器沟通,一旦对上暗号,那么两端就可以按照商量好的 DP Alt Mode 来控制MUX拍好输出线路的顺序,这样就可以USB 归USB,DP归DP了。

可以从下图的功能框图看到,MUX和PD控制器的上游,则是主机的USB Host(USB主控)以及 DP Source(DP信号源), Type-C的性能三维就是由这些上游的应用以及MUX本身的性能所决定的了(MUX走USB和DP信号,会影响这二维的性能)

img

举具体的例子

例如USB 带宽方面,12英寸Macbook 之所以只能支持到 5Gbps的USB 3.2 Gen1 传输,是因为上游的USB Host只支持到 5Gbps。而UPD2018 的上游USB Host采用的是 ASM1142,一颗 USB3.2 Gen2主控,因此可以支持到10Gbps,但是Host上游的PCIe带宽只给了PCIe 3.0 X1,因此实际上也是不满10Gbps的

img

DP (视频)带宽方面,很简单粗暴,直接看主机GPU的DP支持就可以了

例如英特尔10代之前的移动端处理器核显仅支持DP1.2(HBR2)输出,因此导致18年19年款的13英寸 Macbook Pro 即使装备了支持DP1.4(HBR3)的Titan Ridge 雷电控制器,由于核显的拖累,依旧只能DP1.2 输出(笑)

MUX支持方面,缺少比较直观的例子,拿雷电设备举例:早期的雷电3设备(Alpine Ridge时期的JHL/DSL6x40 系列)由于只支持 DP1.2 的信号源,在触发为DP Alt Mode之后也是只支持DP 1.2 输出;USB 也会受制于MUX ,比如 普瑞科技 的 PS8743 和 PS8750 作为母口端的MUX只支持USB3.2 Gen1 以及 HBR2 [9]

  • DP Alt mode 设备口构成

如下图所示[8]总体来说跟主机口没什么区别,也还是 PD 控制器加上 MUX的形式,区别只在于这里的MUX是解复用功能

img

但是,但是啊,我们已经拆过不少 Type-C转接器了,这些转接器里面 除了 DockCase DPR01S (DeMUX为PS8822)以外,为什么只有PD控制器而没有MUX?!这不是跟指导文档背道而驰吗

先进型 Type-C 扩展设备拆解存档

图标

但其实文档介绍的是基于完整的 Type-C 接口所设计的结构,即设备端是具有完整的Type-C接口,需要独立的线缆进行连接的情况

img

在常规情况下,如果采用的是尿袋式的设计,比如下面这种Type-C 定义直接焊死而不是给一个Type-C 口随意插,那么在设计时就不需要 MUX来应对Type-C正反插情况了,在Cypress的指导中也有提及[10]

If you are using type-C receptacle and plug combination you will not need a switch. If you have both USB-C connectors as receptacles, connected via a type-C cable (EMCA) then you will require a switch. DP source (FPGA) <---->Switch<------> USB-C receptacle <---------------------> USB-C plug <------> DP sink (FPGA) otherwise, DP source (FPGA) <-----> Switch <-----> USB-C receptacle <---------- USB-C cable ----------> USB-C receptacle <-----> Switch <-----> DP sink (FPGA)

img

当然,设备端的MUX也会影响最终性能,就如水路一样,最后的出水速度是受到整条链路上所有环节的影响的

经过了设备端的解复用之后,留给下游的又是简单纯粹的 USB 协议口和 DP 协议口(USB2.0 和 DP的 Configuration 通道仍需要 PD控制器转发来保证正常功能),在原先开发的各种USB 玩法 以及 DP玩法 可以直接捡起来套上去,不得不说这样的Type-C 开发出来对原先的硬件环境十分友好,和先前仅有的区别是,原本井水不犯河水的 USB 和DP 配件,如今由于 DP Alt Mode的存在被整合到一块电路板上了。

当然,遗憾也是有的,由于对广大的兼容性(免驱)考虑,很多应用难以得到推广

比如转 4G无线网卡的应用

img

另外也是出于成本的考虑以及对 苹果模式的一味模仿,尿袋式的转接器设计依然大行其道。好好设计一个线缆收纳很难吗?

  • USB与DP 进阶硬件认识

在硬件上将 PD 控制器和 MUX 融入 Type-C以后,事实上 Type-C就可以被凹成各种形状了,但主流 的模式其实就两种(按性能分为两种,实际VESA对应定义了6种[4]

首先我们需要对 USB 和 DP 有 基本的硬件认知

目前的信号传输依然主要依靠铜线缆,差分对则是经典的用于铜缆系统的抗干扰硬件设计[11]

简单的来说,我们使用两根线来传输一个信号,即一个差分对一个传输通道

在USB3.2 Gen1和Gen2 中,他们使用一组两个差分对四根线分别实现 5Gbps 和 10Gbps 的收发活动即SSTX 差分对和SSRX 差分对

R→Receive 收

T→Transmit 发

因此在USB中 一组收发 可以实现 10Gbps的 双向传输,USB3.2 Gen2x2可以启用两组共四对信号,因此可以实现 20Gbps 双向传输(是的,Gen2不需要D+D-来传输,Gen2 跟 Gen2x2 只是量变,Gen1 到 Gen2 才是质变,而只使用D+D- 的USB2.0则跟USB3.0可以算是两个物种了)

img

一个完整的DP接口同样含有4对主要连接差分对,Mian Link Lane 0~3 (以下简称ML)

在HBR2下可以完成 每Lane 5.4Gbps的单向传输,HBR3下则是8.1Gbps

除此之外,DP接口还内置了Configuration 1&2 用于协议配置,Auxiliary Channel +&- (以下简称Aux对)用于音频传输,有趣的是,DP同样可以在仅 ML0,ML1 两条Lane的模式下工作

img

那么,把USB 限制在 2对差分模式,DP也限制在2对差分模式,可以拼在一起吗?

  • DP Alt Mode 主要模式

答案是肯定的

用于通讯握手的PD协议必须占用一条 Configuration Channel(以下简称CC),电源线和接地定义也不能动,不过剩下的也足够其他协议分的了

常规情况 USB 模式时 Type-C 的针脚分布如下

img

当激活 DP Alt Mode 2Lane (Multi-Function DisplayPort,MFDP) 时,针脚功能如下

img

当激活成 DP Alt Mode 4Lane 时:

img

有没有觉得USB2.0 由于正反插支持占用了4个针脚,只有两个有效,而且480Mbps这么孱弱的速度塞进Type-C实在是丢人?

如果把USB2.0的针脚设定为USB3.2 Gen1或者Gen2 就好了,这样的模式也是有的,被称为Virtual Link,是为VR应用所开发的,Nvidia 的2000系 和AMD 的6000系显卡所搭载的Type-C 就支持该模式[12]

img

注意了,此模式不在 DP Alt Mode的范畴,常规设备是不支持也触发不了这个模式的。这个模式抛弃了USB2.0 链路导致该状态下是无法正常支持键鼠之类的应用。当然,作为专机专用模式也不用在意这种问题了

在Virtual Link 模式下,Type-C和常规 Type-C线缆可以达到非雷电模式下的最高速度,高达4*8.1+10=42.4Gbps的输出带宽外加10Gbps的数据接收带宽,尽管相比标称双向40Gbps的雷电3和雷电4仍然有显著差距,但是满足绝大部分应用是完全不成问题的了。

  • 如何触发 DP Alt Mode

如上文提到的, 不管是DP Alt Mode 还是上面提到的 Virtual Link,抑或是雷电,都是作为Alt Mode 触发的,而触发方式,都是通过Power Delivery 的通信功能

img

Type-C Alt Mode 大致配置流程如下:

  1. USB 连接 通过CC侦测到
  2. VBUS 引脚 提供默认电源配置 5V@500mA
  3. VBUS 所需的额外USB电力传输可以进行协商,Battery Charge 1.2(BC 1.2)或USB PD 都可以选择
  4. 使用 结构化 供应商定义报文(VDM) 需要USB PD 来发送来协商 Alt Mode 握手
  5. USB 枚举
  6. 如果 DP Alt Mode 协商已经完成,继续进行DP link training来建立DP连接
  7. USB和DP频道准备就绪进行Type-C 数据和视频信号传输。

更具体的 PD 报文内容和触发逻辑不是本篇重点,想具体了解的推荐TI的文档或者去VESA翻更具体的资料

PD Alternate Mode: DisplayPort

www.ti.com

产品实现

了解了 DP Alt Mode Type-C 的原理那么就可以观察他是怎么在产品上实现的了

  • 典型 2Lane DP Alt Mode + DP1.2 产品拓补

直接用在国内销量极大的Type-C 转接器方案 VL100 系列所为案例了

这是一个典型的VL103 转接器拓补,黄色 USB-C 为链接主机的上游接口,兰绿色为充放电专用的下游Type-C,典型应用可以参照Satechi 的多口Type-C转接器[13]

img
img
img

在这个应用中,VL103就是作为PD 控制器,负责下游Type-C 的PD和QC等协议的调度(因此充电Type-C口会有USB2.0定义用于握手,但其实不能挂载USB设备)

同时VL103作为PD控制器也负责DP Alt Mode的调度,但VL103完全不干预USB3.0 和DP 链路的走线,直接连接USB Hub芯片VL817 和 DP to HDMI芯片PS176,而读卡器芯片则是挂在VL817下游,提供了两个读卡器口。

此外,作为固定尿袋外形的转接器,这个拓补方案不需要MUX芯片

需要注意的是,这类典型应用需要兼顾USB3.0接口,因此只能选择 2 Lane DP Alt Mode 模式,,再加上PS176只能支持DP1.2的问题,导致转出的HDMI接口同样只能支持到 2Lane DP1.2的支持上限 4K 30Hz

相似类型的还有采用 Fresco FL7102 PD控制器为主控的绿联功能扩展坞(带SD卡槽版)[14]

img

硬件拓补和上面的Satechi 基本相同,但又有略微的区别

阳联 IT6564 对应 上个产品中的PS176,但 IT6564 可以将DP1.2 转换为 VGA和 HDMI两个输出(又是只支持 2Lane 的 DP1.2 输入,导致HDMI只能4k 30Hz输出。在绿联 CM260中 IT6564 可以获得 满血 4Lane DP1.2 输入 因此可以支持 4K 60Hz HDMI输出)

在本应用中有 3Type-A+ 一套转接器+网口共5个数据口,而常规USB3.0 hub 只能将一个USB扩展为 4个下游 USB,因此本应用中 套了两层GL3510(一个GL3510套在另一个下游,提供了共24-1=7个有效USB3.0接口) 一个被RTL8153B转为千兆网口,还有一个被GL224 转换为一套读卡器,有5个剩余USB下游口但只有3个被做出来,有两个被浪费了(笑)

本应用中同样为了确保下游USB3.0 功能只能选择 2 Lane DP Alt Mode 触发,再由于IT6564只能支持DP1.2,因此HDMI还是只能支持到4k 30Hz

使用该类型拓补的转接器是过去几年中的销售主力,兼顾USB3.x应用与4K 30Hz输出的转接器或者坞站基本都是这类结构,举几个常见的

  1. 华为MateDock 2[15]
  2. 米物 Type-C 七合一多功能转接器 MWCMA01[16]
  3. 惠普HP USB-C to Multi-Port Hub USB-C多端口集线器[17]
  4. ROG Phone (ZS600KL) ASUS Professional Dock[18]
  5. 小米 ZJQ01TM USB-C至HDMI多功能转接器[1]
  • 典型 2Lane DP Alt Mode + DP1.4(HBR3)产品拓补

DP1.2这么菜,导致 2 Lane DP模式只能支持输出4K 30Hz,那么我们引进DP1.4就能支持更高的带宽和分辨率了

比如说DockCase DPR01S 支持到4K 60Hz 和 USB3.0应用共存[19]

img

这里采用的PD控制器FL7112是绿联系列采用的FL7102的后继型号,此外由于搭载了完整的正反插Type-C,使用了 PS882 MUX芯片进行支持; 总体结构和上文的 FL7102 转接器差别不大,但是从MUX到 DP转换器都 选用了支持 DP1.4(HBR3)的型号,PS176 换成了 PS186 用以支持将 2Lane DP1.4 转换为 HDMI 1.4,从而支持4K 60 Hz 输出,当然,前提是主机的Type-C也支持 DP1.4 输出

该类型的转接器同样已经很比较普遍了,目前市面上既支持USB3.x 扩展又支持到4K 60Hz的转接器基本都是这个类型的拓补应用,举一些常见的例子

  1. 戴尔DA300[20]
  2. 戴尔DA310[21]
  3. 苹果 A2119[22]
  • 典型4 Lane DP Alt Mode 产品拓补

上面两类拓补都是由于保证USB 3.0/USB3.2 Gen2 应用,导致被迫选择 2Lane DP模式,在只能支持DP1.2 的情境下极大限制了 视频传输的带宽,即使转接器支持到 HBR3,也由于大量主机只支持DP1.2 输出(比如雷电接口只能核显输出)导致最终只能被多功能转接器锁在4K 30Hz,因此在 Type-C HBR3 输出尚未普及的时候,选择4Lane DP Alt Mode 比升级到 HBR3 更明智一些

于是大量的 4 Lane Mode专注于视频转接的线缆型单对单设备应运而生,比如 Nvidia USB-C to DisplayPort Adapter[23]

img
img
img
img

该配件全机仅有一个功能性配件,即VL103,与上文的Satechi 配件采用的PD主控是一样的, 但在这里被配置为触发的4Lane 模式,可以清晰地看到有四对差分线的走线从上游线直通DP 接口,即ML0~ML3,PD控制器仅负责对DP Alt Mode的触发,完全不干涉DP信号自身;理论上这款线缆在HBR3支持下是可以支持8K 30Hz的输出能力的

在这样的4Lane 触发基础上加上DP信号转换即可以制作成各式各样的Type-C 转视频接口线,例如华为的CP76,Type-C转HDMI线缆[24]

img

采用的,其实还是 VL103 + PS176 的硬件组合,与上文的 Satechi 主体相同,VL103 同样被设置为触发 4Lane 模式,PS176 即使只支持 DP1.2,也凭借着翻倍的带宽支持到了4K 60Hz,发挥了Type-C口完整的 DP输出能力,然而代价是牺牲掉了USB 3.0应用

如果将PS176更换为PS186 设计,支持HBR3 的DP转换,那么HDMI的输出分辨率支持就能高达8K 30Hz了

img
img

然而 4 Lane DP Alt Mode 相对于 2Lane 模式仅仅是牺牲了 USB3.x 的支持,照理来说USB2.0 和PD 功能依然健在,做出跟常规转接器形态一致的设备并不是难事。

确实如此,只不过比较稀少,比如小米的 Type-C 转 Mini DP设备[25]

img

PD控制器采用的是FL7102,可以清晰地看到4对 差分线地走线从Type-C直奔 下游的Mini DP,尽管USB Hub采用的是支持USB3.2 gen1 的FL5000,但上游的走线只给了USB2.0的D+D-定义,因此两个扩展的USB接口被迫限制在在USB2.0模式;此外装备了PD输入口,也算功能齐全了。这款转接器理论上在HBR3支持下也是可以支持到8K分辨率输出,只不过 mini DP的走线过长,抗干扰能力能否满足要求就不得而知了。

目前市面上销售的 Type-C 转单视频口输出的应用可以说全都是应用了这个类型的结构,但是目前依然以支持到DP1.2 转换的为主流,支持到HBR3转换的较少(支持HBR3/DP1.4仍然可以向下兼容HBR2/DP1.2转换,图省事直接购买高规格的即可),支持4Lane 转换的多口转接器除上文提到的以外可以再举几个例子:

  1. 戴尔 USB-C 转 HDMI/DP 适配器[26]
  • 可切换带宽型拓补

那么,既然4Lane 2Lane各有好处,我用什么的时候切什么不好么,再加上HBR3支持,那岂不是香的不行?

其实也是有的,但是非常稀少。翻阅VL102,VL103的文档时,VIA Tech已经给出了实现该功能的拓补(同时也给出了将USB与充电C口融合的参考,然而做的厂家也非常稀少)

img

可以看到相对于上文的拓补,本案例中多出来了类似MUX的芯片VL170,该芯片就是可以用于把设备在2 Lane 与 4Lane 模式之间来回切换的关键

img

感谢 提供的机型线索

这类拓补的应用实物之一就是 Startech DK30C2DAGPD, 很遗憾这里就没有拆解参考了

img
img
img

根据 Startach 本身提供的信息来看,采用的主要IC如下

VIA/VLI - VL102

VIA/VLI - VL170

VIA/VLI - VL817

MegaChips - STDP4320

RealTek - RTL8153

负责视频输出的 STDP4320 支持双DP++输出,只是可惜作为 仅支持DP1.2 输入的方案,最高也就支持到 单口4K 60Hz 或者双 4K 30Hz 输出了

Dual DisplayPort displays: Up to 4096 x 2160p @ 24Hz or 3840 x 2160p @ 30Hz Single DisplayPort display: Up to 4096 x 2160p @ 60Hz or 3840 x 2160p @ 60Hz

此外还有 Kensington 的 SD4820P USB-C 10Gbps Dual Video Driverless Docking Station 可惜这次连使用的芯片信息都没有了

img
img

但是根据Kensington 的手册介绍,扩展坞在4 Lane Mode 下支持单 4k 60Hz 或者 双 4K 30Hz 输出,似乎也不支持 HBR3 应用,甚是可惜

img

除以上两例以外,目前暂时找不到更多类似拓补了,因此举不了更多实例了

  • 再复用接口 拓补

还记得我们在起初的时候对 DP Alt Mode 主机口的认识吗

多功能Type-C 主机口只要上游有 完整的USB通道和DP 信号源就可以以添加 PD控制器和MUX的方式组建了

那么在经过设备的 Type-C 端口,Type C 传输信号被重新分解为 DP 与 USB之后,可以将USB信号复制之后再次和 DP信号 结合成 DP Alt Mode Type-C吗

img

答案依然是肯定的,DA310 就通过 增加 MUX 芯片的方式 在 Type-C 扩展器里实现了信号的重新结合,为下游提供了一个 多功能Type-C[21]

然而美中不足的是该接口似乎吃了 2Lane 和 HBR2 两个DeBuff,最高只能支持到 4K 30hz 输出,装备了 支持 HBR3 的主机端MUX 芯片 PS8802 后表现这么拉跨只能说比较遗憾了

img

但这些缺陷在戴尔的新 WD19DCS中都被解决了

代价是连接主机的一个上游端口变为两根

img
img

单Type-C口可以支持到 8K 30Hz输出,显然是完成了4Lane HBR3 的支持,然而没有 拆解图观察还是比较可惜的。

硬件选用

  • PD控制器概览

上文介绍的案例都是采用的专用PD控制器

作为转接器核心部件的PD控制器其实门槛并不高,常规的MCU即可实现PD控制器的功能

例如 STM 就基于自家的STM32F072 推出了STEVAL-USBC2DP 配件,希望能从 Type-C市场分一杯羹,上文提过的惠普HP USB-C to Multi-Port Hub USB-C多端口集线器[17] 也是用的这个主控

img

然而非专用化的设计必然在外部电路复杂度,功能开发,成本上处于弱势,因此使用这类主控的产品还是风毛菱角

但是PD控制器只能做PD 控制器吗?跟USB Hub 甚至 视频转换 做在一起不行吗?

可以的,也是有产品的

比如 Fresco 的 FL5002 即是 PD控制器 + USB 3.0集线器 (小米,联想有成品,皆是公版仿苹果A2119外形)

Genesys Logic 的GL3510 也是 PD控制器+USB3.0 集线器(米物 转接器)

更进一步的比如 龙讯 LT8711H,安格 AG9321 ,一颗芯片就可完成视频转换,PD充电 的功能

img
  • 主控产品格局

介绍一下主控在Type-C 转接器市场中的主要IC和格局

腾讯文档

docs.qq.com

img

Texas Instrument 我想EE背景的同学就算没用过应该也都听说过,它对电源,信号类的应用市场有着统治级的影响力,其 产品和企业价值观 对全球的 EE 领域从业者都有着深远影响;各位如果拆开自己的笔记本,九成九都可以在主板上发现 TI的芯片。

Cypress 不像 Texas Instrument 那么巨无霸,但在消费电子领域也是巨头,为各类应用都提供了可靠高效的解决方案

这两家巨头 所提供的IC 基本代表了 Type-C 转接设备的顶级产品方案(不止DP Alt Mode,雷电也是)作为头部计算机制造商 HP,Dell 甚至 微软,Apple 的产品使用的都是来自这两大巨头的主控,唯一的遗憾可能就是 TI的主控至今都没有支持 PD Pass through的产品,只有 DC供电的坞站形态或者无供电转接器形态

比如

Dell DA300[20] (TPS65988 ,Texas Instrument)

Dell DA310[21] (CYPD4226+CY7C65219,Cypress)

Dell WD15 (TPS65982,Texas Instruments)

戴尔 USB-C 转 HDMI/DP 适配器[26](CYPD4226+CY7C65219,Cypress)

Surface Dock2[27] (非Type-C 配件,TPS65988,Texas Instrument)

Apple A2119[22] (CYPD5225+CY7C65211,Cypress)

中高端&中端:Parade/Fresco

Fresco 已经被Parade 收购,两家的产品也完成了进一步的整合,目前的第三方新转接器产品基本都使用的该公司主控,并且整体设计方案和防护设计基本都到位,目前综合价格和性能来看还是比较理想的选择

中端:Genesys Logic

因为这家厂子隐藏自家产品资料并且广签NDA导致可获得的资料极少

产品还可以但真正使用Genesys 作为核心设计的产品并不多,基本是以 USB Hub 主控活跃在各家转接器上(苹果与微软的转接器都有用到)

中端&中低端:VIA Tech

VIA算是我们的老朋友了,VIA与国内的第三方厂商联系甚密,产品特点是下限有一定保证,但基本没有再次开发的空间(下限可以且上下限差距极小)

低端:Lontium(龙讯),Algoltek(安格)

虽然两家的 LT8711H 以及 AG9321 公版设计 就是奔着缩成本去的简陋和稀烂,但是低价产品对市场带来的冲击是巨大的。

国内30+元,海外4.5USD,为上述中端产品的生存带来了巨大的压力

  • 常见下级视频类应用

在上文所举例的应用中,我们已经可以看到一些转换器常见的转换应用,比如PS176,PS186,都是基于DP输出的单对单视频转换,由于苹果的采用才在第三方转接器中风行开来

单对单转换的意思是........ 单入单出,那么单个DP输入像USB分线器那样扩展成多屏应用可以吗

也可以的,使用的技术主要是 DP MST (DP菊花链)根据所设置的分辨率(占用带宽)决定显示器扩展数量的上限,分配比例灵活,可以独立设置每个屏幕,但下游的单个显示器也有带宽限制

这里由于转换类型和应用太多所以暂时不做表了

  • 可靠外围设计示例

由于转接器使用环境复杂,比如:

  • 大功耗外围(USB等)设备需要电源设计来保证供电,亦需要应对过流等预期外情况设计保险
  • 信号线本身工作时载有高频跳变的电压,可以将线路当作天线辐射出射频信号,会干扰周围无线设备或被外界干扰,因此也需要无线屏蔽/隔断设计
  • 人体(或其他物体)触摸转接器时可能带有高水平的电荷(静电)从而造成放电现象,放电过程会有极高可能性损坏转接器芯片,甚至损坏连接的主机接口

这些情景却并不是单靠上文提到过的芯片本身的设计指南所能搞定的,需要PCB设计,相关安全器件和设计,产品设计一同来保障

第一点一般会有专用的器件来搞定,比如在DA310 中内置的 TPS2554 作为电流保险

img

第二点一般利用法拉第笼的原理在转接器外围造一层金属罩进行无线屏蔽

img
img

第三点则较为复杂,尽管目前多数IC都会内置 ESD (electrical state discharge)防护,然而并不能确保芯片可以在较恶劣的环境下存活下来,因此外挂各种防护措施还是有价值的,毕竟要是把主机口也挂了那麻烦就大了

其中TVS管就是最常用的方式

img

其他的防护措施这里就不一一介绍了,可以参考该文 INDUSTRIAL USB HUB TEARDOWN: ESD ROBUSTNESS 仅作参考,该文是较为典型的过分堆料

img

一般情况下只要做到像TI参考设计的程度就足够了,即 使用TVS管作为ESD防护以及电源总线上附带过流保险

img
img

此外,PCB的走线也会影响 ESD效果以及对外的无线干扰辐射[28],总之转接器PCB做工是一件比较复杂的考量事项。

总结与指南

总的来说转接器产品有两大特点不同于 朴素认知

  • 作为转接器的核心部件PD控制器并不影响转接器的主要功能(视频转换和USB、扩展)
  • 转接器接口多寡并不和其 成本 呈正相关 (原本可以给的接口会被阉割,市场内的常见手段),将多种接口整合变少才是本事(就像你用来扩展的Type C口)

因此通过接口多寡来计算性价比(价格/接口)基本只能陷入坑货泥潭

此外 新款芯片一般至少需要一年的周期才能真正被采用到新产品里面,因此盲目追新 方案大可不必


  • 推荐

尽管各头部厂商 由于历史原因或者其他的一些因素多少都有一些坑货,而下面的白莲花制造商也少之又少,即使是 Belkin 也能找出一些 智商税产品

但是原则上依然推荐 HP,Dell,苹果,微软的新品转接器,这些厂子的转接器不分高端低端,出手即是代表性产品,但也导致

这些头部厂商的产品也会有一个共性的缺点就是不会在自己的产品上集成读卡器功能

其余的,功能和做工就拉不开多少差距了,很难说有完美的,各方面都做的很优秀的产品

总结一下本文提到的带有拆解文章的产品,转接器功能需求复杂,产品或多或少存有不足,仅作参考,长期更新

依然不建议依赖该表,建议通读

img

  • 排雷

这个市场内显著的坑货有两大类

一类是长得像 Belkin 的 非Belkin 产品

img
img

这类产品一般都是VIA 的VL100系公模产品, 本来做的像样的也有,比如在我的专栏中拆过的Satechi

但由于对压缩成本的追求,VIA的公版设计被无限压缩,导致市面上一大批的公模VIA产品坑点奇多,下面的雷至少踩两个:

  • 质劣价高(物料成本20块左右,直接抄公版设计无需研发成本,防护全无的扩展坞可以卖到150以上,200,300 也是常见)
  • 供电稀烂,带不动一块移动机械硬盘的读写耗电
  • 屏蔽基本无,是一个巨大的2.4Ghz污染源,干扰附近的蓝牙,WIFI设备的正常工作
  • 工厂品控稀烂

涉及品牌包括 绿联,Orico,飞利浦(转接器业务已经被别家收购),Unitek,倍思

国内能叫的上名字的配件厂几乎全部中枪,同样是 VL100系主控,没一家的做工和防护能比得上Satechi(苹果合作款)

img
img

另一类是长得像苹果的非苹果产品

img

这类产品同样有VIA 阵营的VL100系产品牵涉其中

但在低端攻城掠地的 龙讯LT8711H ,安格 AG9321 同样也籍由这样的外型活得滋润(物料成本估计 10块左右,售价一般在30,40元水平)

此外 Fresco 的 FL5002 公版设计也是籍由这种 外形活得滋润,例如 小米ZJQ01TM[1] ,联想也是[2],尽管TVS防护尚可,但是绝对不会装配 屏蔽罩,另外FL5002 发热较大

还有一类较隐蔽坑货就是自己做标致的外壳,内藏稀烂的硬件

外形就请自行想象了,以下三款图内PCBA的售价都在10元内

img
img
img

参考

  1. 1(about:reader?url=https%3A%2F%2Fzhuanlan.zhihu.com%2Fp%2F342165494#ref_1_0)bc全网首拆:小米USB-C至HDMI多功能转接器ZJQ01TM拆解 http://consumer.linxee.cn/CPLT/132.html
  2. 2(about:reader?url=https%3A%2F%2Fzhuanlan.zhihu.com%2Fp%2F342165494#ref_2_0)b拆解报告:联想USB-C迷你集线器 https://www.chongdiantou.com/wp/archives/27256.html
  3. [^](about:reader?url=https%3A%2F%2Fzhuanlan.zhihu.com%2Fp%2F342165494#ref_3_0)INTEL 对USB3.0 射频干扰的测试和相关建议 https://www.intel.com/content/www/us/en/products/docs/io/universal-serial-bus/usb3-frequency-interference-paper.html
  4. 3(about:reader?url=https%3A%2F%2Fzhuanlan.zhihu.com%2Fp%2F342165494#ref_4_0)bTI文档,PD Alternative Mode:Display Port https://www.ti.com/lit/an/slva844b/slva844b.pdf?ts=1614791986776&ref_url=https%253A%252F%252Fwww.ti.com%252Fsitesearch%252Fdocs%252Funiversalsearch.tsp%253FsearchTerm%253DAlternate%2BMode%2BSupport
  5. [^](about:reader?url=https%3A%2F%2Fzhuanlan.zhihu.com%2Fp%2F342165494#ref_5_0)HDMI组织官网对HDMI Alt Mode 的介绍 https://www.hdmi.org/spec/typec
  6. [^](about:reader?url=https%3A%2F%2Fzhuanlan.zhihu.com%2Fp%2F342165494#ref_6_0)视频标准电子协会 VESA 的说明 https://vesa.org/featured-articles/vesa-rolls-out-early-certification-program-for-video-source-and-display-products-using-hbr3-high-bandwidth-link-rate/#:~:text=DisplayPort's%20new%20HBR3%20data%20rate,at%208.1%20Gbps%20per%20lane
  7. [^](about:reader?url=https%3A%2F%2Fzhuanlan.zhihu.com%2Fp%2F342165494#ref_7_0)Dell官方 关于显示带宽的说明 https://www.dell.com/support/manuals/zh-cn/dell-wd19dcs-dock/wd19dcs_user_guide/%E6%98%BE%E7%A4%BA%E5%B8%A6%E5%AE%BD?guid=guid-f73113c5-ee42-47fe-a849-d669e93440e2&lang=zh-cn
  8. 4(about:reader?url=https%3A%2F%2Fzhuanlan.zhihu.com%2Fp%2F342165494#ref_8_0)bTI 文档 Alternative Mode on Type-C https://zhuanlan.zhihu.com/p/335164290
  9. [^](about:reader?url=https%3A%2F%2Fzhuanlan.zhihu.com%2Fp%2F342165494#ref_9_0)普瑞科技主控产品清单 https://www.paradetech.com/products/
  10. [^](about:reader?url=https%3A%2F%2Fzhuanlan.zhihu.com%2Fp%2F342165494#ref_10_0)Cypress, 提问是否需要在设备端使用MUX https://community.cypress.com/t5/USB-EZ-PD-Type-C/do-we-need-a-switch-like-PS8740B-on-both-the-source-and-sink/td-p/187782?start=0&tstart=0
  11. [^](about:reader?url=https%3A%2F%2Fzhuanlan.zhihu.com%2Fp%2F342165494#ref_11_0)TI中文社区对差分对的介绍 https://e2echina.ti.com/blogs_/archives/b/signal_integrity_/archive/2015/05/13/51961
  12. [^](about:reader?url=https%3A%2F%2Fzhuanlan.zhihu.com%2Fp%2F342165494#ref_12_0)Wiki 关于 Virtual Link https://en.wikipedia.org/wiki/VirtualLink
  13. [^](about:reader?url=https%3A%2F%2Fzhuanlan.zhihu.com%2Fp%2F342165494#ref_13_0)Satechi 多口转接器拆解 https://zhuanlan.zhihu.com/p/155895919
  14. [^](about:reader?url=https%3A%2F%2Fzhuanlan.zhihu.com%2Fp%2F342165494#ref_14_0)充电头网 拆解报告:UGREEN绿联3A1C四口多功能扩展坞(带SD卡槽版) https://www.chongdiantou.com/wp/archives/44723.html
  15. [^](about:reader?url=https%3A%2F%2Fzhuanlan.zhihu.com%2Fp%2F342165494#ref_15_0)华为MateDock2扩展坞拆解 http://blog.sina.com.cn/s/blog_702183da0102xf73.html
  16. [^](about:reader?url=https%3A%2F%2Fzhuanlan.zhihu.com%2Fp%2F342165494#ref_16_0)拆解报告:米物3A1C七合一多功能扩展坞MWCMA01 https://www.chongdiantou.com/wp/archives/61247.html
  17. 5(about:reader?url=https%3A%2F%2Fzhuanlan.zhihu.com%2Fp%2F342165494#ref_17_0)b售完存档:全新原装惠普HP USB-C to Multi-Port Hub USB-C多端口集线器外接HDMI USB-C USB3.0 1BG94AA 918965-001 919666-001 https://qzxx.com/49896.html
  18. [^](about:reader?url=https%3A%2F%2Fzhuanlan.zhihu.com%2Fp%2F342165494#ref_18_0)售完存档:全新散装华硕ROG Phone (ZS600KL) ASUS Professional Dock Type-C 游戏手机 电脑 Macbook PD供电 HDMI USB3.0 千M网口 USB-C接口五合一扩展坞ADSU001 https://qzxx.com/44938.html
  19. [^](about:reader?url=https%3A%2F%2Fzhuanlan.zhihu.com%2Fp%2F342165494#ref_19_0)【TearDown】DockCase DPR01S 可视化扩展坞 4K@60Hz 分线款 拆解 https://zhuanlan.zhihu.com/p/345184683
  20. 6(about:reader?url=https%3A%2F%2Fzhuanlan.zhihu.com%2Fp%2F342165494#ref_20_0)b【Teardown】Dell 配件 DA300 拆解 https://zhuanlan.zhihu.com/p/339830297
  21. 7(about:reader?url=https%3A%2F%2Fzhuanlan.zhihu.com%2Fp%2F342165494#ref_21_0)bc【TearDown】 Dell DA310 初步测试和拆解 https://zhuanlan.zhihu.com/p/350808731
  22. 8(about:reader?url=https%3A%2F%2Fzhuanlan.zhihu.com%2Fp%2F342165494#ref_22_0)b拆解报告:苹果最新USB-C 数字影音多端口转换器A2119 https://www.chongdiantou.com/wp/archives/38952.html
  23. [^](about:reader?url=https%3A%2F%2Fzhuanlan.zhihu.com%2Fp%2F342165494#ref_23_0)售完存档:原装Nvidia 雷电3 USB-C to DisplayPort Adapter USB-C转DP显卡转换线 支持3840*2160 4K 60Hz 030-1036-00 DJ8A5T-4000-10H https://qzxx.com/44009.html
  24. [^](about:reader?url=https%3A%2F%2Fzhuanlan.zhihu.com%2Fp%2F342165494#ref_24_0) 拆解报告:华为高清投屏连接线(CP76) https://www.chongdiantou.com/wp/archives/27141.html
  25. [^](about:reader?url=https%3A%2F%2Fzhuanlan.zhihu.com%2Fp%2F342165494#ref_25_0)小米第二款DOCK转换器拆解:支持DP,用料残暴 https://www.sohu.com/a/150498171_296845
  26. 9(about:reader?url=https%3A%2F%2Fzhuanlan.zhihu.com%2Fp%2F342165494#ref_26_0)b拆解报告:DELL戴尔Type-C三合一多功能扩展坞 https://www.chongdiantou.com/wp/archives/66590.html
  27. [^](about:reader?url=https%3A%2F%2Fzhuanlan.zhihu.com%2Fp%2F342165494#ref_27_0)Surface Dock 2 teardown https://dancharblog.wordpress.com/2020/05/28/surface-dock-2-teardown/comment-page-1/#comment-7200
  28. [^](about:reader?url=https%3A%2F%2Fzhuanlan.zhihu.com%2Fp%2F342165494#ref_28_0)ESD Protection Layout Guide https://www.ti.com/lit/an/slva680/slva680.pdf?ts=1616140396901&ref_url=https%253A%252F%252Fwww.google.com%252F


  1. a↩︎

  2. a↩︎

  3. a↩︎

  4. a↩︎

  5. a↩︎

  6. a↩︎

  7. a↩︎

  8. a↩︎

  9. a↩︎

以下所有对寄存器的描述均来自于《ADSP-214xx SHARC Processor Hardware Reference》,后简称《HWR》。

本笔记主要是针对芯片 ADSP21479 寄存器(PLL、SDRAM、SRU、中断等)进行总结和记录。

[TOC]

Register Preview

位类型和操作

许多寄存器旁边都会标注位类型和操作方法,位类型包括 可读可写(RW)、只读(RO)、只读清除(ROC)、只写清除(WOC)、可读可写1清除(RW1C)、 可读可写1设置(RW1S)。

image-20210528134312811

注意不要尝试去写入这些 reversed位 ,读取的值就会使这些位上的值进行更新或者复位。

image-20210528134457084

头文件-外围设备及寄存器宏定义

<def21479.h> 是关于 外围设备(peripherals)和 寄存器(registers)的子集。

<cdef21479.h> 包含了对IOP寄存器的宏定义,对C/C++可用。所有定义均和 <def21479.h> 一致,除了以 p 作为前缀的宏定义 和 (relevant casts)以外,它们的用法如 *pSYSTAT = 0x12345678;

《HWR》仅有第99页中提及了这两份文件。

image-20210602171608976

DEF21479.H

  • 外部接口IOP寄存器(IOP registers for External Port)、SDRAM控制寄存器、AMI寄存器、DMA地址寄存器、SPORT(SP0~SP7)(包含串行接口寄存器、多通道发送接收(Multichannel tx/rx)、SPORT计数寄存器、错误中断控制寄存器、控制寄存器、多通道选择(Multichannel select))、SPI和SPIB寄存器、定时器寄存器、POWER MGT寄存器、外围设备中断优先级控制寄存器(Peripheral interrupt priority control register)、DAI寄存器(DAI参数寄存器、边缘中断锁存寄存器、中断优先级寄存器、(shadow)高/低优先级中断锁存寄存器、DAI状态寄存器、DAI针脚缓存状态寄存器、)、SRU寄存器(包括SRU时钟控制寄存器、数据控制寄存器、FS控制寄存器、针脚控制寄存器、外部Misc.A/B控制寄存器、针脚使能寄存器、shift寄存器的时钟控制和数据控制)、精度时钟控制寄存器(Precision Clock A/B Control Register 0/1)(包括脉冲宽度控制、幅度同步、脉冲宽度控制)、MTM寄存器、PWM寄存器、UART寄存器、TWI寄存器、FIR加速寄存器、IIR加速寄存器、FFT加速寄存器、MLB设备寄存器、WDT寄存器、Shift寄存器、RTC寄存器。

  • DPI、DTCP模块


  • 系统寄存器位定义(MODE1和MMASK寄存器、MODE2寄存器、ASTAT、STKYx和STKYy寄存器、IRPTL寄存器、IMASK寄存器、IMASKP寄存器、LIRPTL寄存器、FLAGS寄存器)

  • IOP控制/状态寄存器位定义(EEMUSTAT寄存器、RUNRSTCTL寄存器、SYSCTL寄存器、BRKCTL寄存器、REVPID、SDCTL寄存器位、SDRRC(SDRAM刷新速率控制)寄存器、SDSTAT(SDRAM状态)寄存器、SDSTAT(SDRAM状态)寄存器2、EPCTL寄存器位)

  • AMICTL寄存器位(DMAC寄存器控制位、SPICTL寄存器、SPISTAT寄存器、SPCTL(0~5、N0~N7)寄存器、GP计时器状态寄存器、GP计时器控制寄存器、电源管理控制寄存器、外部时钟管理控制寄存器、DAI中断锁存寄存器、IDP控制寄存器、IDP PDAP控制寄存器、DAI针脚缓存状态寄存器(0~19)、DAI状态寄存器、DPI针脚缓存状态寄存器(0~13)、DPI中断锁存寄存器)

  • 精度时钟控制寄存器(A0、A1、B0、B1、C0、C1、D0、D1)、精度时钟脉冲宽度控制寄存器、精度时钟幅度同步、精度时钟脉冲宽度控制寄存器

  • 优先级中断控制(Priority Interrupt Control)寄存器(可编程中断(Programmable Interrupt)寄存器位)

  • PWM全局控制寄存器、PWM全局状态寄存器、PWM控制寄存器、PWM状态寄存器、PWM输出禁用、PWM调试状态、PWM极性选择寄存器(Polarity Select Register)

  • TWI寄存器、主设备内部时钟寄存器(TWIMITR)、TWI从设备控制寄存器(TWISCTL)、TWI从设备状态寄存器(TWISSTAT)、TWI主设备控制寄存器(TWIMCTL)、TWI主设备状态寄存器(TWIMSTAT)、TWI中断控制寄存器(TWIIMASK/TWIIRPTL)、TWI先进先出控制寄存器(TWIFIFOCTL)、TWI先进先出状态寄存器(TWIFIFOSTAT)

  • UART寄存器、UARTIIR、UARTLCR、UARTMODE、UARTLSR、UARTTXCTL/RXCTL、UARTTXSTAT/RXSTAT

  • SPDIF传输寄存器、SPDIF通道状态寄存器、SPDIF用户位状态寄存器、SPDIF接收器寄存器、SPDIF传输控制寄存器、SPDIF TX输入数据格式、SPDIF接收控制寄存器、SPDIF接收状态(只读)

  • 采样率转换控制寄存器(0~3)、输入数据格式、输出数据格式、SRC频应复元(Deemphasis)设置、彩艳率转换率(0~3)、采样率转换静音(MUTE)寄存器(SRCMUTE)

  • FIR加速器、IIR加速器、FFT加速器

  • MLB位定义(DCCR/SSCR/SMCR/IBCR/CECR/CSCR)、WDT寄存器位定义、Shift寄存器位定义、RTC寄存器位定义(控制、初始化、状态、初始化状态)

CDEF21479.H

  • 仿真、断点寄存器
  • 外部接口的IOP寄存器
  • SDRAM控制寄存器
  • AMI的IOP寄存器
  • DAM地址寄存器
  • SPORT(0~7)(串行接口寄存器、MT/MR寄存器、TDM寄存器、)
  • SPI寄存器、SPIB寄存器(通过DAI进行路由)
  • 计时器寄存器
  • 电源管理寄存器
  • 外围中断优先级控制寄存器
  • DAI寄存器(DMA参数寄存器、SRU寄存器、采样率转换寄存器)
  • DPI寄存器
  • DTCP模块
  • SPDIF传输寄存器(通道状态缓存、用户位缓存、SPDIF接收寄存器)
  • PCG精度时钟控制寄存器
  • MTM(Memory to Memory)寄存器
  • PWM脉冲调制寄存器
  • UART寄存器
  • TWI寄存器
  • FIR加速寄存器
  • IIR加速寄存器
  • FFT加速寄存器
  • MLB设备寄存器
  • WDT寄存器
  • Shift寄存器
  • RTC寄存器

在《HWR》“自己眼”中,可能自己就这么点儿寄存器。

image-20210528140017190

Reset Register

RUNRSTCTL,运行中复位控制寄存器(Running Reset Control Register)。

表A-5 RUNRSTCTL寄存器位功能描述

image-20210527170816951

可编程中断优先级控制寄存器

  • supports 19 programmable prioritized interrupts

  • 任何外部中断输出都可能被连接至任何可编程优先级中断输入。

表A-6 默认中断路由

image-20210527171119962
image-20210527171204914
image-20210527171219793

目标信号控制寄存器

本寄存器控制了:

  • programmable priority interrupts

  • default interrupt sources

image-20210527171809869

图 A-4 PICR0 寄存器

image-20210527171824344

图 A-5 PICR1 寄存器

image-20210527171841316

图 A-6 PICR2 寄存器

image-20210527171852287

图 A-7 PICR3 寄存器

TWI IN MASTER-TX

Peripherals with Multiple Interrupt Request Signals

TWI和UART有分离的中断输出。两者都默认连接至P14I(DPI)。然而,两者都允许分离连接至默认不路由的PICR,反而提供了更多可通过DAI/DPI中断优先级更改的混合模型。

The TWI and the UART have separate interrupt outputs. Both peripherals are already connected via the P14I (DPI) by default. However both peripherals allow separate connectivity into the PICR that are not routed by default. This provides more flexibility for priority change across the DAI/DPI interrupts.

TWI Register

《HWR》第1193页起定义了TWI的寄存器。第1244页同样给了TWI相关的寄存器一个列表。

image-20210528140209933

<cdef21479.h> 对TWI相关的寄存器定义如下,p为前缀的定义是该寄存器的地址位,通过与<def21479.h> 的定义进行 运算并赋值给对应的寄存器地址进行控制,如 *pTWIMITR = (0x14) | TWIEN;

TWI中所有的Status相关寄存器都是 “只读” 状态,其《位描述》表上都有一个 RO 标志。

image-20210527095053483

在VisualDSP++这款IDE中,也可以通过 直接观察到所有TWI的寄存器值。

image-20210607103816755 image-20210607103747655

TWIMITR

TWIMITR(Master Internal Time Register),即主机内部时间寄存器(如图A-143所示,并在表A-129中描述)。

  • 用于启用TWI模块,以及建立外围时钟(PCLK)和TWI控制器内部定时事件之间的关系。
    • 内部时间参考是从PCLK得出的,使用的是预标定值。PRESCALE = fPCLK / 10 MHz

The internal time reference is derived from PCLK using the prescaled value shown below.

PRESCALE = fPCLK/10 MHz

image-20210525133555377

图 A-143 TWIMITR 寄存器

表A-129 寄存器位功能描述

BITS NAME DESCRIPTION
6-0 PRESCALE 预分频
用于生成一个内部时间参考的外围时钟(PCLK)周期数。
必须设置PRESCALE的值,以创建一个周期为10MHz的内部时间参考。这表示为一个7位的二进制值。
7 TWIEN TWI使能
该位必须设置为从属或主模式操作。
建议在初始化PRESCALE时设置该位,并保持设置,以确保总线繁忙检测逻辑的精确运行。
- 0 = 禁用TWI
- 1 = 启用TWI主、从模式操作。如果该位从高电平过渡到低电平,缓冲器将被刷新,需要2个时钟周期。

TWIDIV

在主模式运行期间,跟SCL相关的TWIDIV(Clock Divider Register),即时钟分频器寄存器(如图A-144所示,并在表A-130中描述)。

  • 被用来创建串行时钟(SCL)的 持续时间。
  • 串行时钟的频率可以从400KHz到小于20KHz不等。产生的时钟分辨率为1/10 MHz或100 ns。

image-20210525134728762

图 A-144 TWIDIV 寄存器

表A-130 TWIDIV 寄存器位功能描述

BITS NAME DESCRIPTION
7-0 CLKLOW 时钟低电平
该时间映射了串行时间低电平的周期。
以8位二进制数表示。
15-8 CLKHI 时钟高电平
该时间映射了串行时钟在等到一个新时钟低电平到来之前的持续时间。
以8位二进制数表示。

TWIMCTL

TWIMCTL(Master Control Register),即TWI主机控制寄存器。

  • 控制了控制与主机模式操作相关的逻辑。
  • 该寄存器内的操作不会影响到从寄设备的操作;且不应该被修改以控制从属模式的功能。

The TWI master mode control register controls the logic associated with master mode operation.

Bits in this register do not affect slave mode operation and should not be modified to control slave mode functionality.

image-20210525140532502

图 A-145 TWIMCTL 寄存器

表A-131 TWIMCTL 寄存器位功能描述

image-20210525143454398

image-20210525143529519

TWIMADDR

在传输的寻址阶段中,TWI控制器的主机使能,并传输TWI主机模式地址寄存器中的内容。

在对本寄存器进行编程时,忽略读/写位。只有从机地址的前7位(6-0)会被写入本寄存器。

例如:从机的地址是 1010 000x ,则本寄存器的写入内容则是 1010 000(16进制的 0x50 )。将该地址发送至总线时,TWI控制器根据 主机控制寄存器上TWIMDIR 位来决定对从机的读写。

During the addressing phase of a transfer, the TWI controller, with its master enabled, transmits the contents of the TWI master mode address register. When programming this register, omit the read/write bit. That is, only the upper 7 bits that make up the slave address should be written to this register. For example, if the slave address is 1010000X, then TWIMADDR is programmed with 1010000, which corresponds to 0x50. When sending out the address on the bus, the TWI controller appends the read/write bit as appropriate, based on the state of the TWIMDIR bit in the master mode control register.

image-20210525140743855

图 A-146 TWIMADDR 寄存器

TWIMSTAT

  • Not directly associated with the generation of interrupts but offer information on the current transfer.
  • Slave mode operation does not affect master mode status bits.
image-20210603153452903

如果TWIMSTAT寄存器中的第2位是1

image-20210603153655529

image-20210603153719024

TWIFIFOCTL

TWIFIFOCTL(FIFO Control Register),即先进先出控制寄存器,只控制FIFO,完全不与主机模式 或 从机模式操作绑定。

image-20210525144403383

图 A-151 TWIFIFOCTL 寄存器

表A-135 TWIFIFOCTL 寄存器位功能描述

image-20210525144738016

TWIFIFOSTAT

  • 指示FIFO缓冲区的接收和发送内容的状态。
  • FIFO缓冲器不区分主数据和从数据。
  • 可以对FIFO进行管理,允许同时进行主、从操作。
image-20210603152156841
image-20210603152211766
image-20210603152235432

TWITXS: 传输FIFO状态。

这些只读位表示FIFO缓冲器中有效数据字节的数量。该状态在每次使用外围数据总线写入FIFO缓冲区或通过传输移位寄存器读取时被更新。

在每次使用外设数据总线写FIFO缓冲区或通过传输移位寄存器读访问时更新。允许同时访问。

  • 00 = FIFO是空的。无论是单字节还是双字节的FIFO外设写入都会立即通过。
  • 01 = FIFO包含一个字节的数据。对FIFO的单字节外围写立即通过。一个双字节的外设写入要等到FIFO为空时才进行。
  • 11 = FIFO已满,包含两个字节的数据。
  • 10 = 保留

TWIIRPTL

TWIIRPTL(TWI interrupt sources register),即TWI中断源寄存器。

  • 包含了有关 functional areas requiring servicing 的信息。

  • 大量的比特被当做鉴定器/指示器来使用,主要用于 further read 以及 为 不同的状态寄存器提供服务(service various status register)。

  • 在维护了与位绑定的中断源后,用户需要清除该中断源位。

  • 所有的位都是粘性的 (sticky)和 RW1C

image-20210525163016113

图 A-1534 TWIIRPTL 寄存器

表A-137 TWIIRPTL 寄存器位功能描述

image-20210525163933340

image-20210525163959598

TWITXINT

首先要搞清楚,这个TWITXINT 是寄存器还是寄存器位,如果是寄存器位,哪它来自于哪个寄存器呢。目前已知包含TWITXINT的寄存器有:TWIIRPTLTWIIMASKTWIFIFOCTL(TWITXINT2)

在TWIIRPT寄存器中的TWITXINT寄存器位:

发送FIFO服务。

如果 TWIFIFOCTL 寄存器中的 XMTINTLEN2 为 0,则每次 TWIFOSTAT 寄存器中的 TWITXS 字段被更新为 01 或 00 时,该位都被设置。

如果 XMTINTLEN 为 1,则每次 TWITXS 被更新为 00 时,该位都被设置。

1 = 发送 FIFO 缓冲区有一个或两个 8 位位置可供写入。

0 = FIFO不需要服务或TWITXS字段在该位最后被清除后没有变化。

TWITXINT interrupt

This interrupt is generated when there is one or two bytes of empty space in the FIFO. Simple data handling is all that is required.

TWIIMASK

TWIIMARK (TWI Interrupt mask register),即TWI中断隐藏寄存器。

  • 使能中断源(interrupt sources)插入中断输出(Interrupt output)
  • 每一个使能位(enable bit)都会与 TWI中断延迟寄存器(TWIIRPTL,即TWI interrupt latch register)一个中断延迟位(interrupt latch bit)通信。
  • 对TWIIMASK寄存器的读写不会影响 TWIIRPTL 寄存器的内容。

image-20210525145706357

图 A-154 TWIIMASK 寄存器

表A-138 TWIIMASK 寄存器位功能描述

image-20210525150058029

image-20210525150122857

TXTWI8

8位传输用FIFO寄存器(TWI 8-bit transmit FIFO register),做数据缓存之用。

  • 存储数据以“先进先出”的顺序进入通信传输缓存。
  • 尽管外围总线写入带宽是32位,但是只有一个字节会被写入8位的 TXTWI8
  • 伴随着每一次数据写入,TWIFIFOSTAT 寄存器中的 TWITXS 传输状态位都会被更新。
  • 当FIFO缓存存满时,仍有数据需要写入的话,核心就会让数据等着,直到转运缓存(TRANSMIT FIFO BUFFER)由至少一个字节的空间时才能完成写入操作。

image-20210525155309392

图 22-7 8位传输FIFO寄存器

image-20210527114613231

例程

主寄存器初始化函数

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
ADAU1772_1_ADDR = 0X3C;  //第一个从设备的地址是0x3C,其ADDR1和ADDR0引脚均为0;
ADAU1772_2_ADDR = 0X3D; //第一个从设备的地址是0x3D,其ADDR1和ADDR0引脚为0和1;

void Master_TWI_Init(void){
// 预分频为 fPCLK/10 MHz
*pTWIMITR = (0x14) | TWIEN; //0x14和0x80进行 位或操作,将结果148写入TWI主机时间寄存器中

// CLKDIV = TWI SCL period ? 10 MHz time reference
// CLKDIV = (1/100 KHz) / 100 ns = 100
// For 40 - 60 duty cycle, CLKHI = 40 and CLKLOW = 60

*pTWIDIV = (CLKHI << 8) | CLKLOW;

// 需要被访问的从设备的地址
*pTWIMADDR = ADAU1772_1_ADDR;

// 传送至从属设备的第一个字节数据
*pTXTWI8 = 0x00;
*pTXTWI8 = 0x85; //(0101 0101b)

/* // 配置TWIFIFOCTL寄存器,为每个数据字节(byte)生成中断
*pTWIFIFOCTL = TWITXFLUSH | TWIRXFLUSH;
*pTWIFIFOCTL = 0;
*/ //暂时禁用该数据写入寄存器配置(包括中断和写入读取规则等)
*pTWIFIFOCTL = 0x15; //即(0 1111b),详细配置信息请参照《ADSP-214xx SHARC Processor Hardware Reference》

// 中断使能位,上方已经写过了,有些重复
#ifdef INTERRUPT_MODE
*pTWIIMASK |= TWITXINT;
#endif

// 打开TWI的控制寄存器
*pTWIMCTL = (N << 6); //??
*pTWIMCTL |= TWIMEN; // 打开主机模式(Master Mode enable)
}

特性 Features

《HWR》第855页起对TWI进行了描述。

image-20210603140215469
  • 需要使用DPI进行针脚信号的路由,不能使用DAI
  • 支持主从模式
  • 支持数据缓存接入和核心数据接入,不支持DMA
  • 最大时钟频率400KHz
  • 7-bit 寻址
  • 支持多播主机仲裁
  • 主时钟同步和时钟低延伸支持
  • 低中断速率
  • 分离多字节接收和传输的FIFOs
  • 在总线锁死时,对数据和时钟线的独立复写控制
  • 峰值抑制的输入滤波器

image-20210527100834503

image-20210527100951355

针脚描述 Pin Descriptions

image-20210527101956389

SRU编程 SRU Programming

TWI信号可以通过 SRU2 ,如表22-3所示进行路由。

image-20210527102029529

Identify the peripherals that you are trying to connect to the SHARC DSP, and count the unique signals. List the unique I/O signals and look carefully to see what else you may be able to eliminate.

  • 如果时钟或帧同步连接至多个设备,算作一个信号。If the same clock or frame sync is connected to multiple devices, it counts as one signal.

  • 如果与一个串行数据流驱动多个设备,也算作一个信号。When a serial data stream drives multiple output devices, it also counts as a single signal.

  • 如果两个信号相同,但极性相反(倒置),算作一个信号。(因为SRU可以从另一个信号中产生任何一个)

  • 如果一个时钟信号是另一个时钟信号的相位对齐的整数子倍数,则将它们组合在一起。

大多数引脚缓冲区在给定的设计中只在一个方向上使用。请注意,许多外设都具有能够实现双向操作的引脚,但仅在系统中的一个方向上使用。当针脚缓冲区是单向的时,SRU的编程会大大简化。

如果针是双向的,确定方向改变的原因。这是另一个别针的状态吗?它是处理器级控制寄存器的状态吗?它是一个端口的软件配置吗?想想当SHARC将逻辑值驱动到双向针上时,以及当针刚刚读取逻辑输入时,可能会控制什么。

注意 下图中的 PBxx_O / PBxx_I / PBENxx_I 。针脚缓冲器就像一个小型缓冲器放大器,可以提供足够的电流来驱动针脚和电路板上的痕迹。打开时(即当其启用输入为逻辑高时),针缓冲输入处的逻辑值被驱动到针缓冲输出上。当关闭时(即,当其启用输入为逻辑低时),缓冲器放大器为高阻抗,并且引脚缓冲器输出的逻辑电平很容易由外部源控制。引脚缓冲区是与DAI相关联的物理IC包引线的逻辑网关。

image-20210603170447943

由于引脚缓冲器是一个片上外设,连接到物理封装上的信号被称为引脚缓冲器的输出。虽然它是SHARC的一个输入,但它是引脚缓冲器的一个输出。请注意,图1显示了两个连接的轨迹,它们被标记为 PBxx_O(引脚缓冲器输出)。其中一个是SRU接口的一部分,另一个是外部封装连接引脚。当引脚缓冲器被用作输入时,信号会沿着这个路径。换句话说,SRU内的引脚缓冲器输出总是等于外部引脚的逻辑值。

——《Configuring the Signal Routing Unit of ADSP-2126x SHARC® DSPs

只有DAI有 PBEN ,DPI只有 PB。

PAGE 874 - SRU PROGRAMMING MODE

1
2
3
4
5
6
7
SRU(LOW, DPI_PBxx_I); /* input buffer is low */
SRU(TWI_DATA_PBEN_O, DPI_PBENxx_I); /* TWI data output*/
//SRU(DPI_PBxx_O, TWI_DATA_I); /* TWI data input */

SRU2(LOW, DPI_PByy_I); /* input buffer is low */
SRU2(TWI_CLK_PBEN_O, DPI_PBENyy_I); /* TWI clock output*/
//SRU2(DPI_PByy_O, TWI_CLK_I); /* TWI clock input*/

时钟频率 Clocking

  • 外围时钟(fPCLK)是TWI时钟频率的基础。
  • 串行时钟频率最高400KHz,最低20KHz;其分辨率为 1/10MHz 或 100ns。

分频数的计算案例如下:

image-20210527102754286

功能描述 Functional Description

下图22-1展示了TWI控制器的架构。

  • 外围接口(peripheral interface)支持32位宽的数据传输,并被处理器用于支持寄存器和FIFO缓冲器的读写。
  • 寄存器块 包含了所有的控制和状态位,并依托程序模型来反映了可以写入或读取的内容。状态位可由其各自的(respective)功能块更新。
  • FIFO缓冲器 被配置为一个1字节宽、2字节深的发送/接收FIFO缓冲器。

image-20210527103515471

  • 发送移位寄存器(transmit shift)串行地将其数据从外部移出芯片(shift its data out externally off chip)。该输出可以被控制以产生确认,也可以被手动改写。
  • 接收移位寄存器(receive shift)从片外串行接收其数据(receive its data serially from off chip)。接收移位寄存器的宽度为1个字节,收到的数据可以被转移到FIFO缓冲区或用于地址比较(address comparison)。
  • 地址比较块 (address compare block)支持在TWI控制器模块作为从机访问时的地址比较。
  • 预分频器块 (prescaler block)必须被编程以产生一个相对于外设时钟的 10MHz 时间基准。这个时间基准用于过滤数据和数据表中电气参数指定的定时事件(见飞利浦的I2C总线规范),以及 TWI_CLOCK 的时钟信号生成。
  • 时钟生成模块 (clock generation module)用于在主模式下生成一个外部串行时钟(TWI_CLOCK)。它包括在多主时钟配置中进行同步所需的逻辑,以及在从属模式下配置时的时钟拉伸。

时钟输出

TWI控制器的时钟输出遵循以下规则。

  1. 一旦时钟高电平(CLKHI)计数完成,串行时钟输出(serial clock output)被驱动为低电平,时钟低电平(CLKLOW)计数开始。

  2. 一旦时钟低电平计数完成,串行时钟线被三振(three-stated),时钟同步逻辑进入延迟模式(阴影区),直到 TWI_CLOCK 线被检测到逻辑1电平。这时,时钟高电平计数开始。

TWI控制器只在主控模式运行时发出时钟,而且只在传输启动时发出。如果总线的仲裁(arbitration)丢失,串行时钟输出立即进入三态(three-states)。如果多个时钟试图驱动串行时钟线,TWI控制器将其时钟与其他剩余的时钟同步。这在图22-2中有所说明。

The TWI controller only issues a clock during master mode operation and only at the time a transfer has been initiated.

image-20210603144317584

TWI控制器遵守《Philips I2C Bus Specification version 2.1 dated January 2000》传输协议。图22-3是简易的TWI传输示意。

image-20210603145223033

图22-4是TWI控制器在传输过程中的寄存器映射。

image-20210603145235075

总线仲裁 Bus Arbitration

image-20210603145739629

开始与结束情景 Start & Stop condition

操作模式 Operating Modes

通用呼叫寻址 General Call Addressing

如果TWI控制器被启用为从机(TWISEN),并且使用TWIGCE位启用了一般呼叫,则TWI控制器总是解码并确认一般呼叫地址。一般呼叫寻址(0x00)由GCALL位的设置表示,根据传输的性质,TWI控制器是一个从属接收者。如果与传输相关的数据不被确认(NAKed),TWINAK位可以被设置。

如果TWI控制器作为主发射器发出一个总调用,可以设置适当的地址和传输方向,同时加载发送FIFO数据。

The TWI controller always decodes and acknowledges a general call address if it is enabled as a slave (TWISEN) and if general call is enabled using the TWIGCE bit. General call addressing (0x00) is indicated by the setting of the GCALL bit, and by the nature of the transfer, the TWI controller is a slave-receiver. If the data associated with the transfer is to be not acknowledged (NAKed), the TWINAK bit can be set.

If the TWI controller is to issue a general call as a master-transmitter, the appropriate address and transfer direction can be set along with loading transmit FIFO data.

从设备模式寻址 Slave Mode Addressing

With the appropriate selection of 7-bit addressing using the TWISLEN bit, the corresponding number of address bits (SADDR) are referenced during the address phase of a transfer.

主设备模式寻址 Master Mode Addressing

无论是启用主发送器还是使用 TWIMLEN 位进行7位寻址的主接收器,TWI主站都会按要求执行所有寻址和数据传输。这包括产生重复启动条件,重新传输第一个地址字节的7位,以及确认和产生一个新的传输方向变化(由 TWIMLEN 位指示)。

Whether enabled as a master-transmitter or master-receiver with 7-bit addressing using the TWIMLEN bit, the TWI master performs all addressing and data transfers as required. This includes generating the repeated start condition, re-transmission of the 7-bits of the first address byte, and acknowledgement and generation of a new transfer direction change (indicated by the TWIMLEN bit).

快速模式 Fast Mode

Fast mode (400 kHz) uses essentially the same mechanics as standard mode (100 kHz). It is the electrical specifications and timing that are different. When fast mode is enabled using the TWIFAST bit, the following timings are modified to meet the electrical requirements.

  • Serial data rise times before arbitration evaluation (tr)
  • Stop condition setup time from serial clock to serial data (tSUSTO)
  • Bus free time between a stop and start condition (tBUF)

数据传输 Data Transfer

PAGE867:

数据传输部分介绍 3个寄存器4个缓冲区域3个缓存状态

寄存器 Register

Serial Shift Register: TWI有一个输入和输出的串行移位器,下面将介绍。

Output Shift Register: 发送移位寄存器接收字节宽的缓冲区数据或寄存器数据(地址),并将其数据从外部串行移出芯片。该输出可以被控制以产生确认信号,也可以被手动改写。

Input Shift Register: 接收移位寄存器从芯片外串行地接收数据。在内部,接收移位寄存器是字节宽的,收到的数据可以被转移到缓冲区或用于地址比较。

中断 Interrupt

image-20210527104039047

调试特征 Debug Feature

Masking

1
2
3
4
bit set IMASK P14I; /* unmasks P14I interrupt */
ustat1=dm(DPI_IMASK_RE); /* set TWI Int */
bit set ustat1 TWI_INT;
dm(DPI_IMASK_RE)=ustat1;

Service

1
2
3
4
5
6
7
8
9
10
11
TWI_ISR:
ustat1 = dm(TWIIRPTL); /* read IRPTL to identify cause*/
bit TST ustat1 TWITXINT; /* test TX buffer bit*/
IF TF jump TX_BUF;

TX_BUF:
dm(TWIIRPTL) = ustat1; /* RW1C to clear TWI TX buffer
interrupt */
r0=dm(TWIMCTL); /* dummy read*/
instruction;
rti;

主设备发送模式

以下为单主机传输模式的的编程过程: 1. Program the TWIMADDR register. - This defines the address transmitted during the address phase of the transfer. 2. Program the TXTWI8 or TXTWI16 registers. - This is the initial data transmitted. - It is considered an error to complete the address phase of the transfer and not have data available in the transmit FIFO buffer. 3. Program the TWIFIFOCTL register. - Indicate if transmit FIFO buffer interrupts should occur with each byte transmitted (8 bits) or with each 2 bytes transmitted (16 bits). 4. Program the TWIIMASK register. - Enable the bits associated with the desired interrupt sources. - For example, programming the value 0x0030 results in an interrupt output to the processor when the master transfer completes, or if a master transfer error has occurred. 5. Program the TWIMCTL register. - This prepares and enables master mode operation. - As an example, programming the value 0x0201 enables master mode operation, generates a 7-bit address, sets the direction to master-transmit, uses standard mode timing, and transmits 8 data bytes before generating a stop condition.

image-20210527104628291

Clock

The PLLD bits define the VCO output clock to core clock ratio to build the processor core clock (CCLK). The post divider can be changed any time and new division ratios are implemented on the fly.

The PCLK and CLKIN clocks are used in the arbitration logic for the shared external bus.

The PLL bit settings PLLM/PLLD in PMCTL register need to be programmed such that the PLLM/PLLD ratio is integer (for example 15/2=7.5 fractional, is not allowed).

IOP Clock (PCLK)

The peripheral clock is derived from the core clock with a fixed post divisor of 2.

This clock is the master clock for most peripherals including the I/O processor (IOP).

PLL

PLL Registers

PMCTL

PMCTL 寄存器,Power management control register。(是的,没错,就是不知道为啥管PLL的要叫PMCTL)

  • Controls the SDCLK to core clock ratio or DDR2CLK to core clock ratio related to the external port timing.
    • The fundamental timing clock of the external port is SDRAM clock (SDCLK). The SDRAM clock ratio settings are independent from the peripheral clock (PCLK).
      • The AMI/SDRAM controller is capable of running at up to 133 MHz for ADSP-2147x processors. See Table 4-2 for more information about EXTERNAL PORT CLOCK FREQUENCIES.
    • The fundamental timing clock of the external port is DDR2 clock (DDR2_CLK). The DDR2 clock ratio settings are independent from the peripheral clock (PCLK).
  • 32位内存映射寄存器(32-bit memory-mapped register)
  • 包含控制位,可控制:锁相环(PLL, phase lock loop)(PLL乘法器值(multiplier)、PLL除法器值(divider)、锁相环旁路模式(PLL bypass mode) 和 外围设备使能时钟控制(clock control for enabling peripherals))
  • 包含状态位,可追踪:CLK_CFG针脚(可读写)
  • PMCTL 寄存器的复位值取决于 CLK_CFG 引脚(bits 5-0 & 17-16)
  • 包含三选一的加速器(FIR、IIR、FFT)

image-20210608101359924

image-20210527150852485

图 A-2 PMCTL 寄存器

表A-3 PMCTL寄存器位功能描述

image-20210527151035867
image-20210527151017770
image-20210527151110432

PMCTL1

image-20210527152044822

图 A-3 PMCTL1 寄存器

表A-4 PMCTL1寄存器位功能描述

image-20210527152155406
image-20210527152229763
image-20210527152251696

PLLD

Page 888: PLLD(PLL Divider)定义了 VCO输出时钟核心时钟 的比值,以构建 处理器核心时钟(CCLK)。正在使用的分频器可以被随时改变,新的分频比率可以实时被应用。

Page 957: PLLD只有2位,可以设置为2、4、8、16。

image-20210529113003651

<def21479.h>:image-20210529113403231

以下这几个操作中均需要用到PLLD,分别是:

  • 输出时钟生成器编程模型 (Output Clock Generator Programming Model)
  • 改变链接口时钟(Changing the Link Port Clock)
  • 发布分频器(Post Divider)

image-20210529111641680

image-20210529111748944

image-20210529112121464

官方示例

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
49
50
51
52
53
54
55
56
57
void Init_PLL(void)
{
int temp,i;

// Step 1 - change the PLLD to 4
temp=*pPMCTL; //备份PMCTL寄存器的值至temp
temp&=~PLLD16 ; //0x20,将PLLD16的值和temp进行逐位“与”运算
temp|=(PLLD4 | DIVEN) ; //0x260 0010 0110 0000
*pPMCTL = temp;

// Step 2 - 等待分频器稳定
SysWait(16);

// Step 3 - set INDIV bit now to bring down the VCO speed and enter the bypass mode
temp&=~DIVEN;
temp|=(INDIV | PLLBP);
*pPMCTL = temp;

// Step 4 -等待PLL锁定
SysWait(4096);

// Step 5 - come out of the bypass mode
temp=*pPMCTL;
temp&=~PLLBP;
*pPMCTL = temp;

// Step 6 - 等待分频器稳定
SysWait(16);

// Step 7 - set the required PLLM and INDIV values here and enter the bypass mode
//PLLM=16, INDIV=0, fVCO=2*PLLM*CLKIN = 2*16*16.625 = 532 MHz
temp = *pPMCTL;
temp&=~ (INDIV | PLLM63);
temp|= (PLL_MULT| PLLBP);
*pPMCTL = temp;

// Step 8 - wait for the PLL to lock
for(i=0;i<4096;i++);

// Step 9 - come out of the bypass mode
temp = *pPMCTL;
temp&=~PLLBP;
*pPMCTL=temp;

// Step 10 - wait for dividers to stabilize
SysWait(16);

// Step 11 - set the required values of PLLD(=2) and SDCKR (=2.5 for ADSP-21489 and 2 for ADSP-21479) here
// fCCLK = fVCO/PLLD = 532/2 = 266 MHz, fSDCLK = fCCLK/SDCKR = 266/2 = 133 MHz
temp=*pPMCTL;
temp&=~(PLLD16 | 0x1C0000 );
temp|= (SDCKR2 | PLLD2 | DIVEN);
*pPMCTL=temp;

// Step 12 - wait for the dividers to stabilize
SysWait(16);
}

问题1: 为啥一定要使用temp变量来进行处理,直接使用 *pPMCTL 不是更方便吗?

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
49
50
51
52
53
54
55
56
void initPLL()
{

/********************************************************************************************/

int i, pmctlsetting;

// Set INDIV bit in PMCTL register
pmctlsetting = *pPMCTL; // 备份PMCTL寄存器的原始值
pmctlsetting |= INDIV; //设置锁相环输出的分频率,0则是1分频,1则是2分频,此处通过或运算设置为二分频
*pPMCTL = pmctlsetting; // 将至重新写入PMCTL寄存器

// Program PLL multiplier to same value as CLK_CFGx pins/previously programmed value in software……
*pPMCTL = pmctlsetting;
pmctlsetting |= PLLBP; //设置锁相环旁路模式
*pPMCTL = pmctlsetting;

//Wait for recommended number of cycles
for (i = 0; i < 4096; i++)
NOP;

// Bring PLL out of bypass mode by clearing PLLBP bit
*pPMCTL ^= PLLBP; // 通过异或操作 取消旁路模式

for (i = 0; i < 16; i++)
NOP;

pmctlsetting = *pPMCTL;
pmctlsetting &= ~PLLM63; //通过按位取反操作和与操作,清除PLLM所有位
pmctlsetting &= ~INDIV; //通过按位取反操作和与操作,清除分频
// *pMCTL |= INDIV;
*pPMCTL = pmctlsetting;

// CLKIN = 16.625 MHz, PLLM=32, PLLD = 1, INDIV= 1 => fINPUT = 16.625/2 = 8.3125 MHz
// CCLK = 2*PLLM*fINPUT/2*PLLD = (2*32*8.3125)/(2*1) = 266 MHz, SDCLK = CCLK/2 = 133 MHz
// VCO frequency = 2*fINPUT*PLLM = 2*8.3125*32 = 532 <= fVCOmax (532 MHz)

pmctlsetting = SDCKR2 | PLLM32 | INDIV | DIVEN; //设置
*pPMCTL = pmctlsetting;

pmctlsetting |= PLLBP; //Setting the Bypass bit
pmctlsetting ^= DIVEN; //Clearing the DIVEN bit
*pPMCTL = pmctlsetting; // Putting the PLL into bypass mode

//Wait for around 4096 cycles for the pll to lock.
for (i = 0; i < 5000; i++)
NOP;

pmctlsetting = *pPMCTL;
pmctlsetting ^= PLLBP; //清除旁路模式
*pPMCTL = pmctlsetting;

//Wait for around 15 cycles for the output dividers to stabilize.
for (i = 0; i < 16; i++)
NOP;
}

更改之后:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
void SystemWait(unsigned int MAX){
int i;
for(i = 0; i < MAX; i++) NOP;
}

void initPLL()
{
*pPMCTL |= INDIV; //设置锁相环输出的分频率,0则是1分频,1则是2分频,此处通过或运算设置为二分频
*pPMCTL |= PLLBP; //设置锁相环旁路模式
SystemWait(4096);

*pPMCTL ^= PLLBP; // 通过异或操作 取消旁路模式
SystemWait(16);

*pPMCTL &= ~( PLLM63 | INDIV ); //PLLM和INDIV位全部或操作后取反,再与原PMCTL里的数据与操作,清除该两个定义位的数据
*pPMCTL = SDCKR2 | PLLM32 | INDIV | DIVEN; //设置这几个位置的值
*pPMCTL = (*pPMCTL | PLLBP) ^ DIVEN
SystemWait(4096);

*pPMCTL ^= PLLBP; //清除旁路模式
SystemWait(16);
}

当使用乘法器(multipliers)和已发布的分频器(post dividers)对PLL进行编程时,DIVENPLLBP 不可以在同一个时钟周期内被编程。注意:DIVEN 位会自动清零(self clearing)。

∵ CLKIN = 16.625 MHz, PLLM=32, PLLD = 1, INDIV= 1 ∴ fINPUT = 16.625/2 = 8.3125 MHz ∴ CCLK = 2*PLLM *fINPUT/2*PLLD = (2*32*8.3125)/(2*1) = 266 MHz ∴ SDCLK = CCLK/2 = 133 MHz, 符合 2147X 对 SDRAM 时钟的要求 VCO frequency = 2*fINPUT*PLLM = 28.312532 = 532 <= fVCOmax (532 MHz)

步骤总结

从官方给出的示例代码中,可以将步骤总结如下:

  1. 设置PLLD - 等待分频器稳定
  2. 设置INDIV位以降低VCO速度,并进入旁路模式 - 等待PLL锁定
  3. 从旁路模式出来 - 等待分频器稳定
  4. 设置PLLM和INDIV,并进入旁路模式 - 等待PLL锁定
  5. 从旁路模式出来 - 等待分频器稳定
  6. 设置PLLD和SDCKR - 等待分频器稳定

从以上步骤可以看出,PLL的初始化,主要是设置 PLLDINDIVPLLMSDCKR 的值,途中反复等待 分频器稳定PLL锁定

问题总结

  1. 进入旁路模式的意义:

Interrupt Control of PINs

Page93

For information on the IRPTL, LIRPTL, and IMASK registers, see SHARC Processor Programming Reference.

下表2-1介绍了经过DAI和DPI的数据通道:

  • DAI共有32个通道(22个外围设备通道,10个miscellaneous通道),DPI共有12个通道(3个外围设备通道,9个miscellaneous通道)
  • DAI允许设置优先级,而DPI不允许
  • DAI和DPI都能识别上升沿(Rising Edge)或下降沿(Falling Edge)
  • 到核心的中断(Interrupt to Core),DAI为2,DPI为1
  • DAI和DPI都是4分频
image-20210602150117965

特征

  • 两个系统中断控制器(SIC, System Interrupt Controller),分别为DAI SIC 和 DPI SIC,连接至核心中断控制器(CIC, Core Interrupt Controller)。

  • DAI SIC 允许高/低中断优先级配置选项

  • DAI中断控制器提供最高32条独立可配置通道

  • DPI中断控制器提供最高12条独立可配置通道

  • DAI SIC和DPI SIC都允许针对波形的上升沿或下降沿进行锁存

  • 与核心锁存中断一致的中断延迟

  • 时钟:系统中断控制器的基础时钟是 4分频 (fPCLK)/4 ;所有中断的确认响应速度为4分频最高。

中断寄存器

可编程中断控制寄存器PICR3 - 0): 为了登记(assign)独立优先级(individual priorities)到各外围通道,19个外围设备可路由至可编程中断输入。

DAI 中断屏蔽寄存器DAI_IMASK):屏蔽上升或下降沿波形。因可屏蔽的边沿有上升沿或下降沿,因此DAI中断屏蔽寄存器分为 DAI_IMASK_RE 和 DAI_IMASK_FE。

DAI 中断屏蔽优先级寄存器DAI_IMASK_PRI):为DAI高/低中断优先级屏蔽中断。

DAI 中断锁存寄存器DAI_IRPTL): 为DAI高/低优先级中断锁存中断。

DPI 中断屏蔽寄存器DPI_IMASK):屏蔽上升或下降沿波形。因可屏蔽的边沿有上升沿或下降沿,因此DPI中断屏蔽寄存器分为 DPI_IMASK_RE 和 DPI_IMASK_FE。

DPI 中断锁存寄存器DPI_IRPTL):为DPI中断锁存中断。

image-20210603134437928
image-20210603134453465

功能描述

可编程中断优先级控制

外围中断

软件中断

多重中断请求信号的外围设备

系统中断控制器

DAI/DPI外围相关事件发生时,这些针脚各自拥有能够指向核心的系统中断控制器。

相对于SHARC核心,音频事件通常发生不频繁,DAI/DPI中断控制器将其所有中断减少到核心主中断系统中的三个中断信号上:

  • 一个映射为DAI低优先级
  • 一个映射为DAI高优先级
  • 第三个映射到DPI中断。

以上这种操作,允许程序更加粗略地去表示优先级。

输出总线中断信号可以有逻辑地导向(ORed)一个中断线并递交至(fed to)核心中断控制逻辑。

The output bus interrupt signals are logically ORed into one interrupt line and fed to the core’s interrupt controller logic.

image-20210602154656729

注意:DAI/DPI中断控制器拥有与核心中断控制器相同的中断延迟,或6个延时周期以相应异步中断。

被用于配置DAI中断控制器的有3个寄存器,被用于配置DPI中断控制器的有2个寄存器。32个DAI中断源和12个DPI中断源中的任意一个都可以用于独立配置开关,来控制进入信号的上升沿、下降沿、上升下降沿(both edges)或无沿(neither edge)。

需要注意的是,当核心中断寄存器是系统寄存器时,DAI/DPI中断控制寄存器是被内存映射的寄存器(memory mapped registers),且通过外围设备总线被接入(accessed via the peripheral bus)。

DAI/DPI中断源

DAI有5个外围(中断)源都被多路复用至(multiplexed into)32个中断源里,并以 DAI_INT 0 ~ 31 作为标签名称。

DPI有3个外围(中断)源都被多路复用至(multiplexed into)12个中断源里,并以 DPI_INT 0 ~ 13 作为标签名称。

下表介绍了DAI/DPI在不同的通信方式和信号响应的关系。

image-20210602195334432

DAI中断锁存优先级设置

DAI系统中断控制器寄存器对( DAI_IRPTL_HDAI_IRPTL_L)取代了通常由核心中断控制器的IRPTL寄存器执行的功能。一个单一的寄存器( DAI_IRPTL_PRI)指定了这些中断被映射到哪个锁存器中。

当一个DAI中断被配置为低优先级(DAI_IMASK_PRI 位被清除,默认设置),它将被锁在 DAI_IRPTL_L 寄存器中。低优先级的DAI中断,DAILI,被连接到 P12I 核心中断上。默认情况下。PICR 寄存器可以改变这种连接。每当DAI的低优先级中断被设置,LIRPTL寄存器中的 DAILI 位就会被设置,核心就会为该低优先级中断服务。

image-20210602200433030

注意: DAI会在中断向量表中触发一个高优先级一个低优先级的中断。当任一来自DAI的中断需要服务时,两个核心ISR之一必须审查(interrogate)DAI的中断控制器以判定其中断源。

中断向量表(Interrupt Vector Table, IVT), Page 177

image-20210602205507981

DPI中断锁存

DPI系统中断控制寄存器(DPI_IRPTL)取代了通常是由核心控制器寄存器(IRPTL)的功能。

当DPI中断配置时,将被锁存在 DPI_IRPTL 寄存器中。默认情况下,DPI中断被连接至P14I核心中断。PICR寄存器可以改变其连接。无论何时,DPI中断一旦设置,LIRPTL 寄存器中已编程的DPI位会被设置,且核心将会为已编程优先级的中断服务。

DAI/DPI边沿触发中断屏蔽

DAI上升沿中断屏蔽寄存器 DAI_IMASK_RE 和 DAI下降沿中断屏蔽寄存器 DAI_IMASK_FE 取代了核心中断控制器 IMASK 的版本。与 IMASK 寄存器一样,这些DAI寄存器提供了一种指定(specify)哪条中断被确认和处理,哪条中断会被忽略的方法。这对寄存器的功能与 IMASK 一致,但具有更高程度的细化。

DAI_IMASK_REDAI_IMASK_FEDPI_IMASK_REDPI_IMASK_FE这些寄存器的使用,能够使程序对上升沿、下降沿、上升下降沿、或者无沿(neither rising or falling edge)的程序确认或响应能够分别独立地屏蔽(masked separately)。

从SRU过来的信号能够被用于生成中断。例如,当 DAI_IMASK_FE 寄存器的 DAI_30_INT 位被设置为1时,任何从外部通道过来的下降沿信号都能在核心中生成中断,且中断锁存器会被设定。对 MASK 寄存器的读取不会清除 IRPTL 寄存器。

DAI/DPI事件中断屏蔽

系统中断控制器需要一个外设的中断源与事件信号相对应的信息(参考第2-8页中的表2-2)。如此一来,就只有上升沿被当做中断源。对于被标记为事件的DAI/DPI外设,程序可以只在上升沿解除中断源的屏蔽。

DAI/DPI中断服务

当多通道被复用至一个中断输出信号时,中断确认的操作方式不尽相同。当DAI/DPI中的服务必须被处理时,三者任一的中断服务程序(interrupt service routines)(DAILI, DAIHIDPII)必须查询RIC以确定中断源。该中断源可能是一个或多个DAI/DPI通道(DAI_INT31-0DPI_INT13-0)。

  • DAI_IRPTL_H 被读取时,高优先级锁存的中断将会被清除。
  • DAI_IRPTL_L 被读取时,低优先级锁存的中断将会被清除。
  • DPI_IRPTL 被读取时,锁存中断将会被清除。
  • DAI_IRPTL_H/L 寄存器被读取时, IDP_FIFO_GTN_INT 中断不会被清除。当中断需要离开的情况发生时,中断自然会被清除。(This interrupt is cleared automatically when the situation that caused the interrupt goes away.)
  • DPI_IRPTL_SH 是被用于读取主寄存器 DPI_IRPTL的影子寄存器。读取这些影子寄存器将会返回 DPI_IRPTL 寄存器中的数据却不会清除里面的内容。

如果在清空锁存器的同一周期内发生中断,则该机制的优先级较低,新的中断器被注册。

注意

  • TWII 和UARTRXI 中断不遵循这条原则。确认信号将在这些外围锁存器中发生。
  • 读取中断锁存器(DAI_IRPTL_XDPI_IRPTL )将会清除中断(只读清除类型)。因此,ISR必须为所有已发现的中断提供服务。即如果复用中断(mumtiple interrupts)被锁存在复用屏蔽寄存器(multiple mask registers)中,必须在执行 RTI 指令前,对所有中断进行服务。

RTI ((interrupt) return instruction):中断返回指令

在中断服务程序中用于返回中断指令,在运行中断之前,用JSR指令将PC(程序计数器)和SR(状态寄存器)压入堆栈,当中断服务程序结束时,执行RTI或RTIS指令,将PC和SR从堆栈中弹出。

——RTI

中断服务

中断服务部分主要描述了中断服务程序操作(interrupt service routines operate)如何正确清除中断请求。

中断驱动I/O是较为有利(advantageous)的,因为核心并不需要去轮询(poll)输入信号。当一次中断触发时,定序器(sequencer)通常会完成其现有的指令并跳转至中断向量表(IVT)。(向量)地址(the address)通常会从向量表里指向ISR程序。定序器(sequencer)跳转至该程序,完成程序执行并通过执行RTI指令退出程序。然而,这条规则并不对所有情况适用,在ISR程序中,有三种中断确认机制,均取决于外围设备:

  • RTI指令
  • 只读清除(ROC)状态位 + RTI指令
  • 写1清除(W1C,Write-1-to-clear)状态为 + RTI指令

锁存器必须在被读取的时候清除中断源,因此DAI/DPI被设计来正确地执行此项工作。需要注意的是,锁存器读取操作会在退出中断程序(exiting an interrupt routine)前自动确认请求(automatically acknowledges the request)。在W1C机制,程序必须写入锁存器的特定位(specific bit)以正确清除中断(terminate the interrupt properly)。

注意:如果确认机制没有被正确遵守,中断将可能在未可预知且频率不定(unwanted and sporadic)的情况下发生。

核心缓存服务请求(输入输出模式)

如果数据流外围设备通过核心访问各自DMA FIFO的数据缓存,则缓存(器)在中断确认过程中发挥着重要作用。

例如,一个接收缓存已满,中断生成时ISR中的缓存被读取,就会触发清除请求(ROC + RTI)。同样的,如果一个传输缓存已空,中断生成时,写入操作将会清除请求(WOC + RTI)。

DMA接入

如果外设通过DMA访问缓冲区,逻辑操作就不同了。在DMA中,缓存状态对中断没有影响。相反,每当DMA计数寄存器达到0时就会产生一个中断。不同的外围设备所使用的中断确认机制都不同。

DMA Direct Memory Access 直接内存访问

是所有现代电脑的重要特色,它允许不同速度的硬件装置来沟通,而不需要依赖于 CPU 的大量中断负载。否则,CPU 需要从来源把每一片段的资料复制到暂存器,然后把它们再次写回到新的地方。在这个时间中,CPU 对于其他的工作来说就无法使用。

中断延迟

优秀的编程会要求一条(完整的)中断服务 确认 中断请求尽可能简洁地返回至外围设备。这种(中断)响应允许外围设备尽可能快地感知到其他事件。

此(中断确认)服务程序(routine)必须去确保(中断)请求在RTI指令执行前被释放,否则(中断)服务程序会在执行完RTI指令后被立即调用。

有些中断请求通过W1C操作来清除,该写入指令并没有让核心停滞(stall the core)。相反,该操作被自动锁存在写缓存中,并在被发送至外围总线前会通过外围时钟(PCLK)进行同步。

在W1C操作到达外围设备前,此操作可能会需要多个 CCLK 周期(cycles)。如果 W1C 操作在服务程序的结束点进行操作,一个 dummy 读取操作需要在RTI指令前被执行,以确保外围设备能够在RTI之前释放请求。

下列案例描述了中断延迟:

  • 对于具有W1C确认机制的外设来说,写入外设的状态寄存器以清除中断会导致一定的延迟(因为寄存器的写入效应延迟)。
  • 中断驱动的数据传输(核心或DMA)来自任何产生中断和使用ISR程序(routine)的外设,写入外设数据缓冲区(以清除中断)或控制寄存器会导致一定的延迟(因为存在寄存器写入效果延迟和缓冲区时钟域)。

如果像案例所示,程序在延迟的周期内(最多10个CCLK周期),程序从中断服务程序(RTI指令)中生成,中断再次出现。为了避免中断多次出现,需要采取下列其中一种措施:(注意:中断再生的限制(interrupt regeneration restriction)不适用于DMA操作模式下的任何SPORT。)

  1. 在中断返回(RTI)前,从相同的外围区块中读取IOP寄存器。读取操作(的同时)会强制写入,如下列样例所示。

SPI中断服务程序

1
2
3
4
R0 = dm(i0,m0);
dm(TXSPI) = R0; // 写入SPI数据缓存
R0 = dm(SPICTL); /* this dummy read forces the previous write to complete */
rti;

PWM中断服务程序:

1
2
3
4
r1 = PWM_STAT3;
dm(PWMGSTAT)=r1; /* W1C to PWM status reg */
r0=dm(PWMGSTAT); /* this dummy read forces the previous write to complete */
rti;
  1. 在写入操作后添加足够的NOP指令。在最坏的情况下,程序需要在写入后添加10条NOP指令,如下面的示例代码所示。

中断服务程序

1
2
3
4
5
R0 = 0x0;
dm(SPICTL) = R0; /* or disable SPI control */
nop; nop; nop; nop; nop;
nop; nop; nop; nop; nop;
rti;

DMA完成类型

在SHARC处理器中,中断在内部传输完成(此时DMA计数器过期(expired))后被生成。但是,在某些案例中,传输可能尚未完成(不同通道优先级的原因)且有效的数据仍然存在于(resides in)外设的缓冲区中等待着被传输。为了解决此问题,引入了中断访问完成模式(interrupt access completion mode),在此模式下,上一个数据离开缓存时,中断会被生成。此模式可用于 SPORT 、 SPI 、 连接口 和 外部接口DMA。

调试特征

影子中断寄存器

  • 影子中断寄存器(Shadow Interrupt Register)可用于 IDP, S/PDIF, ASRC, UART, TWI 和 DAI/DPI。

  • DAI/DPI 中断控制器拥有可以简化调试活动且不会操纵状态控制(manipulate status control)的影子寄存器。

  • 任何对 DAI_IRPTL_x_SHDPI_IRPTL_SH 影子寄存器的读取都会提供 和 读取 DAI_IRPTL_xDPI_IRPTL 寄存器一样的数据。

  • 对DAI/DPI影子寄存器的读取不会改变核心中断控制器(core interrupt controller)对中断的确认状态。

术语总结

中断确认

中断请求

中断服务

中断延迟

SPORT

对所有SPORT的研究仅限于对I2S开发中需要的研究。

首先,SPORT是指Serial Port,即串行接口。有0 ~ 7 共8个这样的SPORT。

image-20210629151245935

如果需要用到I2S模式,则需要针对 SPCTLxSPMCTLx 两个寄存器中的某些位做单独设置,其设置指引表格如下 :

image-20210629150923785

SPCTL

SPCTL 寄存器在多种模式下具有不同的位定义。

寄存器位指示

image-20210629162509309

image-20210629162550029

image-20210629162728195

寄存器位说明

image-20210629172318405

image-20210629172412087

image-20210629172430662

image-20210629172455121

image-20210629172510903

image-20210629172534214

image-20210629172549089

SPCTLNx

FE: frame edge 帧边沿

FS: frame sync 帧同步

These registers (where x signifies SPORT 0 through 7) allow programs to set frame sync edge detection for I2S compatibility. These registers also allow interrupts to be generated when transmit DMA count is expired or when the last bit of last word is shifted out.

image-20210630162335568

注意:212XX系列和213xx系列芯片上并没有这个寄存器。

image-20210630162415539
image-20210630162442482
image-20210630162505383

SPMCTLx

串行接口多通道控制寄存器,Serial ports multichannel control registers

在214xx系列芯片中,该寄存器独立工作,并不成对操作;因此每一个SPORT都有其独立的多通道控制寄存器,所以只需要向两个SPMCTLx寄存器写一次,就可以将SPORT作为一对来操作。

image-20210630162916913

其中,x表示0、2、4、6,y表示1、3、5、7。

image-20210630163319226
image-20210630163357041
image-20210630163451919

DMA

DMA(Direct Memory Access,直接存储器访问) 是所有现代电脑的重要特色,它允许不同速度的硬件装置来沟通,而不需要依赖于 CPU 的大量中断负载。否则,CPU 需要从来源把每一片段的资料复制到暂存器,然后把它们再次写回到新的地方。在这个时间中,CPU 对于其他的工作来说就无法使用。

CPU和DMA控制器对内存的访问是交替进行的,因为对内存的访问涉及到总线控制,而DMA控制器和CPU在同一时刻仅有一个能获取总线控制权。更具体的DMA控制器与CPU工作方式见下方 传送方式

DMA传输方式无需CPU直接控制传输,也没有中断处理方式那样保留现场和恢复现场过程,通过硬件为RAM和IO设备开辟一条直接传输数据的通道,使得CPU的效率大大提高。

DMA 传输将数据从一个地址空间复制到另外一个地址空间。当CPU 初始化这个传输动作,传输动作本身是由 DMA 控制器来实行和完成。典型的例子就是移动一个外部内存的区块到芯片内部更快的内存区。像是这样的操作并没有让处理器工作拖延,反而可以被重新排程去处理其他的工作。DMA 传输对于高效能 嵌入式系统算法和网络是很重要的。

DMA

在实现DMA传输时,是由 DMA控制器 直接掌管总线,因此,存在着一个总线控制权转移问题。即DMA传输前,CPU要把总线控制权交给DMA控制器,而在结束DMA传输后,DMA控制器应立即把总线控制权再交回给CPU。一个完整的DMA传输过程必须经过 DMA请求DMA响应DMA传输DMA结束 4个步骤。

请求:CPU对DMA控制器初始化,并向I/O接口发出操作命令,I/O接口提出DMA请求。

响应:DMA控制器对DMA请求判别优先级及屏蔽,向总线裁决逻辑提出总线请求。当CPU执行完当前总线周期即可释放总线控制权。此时,总线裁决逻辑输出总线应答,表示DMA已经响应,通过DMA控制器通知I/O接口开始DMA传输。

传输:DMA控制器获得总线控制权后,CPU即刻挂起或只执行内部操作,由DMA控制器输出读写命令,直接控制RAM与I/O接口进行DMA传输。在DMA控制器的控制下,在存储器和外部设备之间直接进行数据传送,在传送过程中不需要中央处理器的参与。开始时需提供要传送的数据的起始位置和数据长度。

结束:当完成规定的成批数据传送后,DMA控制器即释放总线控制权,并向I/O接口发出结束信号。当I/O接口收到结束信号后,一方面停 止I/O设备的工作,另一方面向CPU提出中断请求,使CPU从不介入的状态解脱,并执行一段检查本次DMA传输操作正确性的代码。最后,带着本次操作结果及状态继续执行原来的程序。

由此可见,DMA传输方式无需CPU直接控制传输,也没有中断处理方式那样保留现场和恢复现场的过程,通过硬件为RAM与I/O设备开辟一条直接传送数据的通路,使CPU的效率大为提高。

传送原理

DMA技术的出现,使得外围设备可以通过DMA控制器直接访问内存,与此同时,CPU可以继续执行程序。那么DMA控制器与CPU怎样 分时使用内存 呢?通常采用以下三种方法:

  1. 停止CPU访问内存;

  2. 周期挪用;

  3. DMA与CPU交替访问内存。

停止CPU访问内存

当外围设备要求传送一批数据时,由DMA控制器发一个停止信号给CPU,要求CPU放弃对地址总线、数据总线和有关控制总线的使用权。DMA控制器获得总线控制权以后,开始进行数据传送。在一批数据传送完毕后,DMA控制器通知CPU可以使用内存,并把总线控制权交还给CPU。图(a)是这种传送方式的时间图。很显然,在这种DMA传送过程中,CPU基本处于不工作状态或者说保持状态。

image-20210630135714198

优点: 控制简单,它适用于数据传输率很高的设备进行成组传送。

缺点: 在DMA控制器访问内存阶段,内存的效能没有充分发挥,相当一部分内存工作周期是空闲的。这是因为,外围设备传送两个数据之间的间隔一般总是大于内存存储周期,即使高速I/O设备也是如此。例如,软盘读出一个8位二进制数大约需要32us,而半导体内存的存储周期小于0.5us,因此许多空闲的存储周期不能被CPU利用。

周期挪用

当I/O设备没有DMA请求时,CPU按程序要求访问内存;一旦I/O设备有DMA请求,则由I/O设备挪用一个或几个 内存周期。这种传送方式的时间图如下图(b):

image-20210630135800538

I/O设备要求DMA传送时可能遇到两种情况: 1. 此时CPU不需要访内,如CPU正在执行乘法指令。由于乘法指令执行时间较长,此时I/O访内与CPU访内没有冲突,即I/O设备挪用一二个内存周期对CPU执行程序没有任何影响

  1. I/O设备要求访内时CPU也要求访内,这就产生了访内冲突,在这种情况下I/O设备访内优先,因为I/O访内有时间要求,前一个I/O数据必须在下一个访问请求到来之前存取完毕。显然,在这种情况下I/O 设备挪用一二个内存周期,意味着CPU延缓了对指令的执行,或者更明确地说,在CPU执行访内指令的过程中插入DMA请求,挪用了一二个内存周期。 与停止CPU访内的DMA方法比较,周期挪用的方法既实现了I/O传送,又较好地发挥了内存和CPU的效率,是一种广泛采用的方法。但是I/O设备每一次周期挪用都有申请总线控制权、建立线控制权和归还总线控制权的过程,所以传送一个字对内存来说要占用一个周期,但对DMA控制器来说一般要2—5个内存周期(视逻辑线路的延迟而定)。因此,周期挪用的方法适用于I/O设备读写周期大于内存存储周期的情况。

DMA与CPU交替访问内存

如果CPU的工作周期比内存存取周期长很多,此时采用交替访内的方法可以使DMA传送和CPU同时发挥最高的效率。这种传送方式的时间图如下:

image-20210630135821665

此图是DMA与CPU交替访内的详细时间图.假设CPU工作周期为1.2us,内存存取周期小于0.6us,那么一个CPU周期可分为C1和C2两个分周期,其中C1专供DMA控制器访内,C2专供CPU访内。

这种方式不需要总线使用权的申请、建立和归还过程,总线使用权是通过C1和C2分时制的。CPU和DMA控制器各自有自己的访内地址寄存器、数据寄存器和读/写信号等控制寄存器。在C1周期中,如果DMA控制器有访内请求,可将地址、数据等信号送到总线上。在C2周期中,如CPU有访内请求,同样传送地址、数据等信号。事实上,对于总线,这是用C1,C2控制的一个多路转换器,这种总线控制权的转移几乎不需要什么时间,所以对DMA传送来讲效率是很高的。

这种传送方式又称为 透明的DMA 方式,其来由是这种DMA传送对CPU来说,如同透明的玻璃一般,没有任何感觉或影响。在透明的DMA方式下工作,CPU既不停止主程序的运行,也不进入等待状态,是一种高效率的工作方式。当然,相应的硬件逻辑也就更加复杂。

ADSP芯片中的DMA

此处仅以《HWR》文件做参考。

  1. 外围设备可以通过DMA(控制器)访问缓存,但其逻辑操作会有所区别。
  2. 在DMA中,缓存器状态与中断没有差别。相反,不管是否归零,DMA计数寄存器都会生成一个中断。
  3. DMA控制器的确认机制与外设不同。
  4. 外部接口拥有两个可以控制 SDRAM/DDR2异步内存接口(AMI,Asynchronous Memory Interface)的DMA通道。AMI控制器通过额外的8/16bits数据宽度以支持DMA;SDRAM/DDR2 通过额外的16bits数据宽度以支持DMA。
  5. 外部接口DMA通过不同的寻址类型(由内向外或由内向内)以支持两种不同的DMA通道。

External ports

外部接口(External ports)具有以下特征:

  1. 支持两种DMA通道
  2. 支持4种模式:标准模式、可以自由选择方向的链式模式(chained mode)、点选列表模式(tap list mode)(Scatter 或 Gather)、延迟线模式(delay line mode)(写入以读取)
  3. 所有以上模式可以循环运行(operate in circular fashion);且在循环模式下,一些模式允许回写索引指针,以正确寻址下一个传输控制块(TCB)
  4. 支持由内向外 由内向内寻址。

寻址

外部接口DMA不仅支持由内向外寻址,还支持由内向内寻址。通过所有外部参数寄存器的内部地址索引以完成该项任务。DMA控制器通过地址以辨别传输(工作)而不是通过额外的控制位设置(control bit setting)。

注意:如果使用内部或外部索引地址,DMA通道的优先级将会改变。

SHARC芯片支持另一种具有更高优先级,但是只支持标准DMA模式的索引模式,即由内向内的DMA索引模式。

注意:DMAC,即Directory Memory Access Control (Rigister),直接内存访问控制寄存器。

TCB

1
2
3
4
5
6
7
8
9
/* TCB = "Transfer Control Block" */
/* TCB format: ECx (length of destination buffer),
EMx (destination buffer step size),
EIx (destination buffer index (initialized to start address)),
GPx ("general purpose"),
CPx ("Chain Point register"; points to last address (IIx) of next TCB to jump to upon completion of this TCB.),
Cx (length of source buffer),
IMx (source buffer step size),
IIx (source buffer index (initialized to start address)) */
image-20210701013537361

image-20210629155207745

image-20210629160318759

Others

DMA、TCB、SPORT之间的关系

DMA,Directly Memory Access,直接内存访问。

TCB,Transfer Control Block,传输控制块。

SPORT,Serial Port,串行接口。

Serial Peripheral ,即串行外设。

Clock、Arbitration、PLL、prescale

《HWR》第884页——PLL

PCLK

CLKIN

LATENCY

TWI 效果延迟(时间)

在TWI寄存器设置后,其效果延迟大概是 1.5到2个PCLK周期。

image-20210525153855627

ASM("NOP")

blog.csdn.net

asm()作用

将函数内部的参数翻译为汇编指令,在C语言环境下直接使用汇编指令执行。

  • asm("nop")是内嵌汇编做空指令延时用的;

  • nop是一个空等待汇编指令,这个指令执行时,单片机是什么也不做,仅仅起一个时间延时作用。

CC2530属于8051系列单片机,asm(“nop”)执行的是一条空指令(单周期指令),占用时间是一个机器周期,晶振为32Mhz。

于是,机器周期=12*1/32=0.375us ; 即一句asm(“nop”)延时了0.375us。

时钟周期

时钟周期也称为振荡周期,定义为时钟脉冲的倒数(可以这样来理解,时钟周期就是单片机外接晶振的倒数,例如12M的晶振,它的时间周期就是1/12 us),是计算机中最基本的、最小的时间单位。

在一个时钟周期内,CPU仅完成一个最基本的动作。对于某种单片机,若采用了1MHZ的时钟频率,则时钟周期为1us;若采用4MHZ的时钟频率,则时钟 周期为250us。由于时钟脉冲是计算机的基本工作脉冲,它控制着计算机的工作节奏(使计算机的每一步都统一到它的步调上来)。显然,对同一种机型的计算机,时钟频率越高,计算机的工作速度就越快。具体计算就是1/fosc。也就是说如果晶振为1MHz,那么时钟周期就为1us;6MHz的话,就是1/6us。

8051单片机把一个时钟周期定义为一个节拍(用P表示),二个节拍定义为一个状态周期(用S表示)。

机器周期

在计算机中,为了便于管理,常把一条指令的执行过程划分为若干个阶段,每一阶段完成一项工作。例如,取指令、存储器读、存储器写等,这每一项工作称为一个基本操作。完成一个基本操作所需要的时间称为机器周期。一般情况下,一个机器周期由若干个S周期(状态周期)组成。

8051系列单片机的一个机器周期同6个 S周期(状态周期)组成。前面已说过一个时钟周期定义为一个节拍(用P表示),二个节拍定义为一个状态周期(用S表示),8051单片机的机器周期由6个 状态周期组成,也就是说一个机器周期=6个状态周期=12个时钟周期。 具体计算为:时钟周期 X cycles。如果单片机是12周期的话,那么机器周期就是T×12。假设晶振频率为12M,单片机为12周期的话,那么机器周期就是1us。

例如外接24M晶振的单片机,他的一个机器周期=12/24M 秒;52系列单片机一个机器周期等于12个时钟周期。设晶振频率为12MHz时,52单片机是12T的单片机,即频率要12分频。12M经过分频变为1M,由T=1/f,即一个机器周期变为1us。

指令周期

执行一条指令所需要的时间,一般由若干个机器周期组成。指令不同,所需的机器周期也不同。通常,包含一个机器周期的指令成为单周期指令,比如CLR,MOV等等。包含两个机器周期的指令称为双周期指令。另外还有4周期指令,比如乘法和除法指令。对于一些简单的的单字节指令,在取指令周期中,指令取出到指令寄存器后,立即译码执行,不再需要其它的机器周期。对于一些比较复杂的指令,例如转移指令、乘法指令,则需要两个或者两个以上的机器周期。

总线周期

由于存贮器和I/O端口是挂接在总线上的,CPU对存贮器和I/O接口的访问,是通过总线实现的。通常把CPU通过总线对微处理器外部(存贮器或 I/O接口)进行一次访问所需时间称为一个总线周期。

总结一下,时钟周期是最小单位,机器周期需要1个或多个时钟周期,指令周期需要1个或多个机器周期;机器周期指的是完成一个基本操作的时间,这个基本操作有时可能包含总线读写,因而包含总线周期,但是有时可能与总线读写无关,所以,并无明确的相互包含的关系。 指令周期:是CPU的关键指标,指取出并执行一条指令的时间。一般以机器周期为单位,分单指令执行周期、双指令执行周期等。现在的处理器的大部分指令(ARM、DSP)均采用单指令执行周期。机器周期:完成一个基本操作的时间单元,如取指周期、取数周期。时钟周期:CPU的晶振的工作频率的倒数。

问题

个人对TWI作为主设备时,数据的发送流程框图的理解如下:

  • TWI在需要发送数据时,才生成TWI时钟信号,通过SCLK线(对应评估板上的 DPI11, 以及下图的 TWI_CLK_PBEN_O )输出。
  • 需要传输的数据通过TWI接口写入FIFO中(对应的寄存器是TXTWI8 ),并通过SDA线(对应21479评估板上的 DPI12 , 以及下图的 TWI_DATA_PBEN_O )输出,从机收到数据后通过SDA线(对应下图的 TWI_DATA_ I)返回确认(ACK)信息。
    • TWIIRPTL 寄存器中,TWIMCOM 位为1则指示TWI初始化完毕,TWITXINT 为1则指示FIFO寄存器有空位,如果为0则说明 TWIFIFOSTAT 寄存器中的 TWITXS 位没有变化,即数据无法通过SDA发送出去;TWIMERR 则指示主设备传输过程中存在错误,具体错误需要查看 TWIMSTAT 寄存器。
  • 查看 TWIMSTAT 寄存器可知,TWIMSTAT_REER 位为1,该位为1则指示传输缓冲区读取错误,传输移位寄存器需要数据而缓冲区为空。
  • 检查显示,TXTWI8 写入存在问题,写入语句 *pTXTWI8 = 0xAA; 执行后,观察寄存器窗口查看到数据仍为0x00。
image-20210607155906359
image-20210607163859502

参考

  1. DMA
  2. DMA原理介绍

预备知识

C标准库

image-20210524001458724

文本流

image-20210524001643408

二进制流

image-20210524001722423

基本概念

字符集和字符编码

UNICODE主页

image-20210524002528437

字符集对内存的影响

字符集涉及编码规则,包括单个字符所占用的空间大小,进而影响数据在硬件中的内存占用。

image-20210526002443105

如果将UTF-8转换成更为精简的GBK字符集,则会输出不同的结果。

image-20210526002630693

可移植操作系统接口(英语:Portable Operating System Interface,缩写为POSIX)是IEEE为要在各种UNIX操作系统上运行软件,而定义API的一系列互相关联的标准的总称,其正式称呼为IEEE Std 1003,而国际标准名称为ISO/IEC 9945。此标准源于一个大约开始于1985年的项目。POSIX这个名称是由理查德·斯托曼(RMS)应IEEE的要求而提议的一个易于记忆的名称。它基本上是Portable Operating System Interface(可移植操作系统接口)的缩写,而X则表明其对Unix API的传承。

Linux基本上逐步实现了POSIX兼容,但并没有参加正式的POSIX认证。[1]

微软的Windows NT声称部分实现了POSIX标准。

当前的POSIX主要分为四个部分[2]:Base Definitions、System Interfaces、Shell and Utilities和Rationale。

——Wikipedia.org的 可移植操作系统接口

一般情况下,应用程序通过应用编程接口(API)而不是直接通过系统调用来编程。这点很重要,因为应用程序使用的这种编程接口实际上并不需要和内核 提供的系统调用对应。一个API定义了一组应用程序使用的编程接口。它们可以实现成一个系统调用,也可以通过调用多个系统调用来实现,而完全不使用任何系 统调用也不存在问题。实际上,API可以在各种不同的操作系统上实现,给应用程序提供完全相同的接口,而它们本身在这些系统上的实现却可能迥异。

在Unix世界中,最流行的应用编程接口是基于POSIX标准的。从纯技术的角度看,POSIX是由IEEE的一组标准组成,其目标是提供一套大体上基于Unix的可移植操作系统标准。Linux是与POSIX兼容的。

POSIX是说明API和系统调用之间关系的一个极好例子。在大多数Unix系统上,根据POSIX而定义的API函数和系统调用之间有着直接关 系。实际上,POSIX标准就是仿照早期Unix系统的界面建立的。另一方面,许多操作系统,像Windows NT,尽管和Unix没有什么关系,也提供了与POSIX兼容的库。

Linux的系统调用像大多数Unix系统一样,作为C库的一部分提供如图5-1所示。如图5-1所示C库实现了Unix系统的主要API,包括标 准C库函数和系统调用。所有的C程序都可以使用C库,而由于C语言本身的特点,其他语言也可以很方便地把它们封装起来使用。此外,C库提供了POSIX的 绝大部分API。

从程序员的角度看,系统调用无关紧要;他们只需要跟API打交道就可以了。相反,内核只跟系统调用打交道;库函数及应用程序是怎么使用系统调用不是内核所关心的。

——《Linux内核设计与实现(第2版)》第5章

简单总结

完成同一功能,不同内核提供的系统调用(也就是一个函数)是不同的,例如创建进程,linux下是fork函数,windows下是creatprocess函数。好,我现在在linux下写一个程序,用到fork函数,那么这个程序该怎么往windows上移植?我需要把源代码里的fork通通改成creatprocess,然后重新编译...

posix标准的出现就是为了解决这个问题。linux和windows都要实现基本的posix标准,linux把fork函数封装成posix_fork(随便说的),windows把creatprocess函数也封装成posix_fork,都声明在unistd.h里。这样,程序员编写普通应用时候,只用包含unistd.h,调用posix_fork函数,程序就在源代码级别可移植了

[cnblogs.com](https://www.cnblogs.com/ybtools/p/6432464.html#:~:text=构造数据类型指可以通过其他的数据类型进行构造,可由程序员自定义,故又称为 ",自定义数据类型 "。 基本数据类型包括整型(short%2Cint%2Clong)、实型(又称浮点型)(float和double)、字符型char、布尔型bool等,他们都可以用于定义常量和变量。)

PS:本文以C++为例介绍数据类型。

数据类型 

从广义上根据量的值是否可变,可分为常量变量两种数据类型。

根据数据复杂程度,划分为基本数据类型构造数据类型这两大类。

基本数据类型 包括:整型(short,int,long)、实型(又称浮点型)(float和double)、字符型char、布尔型bool等。

构造数据类型 包括:数组类型、枚举类型enum、指针类型、引用类型、结构体struct、联合体union(又称联合,共用体)、类class等。

构造数据类型指可以通过其他的数据类型进行构造,可由程序员自定义,故又称为 "自定义数据类型"。

基本数据类型

基本数据类型包括整型(short,int,long)、实型(又称浮点型)(float和double)、字符型char、布尔型bool等,他们都可以用于定义常量和变量。

基本数据类型,也叫做基础类型,或内置类型。

1、整型(short,int,long)

整型量,包括短整型short、整型int、长整型long,而且3种类型都可以分别再细分为:有符号(signed)以及无符号(unsigned)。

2、实型(又称浮点型)(float和double)

实型,又称为浮点型,它包括两种数据类型:单精度浮点数float和双精度浮点数double。他们都是有符号数据类型。如果一个数值常量,包含小数点、指数部分(字符e),则为浮点数。

双精度浮点型,还可细分为双精度(double型)、长双精度(long double)

3、字符型char

字符型char类型定义的常量,必须要用单括号括起来。

例如:char ch='a' ; //把字符常量'a'存储到ch中。

字符型char类型量也可以细分为有符号(char)和无符号(unsigned char)。

4、布尔型bool

布尔型的取值为true或者false。

布尔型变量的说明:例:bool flag,则布尔型数据的变量flag取值:只有 false 和 true 两个值,即分别是0和1。

构造数据类型

有些比较复杂的数据,单纯用基本数据类型未能表示,在C++中程序员可以用基本数据类型来自定义构造出新的数据类型,称构造数据类型,也称作 构造类型构造数据类型

构造数据类型除了可以用常见的如int、float和double、char、bool等基本数据类型进行构造,也可以包含其他构造类型的数据。

构造数据类型包括:数组类型、枚举类型enum、指针类型、引用类型、结构体struct、联合体union(又称联合,共用体)、class类等,他们可以通过其他的数据类型进行构造,由程序员自定义,所以又称为自定义数据类型。

参考:http://blog.csdn.net/u013174689/article/details/17484223

enum 是 Enumeration // 的缩写,是C/C++中的 枚举 关键字。

特点

符合以下场景时可能需要使用到枚举:

  • 需要使用到的变量 数量较大,通过枚举以简写代码,提高代码可读性
  • 使用整形(integer)进行定义(但不同于直接定义成 int显式整形,使用枚举类型定义的话会变成 隐式整形
  • 所有值都是有固定范围的,是可人为预设的。
  • 具有常量的特性(主要特点是:不可在定义之外的地方被修改)

注意:

  • 在所有枚举值都未被赋值的情况下,枚举值默认从 0 开始,往后逐个加 1(递增)。

定义

枚举格式:一般为 enum 枚举名{ 枚举值表 }; ,也可以省略枚举名,写成如下格式:

1
enum typeName{ valueName1, valueName2, valueName3, ...... };

enum 定义 枚举类型的关键字

typeName是 枚举类型的名称,即 枚举名

valueName1, valueName2, valueName3, ......是每个值对应的名字的列表,所有元素集合即为 枚举值表

注意:最后的;不能少。

使用示例

起始值赋值

1
2
3
4
5
6
7
8
9
enum cats {
juran = 3,
guoran,
dala,
baomei,
baodi,
zhaofeng,
ainiao
};

结果如下:

1
2
3
4
juran = 3
guoran = 4
dala = 5
ainiao = 9

值表中途赋值

1
2
3
4
5
6
7
8
9
enum cats {
juran,
guoran,
dala = 0,
baomei,
baodi,
zhaofeng,
ainiao
};

给出如下:

1
2
3
4
juran = 0
guoran = 1
dala = 0
ainiao = 4

Typedef enum

Typedef enum 的用法一般如:

1
typedef enum{....} a; 

enum 的用法一般如:

1
enum{....} a;

前者是将 enum{….} 定义成一个 a类型,声明变量的时候可以用 a b 格式;可以理解为类似 int i;

后者是将 enum{….} 声明了一个 变量a

枚举遍历

在C 语言中,枚举类型是被当做 int 或者 unsigned int 类型来处理的,所以按照 C 语言规范是没有办法遍历枚举类型的。

不过在一些特殊的情况下,枚举类型必须连续是可以实现有条件的遍历。

1
2
3
4
5
6
7
8
9
10
11
12
#include <stdio.h>

enum DAY{
MON=1, TUE, WED, THU, FRI, SAT, SUN
} day;

int main(){
// 遍历枚举元素
for (day = MON; day <= SUN; day++) {
printf("枚举元素:%d \n", day);
}
}

错误示范

以下错误示范给出的提示均由 Linux的 GNU 编译器 及 Mac的 ClangApple clang version 11.0.0 (clang-1100.0.33.17))编译器给出。

重复定义

不允许 在同一个作用域内 定义 一样的枚举名称 ;也不允许 在同一个作用域内 的不同枚举变量中定义 名称一样的元素

image-20210523204125878
image-20210523204041715

以上两种情况的错误提示如下:

image-20210523182310296
image-20210523204224839

也就是说 枚举名称和枚举元素都要绝对唯一

数值更改

枚举类数据不允许更改数值(包括自增和赋值都不允许),有点类似于常量(const)。

枚举中的元素自增时的错误提示:

image-20210523202049638

枚举中的元素赋值时的错误提示:

image-20210523202501260

根据 网友的回答 :

C支持枚举类型的自增操作,但C++不支持。

以下为常量自增时给出的错误提示:

image-20210523202757582