Quantcast
Channel: 蜗窝科技
Viewing all 48 articles
Browse latest View live

DRAM 原理 2 :DRAM Memory Orgnization

$
0
0

在 DRAM Storage Cell 章节中,介绍了单个 Cell 的结构。在本章节中,将介绍 DRAM 中 Cells 的组织方式。

为了更清晰的描述 Cells 的组织方式,我们先对上一章节中的 DRAM Storage Cell 进行抽象,最后得到新的结构图,如下:

1. Memory Array

DRAM 在设计上,将所有的 Cells 以特定的方式组成一个 Memory Array。本小节将介绍 DRAM 中是如何将 Cells 以 特定形式的 Memory Array 组织起来的。

首先,我们在不考虑形式的情况下,最简单的组织方式,就是在一个 Bitline 上,挂接更多的 Cells,如下图所示:

然而,在实际制造过程中,我们并不会无限制的在 Bitline 上挂接 Cells。因为 Bitline 挂接越多的 Cells,Bitline 的长度就会越长,也就意味着 Bitline 的电容值会更大,这会导致 Bitline 的信号边沿速率下降(电平从高变低或者从低变高的速率),最终导致性能的下降。为此,我们需要限制一条 Bitline 上挂接的 Cells 的总数,将更多的 Cells 挂接到其他的 Bitline 上去。

从 Cell 的结构图中,我们可以发现,在一个 Cell 的结构中,有两条 Bitline,它们在功能上是完全等价的,因此,我们可以把 Cells 分摊到不同的 Bitline 上,以减小 Bitline 的长度。然后,Cells 的组织方式就变成了如下的形式:

当两条 Bitline 都挂接了足够多的 Cells 后,如果还需要继续拓展,那么就只能增加 Bitline 了,增加后的结构图如下:

从图中我们可以看到,增加 Bitline 后,Sense Amplifier、Read Latch 和 Write Driver 的数量也相应的增加了,这意味着成本、功耗、芯片体积都会随着增加。由于这个原因,在实际的设计中,会优先考虑增加 Bitline 上挂接的 Cells 的数量,避免增加 Bitline 的数量,这也意味着,一般情况下 Wordline 的数量会比 Bitline 多很多。

上图中,呈现了一个由 16 个 Cells 组成的 Memory Array。其中的控制信号有 8 个 Wordline、2 个 CSL、2 个 WE,一次进行 1 个 Bit 的读写操,也就是可以理解为一个 8 x 2 x 1 的 Memory Array。

如果把 2 个 CSL 和 2 个 WE 合并成 1 个 CSL 和 1 个 WE,如下图所示。此时,这个 Memory Array 就有 8 Wordline、1 个 CSL、1 个 WE,一次可以进行 2 个 Bit 的读写操作,也就是成为了 8 x 1 x 2 的 Memory Array。

按照上述的过程,不断的增加 Cells 的数量,最终可以得到一个 m x n x w 的 Memory Array,如下图所示

其中,m 为 Wordline 的数量、n 为 CSL 和 WE 控制信号的数量、w 则为一次可以进行读写操作的 Bits。
在实际的应用中,我们通常以 Rows x Columns x Data Width 来描述一个 Memory Array。后续的小节中,将对这几个定义进行介绍。

1.1 Data Width

Memory Array 的 Data Width 是指对该 Array 进行一次读写操作所访问的 Bit 位数。这个位数与 CSL 和 WE 控制线的组织方式有关。

1.2 Rows

DRAM Memory 中的 Row 与 Wordline 是一一对应的,一个 Row 本质上就是所有接在同一根 Wordline 上的 Cells,如下图所示。

DRAM 在进行数据读写时,选中某一 Row,实质上就是控制该 Row 所对应的 Wordline,打开 Cells,并将 Cells 上的数据缓存到 Sense Amplifiers 上。

Row Size

一个 Row 的 Size 即为一个 Row 上面的 Cells 的数量。其中一个 Cell 存储 1 个 Bit 的信息,也就是说,Row Size 即为一个 Row 所存储的 Bit 位数。

1.3 Columns

Column 是 Memory Array 中可寻址的最小单元。一个 Row 中有 n 个 Column,其中 n = Row Size / Data Width。下图是 Row Size 为 32,Data Width 为 8 时,Column 的示例。

Column Size

一个 Column 的 Size 即为该 Column 上所包含的 Cells 的数量,与 Data Width 相同。Column Size 和 Data Width 在本质上是一样的,也是与 CSL 和 WE 控制线的组织方式有关(参考 Memory Array 小节中关于 CSL 的描述)。

2. Memory Bank

随着 Bitline 数量的不断增加,Wordline 上面挂接的 Cells 也会越来越多,Wordline 会越来越长,继而也会导致电容变大,边沿速率变慢,性能变差。因此,一个 Memory Array 也不能无限制的扩大。

为了在不减损性能的基础上进一步增加容量,DRAM 在设计上将多个 Memory Array 堆叠到一起,如下图所示:

其中的每一个 Memory Array 称为一个 Bank,每一个 Bank 的 Rows、Columns、Data Width 都是一样的。在 DRAM 的数据访问时,只有一个 Bank 会被激活,进行数据的读写操作。

以下是一个 DRAM Memory Orgnization 的例子:

Banks 4
Rows / Bank 16K
Columns / Row 1024
Column Size 16 Bits

串口通信技术浅析

$
0
0

1. 前言

最熟悉的陌生人!用这句话形容“串口”是再贴切不过的了。

对嵌入式工程师来说,“串口”是一个再熟悉不过的模块,熟悉到像喝水一样自然。与此同时,有关串口的很多细节,却被渐渐地模糊和忽略,例如:

我们经常挂在嘴边的serial、UART、RS232等概念,究竟是怎么回事?它们之间有何联系?有何区别?

串口的波特率(baud rate)是怎么定义和计算的?比特率(bit rate)又是怎么回事?二者的关系又是怎样?

为什么波特率有误差?通信过程中所容许的误差范围是多少?

本文将对上述问题,进行简单的总结和归纳,以便指导有关的开发工作。

2. 概念解释

2.1 串行通信(Serial communication)

在通信和计算机科学中,Serial communication是一个通用概念,泛指所有的串行的通信协议,如RS232、USB、I2C、SPI、1-Wire、Ethernet等。这里的串行(serial),是相对并行通信(parallel communication)来说的,如下图:

Parallel_and_Serial_Transmission

图片1 并行通信和串行通信

上面图片1是非常容易理解的,这里不再过多解释,有关串行通信的优缺点,可参考“Serial communication[1]”中的解释。

2.2 同步串行通信(Synchronous serial communication)和异步串行通信(Asynchronous serial communication)

理解串行通信的概念之后,大家可能会有疑问:接收方接收到一长串的、表示0/1电平跳变的信号之后,怎么还原出有效的信息呢?有两种方法:

1)发送端在发送串行数据的同时,提供一个时钟信号,并按照一定的约定(例如在时钟信号的上升沿的时候,将数据发送出去)发送数据,接收端根据发送端提供的时钟信号,以及大家的约定,接收数据。这就是常说的同步串行通信(Synchronous serial communication),I2C、SPI等有时钟信号的协议,都属于这种通信方式。

2)发送端在数据发送之前和之后,通过特定形式的信号(例如START信号和STOP信号),告诉接收端,可以开始(或者停止)接收数据了。与此同时,收发两方会约定一个数据发送的速度(就是大名鼎鼎的波特率),发送端在发送START信号之后,就按照固定的节奏发送串行数据,与此同时,接收端在收到START信号之后,也按照固定的节奏接收串行数据。这就是常说的异步串行通信(Asynchronous serial communication),我们本节的主角----串口通信,就是这种通信方式。

注1:严格意义上,START/STOP形式的异步串行通信,称作“asynchronous start-stop communication”,但由于这种形式在异步串行通信里面使用太广泛了,二者也就混为一谈、不加区分了。

注2:根据同步方式的不同,串口也包括异步串口和同步串口两种。本文所指的串口,都是只异步串口。

2.3 串口(Serial port)和RS-232

在计算机的世界里,“串口”是使用串行的方式进行数据传输的一种接口,它是相对于计算机的并行接口来说的。虽然串行通信可以通过多种技术实现(如USB、Ethernet等),但由于历史原因,我们所说的串口,特指符合RS-232规范的接口,下图就是我们比较常见的一种:

Serial_port

图片2 male DE-9 connector

串口是用于实现串行通信的物理接口的一种统称,但只有名称还远远不够,通信的双方需要一些约定和规范,才能正确的进行数据传输,例如需要哪些信号线、信号的电平如何、接口的形状如何、数据的编码格式、数据传输的速率、等等。

在串口通信中,这些内容主要由两部分定义:

1)RS-232(有时候也称作RS-232-C,C是版本)规范,定义“硬件相关”的特性,包括:

电气信号特性,如信号电平(-3V~-15V表示逻辑1,+3~+15V表示逻辑0)等;

接口特性,如连接器(connectors)的定义(9-pin的 DE-9 Male/Female,25-pin的DB-25 Male/Female等)、管脚信号的定义、等等;

电缆(cable)的特性,如电缆的长度(RS-232没有显式的限制电缆的长度,但限制了电容,效果一样)等;

等等。

2)串口硬件,定义“软件相关”的特性,包括:

数据的编码格式(character encoding),就是上面提到的“asynchronous start-stop”格式,也即我们所熟知的的“起始位、数据位、校验位、停止位“;

数据传输的bit rates,也即我们熟悉的波特率(baud rate)。

注3:说来奇怪,RS-232规范规定了串口通信有关的方方面面的特性,唯独没有规定数据传输相关的编码格式和bit rates。可能是硬件的差异太大,以至于该规范无法完全覆盖。

注4:虽然RS-232规范没有规定bit rates,但它做了一个要求----不能超过20Kbps,虽然从现在来看,这就是瞎扯,呵呵。

注5:RS-232定义了各种形态的串口接口,如DE-9、DB-25等等,但这大多和上古时代的通信有关场景以有关,随着数字通信的普及,以及USB等协议的蚕食,这些庞然大物已经越来越少见了。反而在嵌入式场景中,一些简化的形态,如4线(VCC/RX/TX/GND)串口等,反而使用的比较多。

2.4 UART(Universal Asynchronous Receiver/Transmitter)

我们在上一节(2.3)提到,由于硬件的差异太大,RS-232并没有规定串口通信的编码格式和bit rates。因此,这一块的实现,完全由具体的硬件(或者对应的软件负责)。

在早期的产品中,大多使用软件的方式,以一定的速率(bit rates),产生出符合编码格式的bit流。但后来为了提升性能,很多产品(如IBM的PC)使用了专门的硬件模块,完成这个事情,这就是我们经常挂在嘴边的UART。

至此,串口通信有关的术语已经悉数登场,简单总结一下吧:

串行通信(serial communication),泛指使用bit流的形式进行数据通信的方法。

同步串行通信(Synchronous serial communication)和异步串行通信(Asynchronous serial communication),串行通信的不同实现方法,主要区别在于同步的方式。

串口(serial port),特指使用“异步串行通信”的方法进行数据通信的接口,主要是从硬件的角度描述的。

RS-232,定义两个串口之间通信行为的一个规范,偏向于电平、连接器、电缆等硬件特性。

UART(Universal Asynchronous Receiver/Transmitter),一个硬件模块,根据串口硬件所规定编码格式、bit rate,产生处通信所需的bit流。

2.5 TTL电平转换以及USB转串口

最后,再念叨一下TTL电平转换有关的概念。当前,串口应用最广泛的场景,就是嵌入式产品和PC之间的一些数据交互,如debug输出、firmware更新等。但这里有一个比较麻烦的事情:

PC串口符合RS-232规范,其电平是“-3V~-15V/+3~+15V”。而大多数的嵌入式产品,都是使用TTL电平(如0v/3.3v)。因此,这两种电平无法直接连接。怎么办呢?增加一个电平转换电路就是了,于是嵌入式产品和PC之间的连接就变成了如下的形式:
       PC(串口)<---------->电平转换电路<---------->嵌入式产品(串口)

还有更麻烦的事情,随着技术的进步,串口这样的大杀器,渐渐地被PC抛弃了,怎么办呢?USB转串口应运而生了,连接方式变成了:

PC(USB接口)<---------->USB转串口<---------->嵌入式产品(串口)

3. 波特率(baud rate)和比特率(bit rate)

理解了串口中这些既熟悉又陌生的术语之后,我们再来看看波特率(baud rate)。

说实话,在数据通信中,比特率(bit rate)比较容易理解,就是一定时间内,能够传输多少个bit。例如bps,就是bit per second的缩写。那什么事波特率呢?

在通信中,波特率也称作符号速率(symbol rate),指的的是“数据变化”的速率。说着很拗口,我们举个例子:

在计算机系里,小杨和小李是一对好基友,不过小杨是学霸、小李是学渣。所以,期末考试到了,小杨决定“鼎力相助”。怎么办呢?

二人约定,考试时,小杨携带黑色和白色两支笔,根据两支笔出现的情况,表示A、B、C、D四种答案,即:
    白色的笔没有出现    黑色的笔没有出现    A
    白色的笔没有出现    黑色的笔出现          B
    白色的笔出现          黑色的笔没有出现    C
    白色的笔出现          黑色的笔出现           D

同时约定,在考试开始1小时之后,小杨从第1道选择题开始,以每分钟更换一次的速度,更换答案。小李按照这个速度,以及大家的约定,通过观察两支笔出现的情况,获得答案。

确实是个好方法,不过仔细想想,这其实是一个典型的异步通信过程。通信的过程中,答案更新的速度(每分钟1次),就是我们所说的baud rate(或者symbol rate),即1 bd per minute(可以把bd看着baud的单位)。

与此同时,每次更新,传递了多少信息呢?表面上看是A、B、C、D,本质上是由白和黑所代表的两个bit,00、01、10或者11。因此,每次更新传递2个bit的信息,所以bit rate就是2 bits per minute。

上面的例子中,通信的波特率和比特率是不同的,分别为1和2(per minute),而有些通信系统,例如我们所熟知的串口通信,它们却是一样的,例如我们说115200的波特率,实际上的比特率也是115200。因为一次只传输1个bit(0或者1)。

4. 帧格式和波特率误差

我们知道,串口通信的数据格式包括start bit、data bits、parity bit和stop bits,其中:

start bit固定为1bit;

data bits可以为5、6、7、8或者9bits,不过常用的都是8bits;

parity bit是非必须的,一般为0bit;

stop bit可以是1bit和2bits两种,一般都是1bit。

图示如下:

Puerto_serie_Rs232

图片2 串口帧格式

因此,从本质上讲,波特率定义了帧格式中每一个bit的信号的持续时间,即1 / bard rate。而一帧数据传输完成,需要的时间为(1 / bard rate) * 10(以8N1的帧格式为例)。

这种异步通信的方法,有一个坏消息,也有一个好消息:

坏消息是,受系统时钟精度、分频系数等影响,波特率可能不精确,存在误差。而在一帧数据的传输过程中,误差会累积。

好消息是,如果误差累积的不多,受start/stop信号的矫正作用,下一帧数据中,可将累积误差清零。

关于误差,我们再稍微详细分析一下。

根据我们的常识,信号是在中间点采样,因此,在一帧数据中,如果误差累积超过(1 / bard rate / 2)的时间,则数据会采样错误。假设理想的baud rate是BDi,实际的baud rate是BDr,则:

每一个bit的误差时间是:1 / BDi – 1 / BDr。

10个bit的误差时间是:10 * (1 / BDi – 1 / BDr)。

因此,安全的误差范围是:abs(10 * (1 / BDi – 1 / BDr)) < 1 / BDi / 2。

以115200的波特率为例,带入上面的公式:

abs(10 * (1 / 115200– 1 / BDr)) < 1 / 115200 / 2

-1 / 115200 / 2 < 10 * (1 / 115200– 1 / BDr) < 1 / 115200 / 2

(20 / 21) * 115200 < BDr < (20 / 19) * 115200

因此,115200波特率所容许的误差范围是20 / 21 ~ 20 / 19,即+/- 5%。其它波特率也可以带入公式去计算。另外,如果双方都有误差的话怎么办?嘿嘿,你懂的,除2吧。

5. 参考文档

[1] Serial communication,https://en.wikipedia.org/wiki/Serial_communication

[2] Serial port,https://en.wikipedia.org/wiki/Serial_port

[3] RS-232,https://en.wikipedia.org/wiki/RS-232

[4] Asynchronous serial communication,https://en.wikipedia.org/wiki/Asynchronous_serial_communication


原创文章,转发请注明出处。蜗窝科技,www.wowotech.net

蓝牙协议分析(7)_BLE连接有关的技术分析

$
0
0

1. 前言

了解蓝牙的人都知道,在经典蓝牙中,保持连接(Connection)是一个相当消耗资源(power和带宽)的过程。特别是当没有数据传输的时候,所消耗的资源完全被浪费了。因而,对很多蓝牙设备来说(特别是功耗敏感的设备),希望在无数可传的时候,能够断开连接。但是,由于跳频(hopping)以及物理通道(Physical Channel)划分的缘故,经典蓝牙连接建立的速度实在难以忍受(要好几秒)。对那些突发的数据传输来说,几秒钟的连接延迟,简直是灾难。

因此,蓝牙SIG制订BLE规范的时候,充分考虑了这方面的需求,极大的简化了连接的建立过程,使连接速度可以达到毫秒级(最快3.75ms就可以搞定)。与此同时,为了节省功耗,也调整了跳频的策略。至此,相比广播通信而言,BLE面向连接的通信,几乎没有额外的代价。

在“蓝牙协议分析(5)_BLE广播通信相关的技术分析”中,我们对BLE的广播通信有了比较全面的了解,本文将接着分析和面向连接的通信有关的技术,包括连接的建立和断开、BLE跳频(Hopping)技术、Link Layer的应答、重传、流控、等等。

2. 怎样才算是建立了连接?

开始之前,我们先回答一个问题,对通信的双方而言,怎样才算建立了连接呢?

从字面上理解,建立了连接,就是指:

二者之间,建立了一条专用的通道,它们可以随时随地的通信。

当然,在蓝牙这种资源有限的通信系统中,通道无法独占,退而求其次,分时也Okay。因此,在BLE中建立了连接,是这样定义的:

在约定的时间段内,双方都到一个指定的物理Channel上通信。

其中,“约定好的时间段”,是时分的概念。而“到指定的物理Channel上”,是跳频的概念。后面的分析,将会围绕这两个概念进行。

另外,和“蓝牙协议分析(5)_BLE广播通信相关的技术分析”类似,我们也将从Link Layer、HCI、GAP三个层次,分别介绍。

3. Link Layer

3.1 角色的定义

和经典蓝牙一样,协议为处于连接状态的BLE设备,定义了两种Link Layer角色:Master和Slave。Master是连接的发起方(Initiator),可以决定和连接有关的参数(很重要,后面会详细介绍)。Slave是连接的接受方(Advertiser),可以请求(或建议)连接参数,但无法决定。

注1:两个BLE设备之间,只能建立一条连接。

3.2 PDU的定义

和广播通信不同,面向连接的通信使用特定的PDU,称作Data Channel PDU,格式如下(LSB---->MSB):

Header(16 bits) Payload(Variable size) MIC(32 bits)

16bits的Header的格式如下:

LLID(2 bits) NESN (1bit) SN(1 bit) MD(1 bit) RFU(3 bits) Length(8 bits)

Data Channel传输的PDU有两类,一类是数据,称作LL Data PDU,另一类中控制信息,称作LL Control PDU。LLID用于区分PDU的类型,具体可参考后面3.2.1和3.2.2的描述。

NESN(Next Expected Sequence Number)和SN(Sequence Number),用于数据传输过程中的应答(Acknowledgement)和流控(Flow Control),具体可参考后面3.7的介绍。

MD(More Data),用于连接的关闭(或者说保持),具体可参考后面3.5的介绍。

RFU(Reserved for Future Use)。

Length,有效数据的长度(Payload+MIC),只有8-bits,因此Link Layer所能传输的最大数据是255 bytes(有MIC的话是251bytes),如果L2CAP需要传输更多的数据,需要分包之后传输(这也是L2CAP的主要功能之一,具体可参考“蓝牙协议分析(3)_蓝牙低功耗(BLE)协议栈介绍”)。

