Using WAITPEQ with WR Effect & 5v I/O

feilipufeilipu Posts: 12
edited 2020-11-19 - 23:39:02 in Propeller 1
I'm trying to respond to a Z80 bus running at 7.3728MHz, using the WAITPEQ instruction.

Based off the apparent timing, I have less than 180ns to lower the /WAIT line, after receiving the correct match for /IORQ and Address lines.
But, I'm missing the window. See attached image.

Currently, I'm using WAITPEQ in the normal way, and then following the match with a ANDN instruction to lower the /WAIT line.
                        waitpeq port_base_addr,port_active_mask  ' wait until we see our addresses, together with /IORQ low
                        andn    outa,bus_wait                    ' set /WAIT line to active

But that is too slow, as evidenced by the traces.

What I hoped would work is to set outa to be the matching port_base_address values, and use the WR effect to change the /WAIT line as a side effect.
The /WAIT line is already set to output in the dira register, but all other pins are set to inputs.
My hope was that this would affect the outa register correctly, and allow me to hit the timing window.
                        or      outa,port_base_addr       ' configure the base address to compare with ina
                                                          ' use wr effect to set /WAIT low (/INT gets hit as side effect)
                        waitpeq outa,port_active_mask wr  ' wait until we see our addresses, together with /IORQ low

I had hoped that all 32 bits of outa would be written, and therefore hit the /WAIT as a side effect.
But, this doesn't seem to trigger the /WAIT line at all.

Is this kind of behaviour expected? Is it supported?
Would there be a better way to achieve this outcome?

Any suggestions gratefully accepted.

Cheers, Phillip

