Enable EL6695 DC-Synchron mode (AssignActivate 0x320)

- DC selection must use the structured <Dc><Data AssignActivate/> XSD
  element; legacy DcData hex writes get normalized to zeros by TwinCAT
- TwinCAT converts it to DcData '2003...' (0x0320) on save: SYNC0/SYNC1
  cyclic + SYNC0 activate for the bridge
- Verified: clean activation, ticker OP, bSync=True, 90k cycles 0 errors,
  timing unchanged (jitter 7.3us mean)
- docs: pitfall #10 (DC selection method)
This commit is contained in:
Tony Cao 2026-08-09 15:32:56 +08:00
parent 3c4b6e6d54
commit aabfe31526
14 changed files with 137 additions and 0 deletions

BIN
deploy_800b_dc.log Normal file

Binary file not shown.

BIN
deploy_800b_dc2.log Normal file

Binary file not shown.

BIN
deploy_800b_elevated.log Normal file

Binary file not shown.

BIN
deploy_800b_regress.log Normal file

Binary file not shown.

BIN
deploy_800b_regress2.log Normal file

Binary file not shown.

BIN
deploy_800b_regress3.log Normal file

Binary file not shown.

View File

@ -276,6 +276,7 @@ blob = [27 (u16 LE)]
|---|---|---|---|
| 8 | 激活时 EL6695 SAFEOP 失败,AL 状态码 0x0003 | **激活与 J1900 ticker 会话并发**:relink 激活时 ticker 正在跑,桥两侧主站会话冲突 | 激活必须在 J1900 空闲时进行;失败后空载重新激活即恢复 |
| 9 | 数据通但 PLC bSync=False,每周期固定 16 字节失配 | 图案区 [16..799] 与 J1900 统计字段 [264..279] 重叠 | 图案区改为 [16..263]+[280..799](见 §8.3) |
| 10 | 手写 `<DcData>` 十六进制被 TwinCAT 归一化为全零 | DC 模式选择不接受 legacy hex 直写 | **用 XSD 结构化形式 `<Dc><Data AssignActivate="#x320"/></Dc>`**,TwinCAT 读取后自动生成正确 DcData(`2003...`,即 0x0320)并启用 DC-Synchron(2026-08-09 已验证) |
### 8.5 800B 实测性能

13
scripts/tc-ads-quick.ps1 Normal file
View File

@ -0,0 +1,13 @@
$ErrorActionPreference = 'Continue'
Add-Type -Path 'C:\Program Files (x86)\Beckhoff\TwinCAT\3.1\Components\Base\v170\TwinCAT.Ads.dll'
$c = New-Object TwinCAT.Ads.TcAdsClient
$c.Connect('169.254.176.217.1.1', 851)
$h = $c.CreateVariableHandle('GVL_Sync.nCycles')
$n1 = $c.ReadAny($h, [uint64])
Start-Sleep -Milliseconds 5000
$n2 = $c.ReadAny($h, [uint64])
$c.DeleteVariableHandle($h)
Write-Host ("nCycles rate = {0} Hz" -f [math]::Round(($n2 - $n1) / 5.0, 1))
$bs = $c.ReadAny($c.CreateVariableHandle('GVL_Sync.bSync'), [bool])
Write-Host "bSync = $bs"
$c.Dispose()

15
scripts/tc-ads-setrun.ps1 Normal file
View File

@ -0,0 +1,15 @@
$ErrorActionPreference = 'Continue'
Add-Type -Path 'C:\Program Files (x86)\Beckhoff\TwinCAT\3.1\Components\Base\v170\TwinCAT.Ads.dll'
$c = New-Object TwinCAT.Ads.TcAdsClient
$c.Connect('169.254.176.217.1.1', 10000)
Write-Host "before: $($c.ReadState().AdsState)"
try {
$c.WriteControl((New-Object TwinCAT.Ads.StateInfo([TwinCAT.Ads.AdsState]::Run, 0)))
Write-Host "WriteControl Run sent"
} catch { Write-Host "err: $_" }
$c.Dispose()
Start-Sleep 10
$c2 = New-Object TwinCAT.Ads.TcAdsClient
$c2.Connect('169.254.176.217.1.1', 10000)
Write-Host "after: $($c2.ReadState().AdsState)"
$c2.Dispose()

13
scripts/tc-ads-state.ps1 Normal file
View File