Payload是有效数据(SDU,L2CAP的PDU),长度由Header中的Length字段觉得,有效范围是0~255。

3.2.1 LL Data PDU

LL Data PDU有两种:

Header中的LLID=01b时,Continuation fragment of an L2CAP message, or an Empty PDU。这种类型的PDU,要么是一个未传输完成L2CAP message(长度超过255,被拆包,此时不是第一个),要么是一个空包(Header中的Length为0)。

Header中的LLID=01b时,Start of an L2CAP message or a complete L2CAP message with no fragmentation。这种类型的PDU,要么是L2CAP message的第一个包,要么是不需要拆包的完整的L2CAP message,无论哪种情况,Header中的Length均不能为0。

3.2.2 LL Control PDU

Header中的LLID=11b时,表示这个数据包是用于控制、管理LL连接的LL control PDU。LL control PDU的payload的格式如下:

Opcode(1 octet) CtrlData(0 ~ 26 octets)

其中Opcode指示控制&管理packet的类型,包括:

LL_CONNECTION_UPDATE_REQ,连接参数的更新;
LL_CHANNEL_MAP_REQ,Channel map的更新;
LL_TERMINATE_IND,连接即将被关闭的通知(可以通知被关闭的原因);
LL_ENC_REQ、LL_ENC_RSP、LL_START_ENC_REQ、LL_START_ENC_RSP,加密有关的请求;等等,具体可参考“BLUETOOTH SPECIFICATION Version 4.2 [Vol 6, Part B]”。

3.3 连接的建立

对BLE来说,连接建立的过程很简单,包括:

1)处于connectable状态设备(Advertiser),按照一定的周期广播ADV_IND或者ADV_DIRECT_IND包(可参考“蓝牙协议分析(5)_BLE广播通信相关的技术分析”)。

2)主动连接的设备(Initiator),在收到广播包之后,会回应一个CONNECT_REQ请求,该请求携带了可决定后续“通信时序”的参数,例如双方在哪一个时间点、哪一个Physical Channel收发数据,等等,后面会详细描述。

3)Initiator在发出CONNECT_REQ数据包之后,自动转变为Connection状态,成为Master角色(注意:这是“自动”的,不需要等待另一方的回应)。同样,Advertiser在收到CONNECT_REQ请求之后,也自动转变为Connection状态,成为Slave角色。

4)此后,双方按照CONNECT_REQ参数所给出的约定,定时到切换到某一个Physical Channel上,按照Master->Slave然后Slave->Master的顺序,收发数据,直至连接断开。

master在发出连接请求的时候,需要在CONNECT_REQ PDU的payload中,定义和连接有关的参数。payload的格式如下:

InitA (6 octets) AdvA (6 octets) LL Data (22 octets)

 

其中InitA和AdvA分别是Master和Slave的蓝牙地址,LL data则包含了所有的连接参数,包括:

AA
(4 octets)
CRCInit
(3 octets)
WinSize
(1 octet)
WinOffset
(2 octets)
Interval
(2 octets)
Latency
(2 octets)
Timeout
(2 octets)
ChM
(5 octets)
Hop
(5 bits)
SCA
(3 bits)

AA,LL Connection的Access Address,在不同设备组合之间,需要唯一,并遵守一些原则,具体可参考“BLUETOOTH SPECIFICATION Version 4.2 [Vol 6, Part B]”。

CRCInit,用于CRC计算的一个初始值,由Link Layer随机生成。

WinSize和WinOffset,全称是transmitWindowSize和transmitWindowOffset,用于决定连接双方收发数据的时间窗口(第2章提到的时分的概念)。下面3.4小节会详细介绍。

connInterval,全称是connInterval,连接双方收发数据的周期。由于一个Master可能会和多个Slave建立连接,因此蓝牙的信道资源不能被某一个LL Connection所独占,所以一个收发周期中,可能有多个连接进行收发数据(具体的时间窗口,由transmitWindowOffset决定)。下面3.4小节会详细介绍。

Latency和Timeout,全称是connSlaveLatency和connSupervisionTimeout,和连接超时、自动断开有关,具体可参考3.4小节的描述。

ChM的全称是Channel map,用于标识当前使用和未使用的Physical Channel。Hop的全称是hopIncrement,它和ChM一起决定了数据传输过程中的跳频算法,具体可参考3.6小节的描述。

SCA(sleep clock accuracy),用于定义最差的Master睡眠时钟精度,具体可参考“BLUETOOTH SPECIFICATION Version 4.2 [Vol 6, Part B]”,本文不再详细介绍。

3.4 连接建立后的通信过程

3.3小节提到,当Master发出/Slave收到CONNECT_REQ后,就自动进入连接状态,那双方在收发数据的时间窗口怎么确定呢?可参考下面图片1和图片2:

BLE连接时序---Master视角

图片1 BLE连接时序---Master视角

BLE连接时序---Slave视角

图片2 BLE连接时序---Slave视角

1)从Master的视角看,当它发出CONNECT_REQ后,会在1.25 ms + transmitWindowOffset到1.25ms + transmitWindowOffset + transmitWindowSize之间,发送第一个packet(M->S)。同理,Slave在收到CONNECT_REQ之后,也会在相应的时间区间去接收packet(M->S)。

a)transmitWindowOffset可以控制这个LL Connection使用哪一段时间进行通信,从而保证了同一个Master和多个Slave之间的多个连接,可以互不影响的通信(时分)。transmitWindowOffset的取值范围是:0 ms到connInterval(后面会介绍connInterval)。

b)从Master发出CONNECT_REQ,到Slave接收到CONNECT_REQ,是有一定的时间延迟的,因此需要一定的时间窗口(transmitWindowSize),才能保证第一个packet能否正确的发送并被接收。transmitWindowSize必须是1.25ms的倍数,最小值是1.25 ms,最大值是(connInterval - 1.25 ms),但不能超过10ms。

c)正常情况下,所有“M->S”数据包的发送,不能超过transmitWindowSize,以便留出S->M的时间。但第一个packet例外(参考上面图片1)。

2)Master发出第一个packet之后,将以此为起始点(称作anchor point),以connInterval为周期,接着发送后续的packet(M->S),以及接收Slave的packet(S->M),具体可参考上面图片1。

a)这样以connInterval为周期的发送(M->S)、接收(S->M)组合(可能有多个),称作Connection Event。因此BLE面向连接的通信的基础,就是Connection Event。

b)connInterval的大小,决定了数据传输的周期。对一个连接来说,每个周期只能有一次的收发,因此connInterval的选择,直接决定了数据传输的速度。BLE协议规定,connInterval必须是1.25ms的倍数,范围是7.5ms~4s。

3)Slave如果没有收到第一个packet(M->S),则会以1.25 ms + transmitWindowOffset为起点,等待connInterval之后,再次尝试接收,直到接收到为止。Slave接收到packet之后,则以收到该packet的时间点为起始点(anchor point),以connInterval为周期,接着接收后续的packet(M->S),以及发送packet给Master(S->M),具体可参考上面图片2。

注2,关于数据传输的速率:
由上面的通信过程可知,BLE面向连接的通信速率,是由connInterval以及每个Connection Event中所传输的数据量决定的。
由上面3.2的描述可知,LL Data PDU的有效负荷不能超过255(251)bytes,不过考虑到一次传输的效率、错误处理等因素,具体的Link Layer不会使用这么大的packet。相应地,为了提高传输速度,一般会在一个Connection Event中,传输多个packet。以iOS为例,它可能会在一个Connection Event中,传输6个packets,每个packet的长度是20bytes。
另外,很多平台为了保证自身作为Master的性能,会限制connInterval的最小值,以iOS为例,最小值是30ms。因此,可估算得到相应的传输速率为20B * 6 / 30ms = 32kbps,是相当缓慢的。

注3:BLE的面向连接通信是使用跳频技术的,即每次Connection Event,都会使用不同Physical Channel收发数据,具体的跳频机制,可参考3.6小节的介绍。

3.5 连接的控制与管理

连接建立之后,Master或者Slave可以借助Link Layer Control Protocol (LLCP),通过LL Control PDU,对连接进行管理控制,包括:

Connection Update Procedure,连接参数(包括connInterval,connSlaveLatency,connSupervisionTimeout)更新的通知。只能由Master发起。

Channel Map Update Procedure,更新Channel map。只能由Master发起。

Encryption Procedure,对连接进行加密,可由master或者slave发起。

Termination Procedure,断开连接。

Connection Parameters Request Procedure,请求更新连接参数(connInterval,connSlaveLatency,connSupervisionTimeout),Slave或者Master都可以发起,和Connection Update Procedure不同是,这是一个协商的过程,不是一定能够成功。

LE Ping Procedure,类似于网络协议中ping操作。

等等。不再详细介绍,具体可参考“BLUETOOTH SPECIFICATION Version 4.2 [Vol 6, Part B]”。

3.6 连接超时及断开

BLE连接断开的原因有两种:一种是预期内的、主动断开,此时会走3.4小节提到的Termination Procedure过程;第二种是一些非预期的原因导致的超时断开,如距离超出、遭受严重的干扰、突然断电等。

对于第一种,是协议内的正常流程,没有什么好说的。而对于第二种,则需要一些timeout机制,检测这写异常情况,具体如下。

1)Master和Slave的Link Layer,都会启动一个名称为TLLconnSupervision的timer,每接收到一个有效的数据包时,该timer都会重置。

2)连接建立的过程中,如果TLLconnSupervision超过6 * connInterval(没有接收到第一个数据包),则认为连接建立失败。

3)在连接成功之后,如果TLLconnSupervision超过connSupervisionTimeout,则说明link loss,则执行超时断开。connSupervisionTimeout是一个可配置的参数,范围是100ms~32s,并且不能大于(1 + connSlaveLatency) * connInterval * 2。

4)BLE协议允许slave忽略掉“connSlaveLatency”个Connection Event,在被忽略的这段时间内,Slave不需要收发数据包,也不会增加TLLconnSupervision,从而引发超时断开。connSlaveLatency是一个整数,有效范围应该在0到((connSupervisionTimeout / (connInterval*2)) - 1)之间,并且不能大于500。

注4:connSlaveLatency是一个非常有用的参数,它允许Slave在数据通信不频繁的时候,忽略掉一些Connection Event,进而可以睡得更久,更加省电。

3.7 跳频(Hopping)策略

BLE的跳频策略是非常简单的,即:每一个Connection Event,更换一次Physical Channel,当然,master和slave需要按照相同的约定更换,不然就无法通信。这个约定如下:

BLE跳频策略

图片3 BLE跳频策略

1)首先,使用一个Basic的算法,利用lastUnmappedChannel和hopIncrement,计算出unmappedChannel。

a)lastUnmappedChannel在连接建立之初的值是0,每一次Connection Event计算出新的unmappedChannel之后,会更新lastUnmappedChannel。

b)hopIncrement是由Master在连接建立时随机指定的,范围是5到16(可参考3.3中的Hop)。

c)确定unmappedChannel的算法为:unmappedChannel = (lastUnmappedChannel + hopIncrement) mod 37,本质上就是每隔“hopIncrement”个Channel取一次,相当直白和简单。

2)计算出unmappedChannel之后,查找当前的Channel map,检查unmappedChannel所代表的Channel是否为used channel。如果是,恭喜,找到了。

Channel map也是由master,在连接建立时,或者后来的Channel map update的时候指定的。

3)如果不是,将所有的used Channel以升序的方式见一个表,表的长度是numUsedChannels,用unmappedChannel和numUsedChannels做模运算,得到一个index,从按照该index,从表中取出对应的channel即可。

3.8 应答(Acknowledgement)和流控(Flow Control)

由3.2小节的描述可知,LL Data PDU的Header中,有NESN(Next Expected Sequence Number)和SN(Sequence Number)两个标记,利用它们,可以很轻松的在Link Layer实现应答、重传、流控等机制。

为了实现这些功能,Link Layer会为每个连接创建两个变量,transmitSeqNum和nextExpectedSeqNum(为了和packet的SN/NESN bit区分,我们将它们简称为sn和nesn),并在连接建立的时候,它们都被初始化为0。

sn用于标识本地设备(Link Layer)发送出去的packets。

nesn是对端设备(Link Layer)用来应答本地设备发送的packet,或者请求本地设备重发packet。

Link Layer在收发packet时,会遵循如下的原则(可结合下面图片4理解):

注5:下面图片4是从“BLUETOOTH SPECIFICATION Version 4.2 [Vol 6, Part B]”中截的一张图,不过spec中画的有问题,我用红色字体改正了。另外,这个图片非常有歧义、难以理解,我会在下面解释。

1)无论是Master还是Slave,发送packet的时候,都会将当前的sn和nesn copy到packet的SN和NESN bit中。

2)无论是Master还是Slave,当接收到一个packet的时候,会将该packet的NESN bit和本地的sn比较:如果相同,说明该packet是对端设备发来的NAK packet(请求重发),则需要将旧的packet重新发送出去;如果不同,说明是对端设备发来的ACK packet(数据被正确接收),则需要将本地的sn加1,接着发送新的packet。

a)以上过程可参考下面图片4中的左边部分。

b)本地的sn,代表本地设备已经发送出去的packet,而packet中的NESN bit,代表对端设备期望本地设备发送的packet。如果二者相同,说明对方期望下次发送的packet,和我们已经发送的packet相同,因此是NAK信号,要求重发。如果二者不同,说明对方设备期望发送一个新的packet,也说明我们上次发送的packet已经成功接收,因此可以将本地的sn加1了。

3)无论是Master还是Slave,当接收到一个packet的时候,会将该packet的SN bit和本地的nesn比较:如果相同,则说明是一个新的packet,接收即可,同时将本地的nesn加1;如果不同,则说明是一个旧的packet,什么都不需要处理。

a)以上过程可参考下面图片4中的右边部分。

b)packet中的SN bit,代表对端设备正在发送的packet,而本地设备的nesn,代表本地设备期望对端设备发送的packet。如果二者相同,则说明是一个期望的packet(新的),就可以收下该packet,并将期望值加1(nesn加1)。如果二者不同,说明不是本地设备期望的packet,什么都不做就可以了。

4)上面2)和3)两个步骤,是相互独立的,因此一个NAK packet,也可能携带新的数据,反之亦然。

5)当一个设备无法接收新的packet的时候(例如RX buffer已满),它可以采取不增加nesn的方式,发送NAK packet。对端设备收到该类型的packet之后,会发送旧的packet(图片4左边部分的“TX old data, sn”分支)。该设备收到这样旧的packet的时候,不会做任何处理(图片4右边部分的“Ignore RX data”分支)。这就是Link Layer的流控机制(Flow control)

BLE应答和流控机制

图片4 BLE应答和流控机制

4. HCI

HCI(Host Control Interface)的功能就简单多了,就是要封装Link Layer所提供的功能,包括两类。

1)连接的建立、关闭、参数设置、管理等,这一类是通过HCI command/event(其格式可参考“蓝牙协议分析(5)_BLE广播通信相关的技术分析”中的介绍)完成的,包括:

LE Create Connection Command,建立连接的命令,需要提供连接有关的参数,包括connInterval(Conn_Interval_Min和Conn_Interval_Max)、connSlaveLatency(Conn_Latency)和connSupervisionTimeout(Supervision_Timeout)。

LE Create Connection Cancel Command,取消或者断开连接。

LE Connection Update Command,更新连接参数,包括connInterval(Conn_Interval_Min和Conn_Interval_Max)、connSlaveLatency(Conn_Latency)和connSupervisionTimeout(Supervision_Timeout)。

LE Set Host Channel Classification Command,配置Channel map。

LE Read Channel Map Command,读取Channel map。

等等。

有关这些命令的具体描述,可参考“BLUETOOTH SPECIFICATION Version 4.2 [Vol 2, Part E] Host Controller Interface Functional Specification”。

2)对ACL data的封装和转发,不再详细说明。

6. GAP

GAP(Generic Access Profile)的主要功能,是定义BLE设备所具备的能力,以实现互联互通的功能。

对BEL基于连接的通信来说,GAP定义了4种连接有关的模式(不同的产品形态,可以选择是否支持这些模式,具体可参考“BLUETOOTH SPECIFICATION Version 4.2 [Vol 3, Part C] 9.3 CONNECTION MODES AND PROCEDURES”):

Non-connectable mode,不可被连接。

Directed connectable mode,可以被“直连”(在知道对方蓝牙地址的情况下的快速连接)。

Undirected connectable mode,可以被“盲连”(不知道对方蓝牙地址)。

Auto connection establishment procedure,可以被自动连接(不需要host干预)。

相应地,GAP定义了5中和这些模式有关的过程(不同的产品形态,可以选择是否支持这些过程):

General connection establishment procedure,通用的连接建立过程,搜索、发现、连接,都需要Host参与。

Selective connection establishment procedure,有选择的连接建立过程,Host需要告诉Controller,自己只希望于特定的设备建立连接。

Direct Connection Establishment Procedure,直接和某一个已知设备建立连接(对方也知道我们)。

Connection Parameter Update Procedure,连接参数的更新过程。

Terminate Connection Procedure,断开连接。

这些mode和procedure的具体描述,可参考蓝牙spec[1]

7. 参考文档

[1] Core_v4.2.pdf

 

原创文章,转发请注明出处。蜗窝科技,www.wowotech.net

DRAM 原理 3 :DRAM Device

$
0
0

在前面的文章中,介绍了 DRAM Cell 和 Memory Array。 本文则以 SDR SDRAM 为例,描述 DRAM Device 与 Host 端的接口,以及其内部的其他模块,包括 Control Logic、IO、Row & Column Decoder 等。

1. SDRAM Interface

SDR SDRAM 是 DRAM 的一种,它与 Host 端的硬件接口如下图所示:

总线上各个信号的描述如下表所示:

Symbol Type Description
CLK Input 从 Host 端输出的同步时钟信号
CKE Input 用于指示 CLK 信号是否有效,SDRAM 会根据此信号进入或者退出 Power down、Self-refresh 等模式
CS# Input Chip Select 信号
CAS# Input Column Address Strobe,列地址选通信号
RAS# Input Row Address Strobe, 行地址选通信号
WE# Input Write Enable,写使能信号
DQML Input 当进行写数据时,如果该 DQML 为高,那么 DQ[7:0] 的数据会被忽略,不写入到 DRAM
DQMH Input 当进行写数据时,如果该 DQMH 为高,那么 DQ[15:8] 的数据会被忽略,不写入到 DRAM
BA[1:0] Input Bank Address,用于选择操作的 Memory Bank
A[12:0] Input Address 总线,用于传输行列地址
DQ[15:0] I/O Data 总线,用于传输读写的数据内容

1.1 SDRAM Operations

Host 与 SDRAM 之间的交互都是由 Host 以 Command 的形式发起的。一个 Command 由多个信号组合而成,下面表格中描述了主要的 Command。

Command CS# RAS# CAS# WE# DQM BA[1:0] & A[12:0] DQ[15:0]
Active L L H H X Bank & Row X
Read L H L H L/H Bank & Col X
Write L H L L L/H Bank & Col Valid
Precharge L L H L X Code X
Auto-refresh L L L H X X X
Self-refresh L L L H X X X
Load Mode Register L L L L X REG Value X

1.1.1 Active

Active Command 会通过 BA[1:0] 和 A[12:0] 信号,选中指定 Bank 中的一个 Row,并打开该 Row 的 wordline。在进行 Read 或者 Write 前,都需要先执行 Active Command。

1.1.2 Read

Read Command 将通过 A[12:0] 信号,发送需要读取的 Column 的地址给 SDRAM。然后 SDRAM 再将 Active Command 所选中的 Row 中,将对应 Column 的数据通过 DQ[15:0] 发送给 Host。

Host 端发送 Read Command,到 SDRAM 将数据发送到总线上的需要的时钟周期个数定义为 CL。

1.1.3 Write

Write Command 将通过 A[12:0] 信号,发送需要写入的 Column 的地址给 SDRAM,同时通过 DQ[15:0] 将待写入的数据发送给 SDRAM。然后 SDRAM 将数据写入到 Actived Row 的指定 Column 中。

SDRAM 接收到最后一个数据到完成数据写入到 Memory 的时间定义为 tWR (Write Recovery)。

1.1.4 Precharge

