Prop123_A9_Prop2_v7z Intermediate Release - 25 March 2016 - USB, improved serial
cgracey
Posts: 14,152
Here is the first-pass USB for the Prop123_A9 board.
The FPGA configuration file (16 cogs, 64 smart I/O pins):
https://drive.google.com/file/d/0B9NbgkdrupkHOXpYUURlVzE2X3M/view?usp=sharing
Updated documentation (see smart pin section):
https://docs.google.com/document/d/1Os88kYoLLpd9xo43U0i54eBIhcFCBOaMG7yKZUDWGWg/edit?usp=sharing
Here is the section for USB:
Here is an example program that does full-speed USB in and out on the same smart pin:
I'm aware of a bug that when the USB smart pins come out of reset, they send an EOP. I will fix this soon. This will need some remedy during reset.
The FPGA configuration file (16 cogs, 64 smart I/O pins):
https://drive.google.com/file/d/0B9NbgkdrupkHOXpYUURlVzE2X3M/view?usp=sharing
Updated documentation (see smart pin section):
https://docs.google.com/document/d/1Os88kYoLLpd9xo43U0i54eBIhcFCBOaMG7yKZUDWGWg/edit?usp=sharing
Here is the section for USB:
%11000 = USB host, low-speed
%11001 = USB host, full-speed
%11010 = USB device, low-speed
%11011 = USB device, full-speed
This mode requires that two adjacent pins be configured together to form a USB pair, whose OUTs will be overridden to control their output states. These pins must be an even/odd pair, having only the LSB of their pin numbers different. For example: pins 0 and 1, pins 2 and 3, pins 4 and 5, etc., can form a USB pair. They can be configured via PINSETM with identical D data of %1_110xx_1. Using D data of %0_110xx_1 will disable output drive and effectively create a USB ‘sniffer’. NOTE: in the current FPGA, there are no built-in 1.5k and 15k resistors, which the final silicon smart pins will contain, so it is up to you to insert these yourself on the DP and DM lines.
The upper (odd) pin is the DP pin. This pin’s IN is raised whenever a change of status occurs in the receiver, at which point a PINGETZ can be used on the lower (even) pin to read the status word. No PINSETX/PINSETY instructions are used for this pin.
The lower (even) pin is the DM pin. This pin’s IN is raised whenever the output buffer empties, signalling that a new output byte can be written via PINSETY. PINSETX is used on this pin to set the NCO baud rate.
These DP/DM electrical designations can actually be switched by swapping low-speed and full-speed modes, due to USB’s mirrored line signalling.
To start USB, clear the DIR bits of the intended two pins and configure them each via PINSETM. Use PINSETX on the lower pin to set the baud rate, which is a 16-bit fraction of the system clock. For example, if the main clock is 80MHz and you want a 12MHz baud rate (full-speed), use 12,000,000 / 80,000,000 * $10000 = 9830. Then, set the pins’ DIR bits. You are now ready to read the receiver status via GETPINZ and set output states and send packets via SETPINY, both on the lower pin.
To affect the line states or send a packet, use PINSETY on the lower pin. Here are its D values:
0 = output IDLE - default state, float pins, except possible resistor(s) to 3.3V or GND
1 = output SE0 - drive both DP and DM low
2 = output K - drive K state onto DP and DM (opposite)
3 = output J - drive J state onto DP and DM (opposite), like IDLE, but driven
4 = output EOP - output end-of-packet: SE0, SE0, J, then IDLE
$180 = SOP - output start-of-packet, then bytes, automatic EOP when buffer runs dry
To send a packet, first do a ‘PINSETY #$180,lowerpin’. Then, after each IN rise on the lower pin, do a ‘PINSETY byte,lowerpin’ to buffer the next byte (D[31:8] are ignored for bytes). The transmitter will automatically send an EOP when you stop giving it bytes.
There are separate state machines for transmitting and receiving. Only the baud generator is common between them. The transmitter was just described, above. Below, the receiver is detailed.
At any time, a PINGETZ can be done on the lower pin to read the current status of the receiver. The upper pin’s IN will be raised whenever a change occurs in the receiver’s status. The receiver’s status bits are as follows:
[31:16] <unused> - $0000
[15:8] byte - last byte received
[7] byte toggle - cleared on SOP, toggled on each byte received
[6] error - cleared on SOP, set on bit-unstuff error, EOP SE0 > 3 bits, or SE1
[5] EOP in - cleared on SOP, set on EOP
[4] SOP in - cleared on EOP, set on SOP
[3] SE1 in (illegal) - cleared on !SE1, set on 1+ bits of SE1
[2] SE0 in (RESET) - cleared on !SE0, set on 7+ bits of SE0
[1] K in (RESUME) - cleared on !K, set on 7+ bits of K
[0] J in (IDLE) - cleared on !J, set on 7+ bits of J
The result of a PINGETZ can be bit-tested for events of interest. It can also be shifted right by 8 bits to LSB-justify the last byte received and get the byte toggle bit into C, in order to determine if you have a new byte. Assume that ‘flag’ is initially zero:SHR D,#8 WC ‘get byte into D, get toggle bit into C CMPX flag,#1 WZ ‘compare toggle bit to flag, new byte if Z IF_Z XOR flag,#1 ‘if new byte, toggle flag IF_Z <use byte> ‘if new byte, do something with it
Here is an example program that does full-speed USB in and out on the same smart pin:
' USB demo program ' - outputs incrementing values and reads them back on different cogs ' - uses P31,P30 as USB pins ' - outputs receiver status onto P15..P0 dat org 'cog0 pinsetm pm_usb,#31 'configure DP pin (passive) pinsetm pm_usb,#30 'configure DM pin (the brain) pinsetx baud,#30 'configure 12Mbps setbyte dira,#$C0,#3 'enable smart pins 31,30 pinsety #3,#30 'set J state (like IDLE, but driven) coginit #1,#@recv 'start receiver cog waitx ##1000 'allow receiver cog time to load pinsety #$180,#30 'send SOP byte (msb must be set) .wait testb ina,#30 wc 'wait for buffer emptied (lower pin) if_nc jmp #.wait pinack #30 'ack lower pin pinsety x,#30 'send byte add x,#1 'increment byte jmp #.wait 'loop pm_usb long %1_11011_1 'USB device, full-speed baud long 9830 '12Mbps @80MHz x long 0 'output value org 'cog1 recv mov dira,##$FFFF 'enable output on p15..p0 .wait testb ina,#31 wc 'wait for byte received (upper pin) if_nc jmp #.wait pinack #31 'ack upper pin pingetz outa,#30 'get status into p15..p0 jmp #.wait 'loop
I'm aware of a bug that when the USB smart pins come out of reset, they send an EOP. I will fix this soon. This will need some remedy during reset.
Comments
Thanks Chip
I wish it was trivial to make more compilations for different boards, but this is the quick way to get these changes out. Once we have more confidence in this design, I'll do a general release and cover the DE0-Nano, etc.
BTW. I had success today getting sync. tx working @ 40M bits thru a FT2232H module... Cool!
I wonder how good setup and hold are. That's fast!
Why do the INs not match the OUTs?
How soon can you do a de-nano or bemicrocv version?
Personal preference is a de-nano since I haven't used the BeMicroCV at all.
The IN's are the INA P30/P31 states (Buffer empty / Status) and the OUT's are the actual smartpin P30/P31 pin states.
Got some stats on that ? - what is the sustained thruput / equiv number of stop bits ?
Did you use Async + Separate CLK, or Sync ?
384k x 11 bits (1 start,8 data,1 source & 1 stop) takes 108.13mS.
I has a few attempts in async mode with a clock but had no joy.
So that is manual Start of Clock, and then TX in Sync Slave mode (external Supplied Clock) ?
Did this test the handshake line ?
The transition pin is loaded with a transition count of 384 * 1024 * 11 *2
The exact amount of clocks for the block size. No extra stop bits are added.
One continual stream of bits @ 40MHz of block length. No handshaking.
FT2232H is in Fast Serial mode and still using VCP mode at the PC end.
in this mode no baud rate setting is required in the PC.
i.e. PST works at baud rates greater than the 3000000 limit.
Interesting, I wonder when the FT2232 needs handshake ?
Maybe a smaller USB buffer in the PC would generate a handshake ?
The clock counts should not actually matter ie >= as the FT2232H will idle and skip clocks at stop.
There will be some systems (different HW) that need a certain number of CLKs per byte, and a handshake.
If you recode to Test handshake and send >= 11 bits per byte, what does that slow to ?
(my guess is the FT2232H needs a CLK to update the handshake, so a continual CLK would also work)
I believe that the smart pin is pretty much complete after this reset fix. There is room for four more modes, but I think I will fill them by just adding modes to the existing function blocks. Any simple suggestions? Maybe some time-this-signal-to-that-signal kind of functions? This would just entail adding a bit of steering logic to the existing measuring block, for example.
Yes, Time-interval A-B is a common and useful requirement.
Also being able to start/stop two cells on the same SysCLK edge, is also useful for Reciprocal Counters:
One cell Captures time on every edge, the other captures EdgeTotals, and you need to be able to gate/arm both those captures, so that the two values read, are guaranteed to belong the the same Fin edge.
I think SW enable alone cannot do that - it always has some annoying, finite aperture effect ?
Here is an example Once/OneShot is needed, as the reads of N and T are separated, and you do not want a new update in one, after the other is read.
In case you miss it in the other post, is there a need to have both TX/RX modes and an output enable? Could you simplify it to simply synchronous and asynchronous modes, then use the %D field to indicate whether you are doing TX or RX? I realize this would actually increase the number of empty slots, but having both the modes and %D seem a bit redundant.
That may have too much latency vs a more direct OE ?
Just keep the spare bits for perhaps a later extension. For now, all bases seem to covered quite well.
I'm not quite sure I'm following. In case I've explained the situation badly, take a look at the following:
You will notice that the Output Enable is on (1) for TX and off for (0) for RX. I don't see a use case for disabling output for TX or enabling output for RX. Conversely, allowing the combinations can cause some hard-to-find bugs.
In the attached image you will see I send 6 packets and then the shifter repeats the last packet.
Filling the shifter with all 1's (PINSETY ##-1,#pin) after the last PINSETY gets around this issue.
As for handshaking, the fast serial mode only has FSDO,FSDI,FSCLK an FSCTS pins available,
In my Tx only test FSCTS is not relevant.
If output is enabled the smartpin does not operate.
Maybe the lower bit of %MMMMM could become the OE control?
For example, JTAG is 2 bit for the TMS state engine part, but can be 1 bit SPI for most of the data.
Here someone may bit-bash the 2 bit part, and use 1 bit (+ Length) control for data.
In this case easy change over from SW to HW modes is beneficial.
Extracting special cases of OE, can take more logic, and it is reasonably common in MCUs to require Port-mode setups
(eg CMOS or Open Drain, and Pullup on/off, so OE is just another pin-mode instance)
IIRC, you said you were unable to get Async to work ?
Other MCUs can Async send at up to SysCLK/2, but do impose lower limits on Rx, for the sampling.
I thought you were sending Data P2 -> PC direction ?
FT2232H Data says this
" 4.8.2 Incoming Fast Serial Data
An external device is allowed to send data into the FT2232H if FSCTS is high."
ie FSCTS is handshake for P2 -> FT2232H direction ?
For other direction handshake from FT2232H -> P2, they expect you to Pause the FSCLK generation in P2.
It's impressive the FT2232H seems to not need the handshake, at least in your tests.
I wonder when the FT2232H does require the Sending device to wait ?
Confirming P2 -> PC is test data direction.
As long as CTS is high before you start transmission the process zooms along nicely.
As soon as transmission starts CTS is pulled low by FT2232H and remains low for the duration of the transmission.
Polling CTS during transmission would appear to be meaningless.
If polling was necessary during transmission this would limit my max speed of 40M bits as my tx SW loop is as tight as possible now .
If you read deliberately slowly at at PC end, does that force longer lows on FSCTS ?
On some systems, handshake support will be required.
If you do add a WAIT line, what does that add in time ?
Quadrature output from clock?
Err, or does NCO already use the counter?
I still don't see what you are getting at. Suppose you were to keep the separate OE bit for those modes. You still have to call PINSETM to enable/disable the OE. At that point, how different would this be than simply turning the smart cell off altogether (i.e. PINSETM #1) when you want to disable? In fact, it seems this is exactly the approach you'd want to take for switching between HW and SW serial.
It seems to me that the only reason OE would be useful is if it was actually controlling the pin output, but not the internal output state. In this case, you could conceivably still use the output of one smart cell for the input to another smart cell without actually outputting the first cell's value on a physical pin.
Actually, now that I think about it, why have the OE bit at all? In every one of the smart modes listed, it's clear that the input or output is determined by the mode. And, for output modes, it seems to me that setting/clearing DIR achieves the same purpose as OE, without the need to call PINSETM (which is 10 clocks, as opposed to 2 clocks for DIR).
So... here's my proposal:
If options 2 and 3 add too much logic, just get rid of the OE bit altogether. I'm sure Chip can come up with a use for that extra bit.