setWatch issue

Posted on
Page
of 2
/ 2
Next
  • Hi,
    I'm having trouble with a setWatch function. I'm monitoring a pulse that is 8uS wide and I want that to trigger the setWatch which contains and SPI write of 32 bits followed by 2 SPI reads of 32 bits. I'm using the MDBT42Q.
    It seems to be triggering randomly and I'm stumped. Suggestions?

    watchID = setWatch(function() {
    
        SPI1.write([READ_PTR, 0x00, 0x00, 0x00], nSEN);
    
        junk = SPI1.send([READ_FIFO, 0x00, 0x00, 0x00], nSEN);
        ecg = 256*(256*junk[1]+junk[2])+junk[3];
    
    //      console.log(ecg);
      
        junk = SPI1.send([READ_LEAD_STATUS , 0x00, 0x00, 0x00], nSEN);
    
      readCount++;
    
    }, ADC_RDY, {repeat: true, edge:'falling'});
    
  • Hi - I'm afraid I'm not sure what to suggest - by 'randomly' do you mean that it triggers even when there is no pulse? Or that sometimes when there are pulses it doesn't trigger?

    It shouldn't be an issue but you could try explicitly adding debounce:0?

  • Thanks @Gordon, I'll give that a try and triple check my hardware connections. What I'm seeing on the scope is several series of SPI transactions with each falling edge of the watched signal.

    I'll either post a resolution or scope images later today. Note that I am using the latest revision of firmware.

  • @Gordon It seems that the watch isn't reliably triggering on the 8uS pulse. I've got it going at a rate of about 222 kHz and trimmed the setWatch down to the following. I've verified that the pulse is present at the pin D16. Note that I am running the module and all of the IO pins at 1.8V.

    The setup code that uses SPI to communicate to the chip is operating properly (that sets up this signal), so I'm sure the supply voltage and IO is good.

    I stripped out all the other code and have it isolated to the setWatch function below.

    Could the issue be that the pulse on D16 is too short (8uS)?

    Output:

    setup complete
    interrupt init complete
    interval timer set
    watch set
    0
    6
    38
    20
    0
    0
    2
    0
    0
    0
    2
    0
    0
    0

    setInterval(function() {
      Bluetooth.println(readCount);
      readCount = 0;
     }, 1000);
    console.log("interval timer set");
    
    
    setWatch(function() {
        readCount++;
    }, D16, {repeat: true, edge:'falling', debounce: 0});
    console.log("watch set");
    
  • @billsalt

    I'm trying to understand your setup:

    • You are running 8us (micro second) low pulse with a frequency of 222kHz.
    • Every pulse increments the readCount by 1.
    • Every second you print readCount (to the log) and re-set the readCount to 0.

    Is that correct?

  • @allObjects close. It is an 8uS pulse. I've tried both the rising and falling edge in the watch with the same results. And yes, it is firing at a rate of approximately 222 kHz. Top trace on the image attached (channel 4).

    Any thoughts would be appreciated, thanks!


    1 Attachment

    • SDS00030.jpg
  • My guts tell me that Espruino is too slow to actually make it that fast...

    There are ways to make it faster by hooking directly into the interrupt... but because JS

    interpretation takes so much time you always miss hits... Did you check the error flag? I guess the internal event queue overflows within no time.

    Do you want to measure how many pulses happen in a second?

  • Do you have a way to control the firing frequency? For example w/ PWM driven pin (of a second Espruino device to minimize interference)?

    I would start at the rate of 100Hz and then crank it up until it becomes 'a wash' (measurements all over the place).

    If the expected firing frequency cannot be safely handled, you have to switch approach: you run a register/counter on a pin and read and reset the value every second. The counting would be uninfluenced by what else is going on your device. Proper timing comes then important - who to reset timer and start period and do the read-out. For better control you could make it inline assembler or compiled C function and call it from JS. There are examples in the forum (tutorial?) how to setup counter register and read and reset it. It was for the STM chips... I'm not sure if it works exactly the same way for the NRF52832... some data sheet and coding examples from the web may help you.

  • Thanks @allObjects. I'll also be interested to hear what @Gordon has to say, but I'm guessing that is indeed my issue.

    No, I'm not measuring. I want to use the pulse to trigger other operations (SPI bus transactions), but if you read earlier, it wasn't working so in the debugging I pared it down to the code shown so as to isolate the issue.

    Appreciate your insights! I guess I was expecting that since the chip I'm using (nRF) would have no issues with normal interrupts of this style, then this should work.

  • No, I do not have control of the timing. This comes from an acquisition chip.

  • Driving the code with an emulator in which you have control over the frequency is meant only to figure the max frequency you code can handle.

    Are you trying to bit-bang something?

    You are aware that a 220kHz frequency has a full cycle time of 4.5us only? 8us pulses don't even fit in... somehow - for me - the numbers do not add up.

    Can you tell be about the acquisition chip? (in dm or else?)

  • @allObjects sorry about that; used to typing the 'k'. If you look at that scope image, you'll see that it is actually 222 Hz. Plenty of time. I'd already run the numbers to make sure I had the time to do the SPI operations, even with Espruino timing on the SPI enable.

    I think I either need to do a bit of pulse stretching hardware, or just ditch Espruino and head directly to C. I was hoping to avoid that since I'm just prototyping, but alas.

    My other thought was whether it would be possible to so some inline C to trigger setWatch with a shorter pulse. Any thoughts on that?

    Appreciate your insights!

  • 222Hz is much better... because I know that an empty loop in Eskpruino a a few KHz at max. Said such, you can use another pin on your device and create the input signal with a PWM as mentioned before. With not too much capacity in the sense wiring and good contacts, I'm sure you can get reliable results. With 222Hz, you have about 4ms to spend between each of the pulses.

  • Using the PWM method how; could you explain? Your idea of using a counter and resetting it on a timer would be completely asynchronous to the acquisition chip A/D; that's not going to work. I need to synchronize on the interrupt pulse and don't see how Espruino can be used in this way as a 'pulse stretcher' without additional hardware.

  • Using the PWM driven pin is there to only 'exercise'/drive your code for figuring timing limits. That is all.

    Again, validate some of the wirings and signal behavior and pin mode setup (with pull up/down?) before setting up the watch. The input pins are so sensitive that the wiring capacity is enough to not produce a signal flank when the source is not a push/pull (only an open drain or source).

    From what I understand is: about every 4.5ms you get a pulse - interrupt from the acquisition device - that should trigger sending over spi 32 bits to the acquisition device and read 64 bits back from it and then do something with these 64 bits.

  • I was going to say - 222kHz is too fast to run JS for, but 222Hz should be fine :)

    However, it could be that there's an issue because of the falling edge triggering. What's the 'normal' state of the signal line? High, with 8us 'low' pulses? If so maybe try edge:rising?

    Why? Espruino actually triggers on both edges (in case you need debounce) but the hardware provides no way to know which edge it was, so the IRQ handler checks the value as soon as it runs. But because it's an 8uS pulse, it's possible that if the IRQ gets delayed by a few uS because of Bluetooth activity, and then by the time it runs the signal is back to the default state.

    But if you're checking for the edge when the signal returns back to the default state then you should be ok.

    Potentially you could set it up to trigger on both edges and then poke the underlying hardware to make it only actually trigger on rising or falling though...

    Another option is to use setWatch with some compiled C code and irq:true so it runs as soon as the IRQ occurs, or even you could use the nRF52 PPI functionality to trigger SPI sends directly from the IRQ without even getting the processor involved (https://www.espruino.com/NRF52LL) however that's definitely a bit tricker!

  • @Gordon and @allObjects thanks for your assistance and advice. I tried the inline C (below) and had almost identical behavior. The 8uS pulse width just is not working. I'll take a look at the PPI function, but my guess is at this point it would be more reliable to go directly to nRF native coding.

    var c = E.compiledC(`
    // void press(bool)
    // int get()
    volatile int data;
    void press(bool state){
      data++;
    }
    int get() {
     int r = data;
     data = 0;
     return r;
    }
    `);
    
    
    setWatch(c.press, D16, {repeat: true, edge:'both', irq: true});
    console.log("watch set");
    
  • @billsalt

    @Gordon 's point to not look for the other flank makes sense. I did not think about this. BUT: it looks like that you have a different issue: either the pulse has not enough energy to make it detectable or the wiring/pull-up/pull-down is still an issue.

    I'm also surprised that the acquisition device sends only a pulse. Interrupt pins - if we are looking at one here - go low until the interrupt is cleared. May be the acquisition device can be programmed differently and behaves like that.

    You mentioned the pulse to be visible in the screenshot of the DSO, channel 4. With everything wired up, could you detect the pulse on the NRF52832 pin with the DSO?

  • The pulse is fine. That scope output is at the pin on the MDBD42Q module. That is the way this part works, and is just fine with microprocessors running native code.

  • Thanks for going into all the details.

  • @Gordon and @allObjects: solved! I used a J-K flip flop (74AC109) inline configured as a toggle. Then changed the setWatch to edge: 'both'. Pretty simple hardware solution.

    Doing my SPI transfers in the setWatch with enough time, helps confirm that the issue was the narrow pulse.

  • Thanks for the feedback. Interesting. The acquisition device pulse is a negative 8us pulse. The MDBT42Q was unable to get triggered on either flank of the pulse. The 74AC109 uses the rising flank on the clock (I assume the acquisition device drives the clock of the flip-flop).... Still seems weird to me that the direct MDBT42Q input was not working but the 74AC109 clock does... A simple NAND constructed R-S flip-flop that would catch the negative flank could have worked too... but would need an extra pin from and JS pulse command on the MDBT42Q to reset it.

  • Close enough; actually a positive 8uS pulse (see the earlier scope image). I think the nRF processor was triggering, but the additional processing with setWatch was too much. Per one of your earlier posts, I was getting stack overflow after a few cycles, so it wasn't keeping up potentially because it was triggering on both edges internally and logging time for each. I don't know enough about the internals, but from what you and Gordon have described it makes sense.

    Since the toggle flip/flop only has the one edge each cycle, and there is a significant amount of time, it resolves the issue and Espruino can 'keep up'. I had J-K flip flops available since they are a general purpose 1-bit memory and easy to convert to lots of uses. A couple of connections and it becomes a toggle, for example. I don't keep standard logic gates around anymore, especially since I'd need a whole new family to do 1.8V logic work that has become the norm.

    Thanks again!

  • Ok, so I managed to reproduce the issue with:

    // Short D11 + D12
    analogWrite(D11, 0.0015, {freq:200});
    //analogWrite(D11, 0.1, {freq:200}); // works fine even with low accuracy
    n=0;
    setWatch(() => n++, D12, {repeat:true,edge:"falling"});
    setInterval(function() {
      print(n);
      n=0;
    }, 1000);
    

    In the Nordic chips, you can watch a pin either in a Low Power or a High Performance mode. In Espruino 2v09 I moved to using the Low Power mode as it uses substantially less power when the device is idle. What I didn't realise is that the Low Power mode isn't just less accurate, it just doesn't seem to be able to register any pulse that's faster than around 25us.

    So, as a fix I just committed code that allows you to enable the high speed mode using hispeed:true for the watch:

    setWatch(() => n++, D12, {repeat:true,edge:"falling",hispeed:true});
    

    This'll allow you to watch faster pin state changes on Nordic chipsets. However the pin 'state' may still be wrong - the pin state is still read in software (it's not reported by the hardware) when the IRQ is executed (which may not be immediately) so as a result a very small positive pulse may instead produce a state=false event because by the time the IRQ has read the pin state the signal has already gone back to 0.

  • Thanks @Gordon! I'll flash the bleeding edge firmware and give it a go, and report back.

    I thought the flip flop solution inventive, but certainly am not interested in the flying chip circus longer term :-}

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

setWatch issue

Posted by Avatar for billsalt @billsalt

Actions