Comments

  • The waitpeq with wr effect is a bit tricky, it effectively turns the waitpeq instruction to an add, the result is then OUTA = OUTA + port_active_mask, so the final result depends on how the port_base_addr and port_active_mask bits are set.

    Here is an example from my VGA Inteface firmware:
    loop                    mov     OUTA,bus_trigger
                            waitpne OUTA,bus_mask
                            waitpeq OUTA,bus_mask      wr 'asserts wait line immediately
    
                            '               W                    I
                            '               A                    O
                            '            MRWI                   AR
                            '            1DRT                   0Q
                            '        ----|||| +-VGA--+ +-DBx--+ ||------
    dir_mask                long    %00000001_00000000_00000000_00000000
    
    bus_trigger             long    %00001000_00000000_00000000_00000000
    bus_mask                long    %00001001_00000000_00000000_01000000
    

    P24 is connected to the Z80 WAIT line. The bus_trigger sets P24 to 0 releasing the Z80, when waitpeq triggers it adds its value to OUTA so P24 turns 1 holding the Z80 WAIT line.

    I must add that my board uses a NPN transistor to drive the Z80 WAIT line, so WAIT is asserted when the pin is 1. To do the opposite you need to set the bit to 1 on both values so the add will "shift" to the upper bit (make sure that the resulting bits don't conflict with anything connected to the pins).
  • Thanks Marco.

    So it is a PLUS function that I’ll have to prepare, rather than an AND function (as the data sheet suggests). I’ll try to digest an answer that works in my morning.

    /WAIT is on P24 and /INT is on P25. So with a bit of luck I may be able to hit both of them with one go.

    Cheers, Phillip
  • feilipu wrote: »
    So it is a PLUS function that I’ll have to prepare, rather than an AND function (as the data sheet suggests). I’ll try to digest an answer that works in my morning.

    Not exactly, I wasn't clear on that, the waitpeq function alone works as the datasheet explains, it is the wr effect that differs from the usual and causes the result (destination register) to be an ADD rather than a copy. So to trigger the waitpeq follow the datasheet with the and mask, bit status, etc. to calculate the OUTA status use the add function.
  • feilipufeilipu Posts: 12
    edited 2020-11-16 - 04:50:33
    Hmm... this is quite interesting.

    I have the code working as expected, but I'm still not hitting the timing window.
    wait_addr               mov     outa,port_base_addr     ' configure the base address to compare with ina
                                                            ' use wr effect to set /WAIT low (/INT gets hit as side effect)
                            waitpne outa,port_active_mask
                            waitpeq outa,port_active_mask wr' wait until we see our addresses, together with /IORQ low
                            or      outa,bus_int            ' clear /INT now we're processing it (and it would have been
                                                            ' set by the waitpeq outa previously)
    
                            test    port_base_addr,ina wz   ' isolate the base address
                if_nz       jmp     #handler_data           ' handle data, otherwise fall through for handling command/status at base address
    
                            test    bus_rd,ina         wz   ' capture port data again, test for RD pin low
                if_z        jmp     #transmit_status
    
                            test    bus_wr,ina         wz   ' capture port data again, test for WR pin low
                if_z        jmp     #receive_command
    
                            or      outa,bus_wait           ' set /WAIT line high to continue
                            andn    acia_status,acia_status_int  ' clear the interrupt status bit
                            jmp     #wait_addr              ' then go back and wait for next address chance
    
    handler_data            andn    acia_status,acia_status_int  ' clear the interrupt status bit
                            test    bus_rd,ina         wz   ' capture port data again, test for RD pin low
                if_z        jmp     #transmit_data
    
                            test    bus_wr,ina         wz   ' capture port data again, test for WR pin low
                if_z        jmp     #receive_data
    
                            or      outa,bus_wait           ' set /WAIT line high to continue
                            jmp     #wait_addr
    

    The /WAIT signal has a nice sharp edge (yellow), at about 200ns after the base address match (blue). This is too late. The window is about 180ns.

    wait%40PLL16.bmp

    I had a thought that since I was overclocking the Propeller that something bad was happening, so I've tested with reduced PLL 8x and 4x. The only result there is that the /WAIT line takes longer to be triggered, scaling out to about 240ns. So it is not overclocking messing things up.

    So this result is not what I expected at all.
    I would have thought that it would take 6+ cyles or no more than 50-60ns to trigger /WAIT. Not 200ns.

    Any thoughts as to what is happening?

    Cheers, Phillip
  • Hi @macca,
    would you be able to check the actual response time for waitpeq on your VGA board, please?

    I've been playing around with variations on this waitpeq code now for 3 days, and the best response I can get is 204ns.

    As far as I understand the waitpeq instruction should be done in 6+ cycles. I'm expecting this to be about 50ns.
    Even if for some reason it was double this (100ns), things would still be acceptable.

    I've also tried active loops like this... but this doesn't go any faster.
    wait          test bus_iorq,ina wz 
           if_z   andn outa,bus_wait
           if_nz  jmp #wait
    

    Is there an inherent penalty in using the wr effect, which slows the waitpeq instruction down?

    Any other thoughts on this issue?

    Regards, Phillip
  • Unfortunately my BitScope micro disappeared so I can't do anything until it decides to reappear.

    In the meantime, all I can say is that I had similar problems caused by the driving circuits. For example, the pull-down on the OR diodes caused delays if too high, I'm using 1k resistors to reduce the delays. I also had to use a faster PN2222A transisor to drive the WAIT line with a 150 ohm series resistor to make it switching fast. Should not matter much with the Z80 at 7 MHz but I had to do these changes to run the interface on the Z180 at 18MHz (SC111 + RomWBW).

    My suggestion is to check the circuits first. I tend to exclude problems with the propeller itself but try to use another chip and maybe try with the standard 80MHz clock for now just to avoid issues with overclocking.
  • maccamacca Posts: 260
    edited 2020-11-18 - 09:23:16
    Unfortunately my BitScope micro disappeared so I can't do anything until it decides to reappear.

    Which of course occurred 10 minutes after posting the message...

    Here is a screenshot of the timings:

    vga_interface_timing.png

    The BitScope may not be very precise but the WAIT line triggers about 100nS after the address decoding conditions, the IOREQ probe is at the junction of the OR diodes, the M1 probe at the junction of the AND diodes, and the WAIT probe at the Z80 WAIT line, so this should include any delay introduced by the driving circuits.
    555 x 475 - 20K
  • feilipufeilipu Posts: 12
    edited 2020-11-19 - 07:09:13
    Hi @macca,

    Yes. You've nailed it. I will have to revise all of the bus I/O solution. The advice to use 4k7 Ohm series resistors does not work in this instance. I'll have to come up with a more robust 5v to 3v3 solution.

    In the screenshot below, the blue trace (2) is the bus IORQ pin. On the Propeller side of the series resistor it is marked in yellow (1). The external trigger (T) is when the Propeller issues /WAIT, about 260ns after the bus /IORQ signal.

    iorq%40PLL16.bmp

    It is easy to see (now) that the Propellor input doesn't see the IORQ input pin go "low" until about 50ns before the /WAIT is triggered (as it should be).

    Bad that I'll have to change the hardware, but good to know where the problem is at.

    EDIT: I've used 1nF capacitors in parallel with the 4k7 Ohm signal input resistors, as well as in parallel to the /INT and /WAIT output diodes.
    This produces a much cleaner (sharper) waveform, and reduces the delay to 41ns.
    Still to see whether the data I/O needs adjustment by reducing the series resistor values, or adding parallel capacitance.

    iorq_cap%40PLL16.bmp

    FURTHER EDIT: Reduced the data bus resistors to 2k2, as they have the most time to settle.
    And also adjusted the ORed address bus lines. Hopefully, now I can put away the iron and get back to making the code work.

    Cheers, Phillip
  • feilipu wrote: »
    FURTHER EDIT: Reduced the data bus resistors to 2k2, as they have the most time to settle.
    And also adjusted the ORed address bus lines. Hopefully, now I can put away the iron and get back to making the code work.

    Careful with that, better you read this first:

    https://www.parallax.com/package/an010-low-cost-bidirectional-mixed-voltage-interfacing/

    A too low series resistor may damage the pin, and as far as I can tell, the series resistor on the data bus doesn't introduce any significant delay, there is plenty of time to read the data from the Z80, and when writing to the bus the Z80 is in wait mode and there is still much time for the bits to settle.

    There is a discussion somwhere on the forum about interfacing a 5 volt device with the Propeller,
    https://forums.parallax.com/discussion/85474/how-to-safely-interface-a-5v-signal-to-the-propeller-see-post-reply-104
  • Using the math from the appnote, (5V - 3.3V) / 0.0005A = 3400Ω

    Since there's some inherent resistance and the high logic level is usually a little less than 5V, 3.3kΩ is the lowest allowed resistor. However, I think it has been said that in practice the protection diodes can sink quite a bit more current than 500µA, especially if you're not stressing them in every pin. It's probably still best not to tempt your luck if it can be at all avoided.
  • feilipufeilipu Posts: 12
    edited 2020-11-20 - 00:53:29
    macca wrote: »
    There is a discussion somwhere on the forum about interfacing a 5 volt device with the Propeller,
    https://forums.parallax.com/discussion/85474/how-to-safely-interface-a-5v-signal-to-the-propeller-see-post-reply-104

    Yes, I saw forum post above, and read it through. It was the post by @javer that reminded me (electronics 101) to use a serial capacitor.
    My selection of a 1nF capacitor was based on components to hand, but it seems to work well.

    I tend to buy components on a project to project basis, so I unfortunately don't keep a stock of 3k3 Ohm resistors. So paralleling up 4k7 resistors for the data bus was a nearest option. I'd use 3k3 Ohm if I had some components.
    IMHO, the data lines do need to be improved from standard 4k7 Ohm solution though. I checked with the scope and they barely settle in time on the input side, and I'm not sure that the bus side was fully settled when swapped to use Propeller output.

    The "gold standard" may be to use serial capacitors paralleled with 3k3 Ohm serial resistors. But, the board is too small to fit the extra capacitors on every line. Choices are 1) stand up the resistors so they use less board space, but this is a bit ugly, 2) move to SMD for the I/O solution, but this will make it more difficult for other people to build it, or 3) find resistor and capacitor packs that would do the job with less real estate, but this means specialist components. Still mulling over the right way to go here.

    Anyway, I think (hope) there are no more hardware impediments to making the code work now.
  • feilipu wrote: »
    1) stand up the resistors so they use less board space, but this is a bit ugly, [...] or 3) find resistor and capacitor packs that would do the job with less real estate, but this means specialist components.

    The footprint for a SIP parallel resistor array also allows the ugly vertical resistors. So someone building it could pick their poison...

    You can also get SIP capacitor arrays, but they're hella expensive. The usual ceramic cap footprint is probably small enough to still fit with 0.1" pitch (for easy paralleling with the resistor array), maybe if rotated a little.
  • You can also get SIP capacitor arrays, but they're hella expensive.

    Yes, I agree They seem to be pretty much unobtainable.
    I was looking at the Bourn series, but they were obsoleted and nowhere seems to carry them as NOS.

    So, in the end I decided to go with big SMD, and to use only two components to make the build a good starter kit for someone who wants to get started in SMD.
    Just two component types, non-polarised. Resistors on the front, capacitors on the back.
    Hopefully, keeping it relatively simple.


    RC2014_UX_MODULE_BRD.png

    The interface code is working great now. Here's the repository for anyone following along.
    UX Module for RC2014.

    Cheers, Phillip
Sign In or Register to comment.