在进行下一次的 Read 或者 Write 操作前,必须要先执行 Precharge 操作。(具体的细节可以参考 DRAM Storage Cell 章节)

Precharge 操作是以 Bank 为单位进行的,可以单独对某一个 Bank 进行,也可以一次对所有 Bank 进行。如果 A10 为高,那么 SDRAM 进行 All Bank Precharge 操作,如果 A10 为低,那么 SDRAM 根据 BA[1:0] 的值,对指定的 Bank 进行 Precharge 操作。

SDRAM 完成 Precharge 操作需要的时间定义为 tPR。

1.1.5 Auto-Refresh

DRAM 的 Storage Cell 中的电荷会随着时间慢慢减少,为了保证其存储的信息不丢失,需要周期性的对其进行刷新操作。

SDRAM 的刷新是按 Row 进行,标准中定义了在一个刷新周期内(常温下 64ms,高温下 32ms)需要完成一次所有 Row 的刷新操作。

为了简化 SDRAM Controller 的设计,SDRAM 标准定义了 Auto-Refresh 机制,该机制要求 SDRAM Controller 在一个刷新周期内,发送 8192 个 Auto-Refresh Command,即 AR, 给 SDRAM。

SDRAM 每收到一个 AR,就进行 n 个 Row 的刷新操作,其中,n = 总的 Row 数量 / 8192 。
此外,SDRAM 内部维护一个刷新计数器,每完成一次刷新操作,就将计数器更新为下一次需要进行刷新操作的 Row。

一般情况下,SDRAM Controller 会周期性的发送 AR,每两个 AR 直接的时间间隔定义为 tREFI = 64ms / 8192 = 7.8 us。

SDRAM 完成一次刷新操作所需要的时间定义为 tRFC, 这个时间会随着 SDRAM Row 的数量的增加而变大。

由于 AR 会占用总线,阻塞正常的数据请求,同时 SDRAM 在执行 refresh 操作是很费电,所以在 SDRAM 的标准中,还提供了一些优化的措施,例如 DRAM Controller 可以最多延时 8 个 tREFI 后,再一起把 8 个 AR 同时发出。

更多相关的优化可以参考《大容量 DRAM 的刷新开销问题及优化技术综述》文中的描述。

1.1.6 Self-Refresh

Host 还可以让 SDRAM 进入 Self-Refresh 模式,降低功耗。在该模式下,Host 不能对 SDRAM 进行读写操作,SDRAM 内部自行进行刷新操作保证数据的完整。通常在设备进入待机状态时,Host 会让 SDRAM 进入 Self-Refresh 模式,以节省功耗。

更多各个 Command 相关的细节,可以参考后续的 DRAM Timing 章节。

1.2 Address Mapping

SDRAM Controller 的主要功能之一是将 CPU 对指定物理地址的内存访问操作,转换为 SDRAM 读写时序,完成数据的传输。
在实际的产品中,通常需要考虑 CPU 中的物理地址到 SDRAM 的 Bank、Row 和 Column 地址映射。下图是一个 32 位物理地址映射的一个例子:

2. SDRAM 内部结构

如图所示,DRAM Device 内部主要有 Control Logic、Memory Array、Decoders、Reflash Counter 等模块。在后续的小节中,将逐一介绍各个模块的主要功能。

2.1 Control Logic

Control Logic 的主要功能是解析 SDRAM Controller 发出的 Command,然后根据具体的 Command 做具体内部模块的控制,例如:选中指定的 Bank、触发 refresh 等的操作。

Control Logic 包含了 1 个或者多个 Mode Register。该 Register 中包含了时序、数据模式等的配置,更多的细节会在 DRAM Timing 章节进行描述。

2.2 Row & Column Decoder

Row Decoder 的主要功能是将 Active Command 所带的 Row Address 映射到具体的 wordline,最终打开指定的 Row。同样 Column Decoder 则是把 Column Address 映射到具体的 csl,最终选中特定的 Column。

2.3 Memory Array

Memory Array 是存储信息的主要模块,具体细节可以参考 DRAM Memory Orgization 章节的描述。

2.4 IO

IO 电路主要是用于处理数据的缓存、输入和输出。其中 Data Latch 和 Data Register 用于缓存数据,DQM Mask Logic 和 IO Gating 等则用于输入输出的控制。

2.5 Refresh Counter

Refresh Counter 用于记录下次需要进行 refresh 操作的 Row。在接收到 AR 或者在 Self-Refresh 模式下,完成 一次 refresh 后,Refresh Counter 会进行更新。

3. 不同类型的 SDRAM

目前市面上在使用的 DRAM 主要有 SDR、DDR、LPDDR、GDDR 这几类,后续小节中,将对各种类型的 DRAM 进行简单的介绍。

3.1 SDR 和 DDR

SDR(Single Data Rate) SDRAM 是第一个引入 Clock 信号的 DRAM 产品,SDR 在 Clock 的上升沿进行总线信号的处理,一个时钟周期内可以传输一组数据。

DDR(Double Data Rate) SDRAM 是在 SDR 基础上的一个更新。DDR 内部采用 2n-Prefetch 架构,相对于 SDR,在一个读写周期内可以完成 2 倍宽度数据的预取,然后在 Clock 的上升沿和下降沿都进行数据传输,最终达到在相同时钟频率下 2 倍于 SDR 的数据传输速率。(更多 2n-Prefetch 相关的细节可以参考 《Micron Technical Note - General DDR SDRAM Functionality》文中的介绍)

Prefetch 的基本原理如下图所示。在示例 B 中,内部总线宽度是 A 的两倍,在一次操作周期内,可以将两倍于 A 的数据传输到 Output Register 中,接着外部 IO 电路再以两倍于 A 的频率将数据呈现到总线上,最终实现两倍 A 的传输速率。

DDR 后续还有 DDR2、DDR3、DDR4 的更新,基本上每一代都通过更多的 Prefetch 和更高的时钟频率,达到 2 倍于上一代的数据传输速率。

DDR SDRAM Standard Bus clock (MHz) Internal rate (MHz) Prefetch (min burst) Transfer Rate (MT/s) Voltage
DDR 100–200 100–200 2n 200–400 2.5/2.6
DDR2 200–533.33 100–266.67 4n 400–1066.67 1.8
DDR3 400–1066.67 100–266.67 8n 800–2133.33 1.5
DDR4 1066.67–2133.33 133.33–266.67 8n 2133.33–4266.67 1.05/1.2

Transfer Rate (MT/s) 为每秒发生的 Transfer 的数量,一般为 Bus Clock 的 2 倍 (一个 Clock 周期内,上升沿和下降沿各有一个 Transfer)
Internal rate (MHz) 则是内部 Memory Array 读写的频率。由于 SDRAM 采用电容作为存储介质,由于工艺和物理特性的限制,电容充放电的时间难以进一步的缩短,所以内部 Memory Array 的读写频率也受到了限制,目前最高能到 266.67 MHz,这也是 SDR 到 DDR 采用 Prefetch 架构的主要原因。
Memory Array 读写频率受到限制,那就只能在读写宽度上做优化,通过增加单次读写周期内操作的数据宽度,结合总线和 IO 频率的增加来提高整体传输速率。

3.2 LPDDRx

LPDDR,即 Low Power DDR SDRAM,主要是用着移动设备上,例如手机、平板等。相对于 DDR,LPDDR 采用了更低的工作电压、Partial Array Self-Refresh 等机制,降低整体的功耗,以满足移动设备的低功耗需求。

3.3 GDDRx

GDDR,即 Graphic DDR,主要用在显卡设备上。相对于 DDR,GDDR 具有更高的性能、更低的功耗、更少的发热,以满足显卡设备的计算需求。

4. 参考资料

  1. Memory Systems - Cache Dram and Disk
  2. 大容量 DRAM 的刷新开销问题及优化技术综述 [PDF]
  3. Micron Technical Note - General DDR SDRAM Functionality [PDF]
  4. Everything You Need To Know About DDR, DDR2 and DDR3 Memories [WEB]
  5. 記憶體10年技術演進史 [WEB]

DRAM 原理 4 :DRAM Timing

$
0
0

DRAM Device 章节中,我们简单介绍了 SDRAM 的 Active、Read、Write 等的操作,在本中,我们将详细的介绍各个操作的时序。

+

1. Overview

如上图所示,SDRAM 的相关操作在内部大概可以分为以下的几个阶段:

  1. Command transport and decode

    在这个阶段,Host 端会通过 Command Bus 和 Address Bus 将具体的 Command 以及相应参数传递给 SDRAM。SDRAM 接收并解析 Command,接着驱动内部模块进行相应的操作。

  2. In bank data movement

    在这个阶段,SDRAM 主要是将 Memory Array 中的数据从 DRAM Cells 中读出到 Sense Amplifiers,或者将数据从 Sense Amplifiers 写入到 DRAM Cells。

  3. In device data movement

    这个阶段中,数据将通过 IO 电路缓存到 Read Latchs 或者通过 IO 电路和 Write Drivers 更新到 Sense Amplifiers。

  4. System data transport

    在这个阶段,进行读数据操作时,SDRAM 会将数据输出到数据总线上,进行写数据操作时,则是 Host 端的 Controller 将数据输出到总线上。

在上述的四个阶段中,每个阶段都会有一定的耗时,例如数据从 DRAM Cells 搬运到 Read Latchs 的操作需要一定的时间,因此在一个具体的操作需要按照一定时序进行。

同时,由于内部的一些部件可能会被多个操作使用,例如读数据和写数据都需要用到部分 IO 电路,因此多个不同的操作通常不能同时进行,也需要遵守一定的时序。

此外,某些操作会消耗很大的电流,为了满足 SDRAM 设计上的功耗指标,可能会限制某一些操作的执行频率。

基于上面的几点限制,SDRAM Controller 在发出 Command 时,需要遵守一定的时序和规则,这些时序和规则由相应的 SDRAM 标准定义。在后续的小节中,我们将对各个 Command 的时序进行详细的介绍。

2. 时序图例

后续的小节中,我们将通过下图类似的时序图,来描述各个 Command 的详细时序。

上图中,Clock 信号是由 SDRAM Controller 发出的,用于和 DRAM 之间的同步。在 DDRx 中,Clock 信号是一组差分信号,在本文中为了简化描述,将只画出其中的 Positive Clock。

Controller 与 DRAM 之间的交互,都是以 Controller 发起一个 Command 开始的。从 Controller 发出一个 Command 到 DRAM 接收并解析该 Command 所需要的时间定义为 tCMD,不同类型的 Command 的 tCMD 都是相同的。

DRAM 在成功解析 Command 后,就会根据 Command 在内部进行相应的操作。从 Controller 发出 Command 到 DRAM 执行完 Command 所对应的操作所需要的时间定义为 tParam。不同类型的 Command 的 tParam 可能不一样,相同 Command 的 tParam 由于 Command 参数的不同也可能会不一样。

+

NOTE:
各种 Command 的定义和内部操作细节可以参考前面的几篇文章,本文将主要关注时序方面的细节。

3. Row Active Command

在进行数据的读写前,Controller 需要先发送 Row Active Command,打开 DRAM Memory Array 中的指定的 Row。Row Active Command 的时序如下图所示:

Row Active Command 可以分为两个阶段:

3.1 Row Sense

Row Active Command 通过地址总线指明需要打开某一个 Bank 的某一个 Row。

DRAM 在接收到该 Command 后,会打开该 Row 的 Wordline,将其存储的数据读取到 Sense Amplifiers 中,这一时间定义为 tRCD(RCD for Row Address to Column Address Delay)。

DRAM 在完成 Row Sense 阶段后,Controller 就可以发送 Read 或 Write Command 进行数据的读写了。这也意味着,Controller 在发送 Row Active Command 后,需要等待 tRCD 时间才能接着发送 Read 或者 Write Command 进行数据的读写。

3.2 Row Restore

由于 DRAM 的特性,Row 中的数据在被读取到 Sense Amplifiers 后,需要进行 Restore 的操作(细节请参考 DRAM Storage Cell 文中的描述)。Restore 操作可以和数据的读取同时进行,即在这个阶段,Controller 可能发送了 Read Command 进行数据读取。

DRAM 接收到 Row Active Command 到完成 Row Restore 操作所需要的时间定义为 tRAS(RAS for Row Address Strobe)。
Controller 在发出一个 Row Active Command 后,必须要等待 tRAS 时间后,才可以发起另一次的 Precharge 和 Row Access。

4. Column Read Command

Controller 发送 Row Active Command 并等待 tRCD 时间后,再发送 Column Read Command 进行数据读取。
数据 Burst Length 为 8 时的 Column Read Command 时序如下图所示:

Column Read Command 通过地址总线 A[0:9] 指明需要读取的 Column 的起始地址。DRAM 在接收到该 Command 后,会将数据从 Sense Amplifiers 中通过 IO 电路搬运到数据总线上。

DRAM 从接收到 Command 到第一组数据从数据总线上输出的时间称为 tCAS(CAS for Column Address Strobe),也称为 tCL(CL for CAS Latency),这一时间可以通过 mode register 进行配置,通常为 3~5 个时钟周期。

DRAM 在接收到 Column Read Command 的 tCAS 时间后,会通过数据总线,将 n 个 Column 的数据逐个发送给 Controller,其中 n 由 mode register 中的 burst length 决定,通常可以将 burst length 设定为 2、4 或者 8。

开始发送第一个 Column 数据,到最后一个 Column 数据的时间定义为 tBurst。

5. Column Write Command

Controller 发送 Row Active Command 并等待 tRCD 时间后,再发送 Column Write Command 进行数据写入。数据 Burst Length 为 8 时的 Column Write Command 时序如下图所示:

Column Write Command 通过地址总线 A[0:9] 指明需要写入数据的 Column 的起始地址。Controller 在发送完 Write Command 后,需要等待 tCWD (CWD for Column Write Delay) 时间后,才可以发送待写入的数据。tCWD 在一些描述中也称为 tCWL(CWL for Column Write Latency)

tCWD 在不同类型的 SDRAM 标准有所不同:

Memory Type tCWD
SDRAM 0 cycles
DDR SDRAM 1 cycle
DDR2 SDRAM tCAS - 1 cycle
DDR3 SDRAM programmable

DRAM 接收完数据后,需要一定的时间将数据写入到 DRAM Cells 中,这个时间定义为 tWR(WR for Write Recovery)。

6. Precharge Command

在 DRAM Storage Cell 章节中,我们了解到,要访问 DRAM Cell 中的数据,需要先进行 Precharge 操作。相应地,在 Controller 发送 Row Active Command 访问一个具体的 Row 前, Controller 需要发送 Precharge Command 对该 Row 所在的 Bank 进行 Precharge 操作。

下面的时序图描述了 Controller 访问一个 Row 后,执行 Precharge,然后再访问另一个 Row 的流程。

DRAM 执行 Precharge Command 所需要的时间定义为 tRP(RP for Row Precharge)。Controller 在发送一个 Row Active Command 后,需要等待 tRC(RC for Row Cycle)时间后,才能发送第二个 Row Active Command 进行另一个 Row 的访问。

从时序图上我们可以看到,tRC = tRAS + tRP,tRC 时间决定了访问 DRAM 不同 Row 的性能。在实际的产品中,通常会通过降低 tRC 耗时或者在一个 Row Cycle 执行尽可能多数据读写等方式来优化性能。

NOTE:
在一个 Row Cycle 中,发送 Row Active Command 打开一个 Row 后,Controller 可以发起多个 Read 或者 Write Command 进行一个 Row 内的数据访问。这种情况下,由于不用进行 Row 切换,数据访问的性能会比需要切换 Row 的情况好。
在一些产品上,DRAM Controller 会利用这一特性,对 CPU 发起的内存访问进行调度,在不影响数据有效性的情况下,将同一个 Row 上的数据访问汇聚到一直起执行,以提供整体访问性能。

7. Row Refresh Command

一般情况下,为了保证 DRAM 数据的有效性,Controller 每隔 tREFI(REFI for Refresh Interval) 时间就需要发送一个 Row Refresh Command 给 DRAM,进行 Row 刷新操作。DRAM 在接收到 Row Refresh Command 后,会根据内部 Refresh Counter 的值,对所有 Bank 的一个或者多个 Row 进行刷新操作。

DRAM 刷新的操作与 Active + Precharge Command 组合类似,差别在于 Refresh Command 是对 DRAM 所有 Bank 同时进行操作的。下图为 DRAM Row Refresh Command 的时序图:

DRAM 完成刷新操作所需的时间定义为 tRFC(RFC for Refresh Cycle)。

tRFC 包含两个部分的时间,一是完成刷新操作所需要的时间,由于 DRAM Refresh 是同时对所有 Bank 进行的,刷新操作会比单个 Row 的 Active + Precharge 操作需要更长的时间;tRFC 的另一部分时间则是为了降低平均功耗而引入的延时,DRAM Refresh 操作所消耗的电流会比单个 Row 的 Active + Precharge 操作要大的多,tRFC 中引入额外的时延可以限制 Refresh 操作的频率。

NOTE:
在 DDR3 SDRAM 上,tRFC 最小的值大概为 110ns,tRC 则为 52.5ns。

8. Read Cycle

一个完整的 Burst Length 为 4 的 Read Cycle 如下图所示:

9. Read Command With Auto Precharge

DRAM 还可以支持 Auto Precharge 机制。在 Read Command 中的地址线 A10 设为 1 时,就可以触发 Auto Precharge。此时 DRAM 会在完成 Read Command 后的合适的时机,在内部自动执行 Precharge 操作。

Read Command With Auto Precharge 的时序如下图所示:

Auto Precharge 机制的引入,可以降低 Controller 实现的复杂度,进而在功耗和性能上带来改善。

NOTE:
Write Command 也支持 Auto Precharge 机制,参考下一小节的时序图。

10. Additive Latency

在 DDR2 中,又引入了 Additive Latency 机制,即 AL。通过 AL 机制,Controller 可以在发送完 Active Command 后紧接着就发送 Read 或者 Write Command,而后 DRAM 会在合适的时机(延时 tAL 时间)执行 Read 或者 Write Command。时序如下图所示:

Additive Latency 机制同样是降低了 Controller 实现的复杂度,在功耗和性能上带来改善。

11. DRAM Timing 设定

上述的 DRAM Timing 中的一部分参数可以编程设定,例如 tCAS、tAL、Burst Length 等。这些参数通常是在 Host 初始化时,通过 Controller 发起 Load Mode Register Command 写入到 DRAM 的 Mode Register 中。DRAM 完成初始化后,就会按照设定的参数运行。

NOTE:
初始化和参数设定过程不在本文中详细描述,感兴趣的同学可以参考具体 CPU 和 DRAM 芯片的 Datasheet。

12. 参考资料

  1. Memory Systems - Cache Dram and Disk
  2. High Performance Dram System Design Constraints and Considerations

DRAM 原理 5 :DRAM Devices Organization

$
0
0

随着系统对内存容量、带宽、性能等方面的需求提高,系统会接入多个 DRAM Devices。而多个 DRAM Devices 不同的组织方式,会带来不同的效果。本文将对不同的组织方式及其效果进行简单介绍。

相关文章:

DRAM 原理 1 :DRAM Storage Cell

DRAM 原理 2 :DRAM Memory Organization

DRAM 原理 3 :DRAM Device

DRAM 原理 4 :DRAM Timing

1. Single Channel DRAM Controller 组织方式

Single Channel 指 DRAM Controller 只有一组控制和数据总线。 在这种场景下,DRAM Controller 与单个或者多个 DRAM Devices 的连接方式如下所示:

1.1 连接单个 DRAM Device

Single Channel 连接单个 DRAM Device 是最常见的一种组织方式。 由于成本、工艺等方面的因素,单个 DRAM Device 在总线宽度、容量上有所限制,在需要大带宽、大容量的产品中,通常接入多个 DRAM Devices。

1.2 连接多个 DRAM Devices

上图中,多个 DRAM Devices 共享控制和数据总线,DRAM Controller 通过 Chip Select 分时单独访问各个 DRAM Devices。此外,在其中一个 Device 进入刷新周期时,DRAM Controller 可以按照一定的调度算法,优先执行其他 Device 上的访问请求,提高系统整体内存访问性能。

NOTE:
CS0 和 CS1 在同一时刻,只有一个可以处于使能状态,即同一时刻,只有一个 Device 可以被访问。

