Minimum GPIO Pulse Width

I need to generate a single pulse a ~10uS wide on an IMP003. I’ve configured the output pin as:
PinGE_RST <- hardware.pinG;
PinGE_RST.configure(DIGITAL_OUT);

This code generates a pulse of ~223uS:
PinGE_RST.write(1);
local e = hardware.micros() + 10;
while(hardware.micros() < e);
PinGE_RST.write(0);

This code generates a pulse of ~136uS:
PinGE_RST.write(1);
imp.sleep(0.00001);
PinGE_RST.write(0);

This code generates a single pulse of ~29uS:
PinGE_RST.write(1);
PinGE_RST.write(0);

Is it possible to produce a single pulse of less than 29uS with a GPIO configured pin?

The best way to produce very short, guaranteed-duration pulses is to use a SPI peripheral. Configure it to the speed you want (here, 100KHz) and write a byte with just the one bit set.

Peter

Hi Peter.

By sheer coincidence I’ve managed to connect this reset line to an i2c SDA pin so I can give it a crack. However this approach seems a slightly unorthodox method to generate a single pulse.

According to the documentation the IMP003 has an internal crystal running at 26MHz. I am using an external crystal whose frequency is very close to the reciprocal of the ~29uS pulse generated. Could the external crystal be limiting the speed at which the code runs? At what point does the 1uS imp.sleep resolution become usable?

Franc

What sort of precision are you looking for? I see using imp.sleep as risky for high precision timing. Squirrel execution might be halted during imp.sleep, but you still have interrupt handlers that could rob you of a microsecond or two. For consistency, you’ll need to find a way of lowering PinGE_RST through a hw service like SPI, rather than doing it programmatically. I use a PTPG output for some precision output timing. That may work for you, but it needs an external trigger, or you’d need to wire one of your GPIO outputs into the trigger input to set it off

If you are determined to use Squirrel, you might get a slightly shorter pulse from:

`            local p=PinGE_RST.write.bindenv(PinGE_RST)
            p(1)
            p(0)
`

Whoops, mixed up my busses. SPI not i2c.

Bugger, that pin is connected to MISO. Is there anyway to configure and output from a slave without receiving input from a master? Also can CLK be suppressed as I already have something connected to that pin.

You’re a legend @coverdriven! The code you recommended generates a single pulse of ~9.1uS. Why is it so?

I thought I’d do some more testing and came up with the following for imp.sleep(x) between p(1)/(0) and between the standard PinGE_RST.write(1)/(0):
x = 0.001 = ~1.11mS, ~1.13mS
x = 0.0001 = ~203uS, ~232uS
x = 0.00001 = ~117uS, ~142uS
x = 0.000001 = ~104uS, ~128uS

Entering more zeros doesn’t reduce the width of the pulse any further.

The timing of imp.sleep doesn’t seem to be accurate at or below a millisecond. The imp.sleep API is a bit misleading, stating imp.sleep has a resolution of 1uS and “is the most precise way to do nothing”. 1uS resolution is in the noise when using imp.sleep in 100s of uS or in mS.

I don’t quite get what you mean about external crystal and imp003? Is this connected to a different IC?

On timing, you can likely get a longer pulse with something like:

p(1)
p(1)
p(1)
p(0)

…which might give you close to 27us based on your 9.1us measurement before.

imp.sleep does sleep accurately, however you’re running in an interpreted environment so there’s overhead to actually run the subsequent commands. Note that @coverdriven’s code causes the system to perform the object lookup in the VM earlier and then store a reference to it, allowing it to be executed more quickly.

What device are you using that needs such an accurate reset pulse? I’ve never come across anything like that in the real world.

Hi Hugo.

I’ve implemented the low power IMP003 design as per para 15.2 of the spec. Y1 is a ABS07-120-32.768kHz. The reciprocal of the operating frequency of Y1 is very close to the pulse width of 29uS that I produced with PinGE_RST.write(1); PinGE_RST.write(0); code. I just thought it was an amazing coincidence.

Yes that does work, great stuff:
4 x p(1)'s = ~37uS
3 x p(1)'s = ~28uS
2 x p(1)'s = ~18uS

I’m interfacing the IMP003 with the MSGEQ7. The IC requires a minimum 100nS reset pulse width, I chose 10uS as a starting point; 10uS seemed reasonable rather than >100uS or mS as I have other things I need to do with the IMP in the mS timeframe. I may need to lengthen pulses to counter high capacitance in the board design but I’ll cross that bridge if need be.

I’m not sure SPI as mentioned by Peter is the best solution as I assume it will generate a square wave on a CLK line that I don’t need - I’d rather not do this if I don’t have to, unless CLK can be programatically suppressed of course. I think I have a workable solution with bindenv(). If you have any other ideas I’m all ears.

Oh wow, now that’s an interesting chip company. Every now and then new ones come along who make all sorts of strange chips…

You can configure SPI with no clock pin for just this reason (NO_SCLK option). This is how the ws2812 library generates the arbitrary waveforms that are needed to drive that chip.

But, for a reset pulse of >100ns I’d just do a ~10us pulse with the above code and move on with the rest of the design. Actually, I’d actually probably just end up with a 30us pulse and move on without even using bindenv :wink:

Yes, they seem to have carved out a niche market, not many others making those types of chips. I searched far and wide for something like the MSGEQ7.

I thought about using SPI but realised I need to perform an analogue pin read every time the strobe goes low so I persevered with bindenv and got it working with the assistance of this very helpful EE Times article, which explains the timing much better than the MSGEQ7 spec sheet. Ugly code but it works a treat! Thanks guys.