SDRAMThing - "Free-Running"

Updates (Scroll down a bit for the "basic idea")

Mar '16: sdramThing was featured on the Hackaday Blog!

This page needs some revision/updating... Here's a brief overview of the latest Status:

sdramThing4.5 is now a functional sample/repeat logic-analyzer attachment for my analog 'scope. Using the LCD, cursors can be moved to select a portion of the sampled data for repeating on the oscilloscope. sdramThing4.5 runs the SDRAM off a faster clock than the AVR. Its current ratsnest-wiring allows for sampling of data at 30MHz, with an AVR clock of 15MHz. Interfacing the slower AVR to the faster SDRAM requires "one-shot" circuitry and some very precise timing accomplished via Assembly instructions, knowledge of the durations of each assembly instruction, and knowledge that the AVR runs each instruction back-to-back in synchronization with the clock-input.

Thoughts have been bouncing around regarding how to use sdramThing's "Free-running" technique with other systems. E.G. single-board-computers like a Raspberry Pi would allow for a dedicated screen, keyboard/mouse, and *significant* computing-power for displaying/processing the data. Interestingly, despite the significant computing-power available in such a system, the actual interface to the GPIOs is quite limited. Others have suggested that pin-toggle-rates of 50MHz are difficult to achieve. Further, due to things like the MMU, branch-prediction, pipelining, cache, etc... it's not exactly possible to time those GPIOs with the precision/accuracy achievable with a simpler system like an AVR (again, that level of precision is currently *required* for sdramThing).

HOWEVER: It came to my attention that SDRAM has a Clock-Enable input which can be used for *pausing* reads/writes, and more. THIS would allow for a simpler system than sdramThing4.5, only two one-shot circuits would then be necessary AND that necessity of precision-timing is rendered moot!

THUS: I'm looking into a new revision, wherein sdramThing's core concepts can be applied to nearly any system, no longer requiring coding in Assembly, it could probably even be programmed in Python. The new path is looking something a bit more like a peripheral, rather than an entire system--completely independent of a uC or any dedicated processor--and could plausibly even be attached to a computer's parallel-port, if so-desired.

THIS PAGE is not particularly regularly-updated. Please visit the project-pages at: https://hackaday.io/project/4159-sdramthing45-logic-analyzer and the newer "peripheral" at: https://hackaday.io/project/10119-sdramthingzero-133mss-32-bit-logic-analyzer

Mar '15: We're Now At sdramThing4.0!

Feb '14: Added notes re: sdramThing3.0

The basic idea is this: Using an AVR to control an SDRAM *severely* limits the speed of the SDRAM... Maybe there's a way to *load* the SDRAM *once*, and when finished have the SDRAM send its own read-next-address commands to itself at full-speed!

I've a ton of ideas what this could be used for. The simplest, for now, is driving the good-ol' laptop LCD. Done and Done. (See the bottom of this page re: LVDS/FPD-Link)

If you think about it like a display-driver/frame-buffer (or my old LCD controller project) SDRAM actually has *all* the Timing, addressing, and multiplexing abilities built-in. Awesome. So there're just a few hurdles to overcome, and I've managed to overcome some of the bigger ones:

    • Can the SDRAM send commands to itself? Yes.

SDRAM can only "burst" a single page at a time. But, we can use one "burst" to trigger the next...

Because the SDRAM is Synchronous, data output from the data-pins is held until the next clock-cycle. Thus, the data-pins can be tied directly to the same SDRAM's command/address pins. The data locations can be loaded with SDRAM commands, and thus it creates a feedback loop which allows the SDRAM to output its entire memory entirely independently of processor control.

    • Can we somehow refresh the "Dynamic" memory banks *while* it's sending commands to itself? Yes.

SDRAM is Dynamic memory, the data is stored in capacitors which must be regularly-refreshed.

The built-in "Auto-Refresh" command requires that all banks in the memory be closed. Thus, to use Auto-Refresh the system can no longer send commands to itself. However, by merely opening and closing a memory-page, that page is inherently refreshed. The "Open Page" and "Close bank" commands can easily be sent by the SDRAM's data pins and processed without interfering with the ongoing "read" command.

Further, the SDRAM specs say an entire refresh is necessary every 64ms, but my experiments show that the data is retained quite reliably for several seconds.

    • Can I send both a command *and* data to the SDRAM from the uC when it's got its command and data pins tied together? Yes.