上述的这种组织方式只增加总体容量,不增加带宽。下图中描述的组织方式则可以既增加总体容量,也增加带宽。

上图中,多个 DRAM Devices 共享控制总线和 Chip Select 信号,DRAM Controller 同时访问每个 DRAM Devices,各个 Devices 的数据合并到一起,例如 Device 1 的数据输出到数据总线的 DATA[0:7] 信号上,Device 2 的数据输出到数据总线的 DATA[8:15] 上。这样的组织方式下,访问 16 bits 的数据就只需要一个访问周期就可以完成,而不需要分解为两个 8 bits 的访问周期。

2. Multi Channel DRAM Controller 组织方式

Multi Channel 指 DRAM Controller 只有多组控制和数据总线,每一组总线可以独立访问 DRAM Devices。 在这种场景下,DRAM Controller 与 DRAM Devices 的连接方式如下所示:

2.1 连接 Single Channel DRAM Devices

这种组织方式的优势在于多个 Devices 可以同时工作,DRAM Controller 可以对不同 Channel 上的 Devices 同时发起读写请求,提高了读写请求的吞吐率。

NOTE:
CS0 和 CS1 在同一时刻,可以同时处于使能状态,即同一时刻,两个 Devices 可以同时被访问。

2.2 连接 Multi Channel DRAM Device

在一些 DRAM 产品中,例如 LPDDR3、LPDDR4 等,引入了 Multi Channel 的设计,即一个 DRAM Devices 中包括多个 Channel。这样就可以在单个 Device 上达成 Multi Channel 同时访问的效果,最终带来读写请求吞吐率的提升。

蓝牙协议分析(8)_BLE安全机制之白名单

$
0
0

1. 前言

在万物联网的时代,安全问题将会受到非常严峻的挑战(相应地,也会获得最大的关注度),因为我们身边的每一个IOT设备,都是一个处于封印状态的天眼,随时都有被开启的危险。想想下面的场景吧:

凌晨2点,x米手环的闹钟意外启动,将你从睡梦中惊醒,然后床头的灯光忽明忽暗……

你的心率、血压、睡眠质量等信息,默默地被竞争对手收集着,并通过大数据分析你的情绪、健康等,随时准备给你致命一击……

我知道你家里有几盏灯、几台电器、几个人,知道你几点睡觉几时醒来,知道你一周做过几顿饭,甚至知道你有一个xx棒、一周使用几次、每次使用多久……

……

算了,不罗列了,有时间的话可以建个iot eyes的站点,专门收集、整理物联网安全有关的内容。这里就先言归正传。

经过前面几篇的蓝牙协议分析,我们对蓝牙(特别是蓝牙低功耗)已经有了一个比较全面的了解。随后几篇文章,我会focus在BLE的安全机制上。毕竟,知己知彼,才能攻防有度。

话说,蓝牙SIG深知物联网安全的水有多深,因此使用了大量的篇幅,定义BLE安全有关的机制,甚至可以不夸张的说,BLE协议中内容最多、最难理解的部分,非安全机制莫属。本文先从介绍最简单的----白名单机制(White list)。

2. 白名单机制

白名单(white list)是BLE协议中最简单、直白的一种安全机制。其原理很简单,总结如下(前面的分析文章中都有介绍):

所谓的白名单,就是一组蓝牙地址;

通过白名单,可以只允许特定的蓝牙设备(白名单中列出的)扫描(Scan)、连接(connect)我们,也可以只扫描、连接特定的蓝牙设备(白名单中列出的)。

例如,如果某个BLE设备,只需要被受信任的某几个设备扫描、连接,我们就可以把这些受信任设备的蓝牙地址加入到该设备的白名单中,这样就可以有效避免其它“流氓设备”的骚扰了。

不过呢,该机制只防君子不防小人,因为它是靠地址去过滤“流氓”的,如果有些资深流氓,伪装一下,将自己的设备地址修改为受信任设备的地址,那就惨了……

3. 白名单有关的HCI命令

注1:本文主要从HCI的角度分析、介绍,如非必要,不再会涉及HCI之下的BLE协议(后续的分析文章,也大抵如此)。

3.1 白名单维护相关的命令

BLE协议在HCI层定义了4个和白名单维护有关的命令,分别如下:

1)LE Read White List Size Command,获取controller可保存白名单设备的个数

该命令的格式为:

OCF Command parameters Return Parameters
0x000F   Status
White_List_Size

Status,命令执行的结果,0为success。

White_List_Size,size,范围是1~255。

注2:由此可知,白名单是保存在controller中,由于size的范围是1~255,因此controller必须实现白名单功能(最少保存一个)。

2)LE Clear White List Command,将controller中的白名单清空

该命令的格式为:

OCF Command parameters Return Parameters
0x0010   Status

Status,命令执行的结果,0为success。

3)LE Add Device To White List Command,将指定的设备添加到白名单

该命令的格式为:

OCF  Command parameters Return Parameters
0x0011 Address_type(1 byte)
Address(6 bytes)
Status

Address_type,设备的地址类型[1],0为Public Device Address,1为Random Device Address。

Address,设备的地址。

Status,命令执行的结果,0为success。

4)LE Remove Device From White List Command,将指定的设备从白名单中移除的命令

该命令的格式为:

OCF Command parameters Return Parameters
0x0012 Address_type(1 byte)
Address(6 bytes)
Status

Address_type,设备的地址类型[1],0为Public Device Address,1为Random Device Address。

Address,设备的地址。

Status,命令执行的结果,0为success。

最后需要说明的是,当controller处于以下三个状态的时候,以上命令除“LE Read Resolving List Size Command”外,均不能执行:

正在advertising;

正在scanning;

正在connecting。

3.2 白名单使用策略有关的命令

BLE设备在发起Advertising、Scanning或者Connecting操作的时候,可以通过Set Advertising Parameters、Set Scan Parameters或者LE Create Connection Command,设置Advertising、Scanning或者Connecting的过滤策略(Filter_Policy),具体如下:

1)Advertising时的白名单策略

LE Set Advertising Parameters Command的命令格式为:

OCF Command parameters Return Parameters
0x0006
Advertising_Filter_Policy(1 byte)
Status

该命令的其它参数请参考[2],Advertising_Filter_Policy的含义如下:

0x00,禁用白名单机制,允许任何设备连接和扫描。

0x01,允许任何设备连接,但只允许白名单中的设备扫描(scan data中有敏感信息?)。

0x02,允许任何设备扫描,但只允许白名单中的设备连接。

0x03,只允许白名单中的设备扫描和连接。

2)Scanning时的白名单策略

LE Set Scan Parameters Command的命令格式为:

OCF Command parameters Return Parameters
0x000B
Scanning_Filter_Policy(1 byte)
Status

该命令的其它参数请参考[2],Scanning_Filter_Policy的含义如下:

0x00,禁用白名单机制,接受所有的广播包(除了那些不是给我的directed advertising packets)。

0x01,只接受在白名单中的那些设备发送的广播包(除了那些不是给我的directed advertising packets)。

0x02,和白名单无关,不再介绍。

0x03,接受如下的广播包:在白名单中的那些设备发送的广播包;广播者地址为resolvable private address的directed advertising packets;给我的给我的directed advertising packets。

注3:Scanning时的白名单策略有点奇怪,既然是主动发起的,要白名单的意义就不大了吧?

3)Connecting时的白名单策略

LE Create Connection Command的命令格式为:

OCF Command parameters Return Parameters
0x000D
Initiator_Filter_Policy(1 byte)
Status

该命令的其它参数请参考[4],Initiator_Filter_Policy的含义如下:

0x00,禁用白名单机制,使用Peer_Address_Type and Peer_Address指定需要连接的设备。

0x01,连接那些在白名单中的设备,不需要提供Peer_Address_Type and Peer_Address参数。

4. 使用示例

4.1 准备工作

后续的测试需要用到如下的设备和软件:

1)蓝牙设备A,作为Advertiser,发送广播数据,接受连接。

2)蓝牙设备B,作为Scanner,扫描设备A的广播数据,发起连接。

上述的1)和2)可以是如下一种:

一个具有bluez(hcitool等工具)的Android手机,可能需要较旧的android版本才行;

带有蓝牙功能的树莓派,允许Debian、Ubuntu等系统(只要不是Android就行);

Linux PC(或者虚拟机)加上一个具有BLE功能的蓝牙适配器。

3)bluez工具集,我们需要使用其中的hcitool命令。

4.2 相关的hcitool命令说明

hcitool中的一些命令,和白名单机制有关,总结如下。

1)hcitool lewlsz,获取controller白名单的size,对应3.1中的LE Read White List Size Command,该命令不需要参数,可直接使用,如下:

root@android:/ # hcitool lewlsz
hcitool lewlsz
White list size: 26

2)hcitool lewlclr,情况controller的白名单,对应3.1中的LE Clear White List Command,该命令也不需要参数,可直接使用,如下:

root@android:/ # hcitool lewlclr
hcitool lewlclr

3)hcitool lewladd,将指定设备添加到白名单中,对应3.1中的LE Add Device To White List Command,其格式如下:

root@android:/ # hcitool lewladd --help
hcitool lewladd --help
Usage:
        lewladd [--random]

其中是必选项,为要添加的蓝牙设备的地址。地址有public和random两种,默认是public,如果需要添加random类型的地址,则要指定--random参数,例如:

root@android:/ # hcitool lewladd 22:22:21:CD:F4:58
hcitool lewladd 22:22:21:CD:F4:58

root@android:/ # hcitool lewladd --random 11:22:33:44:55:66
hcitool lewladd --random 11:22:33:44:55:66

4)hcitool lewlrm,将指定设备从白名单中移除,对应3.1中的LE Remove Device From White List Command,该命令只需要蓝牙地址作为参数,如下:

root@android:/ # hcitool lewlrm --help
hcitool lewlrm --help
Usage:
        lewlrm

5)hcitool lecc,连接BLE设备的命令,对应3.2中的LE Create Connection Command,可以连接指定地址的设备,也可以直接连接白名单中的设备:

root@android:/ # hcitool lecc --help
hcitool lecc --help
Usage:
        lecc [--random]
        lecc --whitelist

一般情况下,我们都是通过hcitool lecc 的方式连接蓝牙设备,不过如果我们需要连接白名单中的设备,可直接使用如下命令:

hcitool lecc --whitelist

6)hcitool cmd,对于其它没有直接提供hcitool命令的HCI操作,我们可以使用hcitool cmd直接发送命令,其使用方法如下:

root@android:/ # hcitool cmd --help
hcitool cmd --help
Usage:
        cmd [parameters]
Example:
        cmd 0x03 0x0013 0xAA 0x0000BBCC 0xDDEE 0xFF

其中ogf、ocf和parameters可以去蓝牙spec的“HCI COMMANDS AND EVENTS”章节查询。需要注意的是,parameters可以使用各种类型(8位、16位、32位),还是很方便的。

4.3 测试步骤

这里仅仅罗列一个简单的测试,步骤包括:

1)设备A作为Advertising设备,不使用白名单,发送正常的ADV_IND(可连接、可扫描)广播包。

2)设备B扫描并连接设备A(应该可以正常连接)。

3)设备A作为Advertising设备,启用白名单,设置Advertising_Filter_Policy为0x2(只允许白名单中的设备连接),且没有把B的地址添加到白名单中。

4)设备B扫描并连接设备A(应该不可以正常连接)。

5)设备A把设备B添加到白名单中,其它策略保持不变。

6)设备B扫描并连接设备A(应该可以正常连接)。

详细步骤如下(我没有测试,有问题的请大家留言告诉我):
1)设备A作为Advertising设备,不使用白名单,发送正常的ADV_IND(可连接、可扫描)广播包。

# disable BLE advertising
hcitool cmd 0x08 0x000A 0x00

# 设置广播参数和广播策略
# Advertising_Interval_Min=0x0800 (1.28 second, default)
# Advertising_Interval_Max=0x0800 (1.28 second, default)
# Advertising_Type=0x00(ADV_IND, default)
# Own_Address_Type=0x00(Public Device Address, default)
# Peer_Address_Type=0x00(Public Device Address, default)
# Peer_Address=00 00 00 00 00 00 (no use)
# Advertising_Channel_Map=0x07(all channels enabled, Default)
# Advertising_Filter_Policy=0x0(禁用白名单)
hcitool -i hci0 cmd 0x08 0x0006 0x0800 0x0800 0x00 0x00 0x00 00 00 00 00 00 00 0x07 0x00

# enable BLE advertising
hcitool cmd 0x08 0x000A 0x01

# set advertising data to Eddystone UUID(可参考[3]中的介绍)
hcitool -i hci0 cmd 0x08 0x0008 1e 02 01 06 03 03 aa fe 17 16 aa fe 00 -10 00 01 02 03 04 05 06 07 08 09 0a 0b 0e 0f 00 00 00 00

2)设备B扫描并连接设备A(应该可以正常连接)。

hcitool lescan
hcitool lecc [bdaddr of A]

3)设备A作为Advertising设备,启用白名单,设置Advertising_Filter_Policy为0x2(只允许白名单中的设备连接),且没有把B的地址添加到白名单中。

# disable BLE advertising
hcitool cmd 0x08 0x000A 0x00

# 设置广播参数和广播策略
# …
# Advertising_Filter_Policy=0x2(只允许白名单中的设备连接)
hcitool -i hci0 cmd 0x08 0x0006 0x0800 0x0800 0x00 0x00 0x00 00 00 00 00 00 00 0x07 0x02

# 清空白名单
hcitool lewlclr

# 随便加一个地址到白名单
hcitool lewladd 11:22:33:44:55:66


# enable BLE advertising
hcitool cmd 0x08 0x000A 0x01

# set advertising data to Eddystone UUID(可参考[3]中的介绍)
hcitool -i hci0 cmd 0x08 0x0008 1e 02 01 06 03 03 aa fe 17 16 aa fe 00 -10 00 01 02 03 04 05 06 07 08 09 0a 0b 0e 0f 00 00 00 00

4)设备B扫描并连接设备A(应该不可以正常连接)。

hcitool lescan
hcitool lecc [bdaddr of A]

5)设备A把设备B添加到白名单中,其它策略保持不变。

# disable BLE advertising
hcitool cmd 0x08 0x000A 0x00

# 设置广播参数和广播策略
# …
# Advertising_Filter_Policy=0x2(只允许白名单中的设备连接)
hcitool -i hci0 cmd 0x08 0x0006 0x0800 0x0800 0x00 0x00 0x00 00 00 00 00 00 00 0x07 0x02

# 将B添加到白名单中
hcitool lewladd [bdaddr of B]


# enable BLE advertising
hcitool cmd 0x08 0x000A 0x01

# set advertising data to Eddystone UUID(可参考[3]中的介绍)
hcitool -i hci0 cmd 0x08 0x0008 1e 02 01 06 03 03 aa fe 17 16 aa fe 00 -10 00 01 02 03 04 05 06 07 08 09 0a 0b 0e 0f 00 00 00 00

6)设备B扫描并连接设备A(应该可以正常连接)。

hcitool lescan
hcitool lecc [bdaddr of A]

5. 参考文档

[1] 蓝牙协议分析(6)_BLE地址类型

[2] 蓝牙协议分析(5)_BLE广播通信相关的技术分析

[3] 玩转BLE(1)_Eddystone beacon

[4] 蓝牙协议分析(7)_BLE连接有关的技术分析

[5] Core_v4.2.pdf

 

原创文章,转发请注明出处。蜗窝科技,www.wowotech.net

蓝牙协议分析(9)_BLE安全机制之LL Privacy

$
0
0

1. 前言

在上一篇文章[1]中,我们介绍了BLE的白名单机制,这是一种通过地址进行简单的访问控制的安全机制。同时我们也提到了,这种安全机制只防君子,不防小人,试想这样一种场景:

A设备表示只信任B、C、D设备,因此就把它们的地址加入到了自己的白名单中,表示只愿意和它们沟通。与此同时,E设备对它们的沟通非常感兴趣,但A对自己不信任啊,肿么办?

E眼珠子一转,想出一个坏主意:把自己的地址伪装成成B、C、D中任意一个(这个还是很容易办到的,随便扫描一下就得它们的地址了)就行了,嘿嘿嘿!

那么问题来了,怎么摆脱“小人E“的偷听呢?不着急,我们还有手段:“链路层的Privacy(隐私)机制”。

2. LL Privacy机制介绍

总结来说,LL Privacy机制是白名单(white list)机制的进阶和加强,它在白名单的基础上,将设备地址转变成Private addresses[2]地址,以降低“小人E“窃得设备地址进而进行伪装的概率。

从白名单的角度看,Non-resolvable private address和Public Device Address/Static Device Address没有任何区别,因此LL Privacy机制主要指Resolvable Private Addresses。因此,LL Privacy机制的本质是:

通过Resolvable Private Addresses,将在空中传输的设备地址加密,让“小人E”无法窃得,从而增加其伪装的难度。

注1:当然,LL Privacy机制可以脱离白名单机制单独使用,不过这样的话好像没什么威力。

注2:有关Resolvable Private Addresses、Identity Address、IRK(Local/Peer IRK)等概念的详细介绍,可参考“蓝牙协议分析(6)_BLE地址类型[2]”,本文将会直接使用。

3. Resolving List

和白名单机制上的White List类似,如果设备需要使用LL Privacy机制,则需要在Controller端保存一个Resolving List,其思路为:

1)BLE设备要按照[1]中的介绍,配置并使能白名单机制,把那些受信任设备的地址(这里为Identity Address)加入到自己的白名单中,并采用合适的白名单策略。

2)如果设备需要使用LL Privacy策略,保护自己(以及对方)的地址不被窃取,则需要将自己(local)和对方(peer)的地址和加密key保存在一个称作Resolving List的列表中。

3)Resolving List的每一个条目,都保存了一对BLE设备的key/address信息,其格式为:Local IRK | Peer IRK | Peer Device Identity Address | Address Type。

Local IRK,本地的IRK,用于将本地设备的Identity Address转换为Resolvable Private Address。可以为0,表示本地地址直接使用Identity Address;

Peer IRK,对端的IRK,用于将对端设备的Resolvable Private Address解析回Identity Address。可以为零,表示对端地址是Identity Address;

Peer Device Identity Address、Address Type,对端设备的Identity Address及类型,用于和解析回的Identity Address进行比对。

4)Resolving List是Host通过HCI命令提供给Controller的,Controller的LL负责如下事项:

发送数据包[3]时:
如果有AdvA需要填充,则判断Resolving List是否有非0的Local IRK,如果有,则使用Local IRK将Identity Address加密为Resolvable Private Address,填充到AdvA中。否则,直接填充Identity Address;
同理,如果有InitA需要填充,则判断Resolving List是否有匹配的、非0的Peer IRK,如果有,则使用Peer IRK将对端的Identity Address加密为Resolvable Private Address,填充到InitA中。否则,直接填充Identity Address。

接收数据包时:
如果数据包中的AdvA或者InitA为普通的Identity Address,则直接做后续的处理;
如果它们为Resolvable Private Address,则会遍历Resolving List中所有的“IRK | Identity Address”条目,使用IRK解出Identity Address和条目中的对比,如果匹配,则地址解析成功,可以做进一步处理。如果不匹配,且使能了白名单/LL Privacy策略,则会直接丢弃。

5)需要重点说明的是,Controller和Host之间所有的事件交互(除了Resolving List操作之外),均使用Identity Address。也就是说,设备地址的加密、解密、比对等操作,都是在controller中完成的,对上层实体(HCI之上)是透明的。

4. 使用场景说明

结合上面2章的解释,罗列一下LL Privacy策略有关的使用场景(大部分翻译自蓝牙spec)。

4.1 设备处于广播状态(Advertising state)时

由[3]中的介绍可知,处于广播状态的BLE设备,根据需要可发送ADV_IND、ADV_DIRECT_IND、ADV_NONCONN_IND和ADV_SCAN_IND 4种类型的广播包,也就是说有4种不同的广播状态,它们的LL privacy策略有稍微的不同,下面分别描述。

1)ADV_IND

设备(Advertiser)发送ADV_IND时,其PDU(connectable undirected advertising event PDU)有一个AdvA字段,该字段的填充策略为(由controller的LL执行):