@ -0,0 +1,13 @@
$ErrorActionPreference = 'Continue'
Add-Type -Path 'C:\Program Files (x86)\Beckhoff\TwinCAT\3.1\Components\Base\v170\TwinCAT.Ads.dll'
foreach ($port in @(10000, 851)) {
try {
$c = New-Object TwinCAT.Ads.TcAdsClient
$c.Connect('169.254.176.217.1.1', $port)
$st = $c.ReadState()
Write-Host "port $port : AdsState=$($st.AdsState) DeviceState=$($st.DeviceState)"
$c.Dispose()
} catch {
Write-Host "port $port : ERR $($_.Exception.Message)"
}
}

View File

@ -0,0 +1,18 @@
#Requires -RunAsAdministrator
$ErrorActionPreference = 'Continue'
# Open project in visible XAE and leave it running for interactive inspection.
$dte = New-Object -ComObject TcXaeShell.DTE.17.0
$dte.MainWindow.Visible = $true
try { $dte.SuppressUI = $false } catch {}
$dte.Solution.Open('C:\Users\tonycao\work\twincat3-auto-cli\TwinCAT_EL6695_Primary_800B\TwinCATProject1.sln')
Start-Sleep 25
$sm = $null
for ($i = 0; $i -lt 20; $i++) {
try { $sm = $dte.Solution.Projects.Item(1).Object; if ($sm) { break } } catch {}
Start-Sleep 3
}
if (-not $sm) { Write-Host 'no sysmgr'; exit 1 }
try { $sm.SetTargetNetId('169.254.176.217.1.1'); Write-Host 'target set' } catch { Write-Host "target: $_" }
Start-Sleep 3
try { Write-Host "IsTwinCATStarted=$($sm.IsTwinCATStarted)" } catch {}
Write-Host 'XAE left open. Inspect: TIID -> 设备 1 (EtherCAT) -> 模块 3 (EK1100) -> 模块 10 (EL6695) -> IO Inputs / IO Outputs -> Online tab'

18
uia_dump.py Normal file
View File

@ -0,0 +1,18 @@
import sys, time
sys.stdout.reconfigure(encoding='utf-8', errors='replace')
from pywinauto import Application
app = Application(backend='uia').connect(process=11748, timeout=10)
wins = app.windows()
print('windows:', len(wins))
for w in wins:
try:
t = w.window_text()
if not t:
continue
print('---', t)
tabs = [x.window_text() for x in w.descendants(control_type='TabItem')]
if tabs:
print(' tabs:', tabs)
except Exception:
pass

15
uia_find_dc.py Normal file
View File

@ -0,0 +1,15 @@
import sys, time
sys.stdout.reconfigure(encoding='utf-8', errors='replace')
from pywinauto import Application
app = Application(backend='uia').connect(process=int(sys.argv[1]), timeout=10)
win = app.top_window()
# look for DC-related text and combo boxes anywhere
texts = win.descendants(control_type='Text')
interesting = [t.window_text() for t in texts if t.window_text() and any(k in t.window_text() for k in ['FreeRun', 'DC', 'Synchron', 'EtherCAT', 'Sync'])]
print('interesting texts:', interesting[:40])
combos = win.descendants(control_type='ComboBox')
print('combos:', [c.window_text() for c in combos])
listitems = win.descendants(control_type='ListItem')
li = [l.window_text() for l in listitems if l.window_text()]
print('listitems:', li[:30])

44
uia_open_el6695.py Normal file
View File

@ -0,0 +1,44 @@
import sys, time
sys.stdout.reconfigure(encoding='utf-8', errors='replace')
from pywinauto import Application
from pywinauto.mouse import click, double_click
app = Application(backend='uia').connect(process=int(sys.argv[1]), timeout=10)
win = app.top_window()
tree = win.descendants(control_type='Tree')[0]
def expand_children(item):
try:
item.expand(); time.sleep(0.4)
except Exception:
pass
return list(item.children())
nodes = []
for root in tree.children():
nodes.extend(expand_children(root))
for name in ['TwinCATProject1', 'I/O', '设备', '设备 1 (EtherCAT)', '模块 3 (EK1100)']:
nxt = None
for n in nodes:
try:
if n.window_text() == name:
nxt = n
break
except Exception:
pass
if nxt is None:
print('missing:', name); sys.exit(1)
nodes = expand_children(nxt)
target = None
for n in nodes:
if n.window_text() == '模块 10 (EL6695)':
target = n
break
if not target:
print('EL6695 not found'); sys.exit(1)
r = target.rectangle()
double_click(coords=(int((r.left + r.right) / 2), int((r.top + r.bottom) / 2)))
time.sleep(4)
win.set_focus()
tabs = [t.window_text() for t in win.descendants(control_type='TabItem')]
print('tabs:', tabs)