Shop OBEX P1 Docs P2 Docs Learn Events
loadp2 loader for P2 - Page 2 — Parallax Forums

loadp2 loader for P2

2

Comments

  • evanhevanh Posts: 15,126
    That worked :)
    trying /dev/serial/by-id/usb-Parallax_Inc_Propeller_P2-ES_EVAL_P23YOO42-if00-port0 with timeout of 50 ms...
    P2 version G found on serial port /dev/serial/by-id/usb-Parallax_Inc_Propeller_P2-ES_EVAL_P23YOO42-if00-port0
    Setting load mode to CHIP
    Setting clock_mode to 12427f8
    Loading fast loader for chip...
    Loading Flash_loader_ebh3.binary - 5088 bytes
    chksum: 42 OK
    Flash_loader_ebh3.binary loaded
    
  • Thanks, Evan! I hope loadp2 will be a lot more stable now.
  • evanhevanh Posts: 15,126
    Ah, just pushed it over the edge with an unstable binary, due to too high sysclock, in the Flash chip that goes wonky. My tweaked loadp2 can recover it, on second attempt, without having to change the dip switches. Yours tries 50 ms then 500 ms without finding the prop2 and repeated attempts doesn't make progress. Actually, I need to solve why it even takes two attempts with my tweaks too ...

  • evanhevanh Posts: 15,126
    Okay, the problem with mine is because of unflushed garbage in the PC's comport buffers. One of the side effects of the errant binary is it spews garbage down the comport.

    My loadp2 actually downloads fine on first attempt because it is operating blindly until the very end and only when it goes to check for the prop2 response of "." does it get confused. This of course has updated the prop2 with the fixed version of the binary so the next attempt is no problem.

    I'm guessing your latest loadp2 is suffering the same garbage in the buffers but with the extra checks it is giving up before downloading the binary.
  • evanhevanh Posts: 15,126
    edited 2019-10-19 15:36
    Oh, I deleted that function call out of hwreset() a few days back and I've noticed you copied me. Doh! My fault.

    EDIT: I couldn't work out why Dave had such a long sleep in there either. It was for the flush. It won't need that long but I guess some is needed ...
  • evanhevanh Posts: 15,126
    edited 2019-10-19 15:35
    Yep, this makes your one work with no issue at all
    void hwreset(int sleeptime)
    {
        int cmd = use_rts_for_reset ? TIOCM_RTS : TIOCM_DTR;
        ioctl(hSerial, TIOCMBIS, &cmd); /* assert bit */
        msleep(2);
        ioctl(hSerial, TIOCMBIC, &cmd); /* clear bit */
        msleep(2);
        ioctl(hSerial, TIOCMBIS, &cmd); /* assert bit */
        msleep(sleeptime);
        tcflush(hSerial, TCIFLUSH);
    }
    
  • evanhevanh Posts: 15,126
    Or if that 90 ms was important for reliable operation on other platforms then an extra step would be in order, say:
    void hwreset(void)
    {
        int cmd = use_rts_for_reset ? TIOCM_RTS : TIOCM_DTR;
        ioctl(hSerial, TIOCMBIS, &cmd); /* assert bit */
        msleep(2);
        ioctl(hSerial, TIOCMBIC, &cmd); /* clear bit */
        msleep(2);
        ioctl(hSerial, TIOCMBIS, &cmd); /* assert bit */
        msleep(45);
        ioctl(hSerial, TIOCMBIC, &cmd); /* clear bit */
        msleep(45);
        ioctl(hSerial, TIOCMBIS, &cmd); /* assert bit */
        tcflush(hSerial, TCIFLUSH);
    }
    
  • evanhevanh Posts: 15,126
    edited 2019-10-19 15:57
    No, 90 ms is too long. Dave would have chosen it to be shorter than the 100 ms timeout but that is actually too close to 100 ms. In colder temperatures RCFAST goes quite a lot faster.

    EDIT: Hmm, unless the spec is guaranteed to be longer than 100 ms on the timeout.
  • evanhevanh Posts: 15,126
    Well, on Linux over a 20 metre USB 1.0 active extension cable + hub, testing at various sleeptime's the flushing of spewing data works right down to a 15 ms sleep time on the first method above. Don't need to duplicate Dave's original fixed 90 ms, IMHO.
  • I've added back in the TCIFLUSH ioctl. Does what's currently in github work for you Evan? If not, what changes would you like to see?
  • evanhevanh Posts: 15,126
    I tested that. For some reason, presumably to do with serial bits still arriving, it needs to have some milliseconds (15 ms for me) duration between the DTR resetting the prop2 and the buffer being flushed, or it won't clean up enough.

    I quite liked the tidiness of moving the settable "sleeptime" into the hwreset() function, providing for both requirements (delay needed for prop2 hard reset response and also this flushing) in one place.
  • OK thanks. I think I'll leave the hwreset API the same for now, but I will adjust the delays.
  • evanhevanh Posts: 15,126
    edited 2019-10-20 18:03
    In that case, to provide same meaning of sleeptime values, I'll recommend this
    void hwreset(void)
    {
        int cmd = use_rts_for_reset ? TIOCM_RTS : TIOCM_DTR;
        ioctl(hSerial, TIOCMBIS, &cmd); /* assert bit */
        msleep(2);
        ioctl(hSerial, TIOCMBIC, &cmd); /* clear bit */
        msleep(2);
        ioctl(hSerial, TIOCMBIS, &cmd); /* assert bit */
        msleep(20);
        ioctl(hSerial, TIOCMBIC, &cmd); /* clear bit */
        msleep(2);
        ioctl(hSerial, TIOCMBIS, &cmd); /* assert bit */
        tcflush(hSerial, TCIFLUSH);
    }
    
  • jmgjmg Posts: 15,140
    edited 2019-10-20 18:57
    evanh wrote: »
    I tested that. For some reason, presumably to do with serial bits still arriving, it needs to have some milliseconds (15 ms for me) duration between the DTR resetting the prop2 and the buffer being flushed, or it won't clean up enough.

    That's for the case of P2 user code sending, when reset arrives ?
    Maybe that's the hardware uart buffers in action ? What baud rate was that at ?

    Another way to mange that, could be to Empty Rx and retry a few times, should unexpected chars appear ?
    That should be both HW delays, and HW buffer size tolerant.


    Other points :
    a) In the UB3 UART Bridge for P2D2, I've bumped the HW buffer to 1536 bytes, so that may store more unwanted chars, if reset during a stream ?
    (some FTDI parts have 2K buffers)

    I do notice the SiLabs code does this
          if (DEVICE_OPEN_f) {  // Reset variable state
           resetState();   // reset buffer states and init uart, 16b loads into pointers, apply baud..
           rxIdleTime = RX_FLUSH_TIME;
          }  // endif DEVICE_OPEN
    
    So maybe a simple re-apply of the open(), can be used to flush the USB-UART HW buffers ? (Perhaps a call to TCIFLUSH does the same thing ?)

    b) Why the double reset pulse ?
    On the UB3 I've added a monostable internally, that pulses the reset pin low for 100us on the leading edge of DTR
    That's done for a couple of reasons - to make reset exit as fast as possible, and to reduce jitter, should someone's design want multiple-P2 sync's / restarts.

  • jmgjmg Posts: 15,140
    evanh wrote: »
    Or if that 90 ms was important for reliable operation on other platforms then an extra step would be in order...

    It may be that longer time is also related to various possible or historic Prop reset circuits ?
    Reset Pulse exit is going to be rather variable, and will depend on user designs.
    Some use differing caps in the edge drive, & even differing edges, and then there is the reset cap on the board itself....
    I've also seen reset-devices that stretch a reset pulse, so the SW needs to be somewhat tolerant to longer exit times, but flexible enough to be quick if P2 is quick.

    That's one reason I favour the multiple-tries, as those can exit as soon as P2 responds.
  • evanhevanh Posts: 15,126
    Eric,
    You've gone back to the bad code. Without putting in an extra reset pulse after the flush, the two sleeps add together making one longer sleep.

    Please use this
    void hwreset(void)
    {
        int cmd = use_rts_for_reset ? TIOCM_RTS : TIOCM_DTR;
        ioctl(hSerial, TIOCMBIS, &cmd); /* assert bit */
        msleep(2);
        ioctl(hSerial, TIOCMBIC, &cmd); /* clear bit */
        msleep(2);
        ioctl(hSerial, TIOCMBIS, &cmd); /* assert bit */
        msleep(40);
        ioctl(hSerial, TIOCMBIC, &cmd); /* clear bit */
        msleep(2);
        ioctl(hSerial, TIOCMBIS, &cmd); /* assert bit */
        tcflush(hSerial, TCIFLUSH);
    }
    
  • evanhevanh Posts: 15,126
    jmg wrote: »
    evanh wrote: »
    Or if that 90 ms was important for reliable operation on other platforms then an extra step would be in order...
    It may be that longer time is also related to various possible or historic Prop reset circuits ?
    This is not the resetting pulse itself but post reset actions. The 2 ms is for the pulse length.

    I'm pretty sure that value of 90 ms was just made as big as Dave thought was possible (100 ms causes problems). Rather than setting at least a middle value like 40 ms.

  • jmgjmg Posts: 15,140
    evanh wrote: »
    jmg wrote: »
    evanh wrote: »
    Or if that 90 ms was important for reliable operation on other platforms then an extra step would be in order...
    It may be that longer time is also related to various possible or historic Prop reset circuits ?
    This is not the resetting pulse itself but post reset actions. The 2 ms is for the pulse length.
    Yes, but the pulse the PC generates, is not always what the processor reset pin sees.
    Common is a transistor edge pulser, which has its own time constant, and that can discharge another Cap on the reset pin, giving another time constant.
    The reset exit time is the sum of those external and variable delays, plus the time the P2 take internally to exit reset.

  • evanh wrote: »
    Eric,
    You've gone back to the bad code. Without putting in an extra reset pulse after the flush, the two sleeps add together making one longer sleep.
    But your code doesn't have an extra reset pulse after the flush, it's before the ioctl(TCIFLUSH).

    And why do you think two reset pulses are necessary? What benefit would there be to resetting the P2 twice?
    Please use this
    void hwreset(void)
    {
        int cmd = use_rts_for_reset ? TIOCM_RTS : TIOCM_DTR;
        ioctl(hSerial, TIOCMBIS, &cmd); /* assert bit */
        msleep(2);
        ioctl(hSerial, TIOCMBIC, &cmd); /* clear bit */
        msleep(2);
        ioctl(hSerial, TIOCMBIS, &cmd); /* assert bit */
        msleep(40);
        ioctl(hSerial, TIOCMBIC, &cmd); /* clear bit */
        msleep(2);
        ioctl(hSerial, TIOCMBIS, &cmd); /* assert bit */
        tcflush(hSerial, TCIFLUSH);
    }
    

  • evanhevanh Posts: 15,126
    edited 2019-10-21 01:48
    Heh, sorry, my bad wording. The flush can be placed anywhere after the 40 ms sleep. Importance of the second DTR reset pulse is to eliminate, from post-reset downloading operations, this added flushing delay.

    So first reset is to stop the garbage coming at the PC's comport from the prop2. The second reset is for downloading sequence to start.

    The two resets could be combined to a single reset but that would need the "sleeptime" parameter inside hwreset() function.

    EDIT: JMG's idea of draining the comport after reset has merit but is obviously a whole other set of API calls to be understood. And will still need some timeout to ensure no late stragglers.


    EDIT2: Or you could make these steps explicit in main loadp2.c sequence.
        if (need_reset) {
            hwreset();
            msleep(50);
            hwreset();
            msleep(sleeptime);
        }
    

    If you did that then hwreset() goes back to smallest code
    void hwreset(void)
    {
        int cmd = use_rts_for_reset ? TIOCM_RTS : TIOCM_DTR;
        ioctl(hSerial, TIOCMBIS, &cmd); /* assert bit */
        msleep(2);
        ioctl(hSerial, TIOCMBIC, &cmd); /* clear bit */
        msleep(2);
        ioctl(hSerial, TIOCMBIS, &cmd); /* assert bit */
        tcflush(hSerial, TCIFLUSH);
    }
    
  • jmgjmg Posts: 15,140
    edited 2019-10-21 02:14
    ersmith wrote: »
    And why do you think two reset pulses are necessary? What benefit would there be to resetting the P2 twice?
    I wondered that too... maybe 2 pulses is a legacy of stopping a streaming P2 ?
    The Python P2 loader has this code for reset - delay between dtr is optional, but likely makes the Sw more circuit tolerant.
        sp.dtr = True  # toggle DTR Orig   - waveform ===\________/========== ~ Optional delay
    #    sleep(0.01)    # UB3 does not need any delay, as it has a monostable on DTR =\_ This delay seems to apply 10ms ~ 12ms measured 
        sp.dtr = False   
    

    The Python loader does not seem to include a flush, so it would be less tolerant of an active-P2.

    Best I think is a single reset pulse, and an early flush to empty the serial buffers.
    eg
    DTR=True,SmallDelay,DTR=False,SmallDelay,Flush, to cover all polarities of reset HW

    then either of

    Reset-exit-delay, poll P2
    or
    repeat of : Smalldelay.ReTry-Poll-P2 - this better covers variations in reset exit delay, but also exits quickly on a fast-RST-circuit p2.
  • jmgjmg Posts: 15,140
    edited 2019-10-21 02:13
    evanh wrote: »
    ... Importance of the second DTR reset pulse is to eliminate, from post-reset downloading operations, this added flushing delay.

    The UART flush should empty any errant chaff, making the two resets redundant ? ( and seems more tolerant of P2 links with large buffers and low baud rates )

  • evanhevanh Posts: 15,126
    Yes, it's for eliminating received garbage. I vaguely remember this issue coming up in the past too. At the time I didn't know what Dave did to fix it. Now I know.
  • ersmithersmith Posts: 5,900
    edited 2019-10-21 15:30
    I still don't see why 2 resets are needed. As far as I can see the sequence for restarting the P2 should be:
      reset the hardware by pulsing RTS and/or DTR
      pause for a short period
      flush input to ignore any garbage sent by P2 before reset
      start talking to the P2 ROM download code
    
    We need to nail down the exact duration for "pause for a short period" (and perhaps it's variable). But I don't see anything in there that should require a second reset.

    Are you saying that tcflush(hSerial, TCIFLUSH) is not working to flush the input, and we need an another reset + delay in its place?
  • jmgjmg Posts: 15,140
    edited 2019-10-22 02:43
    ersmith wrote: »
    I still don't see why 2 resets are needed. As far as I can see the sequence for restarting the P2 should be:
      reset the hardware by pulsing RTS and/or DTR
      pause for a short period
      flush input to ignore any garbage sent by P2 before reset
      start talking to the P2 ROM download code
    
    We need to nail down the exact duration for "pause for a short period" (and perhaps it's variable).
    The pause will be variable based on user circuits. ie if someone has an extra inversion, reset can occur on the other' DTR edge, but a short pause should be ok (a few ms),
    as the P2 will enter reset very soon after the last edge, no matter how the user wires things.

    A delay would be needed before talking to the P2, and I like the looping/retry ping approach, as that also discards garbage, & gives a safety-net, should the flush not work on any systems...
    I did check sending a series of PropVer pings, even with no delays, a while back, and that seemed to never generate unexpected chars.
    Even tho P2 can exit reset part way thru any string, the smart autobaud Chip has, looks only for '>', so it auto-syncs to that char.

  • evanhevanh Posts: 15,126
    edited 2019-10-22 02:04
    Eric,
    Yep, that's the right set of steps. However, the original code had two pauses after the reset. One before the flush and another after the flush. And that's what you've fallen back on. There is nothing wrong with having two reset pulses to hide the delay needed for flushing.


    The upper limit is 100 ms when SPI booting is enabled. That runs from RCFAST so I'd like to give it some clearance. Also, I've noticed, on Linux at least, that the milliseconds of sleep tends to run long.

    Put all that together and I'd like to hold to 50 ms as target delay for reset to first comms.

  • evanhevanh Posts: 15,126
    jmg wrote: »
    I did check sending a series of PropVer pings, even with no delays, a while back, and that seemed to never generate unexpected chars.
    The need for flushing is when the prop2 has an errant program in the SPI Flash chip spewing garbage all the time. It's not fun having to go back to the dip switches and disable the Flash chip each time this happens. And, as you've pointed out, some boards maybe not have the option for disabling the boot EEPROM.
  • jmgjmg Posts: 15,140
    evanh wrote: »
    jmg wrote: »
    I did check sending a series of PropVer pings, even with no delays, a while back, and that seemed to never generate unexpected chars.
    The need for flushing is when the prop2 has an errant program in the SPI Flash chip spewing garbage all the time.
    Understood, and I agree.
    My point was more related to early pings, where the P2 exits reset, in the middle of one of many Prop_Ver strings.
    That seems to be tolerated, because Chip's Autobaud is very specific to only trigger on the '>' char

  • evanhevanh Posts: 15,126
    edited 2019-10-22 12:15
    Uh-oh, somewhere along the line we've lost stand-alone terminal mode too. I had to revert to July's edition loadp2 to get it back.

    EDIT: I've had a look at it. Best guess is it's an auto-baud issue. The only diff in behaviour is the later loadp2's always send "> Prop_Chk 0 0 0 0 " before starting the terminal. The difference between 2 M and 115 k must be too much once set ... In fact telling loadp2 to open the terminal at 2 Mbaud makes it work.

  • @evanh, @jmg : the loadp2 discussion has been very productive and useful, but I worry that it may be lost in this thread (which is about fastspin rather than loadp2). So I'm going to open a new thread for loadp2 and we can carry on there, if you don't mind.
Sign In or Register to comment.