检查Resolving List,查看是否存在非0的Local IRK条目,如果有,则使用Local IRK将自己的Identity Address加密为Resolvable Private Addresses,并填充到AdvA中。否则,直接使用Identity Address。

Advertiser收到连接请求时,请求者的地址会包含在PDU的InitA中,该字段的解析策略为(由controller的LL执行):

如果InitA是Resolvable Private Addresses,且当前使能了地址解析功能,LL会遍历Resolving List中所有的“Peer IRK | Peer Device Identity Address | Address Type”条目,使用Peer IRK解析出Identity Address后和Peer Device Identity Address做比对,如果匹配,则解析成功,再基于具体的白名单策略,觉得是否接受连接;

如果解析不成功,则无法建立连接;

如果InitA不是Resolvable Private Addresses,则走正常的连接过程。

Advertiser收到扫描请求时,对ScanA的处理策略,和InitA类似。

2)ADV_DIRECT_IND

设备(Advertiser)发送ADV_DIRECT_IND 时,其PDU(connectable directed advertising event PDU)包含AdvA和InitA两个地址,它们填充策略为(由controller的LL执行):

检查Resolving List,查看是否存在非0的Local IRK条目,如果有,则使用Local IRK将自己的Identity Address加密为Resolvable Private Addresses,并填充到AdvA中。否则,直接使用Identity Address;

检查Resolving List,查看是否存在非0、和InitA的Identity Address匹配的Peer IRK条目,如果有,则使用Peer IRK将InitA的Identity Address加密为Resolvable Private Addresses,并填充到InitA中。否则,直接使用Identity Address。

Advertiser收到连接请求时,请求者的地址会包含在PDU的InitA中,该字段的解析策略为和上面ADV_IND类似,不再详细说明。

3)ADV_NONCONN_IND and ADV_SCAN_IND

这两个状态下,AdvA的填充策略和上面1)和2)一样,不再详细说明。

当Advertiser收到SCAN请求时,对ScanA的处理策略,和1)中InitA类似,不再详细说明。

4.2 设备处于扫描状态(Scanning state)时

处于Scanning状态的设备(Scanner)在接收到Advertiser发送的scannable的广播包时,需要按照4.1中解析InitA的方法,解析广播包中的AdvA,并根据当前的白名单策略,进行过滤。

Scanner发送scan请求时,需要指定ScanA和AdvA两个地址。其实ScanA的填充策略和4.1中的AdvA类似,不再详细说明。而AdvA,需要和接收到的广播包的AdvA完全一样,不能有改动。

4.3 设备处于连接状态(Initiating state)时

处于Initiating状态的设备(Initiator)在接收到Advertising发送的connectable的广播包时,需要按照4.1中解析InitA的方法,解析广播包中的AdvA,并根据当前的白名单策略,进行过滤。

同理,Initiator发送连接请求时,需要指定InitA和AdvA两个地址。其实InitA的填充策略和4.1中的AdvA类似,不再详细说明。而AdvA,需要和接收到的广播包的AdvA完全一样,不能有改动。

最后,Initiator在接收到Advertising发送的directed connectable广播包时,除了要解析AdvA,如果InitA是Resolvable Private Addresses,则需要使用Local IRK解析InitA。

5. 和LL Privacy有关的HCI命令

不太想写了,需要了解的直接去掰spec吧。

6. 参考文档

[1] 蓝牙协议分析(8)_BLE安全机制之白名单

[2] 蓝牙协议分析(6)_BLE地址类型

[3] 蓝牙协议分析(5)_BLE广播通信相关的技术分析

 

原创文章,转发请注明出处。蜗窝科技,www.wowotech.net


快讯:蓝牙5.0发布(新特性速览)

$
0
0

1. 前言

2016年12月6日,蓝牙SIG发布了5.0版本的核心规范,该规范从距离、速度等多个方面,对BLE进行了增强,蓝牙官网的总结如下[1]

With the launch of Bluetooth 5, Bluetooth® technology continues to evolve to meet the needs of the industry as the global wireless standard for simple, secure connectivity. With 4x range, 2x speed and 8x broadcasting message capacity, the enhancements of Bluetooth 5 focus on increasing the functionality of Bluetooth for the IoT. These features, along with improved interoperability and coexistence with other wireless technologies, continue to advance the IoT experience by enabling simple and effortless interactions across the vast range of connected devices.

相比蓝牙4.2,新增的特性包括[3]

Several new features are introduced in the Bluetooth Core Specification 5.0
Release. The major areas of improvement are:
• Slot Availability Mask (SAM)
• 2 Msym/s PHY for LE
• LE Long Range
• High Duty Cycle Non-Connectable Advertising
• LE Advertising Extensions
• LE Channel Selection Algorithm #2

下面对一些比较有意思的做个简单的介绍(后续有时间会做比较细致的分析)。

2. 2 Msym/s PHY for LE

在蓝牙4.2 1M符号速率(symbol rate)的PHY(称作LE 1M PHY)基础上,增加2M符号速率的PHY(称作LE 2M PHY),二者的区别为:

1)LE 1M PHY的符号速率为1Msym/s,为必选PHY(每个LE设备必须支持),支持ECC(error correction coding,可选),根据不同的编码方式,支持3种bit速率:1Mb/s(LE 1M)、500Bb/s(LE Coded)和125Kb/s(LE Coded)。

2)LE 2M PHY的符号速率为2Msym/s,为可选PHY,不支持ECC(error correction coding),bit速率为2Mb/s(LE 2M,uncoded)。

3. LE Long Range

将最大的发送功率,从4.0/4.1/4.2中的10mW增大到5.0的100mW(够粗暴,哈哈)。

关于BLE的发射功率,spec中有张表,贴过来供大家参考:

ble_tx_power

4. High Duty Cycle Non-Connectable Advertising

蓝牙4.0将Scannable Undirected和Non-connectable Undirected两种Advertising Event的advInterval的最小值限制为100ms,这就限制了BLE广播的最高速率(2.48kbps,参考[4])。而蓝牙5.0不再区别对待,将最小值统一限制为20ms,从理论上讲,最高的广播速率就可以提高5倍(12.4kbps)。

5. LE Advertising Extensions

这个扩展比较好玩。

蓝牙4.0/4.1/4.2的广播通道(可参考[4]),比较简单、直接,预留3个(可以更少)Physical Channel,用于传输Advertising Event。可传输的数据长度为6~37 octets(加上了协议开销)。

而蓝牙5.0,则搞出了新花样(实用性大增,从此之后就没有连接的必要了啊!),总结为:

1)抽象出primary advertising channel和secondary advertising channel的概念。

2)primary advertising channel就是蓝牙4.2及以前的、预留出的、用于传输Advertising Event。

3)而secondary advertising channel,则直接复用了剩余的37个data channel,用于传输扩展的Advertising Event(称作Extended Advertising Event)。此时可传输的数据长度为0 ~ 255 octets,相比之前的37,暴增了很多倍,好爽啊!!

4)因此,在原有的用于传输广播数据的PDU(ADV_IND、ADV_DIRECT_IND、ADV_NONCONN_IND以及ADV_SCAN_IND,称作legacy PDUs)的基础上,增加了扩展的PDU(ADV_EXT_IND、AUX_ADV_IND、AUX_SYNC_IND以及AUX_CHAIN_IND,称作extended advertising PDUs)。

5)相应的,Advertising Event也分为Legacy Advertising Event和Extenteded Advertising Event。

6. 参考文档

[1] https://www.bluetooth.com/specifications/bluetooth-core-specification/bluetooth5

[2] https://www.bluetooth.com/specifications/adopted-specifications

[3] https://www.bluetooth.org/DocMan/handlers/DownloadDoc.ashx?doc_id=421043

[4] 蓝牙协议分析(5)_BLE广播通信相关的技术分析

 

原创文章,转发请注明出处。蜗窝科技,www.wowotech.net

MMC/SD/SDIO介绍

$
0
0

1. 前言

熟悉Linux kernel的人都知道,kernel使用MMC subsystem统一管理MMC、SD、SDIO等设备,为什么呢?到底什么是MMC?SD和SDIO又是什么?为什么可以用MMC统称呢?

在分析Linux kernel的MMC subsystem之前,有必要先介绍一些概念,以便对MMC/SD/SDIO有一个大致的了解,这就是本文的目的。

2. 基本概念

MMC是MultiMediaCard的简称,从本质上看,它是一种用于固态非易失性存储的内存卡(memory card)规范[1],定义了诸如卡的形态、尺寸、容量、电气信号、和主机之间的通信协议等方方面面的内容。

从1997年MMC规范发布至今,基于不同的考量(物理尺寸、电压范围、管脚数量、最大容量、数据位宽、clock频率、安全特性、是否支持SPI mode、是否支持DDR mode、等等),进化出了MMC、SD、microSD、SDIO、eMMC等不同的规范(如下面图片1所示)。虽然乱花迷人,其本质终究还是一样的,丝毫未变,这就是Linux kernel将它们统称为MMC的原因。

mmc_sd_sdio_history

图片1 MMC/SD/SDIO evolution

关于该图片,这里强调几点(其它的,大家可参考[1][2],不再详细介绍):

MMC、SD、SDIO的技术本质是一样的(使用相同的总线规范,等等),都是从MMC规范演化而来;

MMC强调的是多媒体存储(MM,MultiMedia);

SD强调的是安全和数据保护(S,Secure);

SDIO是从SD演化出来的,强调的是接口(IO,Input/Output),不再关注另一端的具体形态(可以是WIFI设备、Bluetooth设备、GPS等等)。

3. 规范简介

MMC分别从卡(Card Concept)、总线(Bus Concept)以及控制器(Host Controller)三个方面,定义MMC system的行为,如下面图片2所示:

mmc_sd_sdio_hw_block

图片2 mmc_sd_sdio_hw_block

不同岗位的工程师,可以根据自己的工作性质,重点理解某一部分的规范,下面从嵌入式软件工程师的视角,简单的介绍一下。

3.1 卡的规范

卡的规范主要规定卡的形状、物理尺寸、管脚,内部block组成、寄存器等等,以eMMC为例[3]

Card Concept(eMMC)

图片3 Card Concept(eMMC)

1)有关形状、尺寸的内容,这里不再介绍,感兴趣的同学可参考[1]。

2)卡的内部由如下几个block组成:

Memory core,存储介质,一般是NAND flash、NOR flash等;

Memory core interface,管理存储介质的接口,用于访问(读、写、擦出等操作)存储介质;

Card interface(CMD、CLK、DATA),总线接口,外界访问卡内部存储介质的接口,和具体的管脚相连;

Card interface controller,将总线接口上的协议转换为Memory core interface的形式,用于访问内部存储介质;

Power模块,提供reset、上电检测等功能;

寄存器(图片1中位于Card interface controller的左侧,那些小矩形),用于提供卡的信息、参数、访问控制等功能。

3)卡的管脚有VDD、GND、RST、CLK、CMD和DATA等,VDD和GND提供power,RST用于复位,CLK、CMD和DATA为MMC总线协议(具体可参考3.2小节)的物理通道:

CLK有一条,提供同步时钟,可以在CLK的上升沿(或者下降沿,或者上升沿和下降沿)采集数据;

CMD有一条,用于传输双向的命令。

DATA用于传说双向的数据,根据MMC的类型,可以有一条(1-bit)、四条(4-bit)或者八条(8-bit)。

4)以eMMC为例,规范定义了OCR, CID, CSD, EXT_CSD, RCA 以及DSR 6组寄存器,具体含义后面再介绍。

3.2 总线规范

前面我们提到过,MMC的本质是提供一套可以访问固态非易失性存储介质的通信协议,从产业化的角度看,这些存储介质一般集成在一个独立的外部模块中(卡、WIFI模组等),通过物理总线和CPU连接。对任何有线的通信协议来说,总线规范都是非常重要的。关于MMC总线规范,简单总结如下:

1)物理信号有CLK、CMD和DATA三类。

2)电压范围为1.65V和3.6V(参考上面图片2),根据工作电压的不同,MMC卡可以分为两类:

High Voltage MultiMediaCard,工作电压为2.7V~3.6V。

Dual Voltage MultiMediaCard,工作电压有两种,1.70V~1.95V和2.7V~3.6V,CPU可以根据需要切换。

3)数据传输的位宽(称作data bus width mode)是允许动态配置的,包括1-bit (默认)模式、4-bit模式和8-bit模式。

注1:不使用的数据线,需要保持上拉状态,这就是图片2中的DATA中标出上拉的原因。另外,由于数据线宽度是动态可配的,这要求CPU可以动态的enable/disable数据线的那些上拉电阻。

4)MMC规范定义了CLK的频率范围,包括0-20MHz、0-26MHz、0-52MHz等几种,结合数据线宽度,基本决定了MMC的访问速度。

5)总线规范定义了一种简单的、主从式的总线协议,MMC卡位从机(slave),CPU为主机(Host)。

6)协议规定了三种可以在总线上传输的信标(token):

Command,Host通过CMD线发送给Slave的,用于启动(或结束)一个操作(后面介绍);

Response,Slave通过CMD线发送给Host,用于回应Host发送的Command;

Data,Host和Slave之间通过数据线传说的数据。方向可以是Host到Slave,也可以是Slave到Host。数据线的个数可以是1、4或者8。在每一个时钟周期,每根数据线上可以传输1bit或者2bits的数据。

7)一次数据传输过程,需要涉及所有的3个信标。一次数据传输的过程也称作Bus Operation,根据场景的不同,MMC协议规定了很多类型的Bus Operation(具体可参考相应的规范)。

3.3 控制器规范

Host控制器是MMC总线规范在Host端的实现,也是Linux驱动工程师比较关注的地方,后面将会结合Linux MMC framework的有关内容,再详细介绍。

4. 总结

本文对MMC/SD/SDIO等做了一个简单的介绍,有了这些基本概念之后,在Linux kernel中编写MMC驱动将不再是一个困难的事情(因为MMC是一个协议,所有有关协议的事情,都很简单,因为协议是固定的),我们只需要如下步骤即可完成:

1)结合MMC的规范,阅读Host MMC controller的spec,理解有关的功能和操作方法。

2)根据Linux MMC framework的框架,将MMC bus有关的操作方法通过MMC controller实现。

具体可参考后续MMC framework的分析文档。

5. 参考文档

[1] https://en.wikipedia.org/wiki/MultiMediaCard

[2] https://en.wikipedia.org/wiki/Secure_Digital

[3] eMM spec(注册后可免费下载),http://www.jedec.org/standards-documents/results/jesd84-b51

 

原创文章,转发请注明出处。蜗窝科技,www.wowotech.net

eMMC 原理 1 :Flash Memory 简介

$
0
0

eMMC 是 Flash Memory 的一类,在详细介绍 eMMC 之前,先简单介绍一下 Flash Memory。

Flash Memory 是一种非易失性的存储器。在嵌入式系统中通常用于存放系统、应用和数据等。在 PC 系统中,则主要用在固态硬盘以及主板 BIOS 中。另外,绝大部分的 U 盘、SDCard 等移动存储设备也都是使用 Flash Memory 作为存储介质。

+

1. Flash Memory 的主要特性

与传统的硬盘存储器相比,Flash Memory 具有质量轻、能耗低、体积小、抗震能力强等的优点,但也有不少局限性,主要如下:

  1. 需要先擦除再写入
    Flash Memory 写入数据时有一定的限制。它只能将当前为 1 的比特改写为 0,而无法将已经为 0 的比特改写为 1,只有在擦除的操作中,才能把整块的比特改写为 1。

  2. 块擦除次数有限
    Flash Memory 的每个数据块都有擦除次数的限制(十万到百万次不等),擦写超过一定次数后,该数据块将无法可靠存储数据,成为坏块。
    为了最大化的延长 Flash Memory 的寿命,在软件上需要做擦写均衡(Wear Leveling),通过分散写入、动态映射等手段均衡使用各个数据块。同时,软件还需要进行坏块管理(Bad Block Management,BBM),标识坏块,不让坏块参与数据存储。(注:除了擦写导致的坏块外,Flash Memory 在生产过程也会产生坏块,即固有坏块。)

  3. 读写干扰
    由于硬件实现上的物理特性,Flash Memory 在进行读写操作时,有可能会导致邻近的其他比特发生位翻转,导致数据异常。这种异常可以通过重新擦除来恢复。Flash Memory 应用中通常会使用 ECC 等算法进行错误检测和数据修正。

  4. 电荷泄漏
    存储在 Flash Memory 存储单元的电荷,如果长期没有使用,会发生电荷泄漏,导致数据错误。不过这个时间比较长,一般十年左右。此种异常是非永久性的,重新擦除可以恢复。

2. NOR Flash 和 NAND Flash

根据硬件上存储原理的不同,Flash Memory 主要可以分为 NOR Flash 和 NAND Flash 两类。 主要的差异如下所示:

  • NAND Flash 读取速度与 NOR Flash 相近,根据接口的不同有所差异;
  • NAND Flash 的写入速度比 NOR Flash 快很多;
  • NAND Flash 的擦除速度比 NOR Flash 快很多;
  • NAND Flash 最大擦次数比 NOR Flash 多;
  • NOR Flash 支持片上执行,可以在上面直接运行代码;
  • NOR Flash 软件驱动比 NAND Flash 简单;
  • NOR Flash 可以随机按字节读取数据,NAND Flash 需要按块进行读取。
  • 大容量下 NAND Flash 比 NOR Flash 成本要低很多,体积也更小;

(注:NOR Flash 和 NAND Flash 的擦除都是按块块进行的,执行一个擦除或者写入操作时,NOR Flash 大约需要 5s,而 NAND Flash 通常不超过 4ms。)

2.1 NOR Flash

NOR Flash 根据与 CPU 端接口的不同,可以分为 Parallel NOR Flash 和 Serial NOR Flash 两类。
Parallel NOR Flash 可以接入到 Host 的 SRAM/DRAM Controller 上,所存储的内容可以直接映射到 CPU 地址空间,不需要拷贝到 RAM 中即可被 CPU 访问,因而支持片上执行。Serial NOR Flash 的成本比 Parallel NOR Flash 低,主要通过 SPI 接口与 Host 连接。


图片: Parallel NOR Flash 与 Serial NOR Flash


鉴于 NOR Flash 擦写速度慢,成本高等特性,NOR Flash 主要应用于小容量、内容更新少的场景,例如 PC 主板 BIOS、路由器系统存储等。

更多 NOR Flash 的相关细节,请参考 NOR Flash 章节。

2.2 NAND Flash

NAND Flash 需要通过专门的 NFI(NAND Flash Interface)与 Host 端进行通信,如下图所示:


图片:NAND Flash Interface


NAND Flash 根据每个存储单元内存储比特个数的不同,可以分为 SLC(Single-Level Cell)、MLC(Multi-Level Cell) 和 TLC(Triple-Level Cell) 三类。其中,在一个存储单元中,SLC 可以存储 1 个比特,MLC 可以存储 2 个比特,TLC 则可以存储 3 个比特。

NAND Flash 的一个存储单元内部,是通过不同的电压等级,来表示其所存储的信息的。在 SLC 中,存储单元的电压被分为两个等级,分别表示 0 和 1 两个状态,即 1 个比特。在 MLC 中,存储单元的电压则被分为 4 个等级,分别表示 00 01 10 11 四个状态,即 2 个比特位。同理,在 TLC 中,存储单元的电压被分为 8 个等级,存储 3 个比特信息。


图片: SLC、MLC 与 TLC


NAND Flash 的单个存储单元存储的比特位越多,读写性能会越差,寿命也越短,但是成本会更低。Table 1 中,给出了特定工艺和技术水平下的成本和寿命数据。


Table 1

SLC MLC TLC
制造成本 30-35 美元 / 32GB 17 美元 / 32GB 9-12 美元 / 32GB
擦写次数 10万次或更高 1万次或更高 5000次甚至更高
存储单元 1 bit / cell 2 bits / cell 3 bits / cell

(注:以上数据来源于互联网,仅供参考)


相比于 NOR Flash,NAND Flash 写入性能好,大容量下成本低。目前,绝大部分手机和平板等移动设备中所使用的 eMMC 内部的 Flash Memory 都属于 NAND Flash。PC 中的固态硬盘中也是使用 NAND Flash。

更多 NAND Flash 的相关细节,请参考 NAND Flash 章节。

