Previous journal: | Next journal: |
---|---|
0162-2023-10-20.md | 0164-2023-10-23.md |
- Created
qspi
branch ontt05-vga-spi-rom
to try tackling QSPI.- I included a
vga_mode
option for selecting between 640x480@60Hz and 1440x900@60Hz timing. Ideal clock for this (at least for my testing) is ~26.6175MHz, because in Mode 1 this gets very clear 1440x900@60, and in Mode 0 it still works OK as 640x480@63. - I ended up using 26.6175MHz (actually 26.620370MHz is nearest the PLL can get) in the repo.
- Merged vga_mode stuff from the qspi branch into main and tagged it 0.2 -- new update to my TT05 submission #192.
- I included a
- Worked out how I'm going to do QSPI (see TL;DR).
- Implemented basic SPI
io[3:0]
with direction switch forio[0]
(MOSI). - Proved my chip still works with it.
- Test whether SPI MOSI/MISO still work with 1kΩ resistors in series. I'd like to include these for safety, at least in the early stages.
- Get QSPI reads working in tt05-vga-spi-rom
- Add QSPI reads to raybox-zero
- Use ~500Ω inline with MOSI to provide basic protection; it's the only pin that really needs to switch between output/input. I'm using 540Ω which will limit 3.3V to ~6mA if there's a short/contention.
- For Winbond W25Q and Renesas AT25SF chips (and maybe others; seems to work with 'BergMicro' BG25Q80A), just program QE to be set (non-volatile), and then quad mode is always able to be used.
- This in turn means we don't have to worry about /WP and /HOLD.
- Overall this should just simplify our design logic to:
- Pre-program the chip to set QE bit. Then, in the design...
- (Optional): Send AB (release power-down)
- Assert /CS and send 6B
- Send 24 address bits
- Switch our design to quad inputs, and send 8 dummy clocks
- Read quad data:
io[3:0]
getsD[7:4]
first, thenD[3:0]
next. - Read as many bytes as needed.
- Release /CS when done.
- 1 clock later, switch back to single-SPI mode (i.e. reassert MOSI as an output, when we know the chip should've gone HiZ).
- MOSI seems to work OK with an inline 1kΩ resistor for protection. When testing with my FPGA, I might drop this to 470Ω or something
- In order to do any quad reads or other quad I/O, Winbond W25Q and Renesas AT25SF devices both need the QE bit set in WSR2.
- QE will take a volatile setting (until POR or system reset) by issuing command 50h (volatile WSR enable), then issuing command 31h (WSR2) with data 02h. This works for both the Renesas chips (verified) and supposedly also the Winbond chips.
- However, there is a better way. That is to write QE into WSR2 as a non-volatile setting: issue command 06h (Write Enable), then issue command 31h with data 02h (as above). Then 5~30ms later1 it should be written as a non-volatile setting.
- This should be an acceptable/dependable/repeatable way to ensure the QE bit remains in effect when used with our target design (host controller), without needing extra logic to do command 50h or 06h.
- The other important advantage is that it should prevent /HOLD2 from mucking us around:
When the QE bit of Status Register 2 is 1, quad-SPI communication is enabled, and the pin is used as 1/0 pin 103 in any command that makes use of quad-SPI. In this setting, do not use the pin for pausing communication.
- If our design can do so, it might be a good idea to ensure that our design asserts /HOLD with a high value when we're not otherwise using it as an output from the SPI memory, just to be sure it won't be interpreted by the memory as a valid hold signal.
- /WP shouldn't be a problem if just connected as an I/O to our design: It's internally pulled high, it only takes effect if SRP1 and SRP0 have been explicitly configured to use it (which is not the factory default), and according to the datasheet this function should be disabled when QE is set:
When the Quad Enable (QE) bit of Status Register 2 is 1, quad-SPI communication is enabled, and the pin is used as 1/0 pin 102 in any command that makes use of quad-SPI. In this setting, do not use the pin for write-protection.
- I've found that my Renesas AT25SF081B and mystery Berg Micro BG25Q80A both support 16-bit WSR1 (command 01) writes that can set/clear QE, including non-volatile (command 06) and volatile (command 50). According to the Winbond doco, that should all work too for W25Q series.
- Get rid of existing /WP and /HOLD resistors (they have internal pullups).
- Test tt05vsr as-is with 1kΩ resistor inline with MOSI (and optionally MISO; good if we want to try full Quad I/O later). SEEMS GOOD with 1k on MOSI; data looks right, I think. NO GOOD with 1k on MISO: creates a delayed and unstable data read signal, maybe because of bad rise time? 270R seems to do OK on MISO; makes it a tiny bit mucky, but seems valid. We can ignore it for now, anyway.
- Verify QE non-volatile behaviour:
- Use Bus Pirate to manually read each of BG25Q80 and AT25SF081B.
- BP read SR1 (command 05)
- BP read SR2 (command 35)
- BP set WEN (06)
- BP read SR1 again
- BP set QE: WSR2 (31) + 02 (QE bit asserted).
- BP read SR1 again; check for changes, esp. for WIP.
- BP read SR2 again; prove QE is set.
- Power-cycle the chip.
- Read SR1&2 again: Is QE permanently set?
Connect to Bus Pirate terminal: picocom -b 115200 /dev/ttyUSB0
- Hit enter, expect
HiZ>
prompt. m5
for SPI mode.- ENTER after each of: 4 1 2 1 2 2
W
(capital) to turn on power- Read MFR/DEV ID:
[0x9F r:3]
:SPI>[0x9F r:3] /CS ENABLED WRITE: 0x9F READ: 0x1F 0x85 0x01 /CS DISABLED SPI>
- MFR: 0x1F
- DEV: 0x8501
- This is consistent with what the datasheet says we should get for AT25SF081B.
- Exit picocom: CTRL+A then CTRL+X
- Read MFR/DEV ID:
[0x9F r:3]
-- got back 1F 85 01, which is correct. - Read SR1:
[0x05 r:3]
-- got back 00 00 00, which is to be expected. - Read SR2:
[0x35 r:3]
-- got back 00 00 00, also to be expected. - Issue WEN:
[0x06]
- Read SR1 again -- got back 02 02 02; good, WEL bit now set.
- Issue Write Disable:
[0x04]
- Read SR1 again -- got back 00 00 00; good, WEL bit now clear.
- Try WSR2 with WEL disabled, to turn on QE bit, then immediately read SR1 and SR2:
[0x31 0x02][0x05 r][0x35 r]
-- expected to not have any effect, and this is what happens: We get back 00 00 (for both SRs). - Issue "Write Enable for Volatile Status Register (50h)":
[0x50]
- Again try WSR2, in volatile mode, to turn on QE bit, then immediately read SR1 and SR2:
[0x31 0x02][0x05 r][0x35 r]
-- oh, it worked, despite the AT25SF081B datasheet implying 50h pairs with only 01h. We go back 00 (SR1) and 02 (SR2), showing QE bit enabled. - Clear volatile QE:
[0x50][0x31 0][0x05 r][0x35 r]
-- expect final result to be 0x00 - Set it again:
[0x50][0x31 0x02][0x05 r][0x35 r]
-- expect final 0x02 - Prove that it cannot be cleared without command 50:
[0x31 0][0x05 r][0x35 r]
-- expect final still 0x02 - Clear it again.
- Now we'll write non-volatile QE, but also toggle /CS and read a stream of SR1 for WIP bit. NOTE: Datasheet says
tWRSR
(Write Status Register Time) is typically 5ms and as much as 30ms. HUGE time!-
I ran this:
[0x06][0x31 0x02][0x05 r:10][0x35 r:10][0x05 r:10 &:100 r &:500 r% r% r% r% r% r% r%:5 r%:10 r%:10 r%:100 r][0x35 r:10]
-
The result seems to be immediate!
/CS ENABLED WRITE: 0x06 /CS DISABLED /CS ENABLED WRITE: 0x31 WRITE: 0x02 /CS DISABLED /CS ENABLED WRITE: 0x05 READ: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 /CS DISABLED /CS ENABLED WRITE: 0x35 READ: 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 /CS DISABLED ...
For reference the crucial parts are where the BUSY bit (0) is never set in WSR1 (read with command 05), and command 35 returns that the QE bit is set (0x02). I confirmed that the QE bit was not previously set, so I trust that this worked.
-
- I turned off the power supplies with lowercase
w
. WARNING: There still seems to be an issue in the BP or something where turning off power supplies still leaves MOSI and CS asserted, but as a result they're still 'leaking' power into the chip that can be seen withv
-- To get around this, I drove /CS low with[
and checkedv
: It fell from 2.61V to 2.41V. Now how to get MOSI low?_
doesn't do it. Hmm... Ah,0;1
should do: Write one0
bit. Yes...v
confirms. Power LED is now off too. - Turn the chip back on with
W
- Read QE:
[0x35 r:3]
-- BP BUG: Still only using;1
(single-bit) mode. Get back to normal with0x35;8
- Prove we're stable with
[0x9F r:3]
- Read QE:
[0x35 r:3]
-- Yep, we get 02 02 02 back. QE still asserted. - VOLATILE write to disable QE:
[0x50][0x31 0][0x35 r:3]
-- yep, returns 00 00 00. - Power off:
[0x00]w[
- Unplug the chip, then unplug the BP.
- Replug the BP, plug in the chip.
- Go back into terminal and repeat steps 1..5 from "Preparing" above.
- Read QE:
[0x35 r:3]
-- yep, QE has stuck around; returns 02 02 02 - OH! I discovered this sequence works too (for example):
- Set QE (volatile):
[0x50][0x01 0 2][0x35 r]
- Clear QE (volatile):
[0x50][0x01 0 0][0x35 r]
- ...not documented? i.e. 16-bit WSR1.
- Set QE (volatile):
- Do steps 1..5 from "Preparing" above. Oddly, on the first try it didn't give a valid response to command 9F. On a retry it gave E0 40 14.
- Read SR1:
[0x05 r:3]
-- got back 00 00 00. OK. - Read SR2:
[0x35 r:3]
-- got back 00 00 00. Not sure if that worked or not. I'll trust it. - Issue WEN:
[0x06]
- Read SR1 again -- got back 02 02 02; good, WEL bit now set.
- Issue Write Disable:
[0x04]
- Read SR1 again -- got back 00 00 00; good, WEL bit now clear.
[0x31 0x02][0x05 r][0x35 r]
-- no effect, as expected.- Issue "Write Enable for Volatile Status Register (50h)":
[0x50]
-- then[0x31 0x02][0x05 r][0x35 r]
-- didn't work; just returned 00 still for WSR2. - Try programming QE to be set:
[0x06][0x31 0x02][0x05 r:10][0x35 r:10][0x05 r:10 &:100 r &:500 r% r% r% r% r% r% r%:5 r%:10 r%:10 r%:100 r][0x35 r:10]
-- that didn't work either; how does the ESP8266 do quad reads from this chip?? Might be worth investigating. - Try doing it using a 16-bit WSR1:
[0x06][0x01 0x00 0x02][0x05 r:10][0x35 r:10][0x05 r:10 &:100 r &:500 r% r% r% r% r% r% r%:5 r%:10 r%:10 r%:100 r][0x35 r:10]
-- that DID work - Power off the chip:
[0x00]w[
- Unplug/replug the chip
- Power on:
W
- Test MFR/DEV:
[0x9F r:3]
-- again, didn't work until 2nd try. Maybe it's because /CS starts off low? [0x35 r]
-- oh, it wasn't retained. Weird. By design maybe?- Huh, how about that. This works:
[0x50][0x01 0x00 0x02][0x35 r]
- Power off like this, now:
[0x00]w
--v
still shows 1.9V because of high /CS, but oh well. - Unplug/replug the chip, then
W
[0x9F r:3]
[0x35 r:3]
-- 00 00 00 (QE clear)[0x50][0x01 0x00 0x02][0x35 r]
-- 02 (QE set)[0x50][0x01 0x00 0x00][0x35 r]
-- 00 (QE clear)[0x06][0x01 0x00 0x02][0x35 r]
-- 02 (QE set)- Hot unplug/replug
[0x9F r:3]
-- E0 40 14[0x35 r]
-- 02 (QE SET still??)- Power off:
[0x00]w
- Unplug/replug
- Power on:
W
[0x9F r:3]
-- E0 40 14[0x35 r]
-- 02 (QE still retained)
OK, I must've been making a mistake last time it appeared to clear. Let's assume that with all 3 chips (AT25SF081B and BG25Q80 verified, W25Q unverified) we can pre-write QE bit to be on.
Working in tt05-vga-spi-rom (tt05vsr), let's start with a naive approach to switch to QSPI read command 6Bh half-way down the screen, without any setup...
We must make sure we tristate MOSI!
Test whether SPI MOSI/MISO still work with 1kΩ resistors in series. I'd like to include these for safety, at least in the early stages.
I'll use my "known good" AT25SF081B that I got from DigiKey because its datasheet and behaviour should be proven.
Tholin's QSPI method (using command EBh) targets Winbond W25Qxxx chips (in particular, W25Q128JVxIM).
The W25Q128JVxIM datasheet states:
Quad SPI instructions require the non-volatile Quad Enable bit (QE) in Status Register-2 to be set. When QE=1, the /WP pin becomes IO2 and /HOLD pin becomes IO3.
"Non-volatile", hey? Hmm.
How is QPI different from Quad SPI and Quad I/O?? This suggests that Quad SPI is 1-1-4, Quad I/O is 1-4-4, and QPI is 4-4-4 (and QPI has its own dedicated mode via command 38h that is issued as well as having to enable QE beforehand). OH, here we go, in section 6.1.4.
Anyway, Tholin's method seems to do this:
- Send FF: stop continuous, if active?? When doing so, it also drives io2+3 high (which would disable /WP and /HOLD if in effect, but could also be risky if the SPI chip is already driving them).
- Send AB: relase from power-down, if in effect
- Send 06: WEN (Write Enable)
- Send 01: Write Status Register, followed by 02 (simply WEL; no effect because it's R/O), then by 02 again (QE<=1 in this case).
- Send EB: Quad I/O Fast Read. Then chip goes into quad input; send it address 000000h followed by A5h mode (actually it just seems like bits
--10----
are the only ones that matter, and they specify continuous mode). After another 4 dummy clocks, it then does 2 more clocks to read the first byte.
I think I've learned the following:
- Quad SPI means 1-1-4 (command and address are both single-width transfers, then data read from memory is quad-width).
- Quad I/O means 1-4-4 (address becomes quad-width transfer, also).
- QPI means command becomes quad-width too?
- Not all devices support all modes. First two (Quad SPI and Quad I/O) are common for any advertised "quad" (or "Q") devices, though?
- Some devices provide separate WSR (Write Status Register) commands, e.g. Send 01 to write to SR1, send 31 to write to SR2.
- Some devices allow WSR to be written as either 8 bits (SR1 only) or 16 bits (SR1+SR2) just via the standard 01 command.
- For at least the Winbond W25Q128JV, the 01 command can be used to write 8 or 16 SR bits (SR1&2; see section 8.2.5), while it also provides WSR2 (command 31) and even WSR3 (command 11).
- In any case, as a safety measure, datasheets say "/CS must be driven high after clocking in the 8th SR bit, or the whole write becomes invalid" and sometimes they add "or 16th SR bit" in cases where the device supports this in a single long write via command 01. Hmm, does this invalidation include SCLK falling, or just an extra SCLK rising edge? Datasheet diagrams imply that falling SCLK is OK. Given our /CS driver would go high on our system clock rising edge, this represents the SCLK falling edge, so that should be OK with no possible contention period...?
- WSR is described usually as being a delayed process that must be polled (via WIP "Write In Progress" status bit). The Winbond datasheet even calls it a "non-volatile" write. Really?
- I'm starting to think that the QE bit must (should?) be programmed in rather than simply set at runtime.
- Some devices provide command 50 ("Write volatile Status Register") that allow for immediate and temporary (as opposed to "non-volatile") setting of the Status Register. Command 50 must be issued before WSR. The AT25SF081B datasheet implies that this only works for command 01, but maybe it does for command 31 (SR2) also? If not, we'd be stuck!
- The WEL bit ("Write Enable Latch") in SR1 is set by command 06, and cleared after successful completion of a write command, including WSR.
- W25Q128JV needs four dummy bytes for command 6B?? Oh, actually, not really... it looks like it needs 8 clocks for the command, 24 for address, then 8 dummy, then data starts. Preamble: 40 clocks. By comparison, command EB needs 8 for command (assuming not in continuous mode), 6 for the address, 2 for mode, and 4 for dummy, then data starts. Preamble: 20 clocks.
- Make it so the VGA timing parameters in
vga_sync.v
are just registers that only update at the end of a frame. - Consider replacing
spiflash
with the Winbond model that Tholin used. - Compare SPI flash ROM datasheets re Quad Enable (QE bit)
-
From a 50MHz clock source, DE0-Nano PLL can hit 25.170068MHz... not exactly 25.1750MHz.
-
25.170MHz clock source (as above):
- Mode 0: 640x480@60, i.e. 25,170,000/800/525 ~= 59.93Hz
- Mode 1: 1152x870@57 syncs on my HP L1908wm monitor
-
26.620370MHz (nearest the PLL can get to 26.61750MHz):
- Mode 0: 640x480@63 works fine
- Mode 1: 1440x900@60 works fine. Very clear.
-
26.5MHz:
- Mode 0: 640x480@63 works fine
- Mode 1: 1440x900@60
-
26.3MHz:
- Mode 0: 640x480@63 works fine
- Mode 1: 1440x900@59
-
26.0MHz:
- Mode 0: 640x480@63 works fine
- Mode 1: 1152x870@59
-
25.0MHz:
- Mode 0: 640x480@59??
- Mode 1: 1152x870@56
-
24.750MHz: NOTE: This frequency matches 800x600@75-div-2
- Mode 0: 640x480@59 works fine as above.
- Mode 1: 1152x870@56
-
24.0MHz:
- Mode 0: 640x480@57, direct MISO is delayed by 1 pixel.
- Mode 1: 1152x870@54, direct MISO is sort of delayed as expected.
-
23.0MHz:
- Mode 0: 640x480@55 works fine
- Mode 1: 1152x870@52
-
20.0MHz:
- Mode 0: ?? - Displays an image (wide aspect) but doesn't like it. Complains that input signal is out of range and won't show what it is.
- Mode 1: No sync
-
27.0MHz:
- Mode 0: 640x480@64 works fine
- Mode 1: 1440x900@61
-
28.0MHz:
- Mode 0: 640x480@67 shows some MISO delays
- Mode 1: 1152x870@63
-
30.0MHz:
- Mode 0: 640x480@71 shows some MISO delays
- Mode 1: 1152x900@67
-
DE0-Nano 4 DIP switches:
The DE0-Nano board contains a 4 dip switches. A DIP switch provides, to the FPGA, a high logic level when it is in the DOWN position, and a low logic level when in the UPPER position.
- Per DE0-Nano schematic, when the switches are open (or "OFF"), they are pulled high. Otherwise, when "ON" they are grounded.
- I'm using this to select
vga_mode
on switch 0. When in the "upper" position it will select vga_mode 0 (low input), else in "DOWN" poition it will select vga_mode 1.
-
Elgato Cam Link 4K doesn't support 1440x900 resolution:
Supported resolutions are listed: here
-
Blue cheapo USB-C HDMI capture dongle can capture it, but 1440x900 isn't one of its native output resolutions, so it scales instead to whatever output mode you select (e.g. 1920x1080) and overall there's a lot of blur and chroma subsampling.
Footnotes
-
I think I've observed it occurs basically instantaneously for the QE bit, but this might not be true of the other bits in WSR2. ↩
-
The datasheet says /HOLD is disabled when QE is set. Hopefully this is accurate, because I would normally only expect that to hold true when using a quad command. ↩