The Smell of Molten Projects in the Morning

Ed Nisley's Blog: Shop notes, electronics, firmware, machinery, 3D printing, laser cuttery, and curiosities. Contents: 100% human thinking, 0% AI slop.

Category: Software

General-purpose computers doing something specific

  • Seiko Epson RTC-65271 Real Time Clock Datasheet

    RTC-65271 Module
    RTC-65271 Module

    I have a stash of RTC65271 real-time clock modules and might use one in an upcoming project. They’re obsolete by nigh onto two decades, but it’s a one-off project and I know I’ve been saving these things for some good reason.

    Alas, the datasheet doesn’t seem to appear anywhere else on the web; you can find an overview & general description, but not how the thing actually works.

    However, if you happen to have a chip and need the datasheet, this is indeed your lucky day: a scanned RTC65271 Datasheet.

    The datasheet alleges it’s “functionally compatible with MC146818A and DS1287“, and those datasheets may be more readable, if not exactly applicable. It seems to be (similar to) the clock chip used in the original PC/AT, if you recall those relics, and might actually use standard hardware & software protocols.

    Dealing with this thing may be more trouble than it’s worth in this day of bus-less microcontrollers with Serial Peripheral Interface widgetry. A back-of-the-envelope count says it’d require three ‘595 output chips and a ‘166 input chip to fit on an SPI bus. Yuch…

    Hey, if you want one, drop me a note. I have far more than a lifetime supply at my current rate of consumption.

  • TCFFHRC Rules Document: LyX / LaTeX Settings

    I’m editing the Trinity College Home Firefighting Robot Contest rules document using the LyX GUI front end to LaTeX to handle the formatting.

    Yes, yes, I know OpenOffice and its ilk have all the features you think you need. When you actually try to put together a book-length document, you find that the features don’t actually work / work together / behave reliably. Been there, done that. Enough times to be wary, indeed.

    So LyX / LaTeX is the least-worst alternative and actually does a pretty good job after you get the various configurations beaten into shape. After that, you just type, add tags, and it’s all good.

    Here’s a list of the settings I’m using… for future reference, natch, because figuring this stuff out from first principles takes a while.

    Document settings

    Document Class: report
    Text Layout: MedSkip vertical, Single line, Two-column
    Page Layout: US Letter, fancy headings
    Page Margins: 0.75 inch all around, 0.3 inch separations</pre>
    <strong>LaTeX Preamble</strong>
    <pre>\usepackage{ragged2e}
    \usepackage{lastpage}
    \usepackage{url}
    \usepackage{dvipost}
    \usepackage{breakurl}
    \usepackage[labelfont={bf,sf}]{caption}
    \renewcommand{\bottomfraction}{0.7}
    \pagestyle{fancyplain}
    \fancyhf{}
    \lhead{\fancyplain{}{Trinity College Home Robot Contests}}
    \rhead{\fancyplain{}{2010 Rules}}
    \lfoot{\fancyplain{Modified \today}{Modified \today}}
    \cfoot{Copyright 2009 by Trinity College}
    \rfoot{\fancyplain{\thepage\ of \pageref{LastPage}}{\thepage\ of \pageref{LastPage}}}
    \RaggedRight
    \dvipostlayout
    \dvipost{cbstart color push Blue}
    \dvipost{cbend color pop}
    

    Trickery

     

    Some of those packages aren’t part of the default LyX / LaTeX installation on Ubuntu. Searching for LaTeX in Synaptic is tedious, but works.

    The three ways to export to PDF are not identical.

    • dvipdfm doesn’t produce clickable TOC links.
    • pdflatex, the default, doesn’t produce change bars, which is a crippling defect for a rules document under heavy revision. It’s OK for the final draft, though.
    • ps2pdf doesn’t produce searchable text; it’s all graphics. Ptooie!

    So use dvipdfm during development (to get change bars) and use pdflatex for the final product (to get clickable links). There has got to be a way around that, but I haven’t a clue as to what’s going on under the hood.

    In order to track changes:

    Document -> Change Tracking -> Track Changes.

    In order to print change bars and suchlike:

    Document -> Change Tracking -> Show Changes in Output

    Figures appear on-screen in dot-for-dot mode by default, so tweak the on-screen ratio to maybe 50%. Force the printed width of all figures to 3 inches for two-column layout. Insist that picture resolution bear some resemblance to reality: 3 inches at 300 dpi -> 1000 pixels across.

    There seems to be no way to export LyX directly to ODT. Exporting to RTF strips off most of the formatting, as you’d expect, and change tracking Goes Away.

    Exporting to HTML produces one honkin’ big lump of HTML with a bazillion image files in a separate directory. That’s probably OK for most purposes.

    Memo to Self: Turn off change tracking for minor editorial tweakage, because nobody really cares.

  • Adding a Device to LTSpiceIV

    Searching around for an LM386 SPICE model turned up this useful thread.

    The model has some limitations, discussed there, but seems practical. So far, the main gotcha is that the output voltage doesn’t center neatly at Vcc/2, but that’s in the nature of fine tuning.

    The trick is getting the model & symbol into Linear Technology’s LTSpiceIV

    Running under WINE in Xubuntu, the emulated C drive is in your home directory at

    .wine/drive_c/

    with the Linear Tech LTSpiceIV files tucked inside that at

    .wine/drive_c/Program\ Files/LTC/LTspiceIV/

    Incidentally, WINE puts the program icon in

    .local/share/icons/05f1_scad3.0.xpm

    It’s not clear what the prefix means, but the actual executable is scad3.exe (I think that’s historical cruft, as the new overall name is LTSpiceIV).

    Copy the LM386.sub file to lib/sub and the LM386.asy file to lib/sym, then restart LTSpiceIV.

    After putting the symbol in the schematic, I had to edit its attributes (other-click the symbol), make both InstName & Value visible to see them on the schematic, then move them to somewhere other than dead-center in the symbol. I can’t figure out how to make that happen automagically, as it does with other symbols. Comparing the two files to ordinary components doesn’t show anything obviously missing.

    Link rot being what it is, here’s the LM386.sub file:

    * lm386 subcircuit model follows:
    
    ************************************original* IC pins:     2   3   7   1   8   5   6   4
    * IC pins:     1   2   3   4   5   6   7   8
    *              |   |   |   |   |   |   |   |
    .subckt lm386 g1  inn inp gnd out  vs byp g8
    ************************************original*.subckt lm386 inn inp byp  g1  g8 out  vs gnd
    
    * input emitter-follower buffers:
    
    q1 gnd inn 10011 ddpnp
    r1 inn gnd 50k
    q2 gnd inp 10012 ddpnp
    r2 inp gnd 50k
    
    * differential input stage, gain-setting
    * resistors, and internal feedback resistor:
    
    q3 10013 10011 10008 ddpnp
    q4 10014 10012 g1 ddpnp
    r3 vs byp 15k
    r4 byp 10008 15k
    r5 10008 g8 150
    r6 g8 g1 1.35k
    r7 g1 out 15k
    
    * input stage current mirror:
    
    q5 10013 10013 gnd ddnpn
    q6 10014 10013 gnd ddnpn
    
    * voltage gain stage & rolloff cap:
    
    q7 10017 10014 gnd ddnpn
    c1 10014 10017 15pf
    
    * current mirror source for gain stage:
    
    i1 10002 vs dc 5m
    q8 10004 10002 vs ddpnp
    q9 10002 10002 vs ddpnp
    
    * Sziklai-connected push-pull output stage:
    
    q10 10018 10017 out ddpnp
    q11 10004 10004 10009 ddnpn 100
    q12 10009 10009 10017 ddnpn 100
    q13 vs 10004 out ddnpn 100
    q14 out 10018 gnd ddnpn 100
    
    * generic transistor models generated
    * with MicroSim's PARTs utility, using
    * default parameters except Bf:
    
    .model ddnpn NPN(Is=10f Xti=3 Eg=1.11 Vaf=100
    + Bf=400 Ise=0 Ne=1.5 Ikf=0 Nk=.5 Xtb=1.5 Var=100
    + Br=1 Isc=0 Nc=2 Ikr=0 Rc=0 Cjc=2p Mjc=.3333
    + Vjc=.75 Fc=.5 Cje=5p Mje=.3333 Vje=.75 Tr=10n
    + Tf=1n Itf=1 Xtf=0 Vtf=10)
    
    .model ddpnp PNP(Is=10f Xti=3 Eg=1.11 Vaf=100
    + Bf=200 Ise=0 Ne=1.5 Ikf=0 Nk=.5 Xtb=1.5 Var=100
    + Br=1 Isc=0 Nc=2 Ikr=0 Rc=0 Cjc=2p Mjc=.3333
    + Vjc=.75 Fc=.5 Cje=5p Mje=.3333 Vje=.75 Tr=10n
    + Tf=1n Itf=1 Xtf=0 Vtf=10)
    
    .ends
    *----------end of subcircuit model-----------

    And the corresponding LM386.asy file:

    Version 4
    SymbolType CELL
    LINE Normal -64 -63 64 0
    LINE Normal -64 65 64 0
    LINE Normal -64 -63 -64 65
    LINE Normal -60 -48 -52 -48
    LINE Normal -60 48 -52 48
    LINE Normal -56 52 -56 44
    LINE Normal -48 -80 -48 -55
    LINE Normal -48 80 -48 57
    LINE Normal -44 -68 -36 -68
    LINE Normal -40 -72 -40 -64
    LINE Normal -44 68 -36 68
    LINE Normal -16 -39 -16 -64
    LINE Normal 0 32 0 48
    LINE Normal 48 -8 48 -32
    SYMATTR Value LM386
    SYMATTR Prefix X
    SYMATTR ModelFile LM386.sub
    SYMATTR Value2 LM386
    SYMATTR Description Low power audio amplifier
    PIN -16 -64 LEFT 8
    PINATTR PinName g1
    PINATTR SpiceOrder 1
    PIN -64 -48 NONE 0
    PINATTR PinName In-
    PINATTR SpiceOrder 2
    PIN -64 48 NONE 0
    PINATTR PinName In+
    PINATTR SpiceOrder 3
    PIN -48 80 NONE 0
    PINATTR PinName V-
    PINATTR SpiceOrder 4
    PIN 64 0 NONE 0
    PINATTR PinName OUT
    PINATTR SpiceOrder 5
    PIN -48 -80 NONE 0
    PINATTR PinName V+
    PINATTR SpiceOrder 6
    PIN 0 48 LEFT 8
    PINATTR PinName bp
    PINATTR SpiceOrder 7
    PIN 48 -32 LEFT 8
    PINATTR PinName g8
    PINATTR SpiceOrder 8

    Props to Roff, who actually created those files…

  • Wine: Adding Runtime Libraries

    While trying to persuade a Windows program to run under Wine, I stumbled across this useful script: winetricks.

    Basically, it downloads & installs the myriad runtime libraries / DLLs / programs that Windows programs generally assume are installed. Those are the things you don’t know are missing and generally can’t figure out how to install on your own.

    It didn’t actually help get the program in question running. As nearly as I can tell, if at first you can’t get a program installed & running under Wine, just give up…

  • Tucking Other Files into an OpenDocument Document

    WordPress doesn’t allow ZIP files, but very often I want to upload a collection of files that all relate to a common topic. For example, the three Tek 492 EPROM HEX files ought to come with a bit of documentation about how to use them.

    Fortunately, OpenDocument documents (sounds like something put out by the Department of Redundancy Department) are actually ordinary ZIP files with a different extension. There’s no good reason you can’t tuck some additional files into that container. Nay, verily, if you use a word processor file, then you can have documentation accompany your files!

    Note that the additional files don’t have any effect on the word processor document: OpenOffice simply uses the files it knows about and ignores the additional ones. You won’t see them in the word processor document; you won’t even know they’re present.

    However, because OpenOffice doesn’t know about them, it won’t transfer them to the new document when you save the file. You must add the files as the last step, after editing and saving the word processor document for the last time.

    I suppose there are pathological cases where this will cause trouble and I certainly hope that OpenDocument validators will complain vehemently about the presence of additional files. Use this knowledge wisely, OK?

    So, for example…

    Create a document and save it as the default ODT format using OpenOffice; let’s call it Tek 492 ROM Images.odt, just so you can see one in action.

    Now, to add those HEX files to it, you’d use the ordinary ZIP utility:

    zip "Tek 492 ROM Images.odt" *hex

    The quotes protect the blanks in the file name and you must type the entire file name out with the extension, because ZIP doesn’t expect to work with ODT files.

    You can list the file’s contents, which will show you all the other files that go into making an OpenDocument document work:

    unzip -l "Tek 492 ROM Images.odt"
    Archive:  Tek 492 ROM Images.odt
    Length     Date   Time    Name
    --------    ----   ----    ----
    39  07-30-09 18:09   mimetype
    0  07-30-09 18:09   Configurations2/statusbar/
    0  07-30-09 18:09   Configurations2/accelerator/current.xml
    0  07-30-09 18:09   Configurations2/floater/
    0  07-30-09 18:09   Configurations2/popupmenu/
    0  07-30-09 18:09   Configurations2/progressbar/
    0  07-30-09 18:09   Configurations2/menubar/
    0  07-30-09 18:09   Configurations2/toolbar/
    0  07-30-09 18:09   Configurations2/images/Bitmaps/
    23156  07-30-09 18:09   content.xml
    18259  07-30-09 18:09   styles.xml
    1240  07-30-09 18:09   meta.xml
    4943  07-30-09 18:09   Thumbnails/thumbnail.png
    8742  07-30-09 18:09   settings.xml
    1889  07-30-09 18:09   META-INF/manifest.xml
    4876  07-30-09 11:56   U1012 - 160-0886-04.hex
    19468  07-30-09 11:56   U2023 - 160-0838-00.hex
    19468  07-30-09 11:56   U2028 - 160-0839-00.hex
    --------                   -------
    102080                   18 files

    For obvious reasons, if you’re stuffing a bunch of files into an ODT file, you should probably ZIP them into a single ZIP file of their own, then add that single file to the ODT file. That means your victims users must also apply UNZIP twice, which may be expecting too much.

    When you want to use the HEX files, extract them:

    unzip "Tek 492 ROM Images.odt" *hex

    And there they are again:

    ls -l
    -rw-r--r-- 1 ed ed 15447 2009-08-11 20:51 Tek 492 ROM Images.odt
    -rw-r--r-- 1 ed ed  4876 2009-07-30 11:56 U1012 - 160-0886-04.hex
    -rw-r--r-- 1 ed ed 19468 2009-07-30 11:56 U2023 - 160-0838-00.hex
    -rw-r--r-- 1 ed ed 19468 2009-07-30 11:56 U2028 - 160-0839-00.hex

    That’s all there is to it…

    For what it’s worth, Microsoft DOCX files (and their ilk) are also ZIP files in disguise, so this same hack should work there, too. However, many folks (myself included) treat MS DOC files with the same casual nonchalonce as they do any other hunk of high-level radioactive waste, so stashing an additional payload in those files might not have a happy ending.

    This trick will certainly come in handy again, so I better write it down…

  • Programming Algorithm for 27HC641 EPROMs

    General idea: replacing a failing Mostek MK36000-series masked ROM in a Tektronix 492 Spectrum Analyzer memory board with an equally obsolete 27HC641 EPROM, using the bits found there.

    The various datasheets give contradictory advice concerning device programming:

    EPROM Burn - Microchip algorithm
    EPROM Burn – Microchip algorithm

    Assuming you have appropriate power supplies, then the waveform on VCE looks like this. The upper trace is the -OE signal for the data latch supplying the byte-to-be-burned, the lower trace is VCE on EPROM pin 21. Set VCC = 6 V on pin 24 while all this is going on. The currents range into the hundreds of mA; this is not a low-power device!

    The squirts on the -OE latch signal before each programming cycle are eight quick writes to those antique DL-1414 displays that share the data bus with the EPROM. They show the current address and data byte during programming, plus other status & error messages.

    The Microchip and GI datasheets both claim that the EPROM cells erase to all 1 bits, like every other EPROM I’ve ever used. The Philips datasheet says:

    … after each erasure, all bits of the 27HC641 are in an undefined state. […] which is neither a logical “1” or a logical “0”

    27HC641 EPROM in programming socket
    27HC641 EPROM in programming socket

    The chip markings suggest they were made by Signetics, which got Borged by Philips some years ago. Lo and behold, the chip erases to a bizarre pattern that may be “undefined” but is perfectly consistent from erasure to erasure.

    Therefore, you cannot blank-check a 27HC641 EPROM before programming it!

    The Philips / Signetics datasheet doesn’t have a programming algorithm and the GI datasheet says you’re supposed to hold VCE at +12.5 V except when you’re asserting the programming data. So I used the Microchip algorithm on a Signetics chip and it seems to program properly.

    The only quirk is that the Arduino Diecimila doesn’t have enough storage to hold the entire EPROM at once, so I verified each data byte as I wrote it, rather than doing the whole chip after the entire programming loop. The top picture shows a single 1 ms programming pulse followed by the 3-ms overburn pulse; the byte read back from the EPROM must agree with the source byte after each pulse. When it’s all done, I manually dump the entire EPROM as an Intel HEX file and verify that against the original HEX file: if it matches, the burn is good.

    The byte-burning function goes a little something like this:

    int BurnByte(word Address, byte Data) {
    
    unsigned Iteration;
    byte Success;
    
     SetVcc(VH);                              // bump VCC to programming level
     SetVce(VIH);                             // disable EPROM outputs
     Outbound.Address = Address;              // set up address and data values
     Outbound.DataOut = Data;
    Success = 0;
    for (Iteration = 1; Iteration <= MAX_PROG_PULSES; ++Iteration) {
    
    RunShiftRegister();
    digitalWrite(PIN_DISABLE_DO,LOW);       // present data to EPROM
    
    SetVce(VH);                             // bump VCE to programming level
    delayMicroseconds(1000);                // burn data for a millisecond
    SetVce(VIH);                            // return VCE to normal logic level
    
    digitalWrite(PIN_DISABLE_DO,HIGH);      // turn off data latch buffer
    SetVce(VIL);                            // activate EPROM outputs
    CaptureDataIn();                        // grab EPROM output
    SetVce(VIH);                            // disable EPROM outputs
    
    RunShiftRegister();                     // fetch data
    
    if (Data == Inbound.DataIn) {           // did it stick?
    Success = 1;
    break;
    }
    }
    
    MaxBurns = max(MaxBurns,Iteration);
    
    if (Success) {                           // if it worked, overburn the data
    
    digitalWrite(PIN_DISABLE_DO,LOW);       // present data to EPROM (again!)
    SetVce(VH);                             // bump VCE to programming level
    delay(3 * Iteration);                   // overburn data
    
    SetVce(VIH);                            // return VCE to normal logic level
    digitalWrite(PIN_DISABLE_DO,HIGH);      // turn off latch buffers
    
    SetVce(VIL);                            // activate EPROM outputs
    CaptureDataIn();                        // grab EPROM output
    SetVce(VIH);                            // disable EPROM outputs
    
    RunShiftRegister();                     // fetch data
    
    Success = (Data == Inbound.DataIn);     // did overburn stick?
    }
    
    return !Success;                         // return zero for success
    }
    

    NOTE: the MK36000 and 27HC641 have slightly different address bit assignments.

    The MK36000 address bits look like this:

    • pin 18 = A11
    • pin 19 = A10
    • pin 21 = A12

    The 27HC641 address bits look like this:

    • pin 18 = A12
    • pin 19 = A11
    • pin 21 = A10

    Now, if you’re building a programmer, just wire up the 27HC641 socket as if it were a MK36000 and everything will be fine. The byte locations within the chip won’t match those in the original MK36000, but it doesn’t matter because you store bytes at and the Tek CPU fetches bytes from the same addresses.

    However, if you’re using a commercial EPROM programmer, it will write the bytes at the locations defined by the 27HC641 address bit assignments (because that’s all it knows), which will not work when plugged into the Tek board. Choose one of the following options:

    • build an interposer board to permute the address bits
    • cut-and-rewire the Tek board (ugh!)
    • write a program to permute the bytes in the HEX file

    Think about it very carefully before you build or program anything, OK? The checksum will most likely come out right even with permuted bits, but the CPU will crash hard as it fetches the wrong instructions.

    Memo to Self: always RTFM, but don’t believe everything you read.

  • Arduino: Using Ancient Litronix DL-1414 LED Displays

    Tek 492 Memory Board Reader
    Tek 492 Memory Board Reader

    While I was putting together the Tek 492 memory board reader, I though it’d be a nice idea to add a small display. While the Arduino has USB serial I/O, the update rate is fairly pokey and an on-board display can provide more-or-less real time status.

    Given that the reader was built for an early-80s memory board, I just had to use a pair of Litronix DL-1414 4-character LED displays from my parts heap. The DL-1414 datasheet [Update: link rot? try that] proudly proclaims:

    The 0.112″ high characters of the DL1414T gives readability up to eight feet. The user can build a display that enhances readability over this distance by proper filter selection.

    I think that distance is exceedingly optimistic.

    DL-1414 LED display schematic
    DL-1414 LED display schematic

    However, I needed to see only a few feet to the benchtop. Even better, adding the displays required no additional hardware: the SPI-driven shift registers on the board already had address and data lines, plus a pair of unused bits for the write strobes. What’s not to like?

    This schematic connects to the one you just clicked on; the two big blue bus lines are the same bus as in that schematic.

    If you don’t have anything else riding the data bus, adding a pullup on the D7 bit that isn’t used by these displays will make all the bits float high; the DL-1414s seem to pull their inputs upward. That came in handy when I was debugging the EPROM-burning code, because reading data without an EPROM in the socket produced 0xff, just like an erased EPROM byte.

    The two displays are the dark-red rectangle in the lower-right of the first picture, covered with a snippet of the Primary Red filter described there.

    These closeups, without and with the filter, demonstrate why you really, really need a filter of some sort.

    DL1414 Unfiltered
    DL1414 Unfiltered
    DL1414 Filtered
    DL1414 Filtered

    Using the displays is straightforward, given the hardware-assisted SPI code from there. You could actually do it with just the I/O pins on an Arduino board, but you wouldn’t be able to do anything else. If you don’t have any other SPI registers, you could get away with a pair of HC595 outputs:  7 data + 2 address + 2 strobes + 5 outputs left over for something else.

    A few constants set the display size and a global buffer holds the characters:

    #define LED_SIZE            4            // chars per LED
    #define LED_DISPLAYS        2            // number of displays
    #define LED_CHARS           (LED_DISPLAYS * LED_SIZE)
    
    char LEDCharBuffer[LED_CHARS + 1];       // raw char buffer, can be used as a string
    

    A routine to exercise the LEDs by scrolling all 64 characters they can display goes a little something like this:

    Serial.println("Exercising LED display ...");
    
     Outbound.Controls |= CB_N_WRLED1_MASK | CB_N_WRLED0_MASK;        // set write strobes high
     digitalWrite(PIN_DISABLE_DO,LOW);                                // enable data outputs
    
     while (digitalRead(PIN_PB)) {
    
      digitalWrite(PIN_HEARTBEAT,HIGH);
    
      byte Character, Index;
    
      for (Character = 0x20; Character < 0x60; ++Character) {
       for (Index = 0; Index < LED_CHARS; ++Index) {
        LEDCharBuffer[Index] = Character + Index;
       }
       UpdateLEDs(LEDCharBuffer);
       delay(500);
    
       if (!digitalRead(PIN_PB)) {
        break;
       }
      }
    
      digitalWrite(PIN_HEARTBEAT,LOW);
     }
    
     WaitButtonUp();
    

    A routine to plop a string (up to 8 characters!) on the LEDs looks like this:

    void UpdateLEDs(char *pString) {
    byte Index = 0;
    
     while (*pString && (Index < LED_CHARS)) {
    
      Outbound.DataOut = *pString;           // low 6 bits used by displays
      Outbound.Address = ~Index;             // low 2 bits used by displays, invert direction
      Outbound.Controls &= ~(Index < LED_SIZE ? CB_N_WRLED1_MASK : CB_N_WRLED0_MASK);
    
      RunShiftRegister();
    
      digitalWrite(PIN_DISABLE_DO,LOW);      // show the data!
    
      Outbound.Controls |= CB_N_WRLED1_MASK | CB_N_WRLED0_MASK;
      RunShiftRegister();
    
      digitalWrite(PIN_DISABLE_DO,HIGH);     // release the buffers
    
      ++pString;
      ++Index;
     }
    
    

    You can use sprintf() to put whatever you like in that string:

    void ShowStatus(word Address,byte Data) {
    
     sprintf(LEDCharBuffer,"%04X  %02X",Address,Data);
     UpdateLEDs(LEDCharBuffer);
    
    }
    

    Not, of course, that anybody would actually use DL-1414 displays in this day & age, but the general idea might come in handy for something more, mmmm, elegant…