Post Go back to editing

MAX14819 EstCom wake-up retries firing way faster than the datasheet says (~2ms instead of 30ms) — stuck after a lot of testing

Thread Summary

The user encountered issues with the MAX14819 (RevID 0x0A) failing to establish communication with an ifm DTI421 sensor over SPI. The solution involved correctly setting the message checksum octet in both transmit and receive configurations, and ensuring the CQ driver was in receive mode before enabling the framer. With these fixes, communication was established, and the Direct Parameter Page was read successfully.
AI Generated Content
Category: Hardware
Product Number: MAX14819

Hey,

We've been chasing a weird one with the MAX14819 (non-A, RevID reads 0x0A) and could use a second pair of eyes from your side.

Quick setup: STM32F413 talking to the chip over SPI, 14.7456MHz crystal (confirmed running — ExtClkMis reads clear), CQ current limit maxed out. The device on the other end is an ifm DTI421 (real IO-Link 1.1, COM2/38.4kBaud) — and we know it's not the sensor's fault, because we plugged the exact same physical unit straight into an ifm AL1060 master and it established communication with no issues at all. So the device is good, and we're stuck on why our master won't talk to it.

What we're seeing: We trigger EstCom and scope the CQ line. The wake-up pulse itself looks textbook — we measured it with cursors and got 80.09µs, 81.02µs, and 80.98µs on three separate pulses, basically dead on the datasheet's 75-85µs spec. So the pulse shape/timing is clearly right.

The problem is what happens around it. The datasheet says a failed attempt should retry after 30ms, up to 3 times. What we actually see is three pulses fired back-to-back, only 1.5-2.6ms apart, and the whole thing (from writing EstCom to it clearing with ComRt=00, i.e. "no device") wraps up in about 20-30ms total, every single time. That's not even long enough to fit ONE 30ms gap, let alone the two you'd need for 3 real retry attempts — so whatever's happening internally, it's not doing the retry sequence the datasheet describes.

A few scope details if it's useful:

  • At 200µs/div we can clearly see the 3 individual pulses, each with sharp edges, and they measure ~80µs wide each (see cursor measurements above).
  • At wider timebases (1ms/div, 500µs/div) the 3 pulses show up as one tight cluster right at the start of the capture, then dead flat for the rest of a 5-10ms window.
  • We also tried the internal 5mA sink (SourceSink=0) vs. source/pull-up (SourceSink=1) config on CQCfg — with the sink config (which matches what a couple of open-source MAX14819 drivers we found use), the 3 pulses spread out a bit more (~1.6-2.6ms apart instead of tightly bunched), and each one grew a "double-dip" shape that we think is just the sink current pulling the line down during the high-Z window — but the total attempt still wraps up in the same ~20-30ms and still reports no device.

Happy to send the actual scope screenshots (PicoScope captures) if that'd help — we've got clean shots of the individual 80µs pulses with cursor measurements, the 3-pulse cluster on a 1-2ms timebase, and the wider "spread out" version after the sink-config change.

