digitalPulse "Timeout on Utility Timer"

Posted on
  • I'm trying to port my NodeMCU code which communicates with the Ti CC1101 modem. Using the NodeMCU ESP8266 board (4MB Flash). I'm using the hardware SPI pins (D5-D7), plus the D8 PIN for chip select.

    The only thing I'm doing so far is trying to reset the modem with the chip select line "wiggling" described in the modem's manual in the section "manual reset". This requires microsecond toggling then issuing an SPI command.

    My code (generated from Typescript):

    var cc1101 = /** @class */ (function () {
        function cc1101(spi, cs) {
            this.spi = spi;
            this.cs = cs;
            spi.setup({});
            this.cs.mode('output');
        }
        cc1101.prototype.sendCmd = function (cmd, cb) {
            this.cs.write(false);
            this.spi.write(cmd);
            this.cs.write(true);
            setTimeout(cb, 0.3, []);
        };
        cc1101.prototype.readReg = function (reg) {
            return this.spi.send(reg, this.cs);
        };
        cc1101.prototype.reset = function (cb) {
            // CS wiggling to initiate manual reset (manual page 45)
            digitalPulse(this.cs, true, [0.03, 0.03, 0.045]);
            digitalPulse(this.cs, true, 0); // Wait for completion
            this.sendCmd(0x30, cb);
        };
        return cc1101;
    }());
    
    function main() {
        var cc = new cc1101(SPI1, NodeMCU.D8);
        cc.reset(function () {
            console.log(cc.readReg(0xf1));
        });
    }
    E.on('init', main);
    

    Uploading with SAVE_ON_SEND using espruino tool, I get this output:

    Espruino Command-line Tool 0.1.30
    -----------------------------------
    
    Explicit board JSON supplied: "ESP8266_4MB"
    Connecting to '/dev/ttyUSB0'
    Connected
    You have pre-1v96 firmware. Upload size is limited by available RAM
    --] 
    --]  ____                 _ 
    --] |  __|___ ___ ___ _ _|_|___ ___ 
    --] |  __|_ -| . |  _| | | |   | . |
    --] |____|___|  _|_| |___|_|_|_|___|
    --]          |_| espruino.com
    --]  2v04 (c) 2019 G.Williams
    --] 
    --] Espruino is Open Source. Our work is supported
    --] only by sales of official boards and donations:
    --] http://espruino.com/Donate
    --] Flash map 4MB:1024/1024, manuf 0xe0 chip 0x4016
    --] 
    --] >
    Upload Complete
    --] Uncaught InternalError: Timeout on Utility Timer
    --]  at line 2 col 35
    --]         digitalPulse(this.cs, 1, 0); // Wait for completion
    --]                                   ^
    --] in function "reset" called from line 4 col 6
    --]     });
    --]      ^
    --] in function called from system
    

    What does this mean? The pulse can't be sent? Or is the pulse sending happening so fast that the hardware timer controlling it already finished when I'm invoking the wait so it starves out?
    I should really wait for the pulse to complete, that's when I can send the RST strobe command to the chip.

    My NodeMCU LUA code for the same thing which works can be found here. Maybe it helps.

  • Hi,

    My code (generated from Typescript):

    Missing pins ....

    start with how to use software SPI

    http://www.espruino.com/Reference#softwa­re

  • And than have a look at this forum post

    http://forum.espruino.com/comments/15065­227/

  • Hi MaBe,

    I'm using the hardware SPI of the ESP8266 (SPI1), and it has only one configuration. The documentation says I don't have to manually specify the MISO/MOSI/SCK pins if I'm okay with the defaults.

    If sck,miso and mosi are left out, they will automatically be chosen.
    However if one or more is specified then the unspecified pins will not
    be set up.

    But you are right, it won't hurt to try manually specify everything if it doesn't work.

    However the error is related to the digitalPulse call, not SPI. The line with the "wait for completion" comment fails as you can see with the timer timeout. The documentation of this function says:

    It uses a hardware timer to produce accurate pulses, and returns
    immediately (before the pulse has finished). Use digitalPulse(A0,1,0)
    to wait until a previous pulse has finished.

    I have to wait for the pulses to go out before I can issue the reset command on the SPI bus.
    Though today while I was browsing the documentation I've also found on the ESP8266 specific page that

    The esp8266 uses FreeRTOS with non-preemptible tasks and has extremely
    limited code space for interrupt handlers, as a result, it is not
    possible to handle certain peripherals at interrupt time and a task
    has to be scheduled instead, which would be OK if tasks were
    pre-emptible, but they are not. This means that functions like
    digitalPulse have to use busy-waiting between edge transitions instead
    of being interrupt driven.

    So maybe it's not even necessary, since the digitalPulse will be a blocking call on the ESP8266 if I understood correctly.

    Anyway, I'm going to dig out my logic analyzer and see what's going on with the pins.

    I've seen your previous comment sent out in the email related to the firmware version :)
    As you can see I'm on 2v04 (below the logo). I don't understand why the espruno-cli says "You have pre-1v96 firmware. Upload size is limited by available RAM".

  • Based on my logic analyzer's output digitalPulse is stable to around 0.1 ms resolution. Below that it doesn't always produced what I ask it to do. :(

  • Thank you, I've upgraded to the 'cutting edge' firmware (2v04.76).

    I still experience some issues. The minimal code to reproduce it:

    var csPin = NodeMCU.D8;
    csPin.mode('output');
    digitalPulse(csPin, true, [0.03, 0.03, 0.045]);
    

    I get only a single low-high transition in this case according to my logic analyzer.

    Interestingly if I prepend this with two 1ms values, the microsecond transitions are generated correctly.

    var csPin = NodeMCU.D8;
    csPin.mode('output');
    digitalPulse(csPin, true, [1, 1, 0.03, 0.03, 0.045]);
    

    And this does make the modem reset work, I can query it's version number afterwards.

    Am I still doing something wrong?


    1 Attachment

    • espruino_pulses_1_1_0.03_0.03_0.045.png
  • I can't attach the bad logic analyzer output for some reason, you can find it on my Google Drive.

    Mod: since then I've edited this post and added the image here.


    1 Attachment

    • espruino_pulses_0.03_0.03_0.045.png
  • Sun 2020.01.19

    'I can't attach the other logic analyzer output'

    FYI - Only one image may be uploaded at a time. Did an attempt at a re-edit allow the ability to perform the additional upload? It's okay to re-edit to test


    Hi @nistvan.86, I'm late to this thread and wont be of much help should this truly be an ESP8266 issue, but I'm not really grasping what isn't working.

    'And this does make the modem reset work, I can query it's version number afterwards.'
    'Am I still doing something wrong?'

    Is the concern still with this msg while 2v04 is currently flashed?

    'You have pre-1v96 firmware'

    Has 'af_output' been tried for pinMode()?

    http://www.espruino.com/Reference#l__glo­bal_pinMode

    0.03 msec is 30 usec and the pulse shown appears to be documented as 29.8 usec
    Was this of concern?

    EDIT: I think I get it, the question is why is it necessary to prepend two place holders?



    Incidentally, I've been playing with digitalPulse() and ran into a similar situation. My (unresolved and unresearched at 'C' code level) belief is that the array mechanism requires whole numbers, and a decimal seems to muck things up. I was able to create narrow usec pulses at the usec level using the following as a patch: (edit as necessary)

      analogWrite( D4, 0.01, { freq : 4000 } );
      // to trun off
      analogWrite( D4, 0, { freq : 1 } );
    

    yes, I know it uses the analog flavor, . . .

    http://www.espruino.com/PWM
    http://www.espruino.com/Software+PWM

    then to create a pulse train, embed within an interval, something like: (use setTimeout() for a single pulse)

      intervalID = setInterval( function() {
        // Fire the enable pulse
        dp4once();
    
      }, freq );
    



    Not sure if this is what you are after, but I'm running short on time tonight and wouldn't be able to respond should you reply. Just thought I'd pass along some ideas. . . .

    Source code links if time allows to research
    https://github.com/espruino/Espruino/blo­b/master/src/jswrap_io.c#L201
    https://github.com/espruino/Espruino/blo­b/master/src/jswrap_io.c#L167

    If I've butt'ed in and not assisting here, please forgive. . . .

  • @nistvan.86 can you build firmware and do further investigation?

  • I'll comment on the issue tracker, but I believe this is a known issue because ESP8266 is using a 32kHz RTC as the base for all timings.

    It won't be to do with using non-integer values (other than you're asking for the pulse length to be shorter than Espruino can accurately manage), and the 1ms pulse length that's sorting things out for you is probably because it's something that can be accurately scheduled with the 32kHz RTC which helps to 'sync' everything up.

  • @Robin had to retry it a couple times before the image appeared. Did the same thing yesterday, but had no luck back then. Anyway, the image is now attached.

    @MaBe I can give it a go on the weekend if you have anything specific in mind to try out. Thank you for the Github issue!

    @Gordon sounds logical. This "hack" solves my problem here, because the longer edges are simply ignored by the modem. But I'm just lucky with my situation, other use cases might not be so forgiving.

  • Mon 2020.01.20

    @nistvan.86 glad that worked, but a bit of a mis-communication. My belief was that multiple upload of images was the issue, and intended to have the subsequent upload in post #7 rather than a replace of your remote account. That said, it appears the issue was with the actual file then?


    @Gordon, regarding post #12, what are the limitations, and what is the range of pulse creation using digitalPulse() please. Is the implication that only a 1msec be the shortest width pulse at a 1KHz rate be all that may be created then? I thought I read (but unable to locate, and unable to reproduce) that 1usec pulse widths were possible at a 1MHz rate?

  • 1usec pulse widths

    On STM32 I believe they probably are, but that's the limit. It'd be better to discuss the intricacies on the issue that got filed, but it's a 32kHz timer so on non-STM32 you should assume accuracy is 1/32768 sec until the timers get implemented differently.

  • I can give it a go on the weekend if you have anything specific in mind to try out.

    Maybe try the hardware timer instead of the RTC.

  • @MaBe I too seem to have some issues here on my d1-mini. I am trying to do IR transmit based on the instructions at the bottom of https://www.espruino.com/pronto.

    I get Uncaught InternalError: Timeout on Utility Timer message.

    It seems that the analogWrite() with 38kHz gives just too much work to do for some reason to the ESP8266. As once I turn the analogWrite() on the previously installed watch for reading the IR (on another pin) starts to be very unreliable. As soon as I did digitalRead() on the same pin the receiver became properly responsive again.

    Perhaps a combination of analogWrite()/SPI and digitalPulse() don't play well together?

    >process.env
    ={ 
      VERSION: "2v04", 
      GIT_COMMIT: "3956264e", 
      BOARD: "ESP8266_4MB", 
    ...
    >function codeToPFTimes(code) {
    :    let times = [];
    :
    :    function pushBit(c) {
    :         times.push(0.16);
    :         times.push(c === '0' ? 0.262 : 0.552);
    :    };
    :
    :    times.push(0.16);
    :    times.push(1.18); // START
    :    code.split('').forEach(pushBit);
    :    times.push(0.16);
    :    times.push(1.18); // STOP
    :    return times;
    :}
    =function (code) { ... }
    >codeToPFTimes('1000000110011111') 
    =[ 0.16, 1.18, 0.16, 0.552, 0.16,  ... 0.552, 0.16, 0.552, 0.16, 1.18 ]
    >analogWrite(No,0.95,{freq:38000});          
    
    >analogWrite(NodeMCU.D1,0.95,{freq:38000­}); 
    =undefined
    >digitalPulse(NodeMCU.D2, 1, codeToPFTimes('1000000110011111')); digitalPulse(NodeMCU.D2, 1, 0); 
    Uncaught InternalError: Timeout on Utility Timer
     at line 1 col 94
    ...gitalPulse(NodeMCU.D2, 1, 0);
    
  • The neopixel module for ESP8266 does a dry-run/pre-roll without emitting any pulses. That dry run is necessary to load the machine code from flash into RAM. Without this dry run the timing of the pules representing the first byte won't have proper timing. It might be the same issue in this case. Reference files:
    jswrap_neopixel.c, line 220...
    jswrap_io.c, line 201...

    There is no dry-run for ESP8266 in jswrap_io.c, so I would assume it is the same issue. That code is not capable of producing very short pulses accurately in the first run.

  • Just to confirm. I confirmed the above mentioned IR sending is working as described without any issue on the Original Espruino board v1.3.

  • The neopixel module for ESP8266 does a dry-run/pre-roll without emitting any pulses. That dry run is necessary to load the machine code from flash into RAM. Without this dry run the timing of the pules representing the first byte won't have proper timing

    Hi @maze1980, are you talking about this section?

    https://github.com/espruino/Espruino/blo­b/e568c6c7ac78e81b4ab40bb28bd92e8052f4e7­b6/libs/neopixel/jswrap_neopixel.c#L229-­L234

  • ok, i can see. can you suggested the change for jswrap_io.c?

  • I don't think it is easy to fix, especially without breaking existing code. Maybe it is possible to change

    digitalPulse(csPin, true, [1, 1, 0.03, 0.03, 0.045]);
    

    to

    digitalPulse(csPin, false, [1, 0.03, 0.03, 0.045]);
    

    and get the desired pulse, just a a little delay. Then there would be no code change required, just a note in the documentation.

  • Post a reply
    • Bold
    • Italics
    • Link
    • Image
    • List
    • Quote
    • code
    • Preview
About

digitalPulse "Timeout on Utility Timer"

Posted by Avatar for nistvan.86 @nistvan.86

Actions