_Project Overview (-)2.0
Apparently I've done a lot of writing and rewriting, having nearly completely forgotten that I'd written it before. Oy. Anyways, here's apparently a more "formal" overview of my most recent projects... discovered burried in SDRAMThing2.0's code-folders.
It has the benefit of going into more detail as to the actual limits pushed in these projects (SDRAMThing and LCDdirectLVDS, specifically.)
----------------
This project demonstrates several concepts which I think to be unique...
pushing the documented limits (and even far-exceeding them) in ways that
technologies that might have seemed out of reach to the typical hobbiest
are now available to them (DIYer, "Maker", "Arduin-ite", whathaveyou).
Much more worthy examples of this sort of thing being done is the
prevalence of USB devices made out of 8-bit (e.g. "AVR", as used in
Arduinos) processors... These devices were in no way intended to work as
USB devices, but someone pushed the limits and that work has since become
so common-place that even the hobbiest can create USB MIDI devices for
lighting their concerts or Burning Man projects, creating interfaces for
tool-changing in "The Gimp", or just hacking around with Max or PureDigital
SDRAM:
* "Free-Running"
Once the memory is loaded, by using a feedback loop, it can control
itself completely independent of external control (e.g. a processor).
* Refresh Requirements
The specifications claim that refreshing the entire memory must be
accomplished every 64ms... with a 64MB SDRAM that means a *significant*
amount of time must be spent doing nothing but refreshing the memory!
My experiments have shown that the reality is that many memories can
endure for far longer than this requirement. On the order of 10 seconds!
* Refresh Methods
Though not documented, the mere act of *accessing* a memory location
causes its contents to be refreshed.
* Documented "refresh" methods require that the entire memory be idle
Meaning it cannot be used for other purposes during this time
* By, instead, "activating" a memory location, as though it's about
to be read, without even intending to read it, its contents are
refreshed. Because of the design of SDRAM, this means that e.g. a
"burst read" can be going-on at the same time as satisfying memory
refresh requirements, by activating and deactivating memory
locations while reading another.
* Writing/Reading methods
While writing memory locations can be accomplished one location at a
time, *reading* always occurs in bursts.
(A "burst" of "1" memory location is an option, however with a slow
processor and many wiring-methods, it would be quite difficult to meet
the timing-requirements necessary to read back that one memory location
at the instant its output is available).
Several methods have been addressed in these experiments, depending on
the wiring-scheme.
Write:
With an 8-bit processor it's nigh impossible to send the "Write"
command to the SDRAM at the same instant as sending the addresss and
data, as the SDRAM requires.
By setting up the address and data while NOP is on the command bus,
then sending the write command followed immediately by NOP, a write
to a single location is possible.
Read is more difficult, due to its "burst" nature.
But there's something to be noted: read (and write) commands can
occur back-to- back at "random" locations.
By setting up the address first, then writing the "read command",
the memory will, essentially, receive the same "read command" from
the same memory-location repeatedly...
Each clock-cycle on the SDRAM is then a "new" read-command, which
stops the previous read-burst and initiates a new read-burst from
that same memory-location.
Giving time to set up the data-port as an input, and read it.
These methods may be usable even when the SDRAM is running at a much
faster clock-speed than the processor.
While the SDRAM specifications claim the data output will be in an
"unknown" or "undefined" state for quite some time between each data
output (on each clock cycle), experiments have shown it to be quite
stable...
When "reading" the same memory location repeatedly, it appears to
remain at that data-value constantly, making read-back at slow rates
feasible. (This may be somewhat dependent on what's in the surround-
ing memory locations, and the length of the read-burst initiated.)
Likewise, if the SDRAM is running at a much faster clock-rate than
the CPU while *writing* we can take into account that write commands
can also occur back-to-back. Thus, even holding the "write command"
on the command-bus for several SDRAM clock-cycles will just cause it
to write the same memory location with the same data repeatedly.
It's possible to do quite a bit, as well, with the DQM ("Data Mask")
pins and "burst" mode. This is especially true when the processor and
SDRAM are running at the same clock-rate
(or with some use of one-shot "glue logic").
E.G. the latest wiring-scheme uses one processor pin for each SDRAM
command pin, and because of the "free-running" method used, these
pins are *also* directly tied to the SDRAM's data-pins. When Free-
Running, the SDRAM's Data Pins output command-instructions back to
itself. E.G. at the last memory-location in a read-burst, a new
read-burst is initiated at the next memory-location. That command is
sent *from* the SDRAM's data Outputs back to its own Command pins.
Thus, writing and reading via the processor becomes more difficult,
as the processor must first use each pin to send the "Write" or
"Read" command to the SDRAM's command inputs, then switch those same
pins to the data to be read/written. So how is this accomplished
when, e.g. for "Write", the SDRAM usually looks for data at the same
instant the "Write Command" is received? Data-Masking. By essentially
telling the SDRAM to ignore what's on its data-bus until that data is
actually available.
Whereas generally the DQM pins are used for the
case where multiple SDRAM chips share the same command and data
busses, when only one chip is to be written, instead we're using it
to use the same bus for command and data on the same chip.
This leads to some timing issues. When the processor says "write at
this address" that's the address that is being masked... the actual
data will be written several addresses later (due to the write-burst)
So it's just a matter of knowing which address we intend to write to
and how long it will take to set up the data and "unmask" it.
So, again, even though we're writing only one memory-location, we're
making use of the "write-burst" method.
While this read/write method is a bit slower, it has the benefit of
saving quite a few processor pins, while also requiring zero (that's
right! Zero!) additional components; no glue-logic, no resistors...
Just the processor, the SDRAM, some wire, and a clock-source for them
both. Also, it does-so in such a way that it's wired perfectly for
free-running.
* Where can this go...? I dunno, exactly. Having 256MB of 133MHz 64bit-wide
free-running data could be useful for something. I've used it to drive
an old laptop LCD at full-resolution, full-color. Once the memory is
loaded, no processor intervention is necessary to refresh an image on
the display.
Other thoughts are:
* Data-logging; with a bit more development a 64-bit wide 133MHz
logic analyzer could be designed using little more than an Arduino,
an ancient and practically unusable SDRAM stick, and *maybe* a
handful of glue logic.
* I've vague thoughts of whether this method could actually be used
as a processor of sorts, instructions stored in certain memory
locations.
I've certainly thought of "NOP" and "Jump" which
could be used for on-the-fly signal-generation...
* Thoughts on parallel free-running SDRAMs, such that one could be used
to write another, and vice-versa...
* Not *fully* understanding USB, it may be possible to use in a way
similar to the 8bit USB devices, except running at full-speed (?)
Most of these ideas have nowhere near the potential to become as
ubiquitous as the 8bit USB devices, but who knows...
LCDs:
* TFT displays have memory at each pixel, so refresh-rates and data-rates
can often be slowed to speeds that even 8-bit processors can accomplish,
without dramatic fading of the image inbetween refreshes
* This particular display has a few quirks which can be made-use-of...
(And may, indeed, exist in other makes/models of most old TFT LCDs?)
By supplying it with a simple signal that's not at all documented,
the display can be forced into a mode where whatever data is stored in
its horizontal buffer will (gradually) be repeated across all rows.
This signal is so simple the entire circuit can be built of nothing more
than a handful of TTL chips, causing the display to hold columnar
patterns of color. E.G. by loading all the columns with a single color
the display can be used as a solid-colored "mood light". Changing the
color bits causes it to slowly fade to the next color.
One possible use: E.G. as a changeable color-filter for stage-lights...
This could *easily* be accomplished with an 8-bit microcontroller.
Another equally-simple signal/circuit causes the display to refresh.
By introducing some randomness in the signal, random color-bars can be
loaded and refreshed continuously... It's hard to describe, but one such
source of signal-randomness is simply the "bounce" on a push-button.
E.G. with a simple circuit and a pushbutton can be made a sort of "zen
machine" which changes patterns each time the button is pressed.
LVDS:
* At the base-level, LVDS appears to have been designed around technologies
already standardized long before it was used in everyday devices.
* TTL chips from early 1980, when pushed just beyond their specifications,
actually appear to satisfy many requirements for LVDS signalling;
Voltage levels are correct, due to "heavy" loading
(These devices were made to drive a few high-impedance inputs at
close to 0V and 5V, but by driving the low-impedance load of an
LVDS input, the signals are more like .5V and 1.5V, which is
pretty durn close to exactly the LVDS specifications)
"PW-Banging":
In an earlier project, leading up to this one and not nearly so
documented, it was determined that a special mode of Pulse-Width-
Modulation signals (usually used to create variable voltage-levels for
motor-control, etc) could be used to drive the high-speed serial signals
necessary for LVDS.
Using this method serves several purposes:
* The PWM outputs on some processors can be driven at much higher
clock frequencies than the processor itself. Leading to faster
refreshing of the display, 8x in my case. Also allowing for displays
whose clock frequency requirements exceed those of the processor.
(In fact, this method was used initially to simulate signal rates
originally tested with the display connected directly to a computer)
* Much of the time used to send signals to the display is spent sending
the same data repeatedly: E.G. For a "Horizontal Sync" the data sent
on the LVDS pins is identical for dozens if not hundreds of cycles.
Thus requiring loading of the PWM control registers once, then
allowing it to run repeatedly.
Due to the nature of PWM, being that it usually turns on at a certain
point in a "cycle" then remains on until the end of that cycle, certain
considerations had to be made with regards to the types of signals
needed by the display. E.G. on the "Red" wire, it would not be able to
turn on bit 0 and bit 4 without turning on the bits inbetween.
For the wire carrying the syncing signals, this is even more complicated
as each sync bit has its own purpose, and this same wire *also* carries
the blue bits.
In the end, 48 colors were possible, spanning the whole range from full-
off, to full-on in each of the three colors, and in every combination.
Using the repeating-nature of PWM, and taking into account the frequency
difference between the CPU and the PWM, the simplest implementation, at
the LCD's documented refresh rates, allowed for 32 individual pixels by
32 pixels, stretched across the entire display.
Slowing the LVDS rate to that of the processor allowed for resolutions
as high as 3 physical pixels per each drawable pixel.
(1024/3 ~= 340 pixels, horizontally)
Because each row is drawn separately, the full vertical resolution is
attainable (340x768) at about 1/5Hz refresh-rate.
"Row-Segment Buffer"
In that same project, one of the greatest limitations is the amount of
memory in the processor; 512 *bytes* total... hardly enough for an entire
image, and not even enough for a single row of pixels (especially in color)
By taking into consideration many images drawn will consist of long
segments, in each row, of the same solid color, memory requirements can be
greatly reduced. Each item to draw on the display has its own "section" on
the screen. But much of the space between these sections is solid white or
black. Thus that entire "row-segment" can be represented in a single packed
byte containing color and duration. If the duration is longer than can be
stored in a single packed-byte, another can be used.
Text, on the other hand, requires quite a few short-horizontal-segments.
Since there's not enough memory for 340 separate segments to fill an entire
row, (in addition to the other memory requirements of the things being
displayed), rotating the text 90 degrees (and thus the screen) is a much
better method. In this way the refresh scrolls from left-to-right instead
of top-to-bottom, the "row-segments" are actually "column-segments", etc.
But, in this way, several full lines of text could be drawn.
This all implies that each row is calculated during the LCD's "Horizontal
Blanking Time". These calculations actually take longer than the time taken
to display them. But the display was found to be quite satisfied with such
long "blanking" times. And during all that time the data sent to the
display is repetative (making use of the "PW-Banging" method) requiring no
additional CPU time to keep the display supplied with a valid signal and
therefore synced.
-------------