What we've already ruled out, since none of it changed the behavior at all:

  • DeviceDly (tried POR default and the datasheet's "IO-Link compliance" values)
  • CyclTmr (tried default 0x00 and a value specifically set to target 30ms per the Table 2 formula)
  • CQCfg source vs. sink (both directions, values matching working reference drivers)
  • A couple ms of settle time inserted after ChanStat.Rst before configuring the rest
  • Doing our own software-level retries with generous 50ms+ gaps between full attempts
  • Cable/reflection weirdness — not physically possible, our wiring is centimeters long, a 2ms echo would need something like 500,000 meters of cable
  • Crystal not running — nope, confirmed fine

Questions we're hoping you can help with:

  1. Is that ~30ms retry delay hard-coded in silicon, or is it actually tied to some register we're missing (CyclTmr, DeviceDly, something else)? We're seeing more like 1.5-2.6ms.
  2. Any known erratum for this RevID (0x0A, MAX14819 non-A) around EstCom timing?
  3. Is there some register write not covered in the "Establish-Communication Sequencer" section that's actually needed to get the real 3-attempt/30ms-spaced behavior?
  4. Does CQCfg's source/sink setting have any documented (or undocumented) effect on EstCom's internal timing? We saw the pulse spacing shift a bit when we changed it, which seems like it shouldn't happen per the datasheet.
  5. Any way to peek at more detailed internal EstCom state (which COM rate it's trying, which attempt number) to help us debug further?
  6. Since the same device works fine on a different, independent master — is there anything about a specific device's physical-layer behavior that could trip up the MAX14819's autonomous EstCom sequencer specifically, versus a master that drives wake-up manually in firmware?

Thanks for any pointers — happy to share our full register config, more scope captures, or a logic analyzer trace if that'd speed things up.

Thread Notes

Parents
  • Hello,

    I would be happy to help you debug this and I am looking into it now. If possible, please send your scope shots, as I believe they will be very helpful. Let me also start by asking a couple of questions:

    (1) Is your microcontroller accessing the SPI interface after the ESTCOM sequence has been activated?  If so, what is it reading/writing?

    (2) From your description, it sounds like a first wake-up pulse happens correctly, but then another happens very shortly after that, is that correct? So there is no COM3, COM2, COM1 messaging sent - just a train of wake-up pulses?

    (3) It looks like you have enabled the driver before starting the EstCom sequence (CQCfg = 0x14), could you please try disabling the driver by setting the DrvDis_ bit (CQCfg_ = 0x16) before setting the EstCom bit? The driver should be disabled before a wake-up sequence is initiated.

    (4) From your register dump, it looks like the Interrupt registers read as 0x00 - is this before the EstCom attempt or after it?  If before, what is the Interrupt register read after the EstCom sequence completes?

    Thank you,

    Shasta

  • on Sep 9, 2026 11:02 AM in reply to ShastaThomas Contains AI Generated Content
    0

    Hi Shasta,

    Thanks for digging into this — really appreciate it. 

    (1) SPI access during EstCom: Yes — my wait loop polls the chip roughly every 10ms while EstCom is active, reading both Interrupt (0x02) and CQCtrl (0x06/07) on each iteration (I also listen on the IRQ pin, but fall back to this timed poll regardless). So I am touching SPI, including a clear-on-read register (Interrupt), during the active sequence. Happy to change this if you think it could be interfering — e.g. only reading once IRQ actually fires, rather than polling on a timer in parallel.

    (2) Confirmed — that matches exactly what I'm seeing. A wake-up pulse, then what looks like a train of additional wake-up-shaped pulses (all measuring ~80µs individually, matching the datasheet's tWU spec), not differently-sized COM3/COM2/COM1 test messages.

    (3) Tried it, and it changed something real. I set CQCfg = 0x16 (DrvDis_=1) before triggering EstCom, same as you suggested. Before this change, the whole EstCom sequence (from setting the bit to it self-clearing with ComRt=00) consistently took only ~20-30ms — too fast to fit even one 30ms retry gap. After the change, that timing shifted dramatically: I'm now seeing pulses spaced roughly 225 ms apart (measured directly on scope, three pulses in a single capture). So disabling the driver first clearly does affect the chip's internal retry timing — it's just landed on a much longer interval than the documented ~30-50ms T_DWU, rather than matching it. Does ~225ms mean anything specific on your end? It doesn't line up with anything I've found in the datasheet myself (closest is T_DSIO, 60-300ms, but that's described as device-side SIO fallback timing, not master retry spacing).

    (4) Clarified with better timing: the 0x00 in my earlier dump was read well after EstCom had already completed and after my own polling loop had already read (and cleared) it. I've since added logging that captures Interrupt at the exact moment EstCom self-clears, before anything else touches it: Interrupt = 0x40, i.e. just WURQInt set, no TxError/RxError/StatusInt alongside it. So a clean completion signal, just for a failed attempt.

    Still no device response in the end, but the driver-disable change clearly touched something real in the chip's timing behavior, which feels like a meaningful step forward. Let me know if the ~225ms number rings a bell, or if there's another register/sequencing detail worth checking next.

    Thanks again,
    Søren

  • Hi Shasta,

    Thanks for the correction — that makes a lot of sense, and explains why DrvDis_ didn't get me anywhere (I'd misread your first message and disabled the whole driver, which as it turns out actually broke the wake-up pulse's timing rather than helping). I found the actual TxEn_ bit you meant in IOStCfg_ (with TXTXENDis_ in Clock_ needed to give SPI authority over it, since I don't have an external TXEN pin wired) — cross-checked against two independent open-source MAX14819 drivers, both of which clear TxEn_/Tx_ right before triggering a wake-up pulse, exactly as you described. I've implemented that now and confirmed via register readback that it's taking effect (IOStCfg_ reads 0x00 as expected). Unfortunately it didn't change the outcome — still no device detected — but I wanted to implement it properly regardless since it's clearly correct per the datasheet.

    To your three questions:

    (1) L+ power: L+ isn't wired to the MAX14819's own L+ sense pin on our board (that's why ChanStat_ always shows UVL+ set — a known/expected artifact on our schematic), but the DTI421 does get its 24V from elsewhere on our board, and I measured directly at the sensor's connector to confirm a steady ~22-24V present. Reading between the lines of your question, I suspect you may be wondering whether the device could be timing out waiting for a wake-up attempt and settling into some other state if too much time passes after power-up. I tested that directly: our normal flow calls EstCom_ from a manually-triggered shell command, which could run anywhere from seconds to minutes after power-up. So I added a temporary boot-time test that triggers EstCom_ automatically right after power-on instead, and I tried it at three different delays after L+ is applied — roughly 200ms (as fast as our boot allows), 300ms, and 1000ms, bracketing and exceeding your spec's T_DSIO_ figure (60-300ms). All three gave the identical "no device detected" result, so I don't think power-on timing explains this — the device doesn't respond whether we try almost immediately or after a full second's delay.

    (2) Scope shot of CQ after EstCom_: Yes, still seeing this behavior. Attached is a fresh capture (with the TxEn_ fix applied) — three wake-up pulses, but now spaced ~5.5-6ms apart rather than the ~1-2ms I originally described (so the TxEn_ change did shift the internal retry spacing again, similar to how DrvDis_ did before — just without breaking the pulse shape this time). Each pulse still measures a clean 80.32µs (zoomed capture also attached).

    (3) Single WuPuls_ (manual, WuPulseEnA=1): Attached. I see a single clean ~80µs pulse, and then — since I'm manually triggering a test message afterward in firmware — a burst of activity a bit later that's our attempt at sending the test message. I don't think that gap is representative of anything meaningful about the chip itself though, since it's bottlenecked by our own SPI/firmware latency (~650µs+ even after some optimization) rather than anything hardware-timed.

    At this point I've also independently ruled out the cable, the connector, and the sensor itself (swapped in the exact cable+DTI421 that works fine with a different, completely generic Class A master, straight onto our board — still nothing), and confirmed via a direct comparison against that working link that our wake-up pulse's shape and even the sensor's power delivery all look correct. Genuinely running short on ideas for what's actually different about our setup — really appreciate you continuing to work through this with me.

    Thanks, Søren

  • Hi Soren,

    Thank you for this.  I just want to double check on your procedure - can you please confirm that you do these steps in the order listed below:

    1. Verify the clock (verify that ExtClkMis is 0)

    2. Configure CQ driver into receive mode (for example, TxEn_ = 0, Tx_ = 0)

    3. Enable the framer (FramerEn_ = 1)

    4. Set EstCom = 1

    Thank you,

    Shasta

  • Hi Shasta,

    Thanks for spelling out the exact order — that turned out to be a real catch. Checking our code against your four steps, I found we had steps 2 and 3 backwards: we were enabling the framer (FramerEn_=1) before putting the driver into receive mode (TxEn_=0/Tx_=0), not after. I've fixed that so the order now matches yours exactly: verify clock → TxEn_=0/Tx_=0 → FramerEn_=1 → EstCom_=1.

    Unfortunately it didn't change the outcome — still no device detected, same clean signature as always (Interrupt_ reads 0x40 at completion, no fault bits). Register dump attached below for reference, confirming the fix is actually taking effect: IOStCfg_ reads 0x80 (TxEn_=0, Tx_=0), ChanStat_ shows FramerEn_=1, CQErr_=0x00 clean on both channels.

    -- Global --
    RevID=0x0a  Clock=0x41 (ExtClkMis=0 XtalEn=1 TXTXENDis=1)  DrvrCurrLim=0xc0
    Status=0x00  Interrupt=0x00  InterruptEn=0x40
    -- Channel 0 --
    CQCtrl=0x00 (EstCom=0 WuPuls=0 CQSend=0 ComRt=0x0)
    ChanStat=0x42 (FramerEn=1 CQFault=0 UVL+=1 L+CLim=0)
    CQCfg=0x14  MsgCtrl=0x27  DeviceDly=0x22  CyclTmr=0x00
    IOStCfg=0x80 (TxEn=0 Tx=0 CQLevel=0)
    CQErr=0x00  RxFIFOLvl=0x00  TrigAssgn=0x00
    -- Channel 1 --
    CQCtrl=0x00 (EstCom=0 WuPuls=0 CQSend=0 ComRt=0x0)
    ChanStat=0x42 (FramerEn=1 CQFault=0 UVL+=1 L+CLim=0)
    CQCfg=0x14  MsgCtrl=0x27  DeviceDly=0x22  CyclTmr=0x00
    IOStCfg=0x80 (TxEn=0 Tx=0 CQLevel=0)
    CQErr=0x00  RxFIFOLvl=0x00  TrigAssgn=0x00
    

    Since I had it fresh, I also re-ran my earlier power-on-timing test (triggering EstCom_ automatically at boot instead of via our normal manual command) with the corrected ordering in place, just in case the two interacted — same result, no device detected whether EstCom_ fires almost immediately at boot or after a deliberate delay.

    At this point I've gone through: pulse width/shape, CQ polarity, retry timing, driver register config (matches two independent reference drivers), the TxEn_/DrvDis_ distinction you clarified, power-on timing, and now operation ordering — all confirmed correct or ruled out, and the device still never responds. Cable, connector, and sensor are also independently confirmed good via a direct swap test with a different master. I'm genuinely not sure what's left to check on our side at this point — is there anything else about the MAX14819's expected behavior here that might explain a device just not responding despite all of this checking out?

    Thanks again for staying with this one, really appreciate it.

    Best, Søren

  • Hi Soren,

    Thank you for being so thorough.  Hmmm ... I am perplexed. Let me spend a day or so talking to some people who might have more insight, and I will get back to you as soon as I can.

    Thank you,

    Shasta

  • Hi Soren,

    I put max14819A EV kit on the bench today and tried a few things. I am able to get my device to establish communication using the sequence that I described above.

    Going through your setup in more detail, though, I see that you appear to have set the CQInv bit in the MsgCtrl register (CQInv = 1). If possible, could you please try clearing that bit and trying the EstCom sequence again?

    Thank you,

    Shasta

  • Hi Shasta,

    Great news — clearing InvCQ_ did it! Combined with the TxEn_/FramerEn_ ordering fix from your last message, EstCom_ now succeeds reliably: Interrupt_ reads 0x50 at completion, and ComRt_ correctly reports COM2 — which matches the DTI421's documented (and only supported) COM rate exactly. Really appreciate you taking the time to put your EV kit on the bench and spot that — that's been the actual root cause the whole time.

    There's a new, separate issue I've run into since, though. With EstCom_ succeeding, I tried reading the device's Direct Parameter Page (Vendor ID, Device ID, etc.) — a message I build and send myself via TxRxData_ (RxBytes/TxBytes/payload) + CQSend_, rather than anything EstCom_ handles internally. Every one of these gets "no response" — RxDataRdy_ never sets within a 100ms timeout, on every address I try.

    A few things I've already checked/ruled out:

    • Message framing: MC byte is RWDirection_(read)=1, ComChannel_=Page(0x20), plus the parameter address (e.g. 0x07 for VendorID1) — matches the standard IO-Link Direct Parameter Page addressing.
    • Timing: tried both a long gap (~1s, from establishing a second channel first) and a short gap (~140ms, sending the read immediately after EstCom_ completes) between establishing and the first read attempt — identical failure either way.
    • TSizeEn_ in MsgCtrl_: added it (matching your value from earlier), no change.
    • ComRt_ is confirmed preserved (read-modify-write) going into the CQSend_ trigger, so the message should be going out at the correct, just-detected COM2 rate.

    So somehow the chip's own internally-generated EstCom_ handshake succeeds, but anything we construct and send ourselves through the normal TxRxData_/CQSend_ path gets no response at all. Is there something different required for a firmware-triggered message send versus what EstCom_ handles automatically? Or anything else about the MsgCtrl_/CQCtrl_ state that might need to change between "communication established" and "ready to accept a normal M-sequence request"?

    Thanks again — feels like we're genuinely close now.

    Best, Søren

  • Hi Shasta,

    Any way I can share the PoC .c code with you, without sharing in public forum?

    If we find the issue, I am happy to share snippets of it publically.

    Best, Søren

  • Hi Shasta,

    Quick follow-up — I found the root cause myself in the meantime, and it's now working reliably.

    Two issues, both related to the message checksum octet:

    1. On transmit, the MAX14819's InsChks_ bit auto-calculates and inserts the checksum, but the SPI master still has to load a placeholder byte into that FIFO slot and count it in TxBytes (per Figure 10 — TxData-1 (MC) | TxData-2 (CKT)). I was only loading the MC byte and setting TxBytes to match, so no checksum octet was actually being transmitted at all.

    2. On receive, RxBytes needs to include the device's checksum octet too (Figure 11 — RxByte-1 | ... | RxBytes-m (CKS)). I was only setting it to the logical data length, so the framer stopped listening one octet short of the real device reply and could never verify its checksum.

    I'd also added an extra IOStCfg.TxEn_ write before CQSend_ a while back, on a guess. Removing it (since CQSend_ already switches the driver to transmit mode on its own) turned out to matter too — with it in place, the reply appeared to start with no idle gap, which is consistent with it slightly delaying the chip's automatic TX→RX handoff.

    With both fixed, I'm now reading the Direct Parameter Page correctly and consistently — Vendor ID 310 and Device ID 967, both matching the DTI421's IODD exactly.

    Thanks again for your help getting EstCom_ working — that was the piece that let me actually see a working reference exchange to compare against.

    Søren

  • Hi Soren,

    I am just closing the loop on this.  I am happy to hear that you were able to fix the timing issues with your code and that you are able to see the part working as expected now.  

    Of course, please reach out to our team anytime if you have further questions or need any more help.

    Best,

    Shasta

Reply Children
No Data

Before You Switch


Switching languages will make ADI Explorer unavailable. Resume your session by switching back to English and reopening ADI Explorer.