"Read" and "Write" commands can be "burst-oriented." By sending the command, and keeping the "Data-Mask" pin active, no data will be read/written during the command-cycle. Now that the burst has begun (internally), set up the data on those same pins and release the data-mask for a single cycle. (Also, the "Read" CAS-Latency is handy)

    • Can it be done with a minimum of parts?

No additional chips necessary uC -> SDRAM straight, woo!

(Well, resistors for SDRAMThing1.0. Oh, and a crystal-oscillator. And whatever other hardware is necessary for whatever's connected to the SDRAM's outputs; e.g. an LCD)

NOTE: later versions of sdramThing add "one-shot" circuitry, multiplexers, and latches (all 7400-series parts) to allow the SDRAM's clock to run faster than the processor clock, to allow for multiple different "modes" (sample/repeat), and to reduce the pin-count in interfacing with the processor. The general concept of "free-running" SDRAM doesn't require this additional circuitry.

    • Can I figure out a way to run the SDRAM at a speed much higher than the processor (especially for "Free running")? YES.

The addition of one-shot circuitry (just a couple latches and some boolean logic) has made it possible to run the SDRAM at 4x (tested) the processor's clock. Currently, the system runs at 2x: the SDRAM at 30MHz, the AVR running at 15MHz. This is likely limited, mostly, by the choice of 74HC-series parts, and the wiring-rats-nest of my prototype.

Further, it would appear that a combination of that one-shot circuitry and use of the CKE (clock-enable) pin could potentially decouple the SDRAM from the processor-clock *entirely.* Cool!

This project has gone on many paths.