3. Raw Flash 和 Managed Flash

由于 Flash Memory 存在按块擦写、擦写次数的限制、读写干扰、电荷泄露等的局限,为了最大程度的发挥 Flash Memory 的价值,通常需要有一个特殊的软件层次,实现坏块管理、擦写均衡、ECC、垃圾回收等的功能,这一个软件层次称为 FTL(Flash Translation Layer)。

在具体实现中,根据 FTL 所在的位置的不同,可以把 Flash Memory 分为 Raw Flash 和 Managed Flash 两类。


图片: Raw Flash 和 Managed Flash


Raw Flash
在此类应用中,在 Host 端通常有专门的 FTL 或者 Flash 文件系统来实现坏块管理、擦写均衡等的功能。Host 端的软件复杂度较高,但是整体方案的成本较低,常用于价格敏感的嵌入式产品中。
通常我们所说的 NOR Flash 和 NAND Flash 都属于这类型。

Managed Flash
Managed Flash 在其内部集成了 Flash Controller,用于完成擦写均衡、坏块管理、ECC校验等功能。相比于直接将 Flash 接入到 Host 端,Managed Flash 屏蔽了 Flash 的物理特性,对 Host 提供标准化的接口,可以减少 Host 端软件的复杂度,让 Host 端专注于上层业务,省去对 Flash 进行特殊的处理。
eMMCSD CardUFS、U 盘等产品是属于 Managed Flash 这一类。

4. 参考资料

  1. NOR NAND Flash Guide: Selecting a Flash Storage Solution [PDF]
  2. Wiki: Common Flash Memory Interface [Web]
  3. Quick Guide to Common Flash Interface [PDF]
  4. MICRON NOR Flash Technology [Web]
  5. MICRON NAND Flash Technology [Web]
  6. Wiki:闪存 [Web]
  7. Wiki:Flash File System [Web]
  8. Wear Leveling in Micron® NAND Flash Memory [PDF]
  9. Understanding Flash: The Flash Translation Layer [Web]
  10. 谈NAND Flash的底层结构和解析 [Web]
  11. 闪存基础 [Web]
  12. Open NAND Flash Interface (ONFI) [Web]

eMMC 原理 2 :eMMC 简介

$
0
0

eMMC 是 embedded MultiMediaCard 的简称。MultiMediaCard,即 MMC, 是一种闪存卡(Flash Memory Card)标准,它定义了 MMC 的架构以及访问 Flash Memory 的接口和协议。而 eMMC 则是对 MMC 的一个拓展,以满足更高标准的性能、成本、体积、稳定、易用等的需求。

eMMC 的整体架构如下图片所示:

图片: eMMC 整体架构


eMMC 内部主要可以分为 Flash Memory、Flash Controller 以及 Host Interface 三大部分。

1. Flash Memory

Flash Memory 是一种非易失性的存储器,通常在嵌入式系统中用于存放系统、应用和数据等,类似与 PC 系统中的硬盘。

目前,绝大部分手机和平板等移动设备中所使用的 eMMC 内部的 Flash Memory 都属于 NAND Flash,关于 NAND Flash 的更多细节可以参考 Flash Memory 章节。

eMMC 在内部对 Flash Memory 划分了几个主要区域,如下图所示:

图片:eMMC 内部分区


  1. BOOT Area Partition 1 & 2
    此分区主要是为了支持从 eMMC 启动系统而设计的。
    该分区的数据,在 eMMC 上电后,可以通过很简单的协议就可以读取出来。同时,大部分的 SOC 都可以通过 GPIO 或者 FUSE 的配置,让 ROM 代码在上电后,将 eMMC BOOT 分区的内容加载到 SOC 内部的 SRAM 中执行。

  2. RPMB Partition
    RPMB 是 Replay Protected Memory Block 的简称,它通过 HMAC SHA-256 和 Write Counter 来保证保存在 RPMB 内部的数据不被非法篡改。
    在实际应用中,RPMB 分区通常用来保存安全相关的数据,例如指纹数据、安全支付相关的密钥等。

  3. General Purpose Partition 1~4
    此区域则主要用于存储系统或者用户数据。 General Purpose Partition 在芯片出厂时,通常是不存在的,需要主动进行配置后,才会存在。

  4. User Data Area
    此区域则主要用于存储系统和用户数据。
    User Data Area 通常会进行再分区,例如 Android 系统中,通常在此区域分出 boot、system、userdata 等分区。

更多 eMMC 分区相关的细节,请参考 eMMC 分区管理 章节。

2. Flash Controller

NAND Flash 直接接入 Host 时,Host 端通常需要有 NAND Flash Translation Layer,即 NFTL 或者 NAND Flash 文件系统来做坏块管理、ECC等的功能。

eMMC 则在其内部集成了 Flash Controller,用于完成擦写均衡、坏块管理、ECC校验等功能。相比于直接将 NAND Flash 接入到 Host 端,eMMC 屏蔽了 NAND Flash 的物理特性,可以减少 Host 端软件的复杂度,让 Host 端专注于上层业务,省去对 NAND Flash 进行特殊的处理。同时,eMMC 通过使用 Cache、Memory Array 等技术,在读写性能上也比 NAND Flash 要好很多。

图片:NAND Flash 与 eMMC

3. Host Interface

eMMC 与 Host 之间的连接如下图所示:

图片:eMMC Interface


各个信号的用途如下所示:

CLK
用于同步的时钟信号

Data Strobe
此信号是从 Device 端输出的时钟信号,频率和 CLK 信号相同,用于同步从 Device 端输出的数据。该信号在 eMMC 5.0 中引入。

CMD
此信号用于发送 Host 的 command 和 Device 的 response。

DAT0-7
用于传输数据的 8 bit 总线。

Host 与 eMMC 之间的通信都是 Host 以一个 Command 开始发起的。针对不同的 Command,Device 会做出不同的响应。详细的通信协议相关内容,请参考 eMMC 总线协议 章节。

4. 参考资料

  1. Embedded Multi-Media Card (e•MMC) Electrical Standard (5.1) [PDF]

eMMC 原理 3 :分区管理

$
0
0


1. Partitions Overview

eMMC 标准中,将内部的 Flash Memory 划分为 4 类区域,最多可以支持 8 个硬件分区,如下图所示:

1.1 概述

一般情况下,Boot Area Partitions 和 RPMB Partition 的容量大小通常都为 4MB,部分芯片厂家也会提供配置的机会。General Purpose Partitions (GPP) 则在出厂时默认不被支持,即不存在这些分区,需要用户主动使能,并配置其所要使用的 GPP 的容量大小,GPP 的数量可以为 1 - 4 个,各个 GPP 的容量大小可以不一样。User Data Area (UDA) 的容量大小则为总容量大小减去其他分区所占用的容量。更多各个分区的细节将在后续小节中描述。

1.2 分区编址

eMMC 的每一个硬件分区的存储空间都是独立编址的,即访问地址为 0 - partition size。具体的数据读写操作实际访问哪一个硬件分区,是由 eMMC 的 Extended CSD register 的 PARTITION_CONFIG Field 中 的 Bit[2:0]: PARTITION_ACCESS 决定的,用户可以通过配置 PARTITION_ACCESS 来切换硬件分区的访问。也就是说,用户在访问特定的分区前,需要先发送命令,配置 PARTITION_ACCESS,然后再发送相关的数据访问请求。更多数据读写相关的细节,请参考 eMMC 总线协议 章节。

eMMC 的各个硬件分区有其自身的功能特性,多分区的设计,为不同的应用场景提供了便利。

2. Boot Area Partitions

Boot Area 包含两个 Boot Area Partitions,主要用于存储 Bootloader,支持 SOC 从 eMMC 启动系统。

2.1 容量大小

两个 Boot Area Partitions 的大小是完全一致的,由 Extended CSD register 的 BOOT_SIZE_MULT Field 决定,大小的计算公式如下:

Size = 128Kbytes x BOOT_SIZE_MULT

一般情况下,Boot Area Partition 的大小都为 4 MB,即 BOOT_SIZE_MULT 为 32,部分芯片厂家会提供改写 BOOT_SIZE_MULT 的功能来改变 Boot Area Partition 的容量大小。BOOT_SIZE_MULT 最大可以为 255,即 Boot Area Partition 的最大容量大小可以为 255 x 128 KB = 32640 KB = 31.875 MB。

2.2 从 Boot Area 启动

eMMC 中定义了 Boot State,在 Power-up、HW reset 或者 SW reset 后,如果满足一定的条件,eMMC 就会进入该 State。进入 Boot State 的条件如下:

Original Boot Operation
CMD 信号保持低电平不少于 74 个时钟周期,会触发 Original Boot Operation,进入 Boot State。

Alternative Boot Operation
在 74 个时钟周期后,在 CMD 信号首次拉低或者 Host 发送 CMD1 之前,Host 发送参数为 0xFFFFFFFA 的 COM0时,会触发 Alternative Boot Operation,进入 Boot State。

在 Boot State 下,如果有配置 BOOT_ACK,eMMC 会先发送 “010” 的 ACK 包,接着 eMMC 会将最大为 128Kbytes x BOOT_SIZE_MULT 的 Boot Data 发送给 Host。传输过程中,Host 可以通过拉高 CMD 信号 (Original Boot 中),或者发送 Reset 命令 (Alternative Boot 中) 来中断 eMMC 的数据发送,完成 Boot Data 传输。

Boot Data 根据 Extended CSD register 的 PARTITION_CONFIG Field 的 Bit[5:3]:BOOT_PARTITION_ENABLE 的设定,可以从 Boot Area Partition 1、Boot Area Partition 2 或者 User Data Area 读出。

Boot Data 存储在 Boot Area 比在 User Data Area 中要更加的安全,可以减少意外修改导致系统无法启动,同时无法更新系统的情况出现。

(更多 Boot State 的细节,请参考 eMMC 工作模式 的 Boot Mode 章节)

2.3 写保护

通过设定 Extended CSD register 的 BOOT_WP Field,可以为两个 Boot Area Partition 独立配置写保护功能,以防止数据被意外改写或者擦出。

eMMC 中定义了两种 Boot Area 的写保护模式:

  1. Power-on write protection,使能后,如果 eMMC 掉电,写保护功能失效,需要每次 Power on 后进行配置
  2. Permanent write protection,使能后,即使掉电也不会失效,主动进行关闭才会失效

3. RPMB Partition

RPMB(Replay Protected Memory Block)Partition 是 eMMC 中的一个具有安全特性的分区。
eMMC 在写入数据到 RPMB 时,会校验数据的合法性,只有指定的 Host 才能够写入,同时在读数据时,也提供了签名机制,保证 Host 读取到的数据是 RPMB 内部数据,而不是攻击者伪造的数据。

RPMB 在实际应用中,通常用于存储一些有防止非法篡改需求的数据,例如手机上指纹支付相关的公钥、序列号等。RPMB 可以对写入操作进行鉴权,但是读取并不需要鉴权,任何人都可以进行读取的操作,因此存储到 RPMB 的数据通常会进行加密后再存储。

3.1 容量大小

两个 RPMB Partition 的大小是由 Extended CSD register 的 BOOT_SIZE_MULT Field 决定,大小的计算公式如下:

Size = 128Kbytes x BOOT_SIZE_MULT

一般情况下,Boot Area Partition 的大小为 4 MB,即 RPMB_SIZE_MULT 为 32,部分芯片厂家会提供改写 RPMB_SIZE_MULT 的功能来改变 RPMB Partition 的容量大小。RPMB_SIZE_MULT 最大可以为 128,即 Boot Area Partition 的最大容量大小可以为 128 x 128 KB = 16384 KB = 16 MB。

3.2 Replay Protect 原理

使用 eMMC 的产品,在产线生产时,会为每一个产品生产一个唯一的 256 bits 的 Secure Key,烧写到 eMMC 的 OTP 区域(只能烧写一次的区域),同时 Host 在安全区域中(例如:TEE)也会保留该 Secure Key。

在 eMMC 内部,还有一个RPMB Write Counter。RPMB 每进行一次合法的写入操作时,Write Counter 就会自动加一 。

通过 Secure Key 和 Write Counter 的应用,RMPB 可以实现数据读取和写入的 Replay Protect。

RPMB 数据读取

RPMB 数据读取的流程如下:

  1. Host 向 eMMC 发起读 RPMB 的请求,同时生成一个 16 bytes 的随机数,发送给 eMMC。
  2. eMMC 将请求的数据从 RPMB 中读出,并使用 Secure Key 通过 HMAC SHA-256 算法,计算读取到的数据和接收到的随机数拼接到一起后的签名。然后,eMMC 将读取到的数据、接收到的随机数、计算得到的签名一并发送给 Host。
  3. Host 接收到 RPMB 的数据、随机数以及签名后,首先比较随机数是否与自己发送的一致,如果一致,再用同样的 Secure Key 通过 HMAC SHA-256 算法对数据和随机数组合到一起进行签名,如果签名与 eMMC 发送的签名是一致的,那么就可以确定该数据是从 RPMB 中读取到的正确数据,而不是攻击者伪造的数据。

通过上述的读取流程,可以保证 Host 正确的读取到 RPMB 的数据。

RPMB 数据写入

RPMB 数据写入的流程如下:

  1. Host 按照上面的读数据流程,读取 RPMB 的 Write Counter。
  2. Host 将需要写入的数据和 Write Counter 拼接到一起并计算签名,然后将数据、Write Counter 以及签名一并发给 eMMC。
  3. eMMC 接收到数据后,先对比 Write Counter 是否与当前的值相同,如果相同那么再对数据和 Write Counter 的组合进行签名,然后和 Host 发送过来的签名进行比较,如果签名相同则鉴权通过,将数据写入到 RPMB 中。

通过上述的写入流程,可以保证 RPMB 不会被非法篡改。

更多 RPMB 相关的细节,可以参考 eMMC RPMB 章节。

4. General Purpose Partitions

eMMC 提供了 General Purpose Partitions (GPP),主要用于存储系统和应用数据。在很多使用 eMMC 的产品中,GPP 都没有被启用,因为它在功能上与 UDA 类似,产品上直接使用 UDA 就可以满足需求。

4.1 容量大小

eMMC 最多可以支持 4 个 GPPs,每一个 GPP 的大小可以单独配置。用户可以通过设定 Extended CSD register 的以下三个 Field 来设 GPPx (x=1~4) 的容量大小:

  • GP_SIZE_MULT_x_2
  • GP_SIZE_MULT_x_1
  • GP_SIZE_MULT_x_0

GPPx 的容量计算公式如下:

Size = (GP_SIZE_MULT_x_2 * 2^16 + GP_SIZE_MULT_x_1 * 2^8 + GP_SIZE_MULT_x_0 * 2^0) * (Write protect group size)

Write protect group size = 512KB * HC_ERASE_GRP_SIZE * HC_WP_GRP_SIZE

  • eMMC 中,擦除和写保护都是按块进行的,上述表达式中的 HC_WP_GRP_SIZE 为写保护的操作块大小,HC_ERASE_GRP_SIZE 则为擦除操作的快的大小。
  • eMMC 芯片的 GPP 的配置通常是只能进行一次 (OTP),一般会在产品量产阶段,在产线上进行。

4.2 分区属性

eMMC 标准中,为 GPP 定义了两类属性,Enhanced attribute 和 Extended attribute。每个 GPP 可以设定两类属性中的一种属性,不可以同时设定多个属性。

Enhanced attribute

  • Default, 未设定 Enhanced attribute。
  • Enhanced storage media, 设定 GPP 为 Enhanced storage media。

在 eMMC 标准中,实际上并未定义设定 Enhanced attribute 后对 eMMC 的影响。Enhanced attribute 的具体作用,由芯片制造商定义。
在实际的产品中,设定 Enhanced storage media 后,一般是把该分区的存储介质从 MLC 改变为 SLC,提高该分区的读写性能、寿命以及稳定性。由于 1 个存储单元下,MLC 的容量是 SLC 的两倍,所以在总的存储单元数量一定的情况下,如果把原本为 MLC 的分区改变为 SLC,会减少 eMMC 的容量,就是说,此时 eMMC 的实际总容量比标称的总容量会小一点。(MLC 和 SLC 的细节可以参考 Flash Memory 章节内容)

Extended attribute

  • Default, 未设定 Extended attribute。
  • System code, 设定 GPP 为 System code 属性,该属性主要用在存放操作系统类的、很少进行擦写更新的分区。
  • Non-Persistent,设定 GPP 为 Non-Persistent 属性,该属性主要用于存储临时数据的分区,例如 tmp 目录所在分区、 swap 分区等。

在 eMMC 标准中,同样也没有定义设定 Extended attribute 后对 eMMC 的影响。Extended attribute 的具体作用,由芯片制造商定义。Extended attribute 主要是跟分区的应用场景有关,厂商可以为不用应用场景的分区做不同的优化处理。

5. User Data Area

User Data Area (UDA) 通常是 eMMC 中最大的一个分区,是实际产品中,最主要的存储区域。

5.1 容量大小

UDA 的容量大小不需要设置,在配置完其他分区大小后,再扣除设置 Enhanced attribute 所损耗的容量,剩下的容量就是 UDA 的容量。

5.2 软件分区

为了更合理的管理数据,满足不同的应用需求,UDA 在实际产品中,会进行软件再分区。目前主流的软件分区技术有 MBR(Master Boot Record)和 GPT(GUID Partition Table)两种。这两种分区技术的基本原理类似,如下图所示:

软件分区技术一般是将存储介质划分为多个区域,既 SW Partitions,然后通过一个 Partition Table 来维护这些 SW Partitions。在 Partition Table 中,每一个条目都保存着一个 SW Partition 的起始地址、大小等的属性信息。软件系统在启动后,会去扫描 Partition Table,获取存储介质上的各个 SW Partitions 信息,然后根据这些信息,将各个 Partitions 加载到系统中,进行数据存取。

MBR 和 GPT 此处不展开详细介绍,更多的细节可以参考 wikipedia 上 MBR 和 GPT 相关介绍。

5.3 区域属性

eMMC 标准中,支持为 UDA 中一个特定大小的区域设定 Enhanced attribute。与 GPP 中的 Enhanced attribute 相同,eMMC 标准也没有定义该区域设定 Enhanced attribute 后对 eMMC 的影响。Enhanced attribute 的具体作用,由芯片制造商定义。

Enhanced attribute

  • Default, 未设定 Enhanced attribute。
  • Enhanced storage media, 设定该区域为 Enhanced storage media。

在实际的产品中,UDA 区域设定为 Enhanced storage media 后,一般是把该区域的存储介质从 MLC 改变为 SLC。通常,产品中可以将某一个 SW Partition 设定为 Enhanced storage media,以获得更好的性能和健壮性。

6. eMMC 分区应用实例

在一个 Android 手机系统中,各个分区的呈现形式如下:

  • mmcblk0 为 eMMC 的块设备;
  • mmcblk0boot0 和 mmcblk0boot1 对应两个 Boot Area Partitions;
  • mmcblk0rpmb 则为 RPMB Partition,
  • mmcblk0px 为 UDA 划分出来的 SW Partitions;
  • 如果存在 GPP,名称则为 mmcblk0gp1、mmcblk0gp2、mmcblk0gp3、mmcblk0gp4;
root@xxx:/ # ls /dev/block/mmcblk0*
/dev/block/mmcblk0
/dev/block/mmcblk0boot0
/dev/block/mmcblk0boot1
/dev/block/mmcblk0rpmb
/dev/block/mmcblk0p1
/dev/block/mmcblk0p2
/dev/block/mmcblk0p3
/dev/block/mmcblk0p4
/dev/block/mmcblk0p5
/dev/block/mmcblk0p6
/dev/block/mmcblk0p7
/dev/block/mmcblk0p8
/dev/block/mmcblk0p9
/dev/block/mmcblk0p10
/dev/block/mmcblk0p11
/dev/block/mmcblk0p12
/dev/block/mmcblk0p13
/dev/block/mmcblk0p14
/dev/block/mmcblk0p15
/dev/block/mmcblk0p16
/dev/block/mmcblk0p17
/dev/block/mmcblk0p18
/dev/block/mmcblk0p19
/dev/block/mmcblk0p20
/dev/block/mmcblk0p21
/dev/block/mmcblk0p22
/dev/block/mmcblk0p23
/dev/block/mmcblk0p24
/dev/block/mmcblk0p25
/dev/block/mmcblk0p26
/dev/block/mmcblk0p27
/dev/block/mmcblk0p28
/dev/block/mmcblk0p29
/dev/block/mmcblk0p30
/dev/block/mmcblk0p31
/dev/block/mmcblk0p32

