Shop OBEX P1 Docs P2 Docs Learn Events
Microsecond delay function! — Parallax Forums

Microsecond delay function!

Hi All,

The delay function _waitus() is a bit off (I ask for 1 microsecond and get 6ish) and not precise enough for my application. How can I make a precision delay function? I need to implement the Atmel 1 wire protocol and I need the microsecond delay to be very accurate. I program in C and am a novice at assembly but want to get my feet wet. Can anyone share what they have done?

Thanks,

Eric

Comments

  • What are you doing after the wait? Can you post a code snippet?

  • Also, what frequency are you running the P2 at?

  • @ke4pjw said:
    What are you doing after the wait? Can you post a code snippet?

    I'm setting an output high or low depending on the bit that needs to be sent. I am using the ATSHA204 device to protect my firmware when I get the firmware written of course. The Atmel 1 wire protocol is an odd one and its not to be confused with the Dallas 1-wire.

  • @ke4pjw said:
    Also, what frequency are you running the P2 at?

    I've tried 200 and 260 mhz

  • Without seeing your code, it will be difficult to see the problem. Usually bit banged serial output like that is done using ASM, and you need to have a precomputed waitx value for the bit period. The a waitx value of clkfreq / 1_000_000 is 1us. I think waitus() is a Spin function. I don't believe such as function is available in PASM. You will have to take into account code execution time, but here is what I got with both SPIN and Proptool, without taking into account code execution.

    Using Spin

    CON
        _xtlfreq = 20_000_000
        _clkfreq = 270_000_000
    
    PUB main()
      repeat
        pinh (8)
        waitus(1)
        pinl (8)
        waitus(1)
    

    Using inline PASM

    CON
        _xtlfreq = 20_000_000
        _clkfreq = 270_000_000
    
    PUB main() | bitperiod
      bitperiod :=  _clkfreq / 1_000_000
    org
    start
      DRVH  #8
      waitx bitperiod
      DRVL  #8
      waitx bitperiod
      jmp   #start
    
    end
    

    Using the smartpins would eliminate the worry about any of these bit related timings, as no code is needed to send them out. There are several examples of using smart pins in the forum.

  • That ATSHA204's one wire is configured for 230.4Kbps. It does not appear to be a 1Mbps connection. Based on the information in the datasheet, you should be able to us jm_FullDuplexSerial in %0100 mode and tie two pins together for RX/TX. I have done that as a proof of concept with the IBus protocol. I suspect you are trying to save a pin, as it also does I2C. I believe Jon is working on a one wire object that would do exactly what you need, though.

  • I've attached my Dynamixel 1.0 object for the P2 -- it shows how to TX and RX on the same pin using smart pin UART modes.

  • @ke4pjw said:
    That ATSHA204's one wire is configured for 230.4Kbps. It does not appear to be a 1Mbps connection. Based on the information in the datasheet, you should be able to us jm_FullDuplexSerial in %0100 mode and tie two pins together for RX/TX. I have done that as a proof of concept with the IBus protocol. I suspect you are trying to save a pin, as it also does I2C. I believe Jon is working on a one wire object that would do exactly what you need, though.

    Thank you for the information. I have created the Atmel bit-bang one-wire library two years ago for the PSOC4 device to protect the drivers I created using the ATSHA204 device. After fiddling with it for three weeks, I got it working very well. I had to create an accurate microsecond delay in assembly for the PSOC4 device which was not trivial. I found that the one-wire worked and couldn't get the I2C version of the chip to work because I couldn't control the wakeup pulse because the PSOC4 device wouldn't release the I2C bus to manually toggle the IO. I am not trying to save a pin. it is more obfuscation than anything and the part is tiny sot23 and impossible to know what it is to a hacker. I ordered 200k pieces with no marking on them and it's a perfect little device but a royal pain to program and use.

    The Propeller 2 is a different animal, and it is hard to even find the info I am looking for right at the moment but getting there. Does propeller 2 support open collector pin configuration? Maybe I am missing something, blind or too tired I just can't see.

    Another question, where is the propeller2.c file? I see the propeller2.h file but not the other... I want to see the _waitus and _waitms functions. Can someone share these, please? I am programming in Catalina Geany btw. I am going with what I know for now so I can at least feel good I am making some progress instead of pulling my hair out.

    The way I want to lay out my project is cog0 is for three high-speed UARTS full-duplex and data multiplexing, cog1 is for I2C comms between three devices and writing the bit-bang stuff tomorrow for that, cog 2 is for high-speed SPI comms with four slave select lines and other control stuff, cog3 is for the one wire ATSHA204 device which will periodically run to make sure the device is still in system or not and shut down the P2 if has been removed or failed to read it, cog4 is for timing stuff, cog5, cog6, cog7 are for the main application which I can't really discuss.

    I appreciate your help :-)

  • jmgjmg Posts: 15,148
    edited 2023-04-10 06:06

    @ke4pjw said:
    That ATSHA204's one wire is configured for 230.4Kbps. It does not appear to be a 1Mbps connection.

    That part is quite a mess.
    It does claim
    "The Wake token is special in that it requires an extra long low pulse of 8μs on the SDA pin (see Table 7-3), which cannot
    be confused with the shorter low pulses that occur during a Data token (Zero, One, ZeroOut, OneOut)"
    but that number is not supported by the tables.
    The Wake looks to actually be 60us LOW then 2.5ms HI - appx a 42:1 ratio.

    It seems to use 230.4k Baud (4.34us) on TX only, however, the RX reply uses nominal 6us (4.60us ~ 8.60us range) ?!
    Full single bit time is nominally 9 of those 4.34us units. (so they suggest 7 bit UART mode, Start+7+Stop = 9 )

    Using a single pin UART at 230.4k certainly simplifies the TX timings, and you can use the sampling alias on TX to decide if you have a 1 or 0.
    The slowest echo can appear as Start+First data bit = LOW, then if sending HI, 2 Hi bits then 2 low bits....
    The fastest echo can appear as Start, then if sending HI 1 hi bit then 1 low bit.
    The typical is somewhere between these, with a lottery of bits depending on the bit sampling !

    So RX SW needs to use a range decision, monotonic 0xff or 0xfe is a zero, anything else can be a one :)

  • SaucySolitonSaucySoliton Posts: 488
    edited 2023-04-10 06:16

    @ke4pjw said:
    Without seeing your code, it will be difficult to see the problem. Usually bit banged serial output like that is done using ASM, and you need to have a precomputed waitx value for the bit period. The a waitx value of clkfreq / 1_000_000 is 1us. I think waitus() is a Spin function. I don't believe such as function is available in PASM. You will have to take into account code execution time, but here is what I got with both SPIN and Proptool, without taking into account code execution.
    Using inline PASM

    CON
        _xtlfreq = 20_000_000
        _clkfreq = 270_000_000
    
    PUB main() | bitperiod
      bitperiod :=  _clkfreq / 1_000_000
    org
    start
      DRVH  #8
      waitx bitperiod
      DRVL  #8
      waitx bitperiod
      jmp   #start
    
    end
    

    That looks like a lot of overhead in the logic analyser. Also, friendly reminder that WAITX delays for N+2 cycles. So whatever bitperiod := _clkfreq / 1_000_000 works out to be, subtract at least 2 to start.

    I did a search for waitus in the Catalina directory and found many copies. Not sure which one it will use. I'm not too familiar with Catalina. I checked a few and they all looked like it was doing the divide. As mentioned by @ke4pjw , the delay count should be calculated ahead of time. However waitx() appears to translate directly into a single assembly instruction. As does pinl() and pinh(). Try the -y option to look at the assembly code generated by the compiler.

  • @jmg I read the wakup token as send $00 and wait at least tWHI (2.5 ms) before sending other data. Looks like an interesting chip. I was looking for something like this that would allow for easy offloading of TLS (SSL). Seems like there should be some purpose built chip for that, but I couldn't find any that were standalone.

  • @RossH : it sounds like Catalina's _waitus() implementation could use a bit of tweaking. If you do something like:

       // pseudo-code
       curcycle = _getct()
       cycles_to_wait = delay / (_clkfreq / 1000000)
       _waitct(curcycle + cycles_to_wait)
    

    you'll get a much more precise result. Caching some of the calculated intermediate values (like clkfreq / 1000000) would also help, especially on the P1 where divides are so expensive..

  • RossHRossH Posts: 5,346

    @ersmith said:
    @RossH : it sounds like Catalina's _waitus() implementation could use a bit of tweaking. If you do something like:

       // pseudo-code
       curcycle = _getct()
       cycles_to_wait = delay / (_clkfreq / 1000000)
       _waitct(curcycle + cycles_to_wait)
    

    you'll get a much more precise result. Caching some of the calculated intermediate values (like clkfreq / 1000000) would also help, especially on the P1 where divides are so expensive..

    Yes, it could do with an update. Perhaps checking the current clock frequency and updating the cached values if it has changed would be a good idea.

    Ross.

  • @RossH said:

    @ersmith said:
    @RossH : it sounds like Catalina's _waitus() implementation could use a bit of tweaking. If you do something like:

       // pseudo-code
       curcycle = _getct()
       cycles_to_wait = delay / (_clkfreq / 1000000)
       _waitct(curcycle + cycles_to_wait)
    

    you'll get a much more precise result. Caching some of the calculated intermediate values (like clkfreq / 1000000) would also help, especially on the P1 where divides are so expensive..

    Yes, it could do with an update. Perhaps checking the current clock frequency and updating the cached values if it has changed would be a good idea.

    Ross.

    Thank you for this :smile:

  • @jmg said:

    @ke4pjw said:
    That ATSHA204's one wire is configured for 230.4Kbps. It does not appear to be a 1Mbps connection.

    That part is quite a mess.
    It does claim
    "The Wake token is special in that it requires an extra long low pulse of 8μs on the SDA pin (see Table 7-3), which cannot
    be confused with the shorter low pulses that occur during a Data token (Zero, One, ZeroOut, OneOut)"
    but that number is not supported by the tables.
    The Wake looks to actually be 60us LOW then 2.5ms HI - appx a 42:1 ratio.

    It seems to use 230.4k Baud (4.34us) on TX only, however, the RX reply uses nominal 6us (4.60us ~ 8.60us range) ?!
    Full single bit time is nominally 9 of those 4.34us units. (so they suggest 7 bit UART mode, Start+7+Stop = 9 )

    Using a single pin UART at 230.4k certainly simplifies the TX timings, and you can use the sampling alias on TX to decide if you have a 1 or 0.
    The slowest echo can appear as Start+First data bit = LOW, then if sending HI, 2 Hi bits then 2 low bits....
    The fastest echo can appear as Start, then if sending HI 1 hi bit then 1 low bit.
    The typical is somewhere between these, with a lottery of bits depending on the bit sampling !

    So RX SW needs to use a range decision, monotonic 0xff or 0xfe is a zero, anything else can be a one :)

    I used the bit-bang Atmel 1-wire protocol to communicate with the ATSHA204 and it does indeed work. It is not like the Dallas 1-wire protocol. This way you can wake the part rather easily and put it to sleep when not in use.

Sign In or Register to comment.