The original intent was to use as little additional circuitry as possible. sdramThing1.0 used nothing more than an AVR, an SDRAM DIMM, and a few resistors, but the SDRAM was then limited to data-bursts at the same speed as the AVR, and required some processing-overhead even during "Free-Running" mode, to calculate the next address, etc. (Also, the choice of resistors, combined with input-capacitance, limited the "Free-Running" speed, and thus the entire system's speed... As I recall 16MHz was OK... but 20MHz was not).

As I recall, sdramThing2.0 removed the processor-overhead during "Free-Running" mode, by wiring the address-lines back to the SDRAM's data-I/O pins, as well.

Skip ahead to sdramThing4.5: Here we have multiplexers which allow for different "Free-Running" modes (in this case, sample and repeat). We also have the one-shot circuitry necessary to decouple the processor's system-clock from that of the SDRAM (now the SDRAM runs at 30MHz while the processor runs at 15MHz). Further, once the "Free-Running" commands are loaded into the SDRAM (by the processor), the processor itself can actually be *removed* from the system entirely! (See the video, below).

Now: sdramThingZero: This is an attempt at completely decoupling the SDRAM from the processor... such that the processor could be any system with a few GPIOs (plausibly, even, a PC's parallel-port and a python script). The processor and SDRAM clocks needn't be synchronized, which is a minor change to sdramThing4.5. BUT, it also means we'll be adding a few (several, actually) buffers and latches in order to reduce the GPIO-count. There are also thoughts on "complex-trigger" schemes, which might require some additional logic.

The end-result is that sdramThing started with basically zero additional circuitry-requirements besides the SDRAM DIMM and the processor, and now has evolved into something a bit more sophisticated, using nothing more than some standard 7400-series chips.

Yes, I am still actively-avoiding programmable-logic with this project. Despite their being harder for hobbiests to implement, there's also the fact that once you insert an FPGA there's no need for "Free-Running" at all. FPGAs are more than capable of implementing that functionality internally. And at that point you might as well use DDR3, as well. Among other things, this project is about making use of scrap parts, seeing what SDRAM is capable of on its own, adding as little support-circuitry as necessary to extend that a bit, and hopefully coming up with something useful in the process.

-------------- This needs to be updated ------------------

I've gone through two different designs: SDRAMThing and SDRAMThing2.0.

SDRAMThing connects the SDRAM's data pins back to its command/address pins via resistors, which act, essentially, like an open-connection when both the address/command and data pins are being driven by the microcontroller. Then when the microcontroller releases control of these pins, there's no place else for the voltage from the data-outputs to drop except into the command/address inputs. (These feedback resistors are physically-huge because... I had a lot of them. And there are so few because I never did get to address-feedback, only command-feedback. But the uC being responsible for addressing is actually not a bad way to go (And now's when I realize they might well be wire-wound resistors acting as inductors and slowing the data-rates.)

SDRAMThing2.0 actually connects the address/command pins *directly* to the data-pins. The reason-being that the resistor, combined with the pins' capacitance, caused the data-transitions to slow, to the point that the SDRAM's maximum speed would be quite limited (even uC speeds were too fast for most reasonable resistances). The added-benefit is that it reduces the number of pins necessary to connect the uC. The drawback is that a simple "write" command is slowed dramatically because the uC first has to send the command, then has to reload those same ports with the data values, then tell the SDRAM the values are ready, then tell the SDRAM the values are done... Nevermind the calculations involved. In all, we're talking quite a few instruction cycles just to write one address... Multiply that by 256Million addresses, and we're talking several minutes to load a single LCD image at 1024x768 (x7 because it's LVDS).

There're definite openings for optimization, and countless pages of implementation ideas.

Other things it could maybe be used for, at some point down the line, is a 133MHz 32+ bit logic-analyzer... And I don't know what else. Basically anything serial or parallel that you might want to stream out (and possibly in) for a second or two at high speeds (possibly repeatedly) and don't mind a long delay between read-back or new writes.

Even further down the line, I've a vague idea of "instructions" located at certain addresses in the SDRAM, that could be addressed randomly, either from a microcontroller, or even by other instructions in the SDRAM. It's plausible to create almost a CPU, or at the very least complicated jump-patterns. Certainly "NOP" is feasible in free-running mode, as is "Jump." And a lot can be done with just those two and a *huge* data-table. Throw in just a tiny bit of uC control during Free-Running mode (e.g. mask the outputs' jump-commands at certain times) and the options are limitless!

Maybe the SDRAM could be capable, with a handful of other parts (an R/C network, and maybe a gate or two), of generating its own high-speed clock signal after it's loaded with the necessary data from the uC (e.g. one bit always toggles between each consecutive address, all jump-commands occur on odd addresses to even addresses). Or maybe the SDRAM could be broken into halves, one would do command/data feedback while the other is loaded with data from the uC at a faster rate than currently possible...

Anyways, pages of ideas. As it stands, though, the first test was connecting the trusty LVDS-LCD, and seeing what was possible. Sure-enough 1024x768, full-color... no problem. If you don't mind waiting 5 minutes for the image to load. (This, actually, would be dramatically reduced if using a regular TTL display, as not only does the LVDS display require 7x the data to be written, but it also requires quite a bit of overhead to convert RGB values to the necessary data-streams; lots of shifts and ORs and masks... I could probably optimize this a bit. And there's further optimization in the ability to update the image, in that the timing-data needn't be rewritten. Further, I probably refresh the SDRAM (a slow process) way more than necessary.)

More photos:

SDRAMThing:

(Whoops, maybe I shouldn't use that flux anymore)

SDRAMThing2.0:

(Note, on SDRAMThing2.0, the CLOCK signal is shielded... this resulted in *tremendous* improvement in data-integrity. There was a time when I actually wrote each address, then verified it... It often resulted in several writes before each address was correct. Shielding the clock signal pretty much eliminated write-errors, to the point I consider it trusty enough to remove verification altogether.)

There WILL be a code-page!

But good lord those notes are informative but poorly organized.

Here're some random notes from the much denser and disorganized code:

(SDRAMThing1.0)

Data/Command Feedback wiring example:

_________/\/\/\________

| _____________ |

| | SDRAM | |

+--->| /RAS DQ5 |><--+

| | | |

| |

| _____________ |

| | uC | |

\---<| CMD Data |>---/

| out out |

When the SDRAM is free-running, the uC is out of the picture (Hi-Z)

DQ5 is essentially wired directly to /RAS

When writing Data/Commands from the uC to the SDRAM

Both uC pins are outputs

----------

Using two chips (or two bytes from a 16bit chip) on the same data-bus to act like one long 8-bit chip with free-running feedback (SDRAMThing1.0)

______

uC |

|(5)

DATA /|><------------*-------------------------*------------> Data Out

I/O | | | | (LCD,etc.)

PORT \|><-----------------*-------*-----------------.

(8bit)|(3) __|____|_ | __|____|_

| | Dq Dc | \ | Dq Dc |

| | | / | |

| | | \ Rc | |

| | DQM C A | / | DQM C A |

| |_________| \ |_________|

CMD | | | | | | | |

OUT |>----------------*---------*---------------/ |

| | | | |

ADDR | | | | |

OUT |>------------------*-------------------------/

| | |

DQML |>------------/ |

DQMH |>--------------------------------------/

|

______|

SDRAMThing2.0:

Data/Command Feedback wiring example:

(SDRAM running from the same clock as the uC)

(This applies to Address pins, as well)

____________________________

| __________________ |

| | SDRAM | |

+--->| /WE DQ5 |><--/

| | |

| | DQM |<---\

| |__________________| |

| __________________ |

| | uC | |

\--><| DATA/CMD DQM |>---/

| in/out out |

Thankfully, there's only one DQM line per DQ byte, so this actually simplifies the physical interface quite a bit (vs. SDRAMThing1.0).

E.G. For a "Write" command:

    1. Enable DQM (Mask the data arriving at the DQ pins; DQ5 will ignore the /WE)

    2. Load the "Write" Command along with the address to the appropriate pins

    3. Enable Chip-Select (Note, that this *immediately* begins the "Write burst," starting at the address specified, but we aren't actually loading data until DQM is disabled... So the actual address written with data will be several bytes later)

    4. Disable Chip Select (The burst will continue)

  1. Load the data to be written

  2. Disable DQM

  3. Enable DQM

This has been proven reliable; only the byte specified in the DQM-disabled cycle gets written. By knowing the number of uC instructions between CS-Enabled and DQM-disabled, the address actually written with data can easily be calculated. (Or it's just as easy to calculate the address-value to send, in order to write to a desired address)

Then to enter "Free-Running" mode, the uC in a similar manner issues a "Read Burst" command, holding DQM active until the uC has a chance to release the Data/Command/Address pins. At which point, the uC is completely out of the picture, and the data previously stored in the SDRAM is output right back to its Command/Address inputs. At the end of the first page is a command to read the next page. (Note that even after wiring all the Address/Command pins to DQ pins, there are *several* DQ pins remaining, which can then be used for other purposes, like driving an LCD, etc).

Thus, each page is filled with commands at the last few bytes in the page:

P = Precharge the next bank

(in case it was already open from a previous page-burst)

A = Activate the next page

R = Read the next page

(This is located a few bytes *before* the end of the page, to account for CAS Latency)

Page 0: Page 1:

------------------------ -----------------------

| | P | A | R |--->| | P | A | R |----> .....

------------------------ -----------------------

As implemented for the LCD, the last page issues a "Read" command back to Page 0. Thus, the same pages are output continuously and repeatedly (refreshing the LCD image). The simple act of Activating a page in memory causes that memory page to be refreshed. And, again, SDRAM refresh isn't necessary nearly as often as specified (once every 10 seconds seems to be plenty). Thus, no explicit "refresh" commands are necessary in this case, since each page is cycled through repeatedly.

Much more complicated jump-patterns can be created... one idea is a NOP command located at the first several pages (say, 2). The SDRAM could be loaded as above, with Page 1 pointing back to Page 0. In the unused memory locations could be cycled Precharge and Activate (but not Read) commands in order to refresh each page in memory...

/-------------------------------------------------------------------\

| --------------------------- --------------------------- |

\->|P A P A P A P A P A P A R| -> |P A P A P A P A P A P A R| --/

--------------------------- ---------------------------

Then, in order to jump out of the NOP pages to a new location, the DQM pin could be activated by the uC, the uC then has control over the SDRAM's command/address inputs to begin a new free-running read-burst at another location. At the end of that location could be a "Read" command to the first page in "NOP"...

This whole system could be implemented in many different ways, depending on the wiring, etc. E.G. the microcontroller might only DQM (and take control of) the address pins, the actual "Read" command would be issued by the free-running SDRAM itself. Or the memory might have many Read commands located in each page, but they may be DQMed until a specific one is desired.

So, what can be done with these complex jump-patterns... well, imagine it a bit like a flow-chart... Possibly a state-machine. In the case of the LVDS-LCD, rather than writing the same data repeatedly in a linear fashion, we could have several states. The serial data-patterns sent during a Horizontal Front Porch, for instance, are identical, but they must be repeated a dozen or more times in each row, and repeated for every row. Instead of loading a dozen *768 identical patterns in the SDRAM, why not have it loaded once and have it cycle? It takes a bit more real-time control from the microcontroller, but could be useful to jump between states like this. And some of these jumps don't require uC control at all, such as jumping from the end of each drawn-row to the Horizontal Front Porch. In other words, 768 separate locations all end up jumping to the same location.

I can also *vaguely* picture some sort of spiralling jump-pattern, where say jumping to the middle of a page causes a jump slightly earlier in that same page, which causes a jump slightly earlier-still... something really vague about a vernier scale... essentially creating a for-loop or a counter *in the SDRAM*. I have yet to figure out the details, but it's plausible to reduce the load on the uC to maybe little more than a periodic DQM pulse, which could be implemented via PWM, requiring no processing overhead at all.

Another example, maybe, is if the SDRAM's available data-outputs are fed to a Digital-To-Analog converter as a function-generator. One jump-location could contain a Sine-Wave, another a triangle, etc. These could be jumped-to and loop-back on themselves to continuously output the wave-form until the uC steps in to choose another.

Basically, anything that can be calculated ahead of time and later bit-banged. Possibly even 480Mbps USB bursts, with a simple shift-register...

---------------

Thoughts on a one-shot circuit, to interface slow uC pins to a fast SDRAM:

(These notes mostly referencing SDRAMThing1.0).

Some commands are perfectly-content being repeated multiple times, as would be the effect of a slow uC's holding the data/address/command lines for several SDRAM clock cycles. This can be to our advantage; e.g. "Read From Column 0", when repeated during every SDRAM clock cycle causes the output to repeat the value at column 0, rather than bursting col[0]->col[burst-length]. Thus, there would be no need to "latch" the data for the slower uC to read it back. Further, the "Write" command is also capable of repeated-access; writing the same value to the same address repeatedly has no negative effect. Whereas, some commands are *not* OK with repeating. And, right now, the only example I can think of is one that has long-since been deemed unnecessary; "Auto-Refresh", which requires a "long" delay before the next operation can be handled; Multiple back-to-back "Auto-Refresh" commands has been found to *damage* the data being refreshed. BUT: SDRAMThing2.0, might well *require* One-Shot, even for repeatable-commands. I have yet to delve into those details... something about One-Shot on the DQM lines, at least, and possibly a bidirectional buffer on the data/command lines. Oy, so much for simplicity. The alternative, (SDRAMThing1.0) it seems, is bidirectional buffers between every fed-back pin. Also reducing simplicity, and there may still be a command or two which still require one-shot.

nCS_RepeatedAccess >------------------------------

| ____

___ -| \

-----------------\ \ | AND |->SDRAM_nCS

_____ | _____ | OR >--|____/

nCS_OneShot >----|D Q|--+---|D Q|--|>o--/___/

| | | |

--|>____| -|>____|

| |

SDRAM_CLK >---+-------------

Disregarding one-shot:

When the uC and the SDRAM are running from the same clock, there's no need for one-shot circuitry in either version of SDRAMThing. This is the simplest to implement, as shown in the photographs above... literally no additional logic is necessary between the SDRAM and the microcontroller. Maybe there's a way to keep it simple despite clock differences, I guess I just have to keep thinking about it.

Another idea involves reading and writing the SDRAM while it's connected to the uC's clock, then switching to the SDRAM's clock for free-running mode... (part of the reasoning earlier about whether it's possible for the SDRAM to generate its own clock signal).

...

-------------------

sdramThing3.0 (Jan-Feb '14):

sdramThing3.0 adds "Sample-and-Repeat" functionality to sdramThing2.0.

The idea is that commands for different purposes can be loaded into the SDRAM, and they can be selected by the microcontroller. The two modes, so far, are "Sample" and "Repeat." In Sample-Mode, data is read into the SDRAM in real-time. in Repeat-Mode, that data is output by the SDRAM.

I now make use of two separate groups of SDRAM-Chips on the DIMM. (These chip-groupings are sometimes called a "bank", but that's confusing because each chip has four internal banks, which are entirely different.) The first "group" of chips is for storing and feeding-back "free-running" commands, and I'm calling it the "Free-Runner". The second group of chips is for data I/O (I'm calling it the "Side-Kick"). Both groups have their own separate Chip-Select input, so the Free-Runner now stores and repeats commands, along with CS according to the purpose of the command.

For now, there are three different sorts of commands:

    • Commands that are fed to both the Free-Runner and the Side-Kick, regardless of the mode (Sample vs. Repeat). These include Precharge and Activate

    • Commands that are sent to the free-runner every time, but only to the Side-Kick when it's in "Repeat" mode. These are the "READ" commands...

    • Commands that are only sent to the side-kick when in "Sample" mode. These are the "WRITE" commands.

So now each page of the Free-Runner is loaded like:

Page 0: Page 1:

--------------------------------- ---------------------------------

| ...| P_FS | A_FS | R_FSr | W_Ss |--->| ...| P_FS | A_FS | R_FSr | W_Ss |--> ...

--------------------------------- ---------------------------------

P_FS = Precharge Free-Runner AND Side-Kick

A_FS = Activate Free-Runner AND Side-Kick

R_FSr = Read Free-Runner AND (Side-Kick when in "Repeat" mode)

W_Ss = Write Side-Kick when in "Sample" mode.

The circuitry has changed slightly, and I'm straying a bit from my desire to avoid glue-logic... In sdramThing2.0, data and Free-Running commands were all stored in the same "group" of chips. Now, data has been moved to the Side-Kick. Since I'm still working with the LCD display (for testing-purposes), this isn't quite so cut-and-dried. The timing information (Pixel-Clock and DE/Vsync/Hsync, which is combined with the Blue values) is still loaded into the Free-Runner, such that it won't change when sampling. The other two pins ("Red" and "Green") are connected to the Side-Kick for Sample/Repeat.

So now it's similar to a logic-analyzer, data is sampled on the red/green pins, and repeated when the sampling is complete.

/---------------------------\

| "Free-Runner" | "Side-Kick"

| _______________ | _____________

| | SDRAM 0 | | | | SDRAM 1 | |

| |---------- | | |---------- |

| x17 | C/A/BA | x17 | 17 | | Sample/

+---->| C/A/BA DQ |><---+----------->| C/A/BA DQ |><-- Repeat

| | in | | in I/O | I/O

| | DQ_CS1R |><----------\ | |

| | | | | |

| | DQ_CS1W |><------\ | | |

| | | | | | |

| | DQ_CS0 |><--\ | | | |

| | /CS | | | | | /CS |

| | in | | | | | in |

| |_______________| | | | |_____________|

| ^ | | | ^

| | | | | |

| | | | | \---------\

| | . . . . . . | | | . . . . . . . . . . |

| | . _____ . | | | . ____ . |

| | . / |-------+ +------------| \ ____ . |

| \--O| NAND |. | | | .| AND |-\ \ . |

| . \_____|--\ | | | /-----|____/ | \ . |

| . . . . . . | | | | | . ____ | NOR O---/

| 1/2 74S51 | | | +--------| \ | / .

| | | | | | .| AND |-/____/ .

| | | | | | /--|____/ .

| /-------/ | | | | | . . . . . . . . . .

| | | | | | | 1/2 74S51

| | | | | | \----------\

| | | | | | |

| | | | | \-----\ |

v | v v v | |

x17 ^ ^ ^ ^ ^ ^ ^

---------------------------------------------------------------------

| C/A/BA CS0 CS0 CS1W CS1R CS1W CS1R | uC |

| out Enable Enable Enable ----|

So, for "Sample Mode" CS1W_Enable is active, for "Repeat Mode" CS1R_Enable is active.

(Yes, that's a 74S51 from the 80's, rated for 4.5-5.5V running at 3.6V, just fine. LS was a no-go here, unlike LCDdirectLVDS, probably due to the longer input->output delay, and the necessity for that delay to align with other signals.)

Below: The "Red" DQ pin is connected via resistor to the "HeartBeat" LED, which fades in and out quickly while in "Sample" mode. (The "Green" DQ pin is pulled high). During sampling this data is stored in the SDRAM "Side-Kick." After sampling completes it is repeated continuously until another "Sample" is performed. Fading of the heartbeat is accomplished by pulsing the pin in accordance to its triangle-wave brightness (see hfModulation in my _commonCode). Individual pulses can be seen here as short horizontal segments in yellow.

(Note that because it's being displayed on the LCD, some of the sampled data is not shown, though is stored and repeated, during the horizontal "blank" periods, off-screen).

Technically, 32 bits of data could be stored and repeated. As-configured, it's still running from the same clock as the microcontroller--16MHz sampling.

The repeated-data could then be viewed by a 'scope, etc.

Currently, the sample-repeat functionality is limited *to* the duration of a frame on the LCD. This needn't be the case, and in fact the system would be more useful if a portion of the sample could be "zoomed" for display on an oscilloscope... (My oscilloscope is *mostly* analog, so choosing a specific portion of the sample to view would require outputting a trigger at the beginning of the scoping-point, and repeating from the end of the scoping-window, rather than repeating the *entire* set of data, which would result in slow 'scope refreshes, causing dim traces that are hard to see).

I've plenty of ideas how to implement this, but most result in removing the LCD from the circuit, entirely, as it would be difficult to keep the display refreshed while also outputting data to the 'scope (without interfering with the display!). Sample-Mode could act as a circular-buffer; when the first change is detected, it would only continue to sample until the end of the buffer. Then for play-back a user-control could choose how far to play before looping back to the beginning (and possibly controlling *where* to loop back to, along with a trigger-output.) With the SDRAM, this will require refreshing of data that's not being output, so it's time to start implementing the Activate-Precharge refresh-method described earlier.

Note, also, that the display is driven by *serial* data, output directly by the SDRAM "Free-Runner", which means each pixel represents *7* samples.

...One step closer to a logic-analyzer!

Sample/Repeat Window:

It is done! Well, it functions anyhow.

The cursors are hard to see in the first photo (and in real-life as well, unfortunately). They are drawn as thick blue 'L'-shapes ( _| and |¯ ) pointing at the beginning and end of the repeat-window (in the second yellow-bar from the top on the LCD). They have thin horizontal lines across the screen, as well. The data is stored just as the LCD draws it, in a raster-fashon. The upper-left cursor is the starting-point, the next *entire* line is output (including that to the left of the starting-point), and so-on, until it reaches the lower-right cursor.

Here's a picture with no data (Sampled data is all Low):

The data between these two points is displayed on the oscilloscope. In the earlier image, it's quite visible on the 'scope how the LED "fading-in" is accomplished by sending (active-low) pulses closer and closer together. The end of the sampling-window is shown on the 'scope as the noise to the right of the clearly-defined pulses. The output of the SDRAM is "floating" at this point, until the sample is repeated again.

There's a trigger output from the microcontroller to the oscilloscope, in order to align the data. So this makes "B-Triggering" entirely doable. And, again, the purpose of the cursors' selecting a "window" of the sample is to allow *fast* and *repeated* output of the same small segment of data, such that e.g. it can be viewed on an analog oscilloscope. If the entire memory was output, even with a trigger at the first-cursor, there would only be one trace-sweep every couple seconds, which would be impossible to see.

Currently, the entire sample (filling nearly an entire SDRAM chip) is almost two seconds of raw binary data at 16MS/s (times two "channels", which are just different data-bits on the SDRAM chip... ignoring the LCD there could be 32 channels). Again, the "Red" and "Green" LCD-data-signals are connected to separate channels, but for this test these channels are tied together, recording and repeating the same data (thus the image is yellow).

In order to update the LCD as well as output the raw-samples for an oscilloscope, I opted to alternate... a couple seconds of oscilloscope-output followed by a screen refresh (which blanks the 'scope), and repeat.

It actually works surprisingly well as a sample/repeat system... could be quite the handy tool for bit-analysis with an analog oscilloscope... Yahknow, for those of us who still use 'em.

The next phase, I suppose, is getting some user-input for the cursor-positioning.

LVDS Signalling (better-known as FPD-Link):

(This is described in much greater detail in LCDdirectLVDS's highly-documented code; see the code-page)

But I put it here for the sake of better explanation.

FPD-Link (poorly-though-oft-referred to as "LVDS") has four signals, They're typically referred to as Rx0,1,2 and RxCLK. But I've found quite a few uses for considering these signals as "color" signals... "Blue" is the most-complicated to consider, as it also contains the timing-signals, but otherwise "Red" and "Green" are pretty-durn-close to serial data streams containing nothing but Red and Green data.

In SDRAMThing 3.0, Red and Green are tied to separate Sample/Repeat bits on the SideKick... Without even considering the LVDS timing, it's pretty easy to just use them as single-bit On/Off values. Tie the "Red" signal high, and it will display full-red, (with a *tiny* *tiny* green tint). Tie it low and there's no Red. Similar with "Green" (but with a *tiny* blue tint).

Thus, the only two signals which need to be considered, timing-wise, are RXCLK and RXin2 ("D/V/H/Blue")

LVDS Bits: MSB LSB

6 5 4 3 2 1 0

SDR Byte: | 0 1 2 3 4 5 6 | 0 DataPort

.____.____ ____.____. ----------

RXclk+: | \ . . / | ... BIT3

| ¯¯¯¯ ¯¯¯¯ ¯¯¯¯ |

One Pixel: |<--- One FPD-Link Pixel Cycle --->|

| |

"Blue/DVH" |____ ____ ____v____ ____ ____ ____|

RXin2: X DE X /V X /H X B5 X B4 X B3 X B2 X ... BIT2

|¯¯¯¯ ¯¯¯¯ ¯¯¯¯^¯¯¯¯ ¯¯¯¯ ¯¯¯¯ ¯¯¯¯|

|<--Not Blue-->| |

| |

"Green" |____ ____v____ ____ ____ ____ ____|

RXin1: X B1 X B0 X G5 X G4 X G3 X G2 X G1 X ... BIT1

|¯¯¯¯ ¯¯¯¯^¯¯¯¯ ¯¯¯¯ ¯¯¯¯ ¯¯¯¯ ¯¯¯¯|

|<------->|-Not Green |

"Red" |____v____ ____ ____ ____ ____ ____|

RXin0: X G0 X R5 X R4 X R3 X R2 X R1 X R0 X ... BIT0

|¯¯¯¯^¯¯¯¯ ¯¯¯¯ ¯¯¯¯ ¯¯¯¯ ¯¯¯¯ ¯¯¯¯|

|<-->|-Not Red |

Of course: The "Not Green/Red" bits above are least-significant-bits

and basically have little/no visible effect

So, for the sample-repeat system, RXClk and "Blue" are loaded *once* into the SDRAM, and their values are never changed during sample or repeat mode. To accomplish this, these two signals are tied to a couple spare DQ pins on the "Free-Runner" group of chips, rather than to the "Side-Kick" (which samples/repeats on all its DQ pins). The cursors, then, in blue, can be written without affecting the sampled data.

Another case I thought about using a similar set-up (treating the Red/Green pins as simple On/Off values) is with LCDdirectLVDS... That system could be used for nothing more than timing the display, and the actual Red/Green image-data could come from an external source. A simple comparator or two could turn it into a two-channel sideways oscilloscope, for instance.

Although, now that I've finally implemented this set-up and see it in action, noticing that the addition of blue is so hard to see against yellow, etc... For this particular case, where memory is not lacking, it might be wise not to use blue as a separate channel... The alternative, it seems, would be to write the RGB color-value wherever the cursor is located *after* reading the sample-data (which will be obliterated by the cursor) into another memory location, then writing it back when the cursor is moved... We'll see.

-------------------

sdramThing4.0 (Mar '15):

sdramThing4.0!!!

I haven't yet sat-down to document this thoroughly... come back for updates!

A BRIEF overview:

    • One-Shots are now implemented

    • The SDRAM is running at 30MHz while the AVR runs at 15MHz

      • (That's 30MS/s for the "logic analyzer")

    • The system can now run *without the processor* (see below)

    • Various electrical improvements

    • Various software improvements

    • Better/Cleaner code/documentation

    • I'm sure I'm forgetting something...

Also, check out the sdramThing project-page at hackaday.io

Finally, check out the video! Wherein I Physically Remove The Processor from the circuit, to demonstrate "Free-Running" (Thanks to my buddy frankstripod for the idea and motivation!)

----------------

To the future (ddrThing?):

ddrThing... maybe? Have done a lot of looking-into the feasibility of doing similar with DDR... it might be possible, but there's a lot more to consider.

First of all, since it outputs data on *each* edge of the clock, commands will (most-likely) have to be stored in two adjacent columns surrounding the rising-clock-edge (where commands are read).

DDR may be more sensitive to clock-rates; allegedly it doesn't run at less than 85MHz (though stretching those limits is half the fun).

Voltage-levels, and more.

One positive side-effect: Since data is output on each clock edge, a DQ pin could *plausibly* be used *as the clock* during free-running mode (maybe a R/C or other delay so it doesn't go crazy).

The specs I've seen, so far, suggest the only way DDR can be used--within specs--is with the "DLL" which requires 200 cycles for syncing whenever there's a change in clock frequency... If it can still function with the DLL disabled (and that does seem to be an option in the mode-register), it's plausible to run the DDR chip at uC speeds for initialization, then DDR speeds when free-running.

Even if it *can* run at uC speeds, and it's decided to *only* use it at those speeds (like sdramThing1.0-3.0), there's a bit more difficulty in the fact that the longest DDR burst-length is 8 columns. sdramThing1.0-3.0 use page-bursts, 1024 columns. So the "Read" command need only occur at the end of the page, reading the *next* page. In DDR, there would have to be READ commands *within* each page, to start bursts at the next column. It's entirely doable, but introduces a bit of overhead... (Would there be enough remaining memory to implement Activate-Precharge-Refresh?).

Until then, some of these things can be tested with sdramThings... (especially BL=8) before soldering up a whole new circuit.

-----------------------