每一个分区会根据实际的功能来设定名称。

root@xxx:/ # ls -l /dev/block/platform/mtk-msdc.0/11230000.msdc0/by-name/
lrwxrwxrwx root root 2015-01-03 04:03 boot -> /dev/block/mmcblk0p22
lrwxrwxrwx root root 2015-01-03 04:03 cache -> /dev/block/mmcblk0p30
lrwxrwxrwx root root 2015-01-03 04:03 custom -> /dev/block/mmcblk0p3
lrwxrwxrwx root root 2015-01-03 04:03 devinfo -> /dev/block/mmcblk0p28
lrwxrwxrwx root root 2015-01-03 04:03 expdb -> /dev/block/mmcblk0p4
lrwxrwxrwx root root 2015-01-03 04:03 flashinfo -> /dev/block/mmcblk0p32
lrwxrwxrwx root root 2015-01-03 04:03 frp -> /dev/block/mmcblk0p5
lrwxrwxrwx root root 2015-01-03 04:03 keystore -> /dev/block/mmcblk0p27
lrwxrwxrwx root root 2015-01-03 04:03 lk -> /dev/block/mmcblk0p20
lrwxrwxrwx root root 2015-01-03 04:03 lk2 -> /dev/block/mmcblk0p21
lrwxrwxrwx root root 2015-01-03 04:03 logo -> /dev/block/mmcblk0p23
lrwxrwxrwx root root 2015-01-03 04:03 md1arm7 -> /dev/block/mmcblk0p17
lrwxrwxrwx root root 2015-01-03 04:03 md1dsp -> /dev/block/mmcblk0p16
lrwxrwxrwx root root 2015-01-03 04:03 md1img -> /dev/block/mmcblk0p15
lrwxrwxrwx root root 2015-01-03 04:03 md3img -> /dev/block/mmcblk0p18
lrwxrwxrwx root root 2015-01-03 04:03 metadata -> /dev/block/mmcblk0p8
lrwxrwxrwx root root 2015-01-03 04:03 nvdata -> /dev/block/mmcblk0p7
lrwxrwxrwx root root 2015-01-03 04:03 nvram -> /dev/block/mmcblk0p19
lrwxrwxrwx root root 2015-01-03 04:03 oemkeystore -> /dev/block/mmcblk0p12
lrwxrwxrwx root root 2015-01-03 04:03 para -> /dev/block/mmcblk0p2
lrwxrwxrwx root root 2015-01-03 04:03 ppl -> /dev/block/mmcblk0p6
lrwxrwxrwx root root 2015-01-03 04:03 proinfo -> /dev/block/mmcblk0p13
lrwxrwxrwx root root 2015-01-03 04:03 protect1 -> /dev/block/mmcblk0p9
lrwxrwxrwx root root 2015-01-03 04:03 protect2 -> /dev/block/mmcblk0p10
lrwxrwxrwx root root 2015-01-03 04:03 recovery -> /dev/block/mmcblk0p1
lrwxrwxrwx root root 2015-01-03 04:03 rstinfo -> /dev/block/mmcblk0p14
lrwxrwxrwx root root 2015-01-03 04:03 seccfg -> /dev/block/mmcblk0p11
lrwxrwxrwx root root 2015-01-03 04:03 secro -> /dev/block/mmcblk0p26
lrwxrwxrwx root root 2015-01-03 04:03 system -> /dev/block/mmcblk0p29
lrwxrwxrwx root root 2015-01-03 04:03 tee1 -> /dev/block/mmcblk0p24
lrwxrwxrwx root root 2015-01-03 04:03 tee2 -> /dev/block/mmcblk0p25
lrwxrwxrwx root root 2015-01-03 04:03 userdata -> /dev/block/mmcblk0p31 

7. 参考资料

  1. Embedded Multi-Media Card (e•MMC) Electrical Standard (5.1) [PDF]
  2. Disk partitioning [Web]
  3. Master Boot Record [Web]
  4. GUID Partition Table [Web]


eMMC 原理 4 :总线协议

$
0
0


1. eMMC 总线接口

eMMC 总线接口定义如下图所示:

各个信号的描述如下:

CLK

CLK 信号用于从 Host 端输出时钟信号,进行数据传输的同步和设备运作的驱动。
在一个时钟周期内,CMD 和 DAT0-7 信号上都可以支持传输 1 个比特,即 SDR (Single Data Rate) 模式。此外,DAT0-7 信号还支持配置为 DDR (Double Data Rate) 模式,在一个时钟周期内,可以传输 2 个比特。
Host 可以在通讯过程中动态调整时钟信号的频率(注,频率范围需要满足 Spec 的定义)。通过调整时钟频率,可以实现省电或者数据流控(避免 Over-run 或者 Under-run)功能。 在一些场景中,Host 端还可以关闭时钟,例如 eMMC 处于 Busy 状态时,或者接收完数据,进入 Programming State 时。

CMD

CMD 信号主要用于 Host 向 eMMC 发送 Command 和 eMMC 向 Host 发送对于的 Response。Command 和 Response 的细节会在后续章节中介绍。

DAT0-7

DAT0-7 信号主要用于 Host 和 eMMC 之间的数据传输。在 eMMC 上电或者软复位后,只有 DAT0 可以进行数据传输,完成初始化后,可配置 DAT0-3 或者 DAT0-7 进行数据传输,即数据总线可以配置为 4 bits 或者 8 bits 模式。

Data Strobe

Data Strobe 时钟信号由 eMMC 发送给 Host,频率与 CLK 信号相同,用于 Host 端进行数据接收的同步。Data Strobe 信号只能在 HS400 模式下配置启用,启用后可以提高数据传输的稳定性,省去总线 tuning 过程。

NOTE:
Extended CSD byte[183] BUS_WIDTH 寄存器用于配置总线宽度和 Data Strobe

2. eMMC 总线模型

eMMC 总线中,可以有一个 Host,多个 eMMC Devices。总线上的所有通讯都由 Host 端以一个 Command 开发发起,Host 一次只能与一个 eMMC Device 通讯。

系统在上电启动后,Host 会为所有 eMMC Device 逐个分配地址(RCA,Relative device Address)。当 Host 需要和某一个 eMMC Device 通讯时,会先根据 RCA 选中该 eMMC Device,只有被选中的 eMMC Device 才会响应 Host 的 Command。

NOTE:
更详细的工作原理请参考 eMMC 工作模式 章节。

2.1 速率模式

随着 eMMC 协议的版本迭代,eMMC 总线的速率越来越高。为了兼容旧版本的 eMMC Device,所有 Devices 在上电启动或者 Reset 后,都会先进入兼容速率模式(Backward Compatible Mode)。在完成 eMMC Devices 的初始化后,Host 可以通过特定的流程,让 Device 进入其他高速率模式,目前支持以下的几种速率模式。

Mode Data Rate Bus Width Frequency Max Data Transfer (x8)
Backward Compatible Single x1, x4, x8 0-26 MHz 26 MB/s
High Speed SDR Single x1, x4, x8 0-52 MHz 52 MB/s
High Speed DDR Dual x4, x8 0-52 MHz 104 MB/s
HS200 Single x4, x8 0-200 MHz 200 MB/s
HS400 Dual x8 0-200 MHz 400 MB/s

NOTE:
Extended CSD byte[185] HS_TIMING 寄存器可以配置总线速率模式
Extended CSD byte[183] BUS_WIDTH 寄存器用于配置总线宽度和 Data Strobe

2.2 通信模型

Host 与 eMMC Device 之间的通信都是由 Host 以一个 Command 开始发起的,eMMC Device 在完成 Command 所指定的任务后,则返回一个 Response。

2.2.1 Read Data

Host 从 eMMC Device 读取数据的流程如上图所示。

如果 Host 发送的是 Single Block Read 的 Command,那么 eMMC Device 只会发送一个 Block 的数据(一个 Block 的数据的字节数由 Host 设定或者为 eMMC Device 的默认值,更多细节请参考 eMMC 工作模式 章节)。
如果 Host 发送的是 Multiple Block Read 的 Command,那么 eMMC Device 会持续发送数据,直到 Host 主动发送 Stop Command。

NOTE:
从 eMMC Device 读数据都是按 Block 读取的。

2.2.2 Write Data

Host 向 eMMC Device 写入数据的流程如上图所示。

如果 Host 发送的是 Single Block Write Command,那么 eMMC Device 只会将后续第一个 Block 的数据写入的存储器中。
如果 Host 发送的是 Multiple Block Write Command,那么 eMMC Device 会持续地将接收到的数据写入到存储器中,直到 Host 主动发送 Stop Command。

eMMC Device 在接收到一个 Block 的数据后,会进行 CRC 校验,然后将校验结果通过 CRC Token 发送给 Host。
发送完 CRC Token 后,如果 CRC 校验成功,eMMC Device 会将数据写入到内部存储器时,此时 DAT0 信号会拉低,作为 Busy 信号。Host 会持续检测 DAT0 信号,直到为高电平时,才会接着发送下一个 Block 的数据。如果 CRC 校验失败,那么 eMMC Device 不会进行数据写入,此次传输后续的数据都会被忽略。

NOTE:
向 eMMC Device 写数据都是按 Block 写入的。

2.2.3 No Data

在 Host 与 eMMC Device 的通信中,有部分交互是不需要进行数据传输的,还有部分交互甚至不需要 eMMC Device 的回复 Response。

2.2.4 Command

如上图所示,eMMC Command 由 48 Bits 组成,各个 Bits 的解析如下所示:

Description Start Bit Transmission Bit Command Index Argument CRC7 End Bit
Bit position 47 46 [45:40] [39:8] [7:1] 0
Width (bits) 1 1 6 32 7 1
Value "0" "1" x x x "1"

Start Bit 固定为 "0",在没有数据传输的情况下,CMD 信号保持高电平,当 Host 将 Start Bit 发送到总线上时,eMMC Device 可以很方便检测到该信号,并开始接收 Command。

Transmission Bit 固定为 "1",指示了该数据包的传输方向为 Host 发送到 eMMC Device。

Command Index 和 Argument 为 Command 的具体内容,不同的 Command 有不同的 Index,不同的 Command 也有各自的 Argument。 更多的细节,请参考 eMMC Commands 章节。

CRC7 是包含 Start Bit、Transmission Bit、 Command Index 和 Argument 内容的 CRC 校验值。

End Bit 为结束标志位,固定为"1"。

NOTE:
CRC 校验简单来说,是发送方将需要传输的数据“除于”(模2除)一个约定的数,并将得到的余数附在数据上一并发送出去。接收方收到数据后,再做同样的“除法”,然后校验得到余数是否与接收的余数相同。如果不相同,那么意味着数据在传输过程中发生了改变。更多的细节不在本文展开描述,感兴趣的读者可以参考 CRC wiki 中的介绍。

2.2.5 Response

eMMC Response 有两种长度的数据包,分别为 48 Bits 和 136 Bits。

Start Bit 与 Command 一样,固定为 "0",在没有数据传输的情况下,CMD 信号保持高电平,当 eMMC Device 将 Start Bit 发送到总线上时,Host 可以很方便检测到该信号,并开始接收 Response。

Transmission Bit 固定为 "0",指示了该数据包的传输方向为 eMMC Device 发送到 Host。

Content 为 Response 的具体内容,不同的 Command 会有不同的 Content。 更多的细节,请参考 eMMC Responses 章节。

CRC7 是包含 Start Bit、Transmission Bit 和 Content 内容的 CRC 校验值。

End Bit 为结束标志位,固定为"1"。

2.2.6 Data Block

Data Block 由 Start Bit、Data、CRC16 和 End Bit 组成。以下是不同总线宽度和 Data Rate 下,Data Block 详细格式。

1 Bit Bus SDR

CRC 为 Data 的 16 bit CRC 校验值,不包含 Start Bit。

4 Bits Bus SDR

各个 Data Line 上的 CRC 为对应 Data Line 的 Data 的 16 bit CRC 校验值。

8 Bits Bus SDR

各个 Data Line 上的 CRC 为对应 Data Line 的 Data 的16 bit CRC 校验值。

4 Bits Bus DDR

8 Bits Bus DDR

在 DDR 模式下,Data Line 在时钟的上升沿和下降沿都会传输数据,其中上升沿传输数据的奇数字节 (Byte 1,3,5 ...),下降沿则传输数据的偶数字节(Byte 2,4,6 ...)。
此外,在 DDR 模式下,1 个 Data Line 上有两个相互交织的 CRC16,上升沿的 CRC 比特组成 odd CRC16,下降沿的 CRC 比特组成 even CRC16。odd CRC16 用于校验该 Data Line 上所有上升沿比特组成的数据,even CRC16 则用于校验该 Data Line 上所有下降沿比特组成的数据。

NOTE:
DDR 模式下使用两个 CRC16 作为校验,可能是为了更可靠的校验,选用 CRC16 而非 CRC32 则可能是出于兼容性设计的考虑。

2.2.7 CRC Status Token

在写数据传输中,eMMC Device 接收到 Host 发送的一个 Data Block 后,会进行 CRC 校验,如果校验成功,eMMC 会在对应的 Data Line 上向 Host 发回一个 Positive CRC status token (010),如果校验失败,则会在对应的 Data Line 上发送一个 Negative CRC status token (101)。

NOTE:
读数据时,Host 接收到 eMMC Device 发送的 Data Block 后,也会进行 CRC 校验,但是不管校验成功或者失败,都不会向 eMMC Device 发送 CRC Status Token。

详细格式如下图所示:

Positive CRC status token

Negative CRC status token

3. eMMC 总线测试过程

当 eMMC Device 处于 SDR 模式时,Host 可以发送 CMD19 命令,触发总线测试过程(Bus testing procedure),测试总线硬件上的连通性。如果 eMMC Device 支持总线测试,那么 eMMC Device 在接收到 CMD19 后,会发回对应的 Response,接着 eMMC Device 会发送一组固定的测试数据给 Host。Host 接收到数据后,检查数据正确与否,即可得知总线是否正确连通。

NOTE: 如果 eMMC Device 不支持总线测试,那么接收到 CMD19 时,不会发回 Response。
总线测试不支持在 DDR 模式下进行。

测试数据如下所示:

NOTE: 总线宽度为 1 时,只发送 DAT0 上的数据,总线宽度为 4 时,则只发送 DAT0-3 上的数据

4. eMMC 总线 Sampling Tuning

由于芯片制造工艺、PCB 走线、电压、温度等因素的影响,数据信号从 eMMC Device 到达 Host 端的时间是存在差异的,Host 接收数据时采样的时间点也需要相应的进行调整。而 Host 端最佳采样时间点,则是通过 Sampling Tuning 流程得到。

NOTE:
不同 eMMC Device 最佳的采样点可能不同,同一 eMMC Device 在不同的环境下运作时的最佳采样点也可能不同。
在 eMMC 标准中,定义了在 HS200 模式下可以进行 Sampling Tuning。

4.1 Sampling Tuning 流程

Sampling Tuning 是用于计算 Host 最佳采样时间点的流程,大致的流程如下:

  1. Host 将采样时间点重置为默认值
  2. Host 向 eMMC Device 发送 Send Tuning Block 命令
  3. eMMC Device 向 Host 发送固定的 Tuning Block 数据
  4. Host 接收到 Tuning Block 并进行校验
  5. Host 修改采样时点,重新从第 2 步开始执行,直到 Host 获取到一个有效采样时间点区间
  6. Host 取有效采样时间点区间的中间值作为采样时间点,并推出 Tuning 流程

NOTE:
上述流程仅仅是一个示例。Tuning 流程执行的时机、频率和具体的步骤是由 Host 端的 eMMC Controller 具体实现而定的。

4.2 Tuning Block 数据

Tuning Block 是专门为了 Tuning 而设计的一组特殊数据。相对于普通的数据,这组特殊数据在传输过程中,会更高概率的出现 high SSO noise、deterministic jitter、ISI、timing errors 等问题。这组数据的具体内容如下所示:

NOTE: 总线宽度为 1 时,只发送 DAT0 上的数据,总线宽度为 4 时,则只发送 DAT0-3 上的数据

5. 参考资料

  1. Embedded Multi-Media Card (e•MMC) Electrical Standard (5.1) [PDF]
  2. SD/MMC Controller, Hard Processor System (HPS) Technical Reference Manual (TRM) [PDF]
  3. CRC wiki [WEB]

原创文章,转发请注明出处。蜗窝科技


玩转BLE(3)_使用微信蓝牙精简协议伪造记步数据

$
0
0

1. 前言

在物联网时代,有一个问题肯定会让人头疼(现在已经初露端倪了):

物联网中的IOT设备有两个主要特点:
1)简单小巧(不具备复杂的人机交互接口,需要手机等终端设备辅助完成配置、控制等功能)。
2)数量和种类繁多(消费者面对的可是数量众多的不同厂家、不同类型的设备)。

基于这两个特点,手机等终端设备一般通过APP(或APK)对IOT设备进行控制,不同厂家的不同设备,通常需要不同的APP/APK。于是出现了这样的结果:
如果你家里有一个小米yeelight的床头灯,你需要安装一个yeelight的APP/APK;
如果你手上戴一个百度智能手环,你需要安装一个百度智能手环APP/APK;
如果你跑步时戴一个xxx运动蓝牙耳机,你需要安装一个xxx运动蓝牙耳机APP/APK;
如果你要骑摩拜单车,你需要安装一个摩拜单车APP/APK;
如果你也行骑一下优拜单车,你需要安装一个优拜单车APP/APK;
……(要列的话,我觉得永远都列不完,大家可以想象一下,这是不是一个灾难??)

既然有问题,肯定就有人试图解决,于是微信IoT、阿里小智、亚马逊IoT等等,互联网大佬们就各显神通了。最终谁能称霸天下,现在还不得而知,本文也不去讨论这些。

作为蓝牙BLE的介绍文章,本文将以微信IoT的“微信蓝牙精简协议”为例,通过“把一个蓝牙适配器模拟成微信计步器”,分别从BLE技术(怎样注册一个GATT service)和微信IoT(微信物联网平台的思路和想法)两个角度,窥一窥IoT江湖的冰山一角(权当开阔眼界了)。

2. 微信蓝牙精简协议简介

微信蓝牙精简协议的思路很简单(具体可参考“http://iot.weixin.qq.com/wiki/new/index.html?page=4-3“),如下图:

微信蓝牙精简协议-框图

图片1 微信蓝牙精简协议框架

总结来说,就是:

通过微信(可以运行在手机、平板、电脑、等硬件上面)统一和IoT设备交互;

交互的介质是BLE协议(可以摇身变为其它无线协议);

交互的过程可由服务器协助完成(服务器可选择微信服务器或者第三方服务器)。

虽然思路简单,背后却有深深的“不怀好意”,因为:

1)IoT设备想要和微信(或者微信背后的服务器)交互,就必须遵守微信定义的协议;

2)IoT设备通过微信和服务的交互(无论是第三方服务器,还是微信服务器),都必须遵守微信定义的协议,并经由微信服务器转发。

基于上面两点,物联网中最重要的两个环节:设备和数据,都掌握在微信的手中了。恐怖!!

到目前为止,“微信蓝牙精简协议”有一个比较成熟的应用实例:微信计步器,其工作流程为:

1)在带有计步功能的BLE设备上,按照协议规定的方式,基于BLE GATT,实现相应的Profile、Service、Attribute。

2)在微信公众平台,为该设备申请一个唯一的设备ID,并和设备的MAC地址一起,在公众平台上注册、授权。

3)在微信的微信运动小程序中,扫描并添加该设备,即可通过BLE读取设备的计步信息。

4)微信运动读取计步信息后,可以进行后续的动作(例如在朋友圈刷排名等)。

以上步骤,后面章节将会使用一个蓝牙适配器(模拟蓝牙计步器),配合自己的手机微信,进行演示说明。

3. 将蓝牙适配器模拟成一个计步器

3.1 环境准备

后续实验基于如下的硬件、软件环境(其它环境也okay,不过我没有测试)。

