如果您使用数字技术,则迟早需要逻辑分析仪。可用的障碍之一是DreamSourceLab的DSLogic逻辑分析仪。至少在网站上不止一次提到他:一,二和三。
它的功能是开源代码以及负责解码信号的开源sigrok库。连同大量令人印象深刻的现有信号解码器列表,该库提供了用于编写自己的API的API。这就是我们要做的。
演示台
, . TTP229-BSF. 8- 16- . Arduino, DSLogic.
sigrok中的每个解码器都是用Python 3编写的独立软件包,并在解码器文件夹下具有自己的目录。与任何Python包一样,解码器包含__init__.py,根据sigrok接受的命名,该文件包含实现本身的pd.py文件。
__init__.py中的代码是标准代码,包括描述协议的文档字符串和解码器导入(d28dee9):
'''
Protocol description.
'''
from .pd import Decoder
pd.py文件包含解码器实现(d28dee9):
class Decoder(srd.Decoder):
api_version = 3
id = 'empty'
name = 'empty'
longname = 'empty decoder'
desc = 'Empty decoder that can be loaded by sigrok.'
license = 'mit'
inputs = ['logic']
outputs = ['empty']
tags = ['Embedded/industrial']
channels = (
{'id': 'scl', 'name': 'SCL', 'desc': 'Clock'},
{'id': 'sdo', 'name': 'SDO', 'desc': 'Data'},
)
def start(self):
pass
def reset(self):
pass
def decode(self):
pass
这是一个最小的实现,可以由库加载,但不解码任何内容。让我们看一下所需的属性:
- api_version – Protocol decoder API, . libsigrokdecode 3- Protocol decoder API. .
- id – , . , .
- name, longname, desc – , , . .
- inputs, outputs – . 'logic' . . , , SPI. SPI . , SPI . 'spi'.
- license, tag – . DSView 1.1.1 + libsigrokdecode tags - .
- 通道 -解码器使用的信号线列表。输入数据格式为逻辑的解码器需要此属性。
和所需的方法:
- start() -解码开始之前调用的方法。在此方法中,应为当前解码会话进行设置。
- reset() -解码停止时调用的方法。应该使解码器返回其初始状态。
- define() -调用信号解码方法。
处理完解码器的最少实现后,您就可以开始解码实际信号了。
全功能解码器
首先,考虑数据信号的时序图。TTP229-BSF具有几种工作模式,我给出了稍后将要使用的模式的时序图。有关微电路所有工作模式的更多详细信息,请参见其文档。
首先,有必要描述解码器将使用的一组强制线。在这种情况下,有两条时钟线(SCL)和数据线(SDO)。
class Decoder(srd.Decoder):
...
inputs = ['logic']
channels = (
{'id': 'scl', 'name': 'SCL', 'desc': 'Clock'},
{'id': 'sdo', 'name': 'SDO', 'desc': 'Data'},
)
当微电路检测到按钮按下时,它将在SDO线上设置数据有效(DV)信号,接收器应根据此信号开始读取数据。让我们找到并解码该信号。
sigrok , . . , , . Protocol decoder API . . wait(). . , self.samplenum .
, , – , :
- 'l'-低电平,逻辑0;
- 'h'-高级,逻辑1;
- 'r'-信号上升,从低电平过渡到高电平;
- 'f'-信号衰减,从高到低状态的转变;
- 'e'-任意信号变化,上升或下降;
- 's'-稳定状态,0或1。
因此,为了找到DV信号的开始,需要一个条件来描述SCL线为高电平,并且数据线(SDO)上的信号下降。我们使用条件调用wait()函数并保存样本编号:
self.wait({0: 'h', 1: 'f'})
self.dv_block_ss = self.samplenum
为了找到DV信号的末端,有必要设置一个条件,使SCL线保持高电平,而数据线变为高电平:
self.wait({0: 'h', 1: 'r'})
完成对wait()函数的最后一次调用后,将知道DV信号的开始和结束的样本数。现在该为它创建注释了。为此,将注释添加到解码器并将其分组在一起(annotation_rows):
class Decoder(srd.Decoder):
...
annotations = (
('dv', 'Data valid'),
)
annotation_rows = (
('fields', 'Fields', (0,)),
)
其中0是属于该组的self.annotations元组中注释的索引。您还需要注册注释的输出:
def start(self):
self.out_ann = self.register(srd.OUTPUT_ANN)
现在,您可以放置DV信号的注释了。这是通过调用put()函数(f613b83)完成的:
self.put(self.dv_block_ss, self.samplenum,
self.out_ann, [0, ['Data valid', 'DV']])
函数参数:注释开始样本编号(self.dv_block_ss),注释结束样本编号(self.samplenum),注释输出标识符(self.out_ann)和注释数据。数据以注释索引(0)的列表和字符串的嵌套列表(从最长到最短)的形式显示,以显示在说明中。如果指定了多行,则界面可以独立选择显示的行,例如,取决于所使用的比例:
类似地,我们为DV信号结束与从微控制器开始读取数据之间的延迟Tw添加注释。接下来,您可以开始解码按钮按下数据。
根据所选择的模式,TTP229-BSF可以使用8个或16个触摸按钮。在这种情况下,发送的数据不包含有关微电路工作模式的信息。因此,对于解码器,值得添加一个选项来指定微电路的工作模式。
class Decoder(srd.Decoder):
...
options = (
{'id': 'key_num', 'desc': 'Key number', 'default': 8,
'values': (8, 16)},
)
def start(self):
...
self.key_num = self.options['key_num']
选择解码器后,此选项可用于在用户界面中设置值。
从时序图中可以看到,当SCL变为有效(低)电平时,SDO线上的数据将暴露出来,而当信号返回至无源电平时将被保存。此时,微控制器和解码器都可以将数据集记录在SDL线上。SCL回到活动层的过渡可以视为下一次数据传输的开始。在这种情况下,解码功能将类似于(ca9a370):
def decode(self):
self.wait({0: 'h', 1: 'f'})
self.dv_block_ss = self.samplenum
self.wait({0: 'h', 1: 'r'})
self.put(self.dv_block_ss, self.samplenum,
self.out_ann, [0, ['Data valid', 'DV']])
self.tw_block_ss = self.samplenum
self.wait([{0: 'f', 1: 'h'}, {0: 'f', 1: 'f'}])
self.put(self.tw_block_ss, self.samplenum,
self.out_ann, [1, ['Tw', 'Tw']])
self.bt_block_ss = self.samplenum
for i in range(self.key_num):
(scl, sdo) = self.wait({0: 'r'})
sdo = 0 if sdo else 1
self.wait({0: 'f'})
self.put(self.bt_block_ss, self.samplenum,
self.out_ann, [2, ['Bit: %d' % sdo, '%d' % sdo]])
self.bt_block_ss = self.samplenum
但是这种放置注释的方法有一个缺点,即最后一位的注释将一直持续到微控制器读取下一个数据为止。
. . , SCL . , SCL 2 ., . 'skip', , , . , . metadata(). Hz.
def metadata(self, key, value):
if key == srd.SRD_CONF_SAMPLERATE:
self.timeout_samples_num = int(2 * (value / 1000.0))
然后,将使用以下形式的skip来编写解码功能中的条件,并附加检查以确保在读取有关所按下按钮的数据期间,微电路未返回其初始状态(6a0422d)。
def decode(self):
...
for i in range(self.key_num):
...
self.wait([{0: 'f'}, {'skip': self.timeout_samples_num}])
self.put(self.bt_block_ss, self.samplenum,
self.out_ann, [2, ['Bit: %d' % sdo, '%d' % sdo]])
if (self.matched & 0b10) and i != (self.key_num - 1):
break
现在,解码器可以处理完整的数据发送。如果除了有关各个位的信息之外,还添加了关于按下哪个按钮的注释,将非常方便。为此,添加更多注释的描述。由于按下按钮的注释涉及整个数据传输,并且与之前添加的注释相交,因此应将其放在单独的组中。让我们为她创建一组新的批注“关键消息”。(91c64e6)。
class Decoder(srd.Decoder):
...
annotations = (
('dv', 'Data valid'),
('tw', 'Tw'),
('bit', 'Bit'),
('key', 'Key press status'),
)
annotation_rows = (
('fields', 'Fields', (0, 1, 2)),
('keymsg', 'Key message', (3,)),
)
def decode(self):
...
keys_pressed = list()
for i in range(self.key_num):
...
else:
key_msg = \
'Key: %s' % (','.join(keys_pressed)) if keys_pressed else 'Key unpressed'
key_msg_short = \
'K: %s' % (','.join(keys_pressed)) if keys_pressed else 'KU'
self.put(self.dv_block_ss, self.samplenum,
self.out_ann, [3, [key_msg, key_msg_short]])
到目前为止,所有代码仅适用于第一条消息。您是否已经注意到解码器名称旁边的19%?这是在decode()函数退出之前已处理的样本的百分比。要处理所有样本,仍然需要在代码周围添加一个无限循环,以对单独的数据包(48f95fb)进行解码。
def decode(self):
...
while True:
self.wait({Pin.SCL: self.passive_signal, Pin.SDO: self.front_edge})
self.dv_block_ss = self.samplenum
...
因为在搜索下一个样本时,如果wait()函数遍历所有解码,解码将自动结束。作为此更改的结果,将按照KDPV中所示处理所有样本和所有数据传输。
最后的接触仍然是增加选择活动信号电平的能力,并且已经准备好用于TTP229-BSF的成熟解码器。最终版本的源代码也可以在GitHub上获得。