-
sdRamblingThing Concepts, revisited
04/15/2022 at 19:46 • 0 commentsI've been contacted, recently, about someone's interest in trying this out... Specifically, if I understand, trying to create a state-machine with lookup-tables.
I think it important to note HOW this thing [supposedly] works:
Unlike typical Static or Dynamic RAMs, which you just supply an address and it gives the value at that address, SDRAM has a function called Read-Burst (also write-burst).
When you start a read burst at some address, it outputs the data from that address, then automatically outputs the data from the address after that one during the next clock cycle, and so-on for a selectable number of addresses. E.G a typical burst-length setting is 4 or 8 locations.
All the SDRAM chips I've worked with can be configured to burst an entire row of data (usually 256, 512, or 1024 bytes).
But, of course, a 1MB chip has way more than 1024 bytes... So a single read-burst /cannot/ output the entire chip's contents.
To do that, you'd have to start a new read-burst in the next row immediately after the first burst completes. (actually, due to CAS-Latency, it has to be started a few clock cycles *before* the previous burst completes, if you want an uninterrupted burst of two rows, or i.e. 2048 bytes).
So, what I've done is add a second identical SDRAM chip in the mix (This is easy when using a DIMM!). This second chip is addressed with the same address bits, uses [most of] the same command-inputs. When a read-burst is initiated on the original chip, that same read burst occurs in this new/second chip. So, now, the two chips together burst 2 bytes simultaneously.
Now, there's no reason to limit this to two chips. A DIMM actually has 8 chips or 8 bytes' worth of chips... So, I group them into two groups, each 4bytes wide...
The memory I want to burst-read (or write) is 4bytes, 32bits. This is the Sample-memory in sdramThingZero (and #sdramThing4.5 "Logic Analyzer") logic-analyzer.
This can also be, say, a framebuffer to drive a LCD... or, basically anything one might want to output/input in a huge continuous burst.
Again, that group of chips, alone, would only be able to burst a maximum of 1024 32bit words, before requiring a precisely-timed NEW read-burst command, telling it to begin a new burst from the next row.
So the other group of chips, 4 bytes' worth/32bits, is loaded-up with that command. This group (I call the "FreeRunner") has its data outputs tied [mostly] directly back to both groups' command/address inputs. (The other group, the "memory" for sampling, or a framebuffer, I poorly named "The SideKick").
So, Now, the FreeRunner and the SideKick BOTH burst the same addresses at the same time. The FreeRunner is MOSTLY filled with "NOP" commands, so mostly doesn't interfere with a row-burst. BUT a few addresses shy of the last address in the burst, it requests a new burst in the next row. Which begins a few clock cycles later, immediately after the first completes.
That's a bit simplified, but should do for now.
Fill the FreeRunner with commands such that the SideKick will burst its entire contents in a continuous stream, 32 bits from each address, once per clock cycle.
Great for sampling data in a logic analyzer, great for refreshing an LCD, I dunno what-all.
....
So, the FreeRunner basically does little else than cycle through all the addresses in the DIMM.
Unfortunately, not much at all like an EPROM lookup table, more like a VGA card. Heh.
...
However, it /is/ a bit like a very limited CPU, The addresses' incrementing after each NOP is a bit like a program-counter.
Now, it is possible to send different commands to the Sidekick and Freerunner. Each group of 4 bytes has a separate Chip-Select. So, e.g. in a logic-analyzer setup, the Freerunner is always burst-reading (outputting the commands stored in it) while the Sample Memory (SideKick) may be burst-writing (sampling data, storing it in memory) OR burst-reading (outputting the stored samples back to the host computer (or LCD/Oscilloscope, in sdramThing4.5).
One is reading the other is either reading OR writing...
So, if you're clever, you *can* decouple the FreeRunner's and SideKick's addresses, and actually have them doing different things. They needn't burst the /entire/ contents, maybe just a few addresses in a short loop, or plausibly repeatedly outputting the same address for read-back to a much slower bus...
....
BUT there are MANY considerations.
First-Off, the address lines are the same for both systems, so even though you can tell one to ignore the command (via chip select), only one "command" can be stored in each memory location. So, the two cannot be given differing instructions at the same time; they'd have to be interleaved.
(I was able to get away with the FreeRunner reading and SideKick writing at the same addresses at the same time because read bursts start three clocks later, whereas write-bursts start immediately. The read command was three addresses *before* the write command).
But here's a really big "gotcha"...
The entire memory must be refreshed, regularly, regardless of what small loop you're running...
So, say you're in a loop waiting for external input... E.G. I thought to add a level-sensitive "trigger" to the logic analyzer.
Before the trigger occurs, the RAM must be refreshed... So the idea was to use as many addresses as necessary to refresh all the rows *within* the "wait for trigger" loop... Say it's 1024 rows by 1024 cols, for a 1MB/chip... That means the wait for trigger loop has to be at least 2048 cols, or two rows, Just For Refreshing. (Open Row/Close Row=Refresh Row).
For the sake of responsiveness, I'd probably put the trigger test between every row refresh, so now we need at least 3 rows, 3000+ addresses/"instructions" just for the loop that detects the trigger.
On the plus-side, I could be repeatedly burst-writing in the SideKick during this time, which would mean it would have 3000+ samples in a circular-buffer *before* the trigger in case that'd be useful.
...
But the point is, as a "state machine," well... it's a lot of work.
...
Now, take my FreeRunner idea and burst-reads out of the picture, and it may be easier to treat the SDRAM like any ol' SRAM/EPROM; a bit of external glue/latching logic to access a memory location in a linear fashion... And since it wouldn't be constantly bursting, one could put it in AutoRefresh whenever it's not being accessed...
...
So, I guess the quick of it is that this concept of using the memory [FreeRunner] to control the memory [SideKick and FreeRunner] is pretty obscure and probably only has a few niche use-cases for which it's probably not even really well-suited. Heh.
It works well for a logic-analyzer whose host-computer/bus is too slow, or too imprecise, to reach the speeds the RAM itself can achieve. It doesn't really make for a very good framebuffer, since writing to it would interrupt the video-feed...
There MAY be other interesting uses, but it's almost certainly not a good idea for a product, unless that product is trying to make use of old tech, keeping it out of ewaste. Heh.
Oh, and BTW, since it's usually the first question: No. It'd be FAR more difficult to implement this in DDR, burst lengths are limited to 8 addresses, or 4 clock cycles, which is *barely* enough to start the next burst. Nevermind weird voltages and timing constraints.
...
It would be quite interesting to see where this technique could go, but it's probably not at all what one might expect going in... That's kinda exactly what made #sdramThing4.5 "Logic Analyzer" so interesting, it seemed to take a path that I would've never predicted, based on weird quirks and limitations... E.G. who woulda thought to put Cursors in the FreeRunner, and thus in a separate yet parallel framebuffer for Blue?
[Heh, this writing didn't come out at all like I expected when I started... I had examples and better explanations that have vanished from my awareness! But, this unexpected-path isn't nearly as interesting, nor maybe as positive/useful, as sT4.5's. Heh.]
-
Why'd I Stop?
01/11/2022 at 17:18 • 0 commentsThis's been in my drafts since the turn of the year (It's now mid-April, and it's been snowing!?). I didn't finish this writing, there's a TON more could be said about how things like this have taken their toll on me. And, quite frankly, I'm a bit afraid to talk about this stuff, for COUNTLESS reasons. But... It happened, and things like it continue to happen. These things affect me every day, some near-decade later, and to lesser-noticed extents some decade prior. Facts are facts, I suppose. Whatever the heck it is, it seems I just can't wrap my head around it, nor really how to function in any reasonable capacity with it's presence in my life. It is what it is (what is it?!). I'm doing the best I can with what I understand.
Here's the original draft. Actually, I've tried to write about this COUNTLESS times, and I bet there are years-old drafts about it all over my projects' logs. Heh. Here's the January 2022 attempt:
....
This project, you may've noticed, went from ludicrous-speed to full-stop in basically one evening.
I've tried to explain to countless folk countless times and countless ways...
I haven't explained, here, because, frankly, it scared me. The event itself, and the implications. Still affect nearly all my projects to this day. Years later. Heck, frankly, it affects nearly every aspect of my life.
...
Today I woke with an analogy in my head...
Imagine the "Pinball Wizard". This guy got really good at pinball, so good that he gained an audience. During a competition he made a mistake... he knows he did. He slipped, missed that button... No one else saw it. The paddle did its thing as though he hadn't. At the time he really didn't think about it... But after the excitement died down, he remembered his fumble... That should've been the end of his game, early-on. Instead, he went on for many more rounds, ultimately winning. What's he supposed to think? Eventually he puts it out of his mind... continues playing when he has time... Until another competition... huge crowd gathered around... He fumbles, again, yet the paddle hits the ball expertly... right up through "The Impossible Loop" gaining a gazillion points, flashing lights, and so many dings nearly every remaining angel-second-class must've gotten their wings. The crowd's going wild, but there's no paddling to do as the ball travels the loop. He knows he missed that shot, has time to think, he starts flailing on the paddle buttons... If those paddles did what they were told, that crowd would've thought he was having a seizure. When the ball returns, he hits it once or twice, as usual, then intentionally starts missing shots, yet those paddles keep hitting it perfectly. Eventually he just stops even pushing the buttons, but the game keeps playing without him.
Hey, this is the 70's, we're talking about, gaming AI is about as sophisticated as Pacman's ghosts... There's no way even the refridgerator-sized computers of the era could achieve the level of real-time physics calculation to keep that ball in play.
So what's left?
Remote controls and a video camera?
Whatever the case, even "in the zone" he knows he missed those shots, especially the ones he intentionally missed.
.
sdramThingZero was at a point where I was coding... Really low-level, I wrote my code changes in "baby steps," thoroughly testing each along the way. Small change, recompile, upload to the AVR, test test test, repeat. There's no operating-system to get a virus on a chip like this, no WiFi for remote-control... I'm coding in C at the lowest level possible. I wasn't even using others' libraries aside from defaults like avr-libc... heck, not even stdio. Certainly not Arduino. Basically aside from the initial boot code that calls main() I'd written /every/ piece of code running on that AVR. Heck, I wasn't even using a bootloader! My hex file was flashed at address 0.
Unlike pinball, there was no reliance on timing with external factors... My process was lock-stepped. Laid out in notes on paper. I was tackling the smallest steps first, building toward a rather large piece that couldn't be broken-up. I needed to be sure the surrounding code was right, so if I later had to debug the big piece I would know whatever was wrong had to be in there. In Other Words, I hadn't even begun coding that bigger piece, except on paper. About halfway through those smaller steps I flashed another small code-change, and instead of getting the results I was expecting, a *tiny* difference from the last, instead the system acted as though I'd written and uploaded the final /large/ code-addition.
Now, /that/ piece of code, which I had not yet typed, was filled with branches that should behave differently under different circumstances. And /new/ behavior. This couldn't've been some simple math or logic or syntax error. It, frankly, /couldn't/ function properly unless it had been fully-implemented, and correctly! I hadn't even typed one line of it. It couldn't function at all; it didn't even exist yet! Yet there it was, acting as if sent back from ten hours in the future.
...
This Sh** Is No Joke. Believe me, I wish it was. I'd been coding AVRs at this level as my main source of income, and hobby, for well over a decade, closer to two! Things continued to be weird like that, and upon looking back I can recall many smaller such instances, before, that I'd chalked-up to simply minor bugs I eventually tracked-down. But, usually in finding them, I'd had some nagging feeling the bugs I found *couldn't* have caused the effects I'd seen. Usually the bugs were simple syntax-errors, a missing semicolon, or an extra one e.g. after a while(), but before the loop it was supposed to contain. I'd eventually find this Glaring mistake, and usually be so glad to have spotted it as to simply fix it and test again, without really thinking about *whether* that mistake *could* cause that glitch. The subsequent test would act exactly as I'd originally intended, so I'd just move on, assuming I'd found and fixed whatever caused the glitch. And usually learning something new along the way, like, early-on, that assignments are allowed in comparisons "if(a=b>c)".... which can get really gnarly if not done VERY carefully, so such things I made a habit of NOT doing, unless there was no other option. And, such habits would make it that much easier to scan my code for bugs... "I know it *can* be done, but I don't do it. There it is, so that must be a mistype."
Unlike those past experiences that I moved-ahead from with merely a nagging feeling I didn't explain, sdramThingZero's "bug" wasn't a mal-function, per se... it was functionality that quite literally had not yet even been written. Quite literally as though I'd flashed the chip with a hex file compiled ten hours in the future. Those nagging feelings, long-ignored, came back to me in a flood at that moment... Memories of trouble-shooting bugs in many old projects, findings of syntax/coding-errors that, suddenly I realized, *couldn't* have caused the effects that yet were "fixed" after the code-fix...
I really don't know how to explain it better. Say your job was to transcribe court-room proceedings from audio recordings... You took a lunch break halfway through, and upon coming back found that two more pages were transcribed than what you had typed. Surely you'd think your boss or a friend did it so you could take off early for the day... right? You might (SHOULD) ask-around to find out whether you can trust whoever did it. Otherwise, for all you know, it might've been the result of a computer-virus. If you're doing work that important, and you can't find the perp, now you have to go over the whole thing again, from the beginning, to make certain it *all* is still transcribed properly.
Other jobs maybe this sort of thing doesn't matter... Maybe these sorts of things happen to everyone and they just have no reason to notice. The pinball wizard just thinks it's excellent reflexes from years of practice. The "Work Hard Play Hard" yard-worker might, upon discovering half the yard's being mowed that he didn't remember doing before lunch, chalk it up to last night's heavy drinking...
Well, I do logic, and if there's anything in this world I'm good at it's that, and I *didn't* take a lunch break, and I didn't drink at the time. It, frankly, could *not* have happened. But It Did. And quite frankly, it scared the he** out of me. To the point that my usual gung-ho troubleshooting mentality (which I frankly somewhat enjoyed), went out the window, replaced by terror, and I haven't touched that code since.
This was not the last such incident, but definitely the most jarring, at least in the realm of my skills/projects.
After that I slowly tested the waters with other projects which, frankly, didn't matter much if such oddities happened. #OMNI 4 - a Kaypro 2x Logic Analyzer, and #Improbable AVR -> 8088 substitution for PC/XT were the big ones.
The former was *supposed* to be just a few nights' effort backing-up a one-of-a-kind 5.25in floppy disk. It literally turned into a months-long near non-stop endeavor trying to squeeze out the data from the last few damaged sectors. I eventually started writing a program to read the entire track as though it was a single sector, then to parse the low-level data (headers, CRC) from it at the MFM-level. It became VERY sophisticated, yet ultimately may've recovered only one sector, whereas eventually I decided instead to use the more de-facto approach to see whether that same sector was readable that way, and sure-enough it came through, along with *several* (and eventually *all*) the others. This using the default method I'd tried *countless* times prior to even begin *thinking* to write that huge program. It didn't work before, so why'd it work then, after all that work, now unfinished and discarded?
It came as quite a blow, frankly. That was a TON of effort, on my part, using decades of related skills and months of new research... I thought I'd contribute that software to the opensource community... and yet ultimately it came down to something a "script-kiddy" could've done, running a small script, easily found online, in a loop, spinning that disk for a few days straight, waiting for luck.
.
The 8088->AVR project was a bit different, in that it was more of a personal-project which I knew from the start might branch off in unknown directions. And it sure did, right off the bat. I'm not much of an artist, so I guess in a way its "bugs" were my art. Working with the CGA video card I ran into quite a few "bugs," mostly related to timing errors and such that I'd love to blame on poor documentation, but were probably more-often due to poor interpretation, on my part. BUT, those "bugs" resulted in some awesome graphics I couldn't've created if I tried... So, I guess, it was a bit like my troubleshooting of years prior, often learning new things along the way. But, really, of little use, otherwise. Heh. On the other hand, after what I'd experienced with sdramThingZero, I was frankly afraid to tread into this realm of sort of accepting whatever *that* was into a project... And the graphics that resulted were often, frankly, eerie in ways that were hard to push through; reminding me regularly of that last night with sdramThingZero. And again, like backing up that floppy disk, taking exponentially longer than I'd expected due not to a lack of understanding of what I needed to do (the AVR circuitry design and drop-in was smooth as silk! That's no easy task; requiring tons of research into pin roles on both the AVR and 8088), but due to matters which, frankly, shouldn't've been matters. Ultimately, with that one, I /again/ found that, essentially, my *first-attempt* should've worked, since the final attempt which *did* work was the result of stripping down all that I'd built-up inbetween. Just like that friggin' floppy disk.
...
I've been homeless for half a decade, since.
.........
...Heh, later the day I posted this, this showed up on the blog...
Notice anything buggy about that for loop? Oh, two things, actually... but one quite relevant.
-
TODOs
02/19/2019 at 03:16 • 0 commentsYup, sTZero's been on hiatus for a while... life 'n such.
UPDATESs will be placed at the bottom...
Here's a thought:
SN74LVC1G123 - might just handle our one-shots... Personally, the idea of using RC timing doesn't quite sit with me, for this project, being largely variable in its sample-rate... But, maybe som'n can be done tying those R and C inputs to something like the SDRAM clock. Or maybe some other path, even with R and C fixed (e.g. at 10ns, for max-sampling at 100MS/s) as long as we can assure that 10ns pulse meets setup/hold times for the instruction-load clock-edge (when sampling at lower rates).
Dunno...
Anyhow:
https://hackaday.com/2019/02/18/inefficient-neopixel-control-solved-with-hardware-hackery/
----
2-29-20:
Vague idea: since trying to interface with an 8-bit bus, maybe read-back of the sampled 32bits could happen by a sort of bucket-brigade. [And maybe similar for writing the free-runner?]. E.g. read the first chip, write from the second to the first, read the first again. Thus, plausibly reducing the number of chips [loading] on the bus, and plausibly the number of latches/buffers.
Also plausible, read first SK chip to bus, read second chip to FR first chip, etc. [Overwriting FR, but can be rewritten], a sort of left-right-forward bucket-brigade. [May be more feasible; since data I/Os are a single pin, loading wouldn't be reduced much if B4->B3->B2->B1, but would if B4s->B3f, B3f->B3s... erm, no...]
BUT: B4-/\/\/-B3-/\/\/-B2-/\/\/-B1-/\/\/-Bus... hmmm. Only not-so-much, *maybe* since all SK chips [and all FR chips] use the same command signals [ [all chips reading/writing simultaneously] I Wonder, since read-commands and write commands take a different number of clock cycles, maybe a read's data would linger long enough to be registered by a write, hmmm. Could be handy elsewhere, too [copying FR commands/NOPs from bank to bank?] ].
BUT: B4s-/\/\/-B3f-/\/\/-B3s-/\/\/-B2f-/\/\/...B1s-/\/\/-Bus... wouldn't have that limitation [read from SK, write to FR simultaneously should work]
[Of course, B4s=1, B3s=0, B3f=0.5... hmmm.... resistor values increase left to right? Diodes? Buffers, of course, but then more control signals /OE, when sampling, no?]
Ideally, would also reduce the number of control signals necessary to select which byte to read-back [knowing they'll always be read in order]... a sort of byte-wide shift-register.
---
8 devices attached to a bus with only one buffer [two slightly preferable]. A shift-register, of sorts...
---
Ahhhh...
But this overwrites one side's data with the other's.
It works[?], in this case because the Sidekick's data is loaded from the sample inputs *not* from the bus, thus Read-only, from the bus's perspective. Whereas the Free-Runner is [or could be] write-only from the bus's perspective.
Sample-data can be destroyed upon read-back AND when writing the Free-Runner. Free-Runner data can be shifted back in during either process. Weird.
The resistors could be replaced with buffers with /OEs tied directly to the other /OE's... I spose that'd be easier to design. And still no extra control signals necessary.
But I'm a bit fixated on using passives; making use of the circuitry inherent to the devices... dunno why. And resistor-nets are a *tiny* bit cheaper, no?
----
And more pondering... I think it requires a DQ latch to store the new FreeRunner data to be shifted in while shifting the data from the SideKick into the other FreeRunner registers... because, at that same time, the last SideKick register is also outputting to the bus [so can't contain the new FR data simultaneously].
Here we have a new dilemma... with another shift-reg comes another control signal [though "strobe" may be necessary elsewhere anyhow]. So, another option is to sacrifice 8 bits of sample-inputs to use as that register. Wastes a lot of memory and brings the sample inputs down to 24 from 32... but, easier to program, faster to read/write, fewer chips, and likely fewer control signals. Definitely a consideration... could be, for instance, an *option* with a few jumpers on a PCB, or could be a simpler design for hobbiests to implement on their own... every chip and wire makes for more points of failure [e.g. noise, propagation delays, etc.] So, for e.g. a first run/prototype/breadboarded weekend project/kit it may be a good option.
----
LOL... these aren't merely registers, they're RAM, with MEGABYTES of addressable storage locations.
I could *easily* sacrifice a single page [or even a row] for nothing but shifting/shuffling data, and not even care what's overwritten in that "temp" page.
And here I was worried that reading back the sample data would be destructive to the "program," and thus would have to rewrite the program memory while reading the sample memory.
LOL MEGABYTES to work with, here. Sheesh!
---
On another note, because of "burst" reads/writes, I think I can copy an entire row [from one bank] of sample data [256-1024 bytes, depending on the chip] during each "shift" operation.... and likely do-so at the full SDRAM speed of, say, 100MSps. So actual read-back into the computer via the bus will be pretty much the limiting bottleneck, *not* the fact that the data has to be copied 7 times!
Further thoughts on this path over at #Memory Shift
https://hackaday.io/project/170172-memory-shift/log/174383-overview
---
Been meaning to link this... I've certainly pondered sdramThing's ability to be used as a processor... I think I've other links/thoughts on the matter in other logs, at #sdramThing4.5 "Logic Analyzer" , on my website [should be in the external-links at this main project-page], and/or in the source-code. TODO maybe someday work on consolidating such notes by topic?
https://hackaday.com/2020/02/20/a-turing-complete-cpu-from-ram/
-
Wouldja lookie there
09/20/2017 at 23:45 • 0 commentsas an aside at #Floppy "Fun" -- Backing up a unique Kay-Pro disk ... I just happened across this:
Heh... guess I'm pretty good at (eventually) reinventing the wheel.
Those are from the z80 datasheet.
-
Random Updates...
01/19/2017 at 03:47 • 0 commentsUPDATE: Apparently I've found a general-spec... See the bottom
-------
sdramThingZero is still on-hold, but of course still runs 'round the ol' back of the head... There's nothing really stopping progress, just haven't gotten around to designing/ordering PCBs. In fact, the breadboarded sdramThingZero is still sitting on my desk right under my monitors.
------
So here's something interesting:
Does that look familiar, at all?
Yep, it's pretty much exactly the same topology as the "one-shot" logic used in this project. Two flip-flops in series, both receiving (in some form) the input, performing some logic on the original and the delayed/latched output, and even an async-input (similar to my "one-shot Bypass" input). This is from the Intel 8284 datasheet, that's the clock-generator used for PC/XT (8088) computers. Besides clock-generation, the 8284's other key feature is what we see here, synchronizing an asynchronous "READY" signal to the system-clock... Just like my one-shots synchronize an asynchronous Chip-Select or Clock-Enable signal to the SDRAM's clock.
Why's this interesting to me...? Maybe this is some sort of de-facto topology used all the time...? The fact is, I designed that circuit without having looked it up... I used knowledge of what was going in and expectations of what I wanted out, and I designed a circuit to do-so. I knew it *would* work, for the most-part (what happens if the asynchronous input comes between the setup/hold times? TI's thoughts here), but I didn't expect that it was good 'nough for a product. And yet, there it is!
------------
SDRAM initialization:
Note, first, I'm no trained expert... this is all what I've gathered in my experience with hacking SDRAMs... (single-data-rate, NOT dual-data-rate!)
See also: https://sites.google.com/site/geekattempts/home-1/sdramthing/using-sdram
Someone commented on my youtube-video, prompting me to respond that... basically... the SDRAM initialization-process, unfortunately, pretty much requires the entirety of the functions one might need to make use of the SDRAM, including ones that are otherwise unnecessary, and more.
What do I mean...?
Well, it's not like SRAM, where you can just turn it on, write a byte, and read it back (and you can repeat the write/read process at any other address, immediately thereafter).
It's not like DRAM, where you can just turn it on, select a row-address, write a byte, and read it back (and you can repeat the select-row/write/read process at any other row/col-address the next time 'round).
So what's it like...?
Well, first, let's *merely* look at the write/read procedure.Note that this example differs from the SRAM/DRAM examples given earlier in that this can only happen *after* initialization, it can't be done immediately after power-up (we'll come back to that).
To write a location and read-back you have to open a row (similar to DRAM), then you have to perform a write at your column, then you can read it back... That's pretty much the same as DRAM, except that if you want to do-so again at a different row, you have to explicitly choose to *close* the original row, first. (Closing a row is called "precharging").
So, realistically the write/read-back procedure is similar to DRAM *unless* you want to access another row.
But, we're just trying to do the *simplest* experiment, right...? Just to make sure we're wired-up correctly.
(See Note1 below)
So, say you're developing a *really simple* project, wherein all you want to do is write data, and read back... And, say 256 bytes is more than enough for you... (when opening a row, you have access to a minimum of 256 bytes/"columns" from that row at a time... some devices support up to 1024).Then you'd be set, you'd never have to think about precharging. (And, another cool side-effect is that as long as a row is open, it is inherently stored in registers rather than merely dynamic-RAM cells/leaky-capacitors, so needn't be refreshed... Handy!). BUT, you *would* have to consider the fact that you can't "activate" a row when a row's already active. Which means your write/read/repeat procedure needs to be: open/activate, write, read, write, read, write, read... (don't open/activate a/the row each time!)
So, now...
Why this long explanation, we were talking about initialization.
OK, SRAM: write/read, write/read...
DRAM: open-row, write/read, [optionally open another row], write/read...
SDRAM: open-row, write/read [optionally: close row, open another row], write/read, write/read...
But, again, we're trying to do a *really* simple experiment... so let's skip the optionals... We'll do *everything* in the same row... then we don't need to implement the "close-row" ("precharge") procedure...
So, to do a *really simple* experiment, we only need to implement three functions, right? open-row, write, read. (And, if we were implementing auto-precharge, as in Note1, we could access the entirety of the memory, and perform additional functions like refreshing, with only those three commands!)
Nope.
Because, unlike SRAM and DRAM we also have to initialize the stupid thing.
Because it's a state-machine, which doesn't power-up into a known state. It has a configuration-register, which (per-specs) isn't automatically-initialized to a known/valid value on power-up... and, should one manufacturer's model just happen to power up in one of *many* of the possible valid states, in the majority of cases, it won't be usable with a *really simple* system.
So, now, we managed to figure out how to whittle down the necessary commands to *use* the memory down to pretty much the same as DRAM: open-row ("activate"), write column, read column (with auto-precharge).
But, the initialization-procedure, which you'd be lucky to get the system working without, includes many of the commands we managed to avoid... Including: "Precharge All" and "Auto-Refresh", in addition to the obviously-needed "Load Mode-Register" (configuration-register) command.
So, to *reliably* use the system, even just for quick verification you understand its wiring/functionality, you have to implement *numerous* commands, many of which will never be used again, and all of which result in no feedback whatsoever as to whether they actually worked... until it comes time to write/read. A whole lot has to be implemented "blindly."
To top that off, many of these commands *cannot* be executed repeatedly (as would be the case if your "chip-select" signal is active for longer than *exactly* one clock-cycle). Which is why I use one-shot circuitry, in this project, and why other earlier versions of sdramThing use inline-assembly to strobe the chip-select for exactly one clock cycle... and why SDRAM *cannot* (within specs) be interfaced to GPIOs, without one-shots, in systems where exact clock-cycle-counts can't be controlled/predicted (e.g. GPIOs on a Raspberry Pi, or any system running interrupts, an operating-system, or with cache, branch-prediction, unpredictable wait-states, etc.)
WEEE!!!
-----------
Note1: Technically, it looks like it might be possible, within specs, to simplify the write/read/repeat process to be more like DRAM, wherein the entirety of the RAM, including other rows, could be accessed with a open-row/write/read (and no need for an explicit close-row command). You can perform the "read" (following the "write") with an "auto-precharge" by merely changing one bit during the "read" command. Then, you could run the same procedure as with DRAM: select a row-address, write a byte, and read it back (with auto-precharge), repeat anywhere you like. The problem is that, because it's *synchronous*, doing it this way is even more complicated than adding an explicit "precharge" command, because it requires that you know *exactly* the number of clock-cycles between requesting the "read-with-auto-precharge" and actually *reading in* that data into your processor, etc.
----------
So, I've been contemplating whether the process of just getting started could be simplified a bit... (while still being reliable enough for early experimentation). And, looking into a couple different specifications from different manufacturers, it looks like the answer is "not really".
The problem is, *in general* the specifications are pretty clear, in their lack of clarity regarding what's to be expected of/from these devices, in general.
E.G. the Micron datasheet I've been doing all my development from explicitly states that it's acceptable to interrupt a read-with-auto-precharge with another read in the same row. Handy. So then you could *always* request an auto-precharge, and if you want to, you could hold that "chip-select" line as long as you want (even long-after reading in the data), and the result would be multiple back-to-back "read" commands, at the same memory-location, each interrupting the auto-precharge of the previous... And, essentially, once you eventually get around to releasing that Chip-Select, the auto-precharge would occur. NICE! The Micron datasheet even shows timing-diagrams of this interruption. It's a thing!
Now, I've just dug up a new-to-me Hynix datasheet which explicitly states that interrupting a read-with-precharge with another read (or write) is *not* allowed. In fact, the wording is "ILLEGAL".
--------
So, what's the point...? I guess it's a question of whether you want to work within the *clearly-defined* specifications for generic devices--not relying on specifications which are vague or device-specific--in which case you should be able to wire-up any brand of chip and use the same code... Vs. whether you want to work with a specific chip (and gain the benefits of its additional features!)...
Note that PCs (Computers) have some sort of general specification that works with darn-near all conforming devices that might be thrown at 'em... So, there must be some specification, somewhere (jedec? paywall?) that defines the guarantee-ables that all devices conform to.
In my experience, I've been referring to that Micron datasheet almost [but-not] exclusively, and expecting that where it's unclear, it's probably that way due to unclarities in the general-spec (e.g. can you perform a row-activate after a row-activate, without an intermediate precharge, if they two row-activates occur *in the same row*? What happens when you select a burst-length that's "Reserved"?)...
It would be a mistake, (one I've probably made) to interpret any specific device's datasheet's specs as *general specs* for all devices conforming to the PC-66/PC-100/PC-133 specs. (E.G. the Hynix device lists burst-modes of up to 128 columns (aside from "full page" bursts), whereas the Micron only lists up to 8... the other mode-settings being "Reserved." E.G.2: Can CKE be disabled at any time, especially in the middle of an operation, or only during burst-reads/writes?)
I haven't found the all-encompassing "general spec" used by PC-66/100/133 *devices*. But, so far, I don't think I've made use of any device-specific features, and have been testing my code on DIMMs from several manufacturers.
And, again, if you're planning to work with a *specific* device, then these factors don't matter... use what the datasheet provides, or experiment and see what happens! Just keep in mind that if you try to do writes/reads without doing an initialization, first, you may not get *anything*, or may get *really confusing* results that work sometimes and not others.
----------------
So, come on... I've been working on sdramThing for nearly five years, now... between sdramThing1.0 and 4.5, and now sdramThingZero. So all it takes, this time, to find an alleged general-spec is a search for "PC-133," a click-through to the wikipedia page, and opening the very first reference? Please, you think I haven't done this before?
Here's the great bit:
The objective of this document is to define a new Synchronous DRAM specification (“PC SDRAM”) which will remove extra functionality from the current JEDEC standard SDRAM specification, so that it will be a “fully compatible” device among all vendor designed parts. It should be easy to design and manufacture and highly cost optimized for the main stream volume desktop Intel architecture PCs.
Right... So, assuming most manufacturers of PC66/100/133 SDRAMs want to be compatible with Intel-Architecture PCs... they'd probably meet all these specs... which is exactly what I was talking about. WEEEEE!!!!
(First observation: Burst-lengths of greater than FOUR are "Reserved". And Full-Page bursts are as well?! WTF. I never...
-
On Hold... + Great Quote.
12/08/2016 at 17:00 • 0 commentsNot sure what my last log was, but this project has been put on-hold, as I've managed to bump some wires, or something, causing it to be much less reliable than it was previously. Time to PCBify, or at least point-to-point-solder it. And haven't had that kinda energy.
In the meantime I leave you with this quote I stumbled upon, might say a bit about me:
"SDRAM represents clinical levels of insanity to initialize" -- @Samuel A. Falvo II
-
FAIL, sorta expected...
11/22/2016 at 10:59 • 4 commentsIn the last log was a TODO:
TODO: Believe it or not I did all that layout without actually verifying the chips I have match those footprints. Usually that'd be the *first* thing I'd do... Usually I'd make my own, in fact, because I rarely trust those provided. This time, for some reason my brain's been on this tetris-style packing-kick. Could be risky. I guess we'll see. I can feel the datasheet-lookup energy building... may be a few days. Or maybe I'll just print the danged thing and set my chips on the printout.
Whelp, I printed it out... and it turns out it was risky.
Out of 7 footprints I chose and laid-out, only 3 were correct.
The 20-pin 7400-series SOICs in my collection are *wide*... Easy enough to fix since it's laid-out on breadboard.
The 56-pin SSOP is 0.5mm spacing, not 0.4mm... Whelp, that was a lot of work for nuthin.
The clock-generator chip is actually SSOP-10 (?!) not SSOP-8, and... I dunno what spacing, smaller than 0.4mm, it seems.
........
I suppose I should take a step back and re-evaluate this ordeal... Maybe I'll spend a few days cleaning the apartment, first.
Or maybe I'll just go play some Tetris... My gameboy's long-gone, and I'm tired of staring at the TV/monitors... I hate using my phone's touchscreen for things like this...
But I just happened to save one of those ridiculous cheapo hand-held games from the 90's with the custom LCDs, and it just happens to have Tetris on it... Time to dig out the file and scouring-pads and dig through the box of batteries.
-
solder-proto for the next-generation
11/21/2016 at 20:22 • 0 commentsApparently it's brain-dump time.
In the previous log I showed my thoughts on making a sorta general-purpose prototype-board that can be used for the first soldered prototype, as well as be used/usable for many other unrelated projects...
Here's the latest fixation... Weee!
What I didn't mention was how this proto-board also looks to the future of *this* project...
This project has two main phases, I see...
First is getting it as fully-functional (sample/repeat, high-speed, trigger, adjustable sample-frequency) as I can... That's easiest done with a uC that has plenty of GPIO pins... Thus I'm using my trusty ol' ATmega8515 40pin-DIPs... and, as I described in the last log, that lays-out perfectly over some otherwise currently-unnecessary breakout-space on my protoboard-design...
The second phase is replacing the dedicated AVR in favor of whatever host one might want to use... e.g. a single-board computer like the Raspberry Pi, or even via an FT2232 chip connecting it directly to your computer via USB. The hurdle, here, is that this requires whittling down the number of required GPIOs to something reasonable... like an 8 or 16-bit data-bus.
There's plenty of contemplation in my various logs regarding how I'll do that, and I don't doubt that I've got it mostly-figured-out... I could probably, if my brain works in my favor for that long, whip it out in less time than it'd take to receive this PCB order.
But, I guess, I tend to take an iterative-approach with my projects, rather'n going gung-ho with a design->PCB... And, the current scenario is that the solderless-breadboarded prototype has become increasingly-flakey (largely, I'm sure, due to wires getting bumped, "antennae" everywhere, etc...(interestingly, when I run it at 50MHz, it interferes with my TV reception!))... The likelihood of this guy lasting a year and being able to just power it up and make use of it is... pretty low.
So, iteratively, I still have a bit I could experiment with and implement while connected to an AVR... and, I wouldn't mind having a reliable prototype that I can come back to later down the line and turn on and expect to still work.
-------
Oy, all that explanation to say... no, I haven't forgotten about the second-phase, in this proto-board's design.
Whittling down the GPIO-necessity is mostly just a matter of a bunch of latches... and low-and-behold, I've laid out this board for two 8bitters... Right under where the AVR goes, currently. And, again, I'll be using *two* of these boards for a single DIMM, so I'll have four 8bit latches available and broken-out. And, again, I've laid out SOIC-breakouts as well, 20pinners, which will also work for 74xx574 latches. So... I think we're set. And if not, then I can just as easily throw a third board at it. (Yay buying in quantities!)
In fact, who knows, I might just bypass the AVR soldered-proto... It's plausible. I do have a PiZero and now also an LCD with HDMI, after all! And I plan to order an HDMI cable/adapter alongside this PCB-order... So, who knows.
--------
The image above shows the current state of the 574 breakout(s)... It wasn't easy fitting them in there, being that the other side is a TSSOP-80/56 breakout, but it wasn't particularly difficult, either. It was easier than I expected, though. A pleasant surprise, for sure.
I *think* I might be able to squeeze that 8-pin TSSOP in between, but that might be almost as much work as the two 20pinners, and plausbly not possible, due to the number and positions of the vias and the red-traces necessary for the current setup.
The idea, there, is to throw in the clock-generator chip... (also explained in previous logs)... That guy basically allows one to select from a huge selection of clock-frequencies anywhere from 500Hz to 200MHz (thus, sample-frequencies). Could be quite the gizmo, and I haven't yet experimented with it.
(Also, it requires I2C, which I'm not expecting the "host" to provide, meaning I might be implementing it via bit-banging via the host-interface, or something).
----
TODO: Believe it or not I did all that layout without actually verifying the chips I have match those footprints. Usually that'd be the *first* thing I'd do... Usually I'd make my own, in fact, because I rarely trust those provided. This time, for some reason my brain's been on this tetris-style packing-kick. Could be risky. I guess we'll see. I can feel the datasheet-lookup energy building... may be a few days. Or maybe I'll just print the danged thing and set my chips on the printout.
----
Anyways, all that to say, of course this project is still aimed at more powerful hosts than this lowly AVR. And of course I'm keeping that in mind while developing this protoboard. These things develop the way they do...
-
solder-proto
11/21/2016 at 13:17 • 8 commentsUPDATE -- New SOIC-breakout... see below.
Working on a solderable-prototype... due to solderless-breadboard-wiring-wonkiness.
Decided not to design a full-on PCB, yet, as it's still in the prototyping-stage...
Decided on 70mm x 70mm boards, they're much cheaper than the width necessary for a DIMM, so I'll "cludge" two together... It's actually pretty easy and stable with thin PCB-material to just overlap them for one or two rows.
So, the board design is somewhat generic.
First things first, the DIMM socket will solder into two 70mm tall boards with this running from end-to-end:
Might take a little hand-drilling for the support-mounts, etc. But I'm more than OK with that.
The thing about the DIMM sockets is that they have this weird footprint with diagonals... more on that in a bit.
Next we have some breakout for surface-mount chips, since 7400's in the speeds we're looking for mostly only come in SSOP, or if you're lucky (as a prototyper) SOIC.
(Yes, this is a breakout, for prototyping. No these traces are not matched-length, and who knows what kind of signal-issues may arise due to their closeness to each other).
Now, you might look at that layout and go "whhhaaaa??!"
But check this out... If I'mma make a prototyping-board and have ten of 'em made, I'mma think of other projects as well... So the above was designed *after* (on the other side of) this:
I don't actually have any SSOP80 chips, that I'm aware of, but I do have some TSSOP56's I'd been planning on using... So this'll break that out nicely, and leave room for later prototypes.
(If you have better ideas how to label the "pin numbers" to accomodate an arrangement like this, I'm all ears. I've thought about A1-A9, B1-9, etc... just to make it clear that these numbers *don't* correspond to the pin-numbers on the likely-smaller chips that'll be installed. I know better, but've been caught slipping-up on TQFP100 adapters fitted with smaller devices).
Again you might say "whhhaaa?!" at the breakout-layout/numbering... Herein, the layout is specifically-designed to occupy as little space as possible while *also* being easily "straddled" with a 32-pin DIP, or even 40-pin, yahknow, with a few extra holes at the ends.
So, that may seem a bit ridiculous, but consider sdramThingZero's parts-tally so far... We've got a 40-pin DIP (AVR), a SSOP-20 (74xx574 latch), and two SOIC-14's (74x00 NANDs). (Though, since this's been designed, I might opt for SSOP-14's in future orders). And, again, consider that this single board-design will be used *twice* to handle the DIMM socket... On one board, I can throw the AVR over the above layout and not waste a whole bunch of holes under the DIP.. On the other board, I can already handle two of my three 7400-series chips... again in that same workspace.
And, I'm currently working on a more generic SOIC-breakout... Which isn't too-difficult considering they're half the space of regular breadboard spacing... meaning that when they're not populated, that space can be used as regular 'ol breadboard:
So, the SOIC can be placed, it's a bit easier to solder to a via than directly to a pin... and it makes for backside-wiring, which I usually prefer. Note, again, if I don't need to place a SOIC, then that entire space can be used just like regular ol' 0.1in breadboarding-space. Should also work quite well with e.g. SOT-3, no?
Then, there's the "center vias" I thought Ted was talking about in the comments, below... But he was talking about different ones. These center-vias alternatingly attach to "planes" on the top and bottom layers, making it easy to essentially have power and ground-planes on a 2-layer board, and easy to "solder-blob" most pins directly to 'em, or insert surface-mount decoupling-caps, pull-resistors, etc. on the back-side.
Debating the use of octagonal vs circular pins/vias... also experimenting with the planes' violating the DRC trace-width rules...
---------
So, this, like all my soldered-breadboard prototypes, will be wired point-to-point with "wire-wrapping" wire... (Though I may try out enameled-wire in the future). It's pretty easy to do when you've got plated-through-holes to solder-to...
Here's an old project, #audioThing pretty small.(I know I've some better examples, but camera's not reachable, and these are the best I've found online...)
Note that I used two overlapping pieces to achieve that shape... just as I intend to do with this project. In that project, the DIP socket actually serves as a bit of structural-support for the overlap. In this project, the DIMM socket will do the same, but I'll probably also solder in some scrap-wire (or resistor-lead cuttings?) through all the remaining overlapping holes... "stitching" the two boards together. (On that note, maybe I won't overlap them, but instead will stitch them together side-by-side? Hmmm, not sure I'll be getting the holes perfectly-spaced with the edge for that... Though I finally have a nibbler-tool again!).
Another project-idea makes use of some funky-connectors with spacing very similar to the PCB-footprint of SDRAM, so another "two-birds-with-one-stone" scenario...
This guy's an early-early prototype of that... Well, it was *supposed* to be an "early-early prototype" but it's been running for two years now, used daily... so don't balk at its ugliness ;)
Note the black connector on the left... Its mate *did* have very-similar (diagonal) footprint-spacing as my DIMM-socket, until I forced it to fit in regular ol' 0.1in (square) breadboard. It was not easy, but it does work. That'd be much harder with a DIMM-socket since, among other things, it's got more than 5 times as many pins... And that's not the real kicker... The real kicker is the fact its pins aren't in 0.1in "columns" but 1.6mm, instead. So, 0.1in "rows", but four 0.63in columns. *really* hard to stretch-to-fit on 0.1in spacing... thus the main reason this new proto-board is being designed in the first place.
But, I think the connector finagled in the image above would be *much easier* to finagle into the DIMM-socket's diagonal spacing than it was on 0.1in (square)... So, again, kinda two-birds-with-one-stone.
And...
I dunno about you, but solderable-breadboard is one of those things I use even in tiny pieces... I've cuttings saved-up that are only two 0.1in-spaced pins... These are handy for e.g. adding strength to snap-apart headers, when they're not soldered-directly to a PCB... Or yahknow some of those headers that the pins slip in-and-out of... or maybe you're putting an LED on a panel-mount and need an inline-resistor that happens to be surface-mount... Breadboard-scraps of all sizes are just handy to have around.
So it strikes me as somewhat surprising I've never heard of "breadboard-grab-bags" from the ol' PCB-manufacturers... surely not everyone makes perfectly-square PCBs that interlock perfectly with all the other boards being fabbed at the same time...
This shot is from https://hackaday.com/2016/10/15/look-what-showed-up-for-bring-a-hack-at-osh-park/
Might be hard to squeeze too many DIP-40 sized breadboards out of these scraps, nevermind needing to add an extra CNC-mill path... But I imagine they've all sorts of shapes/sizes of scrap from *between* boards that could be filled with 0.1in spaced holes. Maybe even oddities like 2mm-spaced... or even some random oddly-shaped SOIC/SSOP-breakouts... A script just randomly throws some useful stuff in whatever space is left-over between boards... don't bother milling them to a specific shape. What're yah gonna do with that crescent-moon-shaped breadboard? Mini Grab-Bag with every order, or "The Big Grab Bag" for $1.00...
(You'll note my boards aren't in purple... I haven't yet ordered boards from @oshpark... How would y'all feel about an order for 10 70mm x 70mm boards with nearly 1500 plated-through-holes on each...? More importantly, how would yer drilling-robot feel about it?)