运行Ubuntu为例的PC、笔记本(或者开发板),包含蓝牙4.0(及以上)功能(自带或者使用蓝牙适配器);

Ubuntu中安装有较新版本的Bluez协议栈及工具集,以及其它必须的软禁包(具体步骤略,碰到问题的时候可以一点点解决);

具有BLE功能的手机(上面有可以正常使用的微信);

3.2 搭建Golang开发环境

在包含Bluez(及相关工具集)的Linux OS中,使用Bluez的工具,可以完成大部分的BLE实验,例如:

hcitool、bluetoothctl等工具,可以进行BLE设备的扫描、连接、配对、广播等操作;

hcitool可以发送HCI command,设置BLE的广播数据;

gatttool可以在GATT层面,完成GATT profile的连接、service attribute的读写等操作;

等等。

但有一个功能点,不是很容易实现,就是如何自定义一个GATT profile(要知道,BLE 90%以上的功能都是通过GATT实现的,如果做到这一点,学习BLE就非常方便了)。当然,BLE不复杂,我们可以直接使用BLuez提供的API,自行开发。如果是产品开发,无可厚非,但是如果仅仅只做个实验,这样大张旗鼓的就不划算了,最好能有一些开源的工具。确实有,我搜集、尝试过几种工具:

1)使用bluez的测试代码(bluez-5.37/test/example-gatt-server),是一个python脚本。这个家伙对环境依赖度比较高,很难用,最终没有用起来。

2)一个由nodejs脚本写的工具(https://github.com/luluxie/weixin-iot)。基本功能还好,不过本人对js不太熟,就算了。

3)一个由Go语言写的工具(https://github.com/paypal/gatt)。功能OK,关键还是新奇的Go语言,果断使用~~

这就是搭建Golang开发环境的原因。至于步骤,很简单(以Ubuntu为例):

1)安装Go语言
sudo apt install golang

2)创建GOPATH环境变量
mkdir ~/gopath
export GOPATH=$HOME/gopath    #为了方便,可以放到~/.profile中

3.3 代码准备

在github上,从https://github.com/paypal/gatt中clone一个仓库,clone的仓库地址为https://github.com/wowotech/gatt。clone后使用go get命令,下载代码到本地:

vim@ubuntu:~$ go get github.com/wowotech/gatt

下载后代码的位置为:

vim@ubuntu:~$ ls $GOPATH/src/github.com/wowotech/

gatt

然后,手动将代码中所有的“github.com/paypal”类型的import修改为“github.com/wowotech”(fuck Go!!)

cd $GOPATH/src/github.com/wowotech/gatt

find . -name "*.go" | xargs sed -i 's/paypal/wowotech/g'

提交记录如下:

https://github.com/wowotech/gatt/commit/1f1c23e94cb7e1b54078a568a60cf1aaef7de195

3.4 编译并运行一个示例文件.

(略)。

3.5 支持“微信蓝牙精简协议”

参考examples/server.go以及蓝牙精简协议的定义[1],新建weixin.go,增加微信蓝牙精简协议。最终的文件如下(代码很简单,熟悉BLE GATT协议的同学,很容易看懂,就不过多解释了):

https://github.com/wowotech/gatt/commit/942e7480ad1664dabacdb5561fa98a831621f7de

注1:可以通过代码中如下的定义修改计步的步数(想刷爆微信运动朋友圈的同学注意了,嘿嘿!!):

+ // steps little endian

+ // 01(steps) 10 27 00(0x002710 = 10000)

+ // http://iot.weixin.qq.com/wiki/new/index.html?page=4-3

+ steps := []byte{ 0x01, 0x5c, 0x74, 0x01 }

3.6 编译、运行、测试

编译:

vim@ubuntu:~/gopath/src/github.com/wowotech/gatt/examples$ go build weixin.go

运行:

vim@ubuntu:~/gopath/src/github.com/wowotech/gatt/examples$ sudo ./weixin

[sudo] password for vim:

2017/03/04 01:03:13 dev: hci0 up
2017/03/04 01:03:14 dev: hci0 down
2017/03/04 01:03:14 dev: hci0 opened
State: PoweredOn
2017/03/04 01:03:14 BD Addr: 5C:F3:70:6A:BA:27
2017/03/04 01:03:14 Generating attribute table:
2017/03/04 01:03:14 handle type props secure pvt value
2017/03/04 01:03:14 0x0001 0x2800 0x02 0x00 *gatt.Service [ E7 FE ]
2017/03/04 01:03:14 0x0002 0x2803 0x32 0x00 *gatt.Characteristic [ 32 03 00 A1 FE ]
2017/03/04 01:03:14 0x0003 0xfea1 0x32 0x00 *gatt.Characteristic [ ]
2017/03/04 01:03:14 0x0004 0x2902 0x0E 0x00 *gatt.Descriptor [ 00 00 ]
2017/03/04 01:03:14 0x0005 0x2803 0x3E 0x00 *gatt.Characteristic [ 3E 06 00 A2 FE ]
2017/03/04 01:03:14 0x0006 0xfea2 0x3E 0x00 *gatt.Characteristic [ ]
2017/03/04 01:03:14 0x0007 0x2902 0x0E 0x00 *gatt.Descriptor [ 00 00 ]
2017/03/04 01:03:14 0x0008 0x2803 0x02 0x00 *gatt.Characteristic [ 02 09 00 C9 FE ]
2017/03/04 01:03:14 0x0009 0xfec9 0x02 0x00 *gatt.Characteristic [ ]

然后在手机下载AirSyncDebugger2.3.0.apk(http://iot.weixin.qq.com/wiki/new/index.html?page=4-3的底部)测试精简协议是否okay:

打开APK---->精简协议---->计步器测试

测试界面如下(Android平台):

wx-蓝牙精简协议-AirSyncDebugger

4. 在微信公众平台注册并授权设备

第2章成功模拟出来一个遵守“微信蓝牙精简协议”的计步器之后,我们需要登录微信的公众平台(可以使用测试帐号),注册一个产品类别,并授权该设备,之后就可以在微信运动界面使用这个设备了。

4.1 登录“微信公众平台接口测试帐号”

打开下面链接:

http://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=sandbox/login

点击登录按钮,用自己微信的扫一扫登录,登录后的界面如下:

wx-iot-登录界面

注意图中红色涂抹的三个信息(要记录下来,后面有用):

微信号:
appID:
appsecret:

4.2 开启设备功能接口

将上面的登录界面往下拉,找到“功能服务”,“设备功能”,点击“开启”,开启设备功能接口,如下图:

wx-iot-设备功能接口

4.3 添加产品

设备功能接口开启后,会出现“设置”按钮,点击进入下一个界面,进行设备功能管理。在该界面,点击“添加产品”按钮,为我们的计步器设备添加一个产品类别:

wx-iot-添加产品

按照提示填入相关的信息(需要注意红色圈出的地方):

wx-iot-基础资料登记1

wx-iot-基础资料登记2

点击“下一步”进入“产品能力登记”界面:

wx-iot-产品能力登记

最后,点击“添加”按钮,将产品添加进去。添加成功后,进入如下的界面(注意其中红色涂抹的那一串数字,是产品的ID,记下来,后面有用):

wx-iot-product_id

4.4 授权设备

4.4.1 获取access_token

根据上面得到的appID和appsecret,在浏览器里面输入如下指令,获取访问微信公众平台的token(令牌):

https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=xxxxxxxxxx&secret=xxxxxxxx

注意红色部分要修改为实际内容(具体可参考4.1章节获取的信息)。

浏览器会返回如下内容:

{"access_token":"xxxxxxxxxxxxxxxxxxx","expires_in":7200}

有两个字段,access_token(记录下来,后面有用)和有效时间(7200小时,很长了)。

4.4.2 为设备生成一个唯一ID(device_id)及二维码(通过微信扫描即可添加设备)

在浏览器输入如下指令:

https://api.weixin.qq.com/device/getqrcode?access_token=xxxxxxxxxxxx&product_id=xxxxx

其中access_token为4.4.1中获取的,product_id为4.3中获取的。

浏览器的返回如下:

{"base_resp":{"errcode":0,"errmsg":"ok"},"deviceid":"xxxxxx","qrticket":"http:\/\/we.qq.com\/d\/AQArGYez06UDOcqKNe1jqWeeLhiF7fIKebEP5hiT"}

deviceid为新生成的唯一ID,记录下来,后面有用。

qrticket是设备的二维码,随便找一个二维码生成的网站(例如http://cli.im/),就可得到图片二维码,如下(注意需要将浏览器返回的转义字符改回正常):

wx-iot-二维码获取

4.4.3 设备鉴权

这一步要借助微信公众平台的debug页面了,单纯的浏览器无法搞定。打开如下的debug地址:

http://mp.weixin.qq.com/debug/

找到如下界面:

wx-iot-设备授权

body输入的内容如下:

{
    "device_num":"1",
    "device_list":[ 
     {
        "id":" xxxxxxxx",
        "mac":"5CF3706ABA27", 
        "connect_protocol":"3",
        "auth_key":"",
        "close_strategy":"1", 
        "conn_strategy":"5",
        "crypt_method":"0",
        "auth_ver":"0",
        "manu_mac_pos":"-1",
        "ser_mac_pos":"-2",
        "ble_simple_protocol": "1"
    }
    ],
    "op_type":"0",
    "product_id": "xxxxx"
}

注意上面红色的字段,id是4.4.2中获得的deviceid,mac是蓝牙设备的物理地址,product_id是4.3中获得产品ID的。

点击“检查问题”,看到如下的成功信息,说明授权成功了:

wx-iot-授权成功

5. 使用手机微信绑定设备

使用微信扫一扫,扫描刚才获得的二维码,点击“绑定设备”,即可添加设备,如下:

wx-扫一扫绑定设备

绑定成功后,设备显示未连接,如下:

wx-绑定设备未连接

接下来要连接设备。对iOS来说,在设置界面无法主动连接BLE设备,必须有应用程序自行连接,这里以微信运动为例,搜索并连接刚才授权的那个设备,即可看到计步数据的更新。步骤如下面图片(不再解释了,大家可以自己试试):

wx-微信运动-设置

wx-微信运动-添加数据来源

wx-微信运动-搜索并添加设备

6. 参考文档

[1] 微信蓝牙精简协议,http://iot.weixin.qq.com/wiki/new/index.html?page=4-3

[2] https://github.com/paypal/gatt

原创文章,转发请注明出处。蜗窝科技,www.wowotech.net

蓝牙协议分析(10)_BLE安全机制之LE Encryption

$
0
0

1. 前言

前面文章介绍了两种BLE的安全机制:白名单[4]和LL privacy[3]。说实话,在这危机四伏的年代,这两种“捂着脸讲话(其它人不知道是谁在讲话,因而不能插话、不能假传圣旨,但讲话的内容却听得一清二楚)”的方法,实在是小儿科。对于物联网的应用场景来说,要做到安全,就必须对传输的数据进行加密,这就是LE Encryption要完成的事情(当然,只针对面向连接的数据),具体请参考本文的介绍。

2. 基本概念

从字面理解,Encryption是一个名词,意思是“加密术”,因此LE Encryption就是“BLE所使用的加密技术”的意思。了解加密概念的同学应该都知道,通信过程中的加密无非就是如下简单的流程:

数据发送方在需要发送数据的时候,按照一定的加密算法,将数据加密;

数据接收方在接收到数据的时候,按照等同的解密算法,将数据解密。

因此,对LE Encryption来说,需要考虑的事情无非就两条:

1)加密/解密的事情,需要在协议的哪个层次去做?

2)使用什么样的加密/解密算法?

对问题1来说,很好回答:无论是从安全的角度,还是从通信效率的角度,都应该由链路层(LL,Link Layer[1])在发送/接收数据的时候,完成加密/解密动作(具体可参考)。而问题2呢,到底要使用什么的算法,这是蓝牙标准化组织的事情,我们在本文只需要了解最终的结论即可(具体可参考)。

3. packet的加密/解密过程

LE加密/解密的过程如下面图片1所示:

LE加密解密

图片1 LE加密/解密过程

Master/Slave的LE Host会保存一个LTK(Long Term Key,至少128bits),对BLE用户(或者应用)来说,这个Key是所有加密/解密动作源头;

每当为某个LE连接启动加密传输的时候,Master和Slave的LL会协商生成一个128bits的随机数SKD(Session Key Diversifier,128bits),并以它为输入,以LTK为key,通过Encryption Engine加密生成SessionKey;

每当有明文数据包需要发送的时候,需要对明文进行加密。加密的过程,是以明文数据包为输入,以SessionKey为Key,同样通过Encryption Engine加密生成密文数据包;

同样,每当收到密文数据包的时候,需要对密文解密。解密的过程,是以密文数据包为输入,以SessionKey为Key,同样通过Encryption Engine解密生成明文数据包。

理解了加密/解密的过程之后,问题随之而来:

1)LTK是怎么来的?

2)SKD是个什么东西?怎么来的?

3)Encryption Engine又什么东西呢?

对于问题1,需要由SMP解答(也就是我们常说的配对过程),具体可参考后续的文章。问题3比较单纯,就是一个由Bluetooth specifiction所规定的加密算法,后面会单独写一篇文章介绍。而问题2,则涉及到LE Encryption的操作流程,具体可参考后面第4章的介绍。

4. Encryption Procedure

LE Encryption的过程主要由Link Layer控制(具体可参考“BLUETOOTH SPECIFICATION Version 4.2 [Vol 6, Part B] 5.1.3 Encryption Procedure”):当连接建立之后,Link Layer可以应Host的请求,使能对数据包的Encryption操作,过程如下(具体可参考“BLUETOOTH SPECIFICATION Version 4.2 [Vol 6, Part D]  6.6 START ENCRYPTION”):

LE encryption

图片2 Start Encryption

1)Host A发送LE Start Encryption HCI命令,请求Link Layer启动加密。该命令的格式如下:

Command OCF Command parameters Return Parameters
HCI_LE_Start_Encryption 0x0019 Connection_Handle
Random_Number
Encrypted_Diversifier
Long_Term_Key
 

Connection_Handle,连接句柄;
Random_Number和Encrypted_Diversifier分别简称为Rand和EDIV(Rand是一个64bits的随机数,EDIV是一个16bits的Diversifier),它们在LE Legacy Pairing的过程中,用于在多个LTK标识某一个具体的LTK。而在新的LE Secure Connections Pairing过程中,则不再使用(赋值为0即可)。关于LE的配对过程,可参考后面SMP的分析文章,这里不再详细描述;
Long_Term_Key,保存在Host段的加密key。

2)LL A收到Host的加密请求之后,会向LL B发送LL_ENC_REQ PDU以请求加密,该PDU的格式为:

Rand (8 octets) EDIV (2 octets) SKDm (8 octets) IVm (4 octets)

Rand和EDIV就是上面的Random_Number和Encrypted_Diversifier;
SKDm(session key diversifier ),是一个64bits的随机数,用于和SKDs一起,生成本次加密的SessionKey;
IVm(initialization vector ),一个32bits的随机数,和IVs一起组成64bits的IV,后面Encryption Engine会使用。

3)LL B收到LL_ENC_REQ PDU之后,会向Host B发送LE Long Term Key Request HCI Event,该Event的格式为:

Event Event code Event Parameters
LE Long Term Key Request 0x3E Subevent_Code
Connection_Handle
Random_Number
Encryption_Diversifier

Subevent_Code为0x05;
Connection_Handle,连接句柄;
Random_Number和Encrypted_Diversifier就是LL_ENC_REQ PDU中的Rand和EDIV,最初是由Host A通过LE Start Encryption命令发送过来的。

4)如果Host B能提供LTK,则通过LE Long Term Key Request Reply HCI命令,将LTK提供给LL B,该命令的格式为:

Command OCF Command parameters Return Parameters
HCI_LE_Long_Term_Key_
Request_Reply
0x001A Connection_Handle
Long_Term_Key
status
Connection_Handle

5)LL B收到LTK之后,会向LL A回应一个LL_ENC_ RSP PDU,该PDU的格式为:

SKDs (8 octets) IVs (4 octets)

SKDs和LL A的SDKm共同组成128bits的SKD;
IVs和LL A的IVm共同组成64bits的IV。

6)LL A收到LL_ENC_ RSP PDU之后,可以向LL B发送LL_START_ENC_REQ PDU,开启Encryption,LL B则回应LL_START_ENC_RSP PDU,这两个PDU均不携带任何的参数。

加密start之后,双方就可以安全的通信了。当然,LE encryption还提供了其它诸如暂停加密(LL_PAUSE_ENC_REQ/LL_PAUSE_ENC_RSP)、重启加密等过程,比较简单,这里就不详细介绍了,具体可参考BLE Spec[2]中的相关描述。

5. 参考文档

[1] 蓝牙协议分析(3)_蓝牙低功耗(BLE)协议栈介绍

[2] Core_v4.2.pdf

[3] 蓝牙协议分析(9)_BLE安全机制之LL Privacy

[4] 蓝牙协议分析(8)_BLE安全机制之白名单

 

原创文章,转发请注明出处。蜗窝科技,www.wowotech.net

蓝牙协议分析(11)_BLE安全机制之SM

$
0
0

注1:此SM是Security Manager的缩写,非彼SM,大家不要理解歪了!

书接上文,我们在“蓝牙协议分析(10)_BLE安全机制之LE Encryption”中介绍了BLE安全机制中的终极武器----数据加密。不过使用这把武器有个前提,那就是双方要共同拥有一个加密key(LTK,Long Term Key)。这个key至关重要,怎么生成、怎么由通信的双方共享,关系到加密的成败。因此蓝牙协议定义了一系列的复杂机制,用于处理和加密key有关的操作,这就是SM(Security Manager)。

另外,在加密链路建立之后,通信的双方可以在该链路上共享其它的key(例如在“蓝牙协议分析(9)_BLE安全机制之LL Privacy”中提到的IRK),SM也顺便定义了相应的规范。

阅读全文>>

USB-C(USB Type-C)规范的简单介绍和分析

$
0
0

从1996年1月USB1.0正式发布至今(2017年9月 USB3.2发布),USB已经走过了21个年头。在这21年的时间了,USB标准化组织(USB Implementers Forum,USB-IF)折腾出来了各式各样、五花八门的接口形态:Type A、Type A SuperSpeed、Type B、Type B SuperSpeed、Mini-A、Mini-B、Micro-A、Micro-B、Micro-B SuperSpeed、Type C等等。

另外,USB接口主要由插座(Receptacle)、插头(Plug)和线缆(Cable)三部分组成,再叠加上这些奇奇怪怪的规范,灾难就发生了:

A产品喜欢用Type A的插座,B产品偏偏喜欢Type B,连接它们的线缆就悲剧了,只能变成A-to-B的了。以此类推,A-to-A、B-to-B、A-to-MicroA、等等,于是我们的抽屉就挤满了各种不明用途的USB线……

好吧,吐槽时间结束,因为本文的主角不是过去的那些奇奇怪怪的接口,而是最新的、红到发紫的USB-C(也称作USB Type C)规范。提起typec,它还真和它的A、B前辈们不太一样:

因为它有自己独立的、自行演化的规范文件----USB Type-C Specification(2014年发8月布1.0版本,2017年7月发布1.3版本)。而前辈们就没有这样的待遇了,它们都依附于具体的USB规范(USB 1.0、USB 1.1、USB 2.0、等等)。

为什么会这样的呢?当然是因为它有独特之处了,具体请参考本文后续的描述。

阅读全文>>

Atomic operation in aarch64

$
0
0

在Linux内核中看到下面这句话:

At least on ARM, pgprot_noncached causes the
memory to be mapped strongly ordered, and atomic operations on strongly ordered
memory are implementation defined, and won't work on many ARMs such as omaps.

所以, 为什么对用户non-cached的内存,部分平台不支持原子操作?

阅读全文>>

CPU 多核指令 —— WFE 原理

$
0
0
今天我想分享一个跟多核锁原理相关的东西,由于我搞 arm 居多,所以目前只研究了 arm 架构下的 WFE 指令,分享出来,如果有表述不精准或者错误的地方还请大家指出,非常感谢。研究这个原因也是只是想搞清楚所以然和来龙去脉,以后写代码可以更游刃有余。 阅读全文>>
Viewing all 48 articles
Browse latest View live


<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>