M48T59Y battery replacement master
authorNick Bowler <nbowler@draconx.ca>
Sat, 9 Jul 2022 16:12:20 +0000 (12:12 -0400)
committerNick Bowler <nbowler@draconx.ca>
Sat, 9 Jul 2022 16:36:53 +0000 (12:36 -0400)
15 files changed:
content/images/m48t59y-fixed.jpg [new symlink]
content/images/m48t59y-fixed.yaml [new file with mode: 0644]
content/images/m48t59y-installed.jpg [new symlink]
content/images/m48t59y-installed.yaml [new file with mode: 0644]
content/images/m48t59y-solder.jpg [new symlink]
content/images/m48t59y-solder.yaml [new file with mode: 0644]
content/images/m48t59y-terminals.jpg [new symlink]
content/images/m48t59y-terminals.yaml [new file with mode: 0644]
content/images/m48t59y.jpg [new symlink]
content/images/m48t59y.yaml [new file with mode: 0644]
content/style.scss
content/weblog/ultra60-nvram.md [new file with mode: 0644]
layouts/default.xsl
layouts/functions.xsl
lib/helpers.rb

diff --git a/content/images/m48t59y-fixed.jpg b/content/images/m48t59y-fixed.jpg
new file mode 120000 (symlink)
index 0000000..d0f066e
--- /dev/null
@@ -0,0 +1 @@
+../../.git/annex/objects/wK/GG/SHA512-s215590--23ec4d09ab8ed674c51d1fa81145f4983e207ca989ec65c3035ba49c876aa01c37df3ca458b80ab7863607ec80ec8ac950bd03e7d83ec493adc40fef80c55f8d/SHA512-s215590--23ec4d09ab8ed674c51d1fa81145f4983e207ca989ec65c3035ba49c876aa01c37df3ca458b80ab7863607ec80ec8ac950bd03e7d83ec493adc40fef80c55f8d
\ No newline at end of file
diff --git a/content/images/m48t59y-fixed.yaml b/content/images/m48t59y-fixed.yaml
new file mode 100644 (file)
index 0000000..6038682
--- /dev/null
@@ -0,0 +1,6 @@
+---
+title: M48T59Y-70PC1 With Battery Clip
+copyright: 2022 Nick Bowler
+license: cc-by-sa-4.0
+description: |
+  Finished repair of M48T59Y part with external battery clip glued on top.
diff --git a/content/images/m48t59y-installed.jpg b/content/images/m48t59y-installed.jpg
new file mode 120000 (symlink)
index 0000000..2fa0639
--- /dev/null
@@ -0,0 +1 @@
+../../.git/annex/objects/jF/WK/SHA512-s821129--859631534da810c3a29d2246edf97a8d6a61a2ac67c21e18aee2753eb96a38a2856e45278f44db7a7a0ef9bb1c1ae6b00bc32e72b9b143b5d14a8abc7e376a1d/SHA512-s821129--859631534da810c3a29d2246edf97a8d6a61a2ac67c21e18aee2753eb96a38a2856e45278f44db7a7a0ef9bb1c1ae6b00bc32e72b9b143b5d14a8abc7e376a1d
\ No newline at end of file
diff --git a/content/images/m48t59y-installed.yaml b/content/images/m48t59y-installed.yaml
new file mode 100644 (file)
index 0000000..2c74fe6
--- /dev/null
@@ -0,0 +1,6 @@
+---
+title: M48T59Y-70PC1 Repair Complete
+copyright: 2022 Nick Bowler
+license: cc-by-sa-4.0
+description: |
+  Repaired M48T59Y chip installed onto the Sun Ultra 60 motherboard.
diff --git a/content/images/m48t59y-solder.jpg b/content/images/m48t59y-solder.jpg
new file mode 120000 (symlink)
index 0000000..5d8078e
--- /dev/null
@@ -0,0 +1 @@
+../../.git/annex/objects/8M/9g/SHA512-s146926--2dd1f0b920387121d4e1f658f151417d55d65dfa27a6b397343deeebde08636236a0e123a9cfa3fdeef8204425c3f7d00a5e5dcee121126535a140a059f6fb04/SHA512-s146926--2dd1f0b920387121d4e1f658f151417d55d65dfa27a6b397343deeebde08636236a0e123a9cfa3fdeef8204425c3f7d00a5e5dcee121126535a140a059f6fb04
\ No newline at end of file
diff --git a/content/images/m48t59y-solder.yaml b/content/images/m48t59y-solder.yaml
new file mode 100644 (file)
index 0000000..dc6253b
--- /dev/null
@@ -0,0 +1,7 @@
+---
+title: M48T59Y-70PC1 Wire Leads
+copyright: 2022 Nick Bowler
+license: cc-by-sa-4.0
+description: |
+  M48T59Y with battery leads connected, after disconnecting the internal
+  battery tabs.
diff --git a/content/images/m48t59y-terminals.jpg b/content/images/m48t59y-terminals.jpg
new file mode 120000 (symlink)
index 0000000..795475d
--- /dev/null
@@ -0,0 +1 @@
+../../.git/annex/objects/98/V1/SHA512-s186948--c3277cf2aea7e159ee6203e9c7f5330f3a1c79a4d2c347c7637c19f354c7cafe2181b54fd40e84eba434a16340fb9cd3a87e76a636d45278846cb46c3d1f606e/SHA512-s186948--c3277cf2aea7e159ee6203e9c7f5330f3a1c79a4d2c347c7637c19f354c7cafe2181b54fd40e84eba434a16340fb9cd3a87e76a636d45278846cb46c3d1f606e
\ No newline at end of file
diff --git a/content/images/m48t59y-terminals.yaml b/content/images/m48t59y-terminals.yaml
new file mode 100644 (file)
index 0000000..806df38
--- /dev/null
@@ -0,0 +1,8 @@
+---
+title: M48T59Y-70PC1 Battery Terminals
+copyright: 2022 Nick Bowler
+license: cc-by-sa-4.0
+description: |
+  M48T59Y with internal battery connections exposed.  The negative connection
+  is on the left, closest to pin 14.  The positive connection is on the right,
+  closest to pin 16.
diff --git a/content/images/m48t59y.jpg b/content/images/m48t59y.jpg
new file mode 120000 (symlink)
index 0000000..40e10d3
--- /dev/null
@@ -0,0 +1 @@
+../../.git/annex/objects/5f/mJ/SHA512-s141937--ebbd8a2ad4b6d4f1c6d66d9f7ba76685c5281bff3d0fb34f7e00e3016b8422c4935aa9b87caa1c4f8ed9b1b7f727b4f2c97d49991f483317c8248f536c225620/SHA512-s141937--ebbd8a2ad4b6d4f1c6d66d9f7ba76685c5281bff3d0fb34f7e00e3016b8422c4935aa9b87caa1c4f8ed9b1b7f727b4f2c97d49991f483317c8248f536c225620
\ No newline at end of file
diff --git a/content/images/m48t59y.yaml b/content/images/m48t59y.yaml
new file mode 100644 (file)
index 0000000..7258310
--- /dev/null
@@ -0,0 +1,9 @@
+---
+title: M48T59Y-70PC1
+copyright: 2022 Nick Bowler
+license: cc-by-sa-4.0
+description: |
+  <p>The <abbr title="Non-Volatile Random Access Memory">NVRAM</abbr> module
+  used in my Sun Ultra 60 workstation.  This combines a normal memory with a
+  real-time clock and an internal lithium primary cell to maintain everything.
+  However, the internal cell is long dead so this chip is dead too.</p>
index 2708bb462e00c701f9b563fe9dec8ac94f67d9e5..abc6c490348130834814e23e9baf7f6abc24f406 100644 (file)
@@ -76,6 +76,16 @@ h5 { @include header_size(60em, 1em); }
 
         p.img { margin: 0.5em 0; }
     }
 
         p.img { margin: 0.5em 0; }
     }
+
+    @media (max-width: 45em) {
+        .inline.gallery {
+            display: block;
+            p.img {
+                a { max-width: 24em; }
+                margin: 1em 0;
+            }
+        }
+    }
 }
 
 p.img {
 }
 
 p.img {
@@ -94,12 +104,22 @@ p.img {
         border: solid 2px;
     }
 
         border: solid 2px;
     }
 
+    a.left { margin: 0 1em 0.5em 0; float: left; clear: left; }
+    a.right { margin: 0 0 0.5em 1em; float: right; clear: right; }
+    a.left, a.right {
+        @media (max-width: 45em) { float: none; margin: 0; }
+
+        max-width: 24em;
+    }
+
     small {
         @include usecolours($color: foreground);
     small {
         @include usecolours($color: foreground);
-        text-align: justify;
         @media (max-width: 24em) { text-align: left; }
         padding: 0.5ex;
         display: block;
         @media (max-width: 24em) { text-align: left; }
         padding: 0.5ex;
         display: block;
+        display: -moz-inline-box;
+        display: inline-block;
+        text-align: justify;
         font-size: 0.9em;
     }
 }
         font-size: 0.9em;
     }
 }
@@ -137,10 +157,12 @@ kbd {
     font-family: monospace;
     font-size: 0.95em;
     &:before { content: "% "; }
     font-family: monospace;
     font-size: 0.95em;
     &:before { content: "% "; }
+    &.ok:before { content: "ok "; }
     &>span { white-space: nowrap; }
 
     blockquote & {
         display: block;
     &>span { white-space: nowrap; }
 
     blockquote & {
         display: block;
+        & + br { display: none; }
         text-align: left;
         padding-left: 3em;
         text-indent: -3em;
         text-align: left;
         padding-left: 3em;
         text-indent: -3em;
@@ -160,6 +182,7 @@ kbd {
 table {
     @include usecolour(border-top, ruledefault, 1px solid);
     border-collapse: collapse;
 table {
     @include usecolour(border-top, ruledefault, 1px solid);
     border-collapse: collapse;
+    clear: both;
     width: 100%;
 }
 
     width: 100%;
 }
 
diff --git a/content/weblog/ultra60-nvram.md b/content/weblog/ultra60-nvram.md
new file mode 100644 (file)
index 0000000..ec96370
--- /dev/null
@@ -0,0 +1,101 @@
+---
+title: M48T59Y-70PC1 NVRAM Battery Replacement
+copyright: 2022 Nick Bowler
+license: cc-by-sa-4.0
+published: 2022-07-09T12:12:21-0400
+---
+
+*[NVRAM]: Non-Volatile Random Access Memory
+*[SRAM]: Static Random-Access Memory
+*[NOS]: New Old Stock
+*[DIP]: Dual In-line Package
+*[SOIC]: Small-Outline Integrated Circuit
+*[MAC]: Media Access Control
+
+Thanks to [Mark Henderson's Sun NVRAM FAQ][nvram-faq] for providing invaluable
+insight regarding this repair.
+{:article-info="article-info"}
+
+[nvram-faq]: http://web.archive.org/web/20150919135835/http://www.squirrel.com/sun-nvram-hostid.faq.html
+
+The Sun Ultra 60 workstation uses an ST M48T59Y-70PC1 battery-backed SRAM with
+real-time clock.  When the embedded lithium primary cell inevitably dies, the
+chip is essentially useless.  The most noticeable negative effect of a dead
+chip is that the workstation always powers up in a default configuration with
+diag-switch?  true, running several minutes of self tests every time, with
+bogus MAC and host ID values.
+
+<%= floating_img(@items["/images/m48t59y.jpg"], caption: <<EOF
+You don't even know you are already dead.
+EOF
+) %>
+
+This device was branded obsolescent by the manufacturer in April of 2008 and
+has presumably been out of production since around that time.  Similar chips
+like the M48T58Y are still made but they are expensive (around $40) and slight
+differences may result in compatibility problems.  It appears that NOS parts
+can be found fairly cheap online but these must be almost 15 years old by now
+and who knows what state the embedded batteries are in.  No thanks.
+
+One option could be to find the SOIC version of the M48T59Y for which NOS also
+seems to be available, although somewhat less readily than the DIP modules, and
+then construct an adapter board to fit into the DIP socket on the motherboard.
+The SOIC package does not include the battery and crystal; instead, it has
+contacts on the top to attach a separate "SNAPHAT" package which are still
+made.  This would be complicated and somewhat expensive.
+
+Fortunately, a straightforward (if time-consuming) repair is possible.  This
+is a literal hackjob: we can dig through the potting to expose the battery
+terminals, disconnect the internal battery, and connect a normal battery clip.
+This enables the use of readily-available CR2032 lithium primary cells that can
+be replaced as needed, just like a normal PC.  Since we already have the chip
+we need, it is not necessary to source any obscure or expensive components.
+
+<%=
+floating_img(@items["/images/m48t59y-terminals.jpg"], left: 1, caption: '')
+%>
+
+<%=
+floating_img(@items["/images/m48t59y-solder.jpg"], left: 1, caption: '')
+%>
+
+The battery contacts are located on the end opposite pin 1, between pins
+14 and 15.  Looking underneath the chip there is a small well at either end
+filled with potting compound.  The battery connections are inside one of
+these.  Using a knife, cut back the plastic outer shell on the battery side,
+then begin scraping away potting compound until the terminals are exposed.
+You can use a suitable DIP socket to help protect the pins from accidental
+damage.
+
+Once the terminals are exposed, the internal battery must be disconnected.
+The thick protruding tabs near the bottom of the module are what we want
+to solder to.  The vertical strips going up and into the module are the
+internal battery terminals.  These can be desoldered from the tabs and
+lifted out of the way, or simply cut off.
+
+With the time-consuming parts completed it is a straightforward matter to
+connect a normal battery clip to the exposed terminals.  As the Ultra 60 has
+no clearance issues I simply glued it to the top of the chip.  Since this
+would obscure the barcode sticker which is useful to restore the original MAC
+address and host ID, I moved this sticker to the side of the chip.
+
+Finally all that remains is to put everything back together and power up
+the system.  The system will run the full self-diagnostic tests again and
+if all goes well, the "NVRAM Battery Detect Test" should no longer display
+any errors.  At the ok prompt, the memory can now be initialized.  Where
+"AA BB CC" are the six hexadecimal digits from the orange barcode sticker:
+
+<kbd class='ok'>set-defaults</kbd><br/>
+<kbd class='ok'>setenv diag-switch? false</kbd><br/>
+<kbd class='ok'>8 0 20 AA BB CC AABBCC mkpl<br/><em>&lt;Ctrl-D&gt;&lt;Ctrl-R&gt;</em></kbd><br/>
+<kbd class='ok'>.idprom</kbd><br/>
+<kbd class='ok'>reset</kbd>
+
+<%= gallery_img(@items["/images/m48t59y-fixed.jpg"], caption: <<EOF
+Just like a bought one!
+EOF
+) %>
+<%= gallery_img(@items["/images/m48t59y-installed.jpg"], caption: <<EOF
+There's no place like home in the Ultra 60.
+EOF
+) %>
index d5be1039e5061cf8c8dc2eff408eeb306c35de0a..768193376d53c73156211540a26460a28e9e9b7a 100644 (file)
 </xsl:template>
 
 <!-- For paragraphs containing only kbd elements, wrap in blockquote. -->
 </xsl:template>
 
 <!-- For paragraphs containing only kbd elements, wrap in blockquote. -->
-<xsl:template match='xhtml:p[*[last()=count(../xhtml:kbd)]]'>
+<xsl:template match='xhtml:p[*[last()=count(../xhtml:kbd|../xhtml:br)]]'>
   <blockquote>
     <xsl:copy>
       <xsl:apply-templates select='node()|@*' />
   <blockquote>
     <xsl:copy>
       <xsl:apply-templates select='node()|@*' />
   </p>
 </xsl:template>
 
   </p>
 </xsl:template>
 
+<!-- Article info block inserted between heading and main contents -->
 <xsl:template match='xhtml:h1[not(preceding::xhtml:h1)]'>
 <xsl:template match='xhtml:h1[not(preceding::xhtml:h1)]'>
+  <xsl:variable name='nodes'
+    select='/document/article/published|//xhtml:*[@article-info]' />
+
   <xsl:copy><xsl:apply-templates select='node()|@*' /></xsl:copy>
   <xsl:copy><xsl:apply-templates select='node()|@*' /></xsl:copy>
-  <xsl:if test='/document/article/published'>
+
+  <xsl:if test='$nodes'>
     <div id='article-info'>
     <div id='article-info'>
-      <p>
-        <xsl:text>Posted </xsl:text>
-        <xsl:value-of select='/document/article/published' />
-      </p>
+      <xsl:apply-templates mode='article-info' select='$nodes'>
+        <xsl:sort data-type='number'
+          select='number(generate-id(..)=generate-id(/document/article))' />
+      </xsl:apply-templates>
     </div>
   </xsl:if>
 </xsl:template>
 
     </div>
   </xsl:if>
 </xsl:template>
 
+<xsl:template mode='article-info' match='/document/article/published'>
+  <p>
+    <xsl:text>Posted </xsl:text>
+    <xsl:value-of select='/document/article/published' />
+    <xsl:if test='/document/article/updated'>
+      <xsl:text>, last updated </xsl:text>
+      <xsl:value-of select='/document/article/updated' />
+    </xsl:if>
+  </p>
+</xsl:template>
+
+<xsl:template match='*[@article-info]' />
+<xsl:template mode='article-info' match='*[@article-info]'>
+  <xsl:copy>
+    <xsl:apply-templates select='@*[local-name() != "article-info"]' />
+    <xsl:apply-templates select='node()' />
+  </xsl:copy>
+</xsl:template>
+
 <xsl:template name='imgpara' match='xhtml:p[count(*)=1]
                                            [normalize-space(text())=""]
                                            [descendant::xhtml:img]'>
 <xsl:template name='imgpara' match='xhtml:p[count(*)=1]
                                            [normalize-space(text())=""]
                                            [descendant::xhtml:img]'>
   <xsl:variable name='images' select='key("gallery", generate-id(.))' />
   <xsl:choose>
     <xsl:when test='count($images) > 1'>
   <xsl:variable name='images' select='key("gallery", generate-id(.))' />
   <xsl:choose>
     <xsl:when test='count($images) > 1'>
-      <div class='gallery'>
+      <div>
+        <xsl:attribute name='class'>
+          <xsl:text>gallery</xsl:text>
+          <xsl:if test='//xhtml:a[f:contains-token(@class, "left")
+                                  or f:contains-token(@class, "right")]'>
+            <xsl:text> inline</xsl:text>
+          </xsl:if>
+        </xsl:attribute>
         <xsl:for-each select='$images'>
           <xsl:call-template name='imgpara' />
         </xsl:for-each>
         <xsl:for-each select='$images'>
           <xsl:call-template name='imgpara' />
         </xsl:for-each>
index a88c3380cc88f3bb0d59491bcb6e33f8316f8830..bbaf90e34bbf971bbddf399fd77e73be398b4bb8 100644 (file)
@@ -1,7 +1,7 @@
 <!--
   Nick's web site: XSLT helper functions.
 
 <!--
   Nick's web site: XSLT helper functions.
 
-  Copyright © 2019-2021 Nick Bowler
+  Copyright © 2019-2022 Nick Bowler
 
   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
 
   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   </func:result>
 </func:function>
 
   </func:result>
 </func:function>
 
+<!--
+  f:contains-token(list, token)
+  Returns true iff the space-separated list contains the given token
+-->
+<func:function name='f:contains-token'>
+  <xsl:param name='haystack' />
+  <xsl:param name='needle' />
+
+  <func:result select='contains(
+                         concat(" ", normalize-space($haystack), " "),
+                         concat(" ", normalize-space($needle), " ")
+                       )' />
+</func:function>
+
 </xsl:stylesheet>
 </xsl:stylesheet>
index 77916dd29492582da2081c4a4a116b7e32105ee1..24d37e4ef33407db32c07153b055ccbb60f8ad6f 100644 (file)
@@ -1,6 +1,6 @@
 # Nick's web site: Ruby helpers for processing
 #
 # Nick's web site: Ruby helpers for processing
 #
-# Copyright © 2018-2021 Nick Bowler
+# Copyright © 2018-2022 Nick Bowler
 #
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 #
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -77,26 +77,31 @@ def counter(name = :default, item = @item)
     name.to_s.capitalize + " " + ($counters[item][name] += 1).to_s
 end
 
     name.to_s.capitalize + " " + ($counters[item][name] += 1).to_s
 end
 
-def img_rep_fallback(item, rep)
-    return rep unless item.reps[rep].raw_path.nil?
-    return :large
+# Return a hash containing :src, :width and :height based on an image item rep.
+def img_rep_attrs(item, rep)
+    rep = :large if item.reps[rep].raw_path.nil?
+    attrs = {}
+
+    attrs[:src] ||= item_uri(item, rep: rep)
+    attrs[:width], attrs[:height] = FastImage.size(item.reps[rep].raw_path)
+
+    return attrs
 end
 
 end
 
-def gallery_img(item, rep: :large, alt: nil, caption: nil)
+def embed_img(item, rep: :large, caption: nil, block_attrs: {}, img_attrs: {})
     return "[image not found]" unless item
 
     return "[image not found]" unless item
 
-    alt ||= item[:title]
-    caption ||= alt
+    img_attrs[:alt] ||= item[:title]
+    caption ||= img_attrs[:alt]
     caption = caption.strip
     caption.gsub!(/\s+/, " ")
 
     caption = caption.strip
     caption.gsub!(/\s+/, " ")
 
-    rep = img_rep_fallback(item, rep)
-    attrs = { :src => item_uri(item, rep: rep), :alt => item[:title] }
-    attrs[:width], attrs[:height] = FastImage.size(item.reps[rep].raw_path)
+    img_attrs = img_rep_attrs(item, rep).merge(img_attrs)
+    block_attrs[:href] = item_uri(item, rep: :info)
 
     b = Nokogiri::XML::Builder.new do |xml|
 
     b = Nokogiri::XML::Builder.new do |xml|
-        xml.a(:href => item_uri(item, rep: :info)) {
-            xml.img(attrs, "generate-gallery" => "generate-gallery")
+        xml.a(block_attrs) {
+            xml.img(img_attrs)
             unless caption.empty?
                 xml << " &#x2060;"
                 xml.small { xml << caption }
             unless caption.empty?
                 xml << " &#x2060;"
                 xml.small { xml << caption }
@@ -106,6 +111,19 @@ def gallery_img(item, rep: :large, alt: nil, caption: nil)
     b.to_xml(:save_with => Nokogiri::XML::Node::SaveOptions::NO_DECLARATION)
 end
 
     b.to_xml(:save_with => Nokogiri::XML::Node::SaveOptions::NO_DECLARATION)
 end
 
+def gallery_img(item, rep: :medium, caption: nil, alt: nil)
+    attrs = { alt: alt, "generate-gallery" => "generate-gallery" }
+    embed_img(item, rep: rep, caption: caption, img_attrs: attrs)
+end
+
+def floating_img(item, rep: :medium, caption: nil, alt: nil, left: nil)
+    battrs = { class: if left then "left" else "right" end }
+    attrs = { alt: alt }
+
+    embed_img(item, rep: rep, caption: caption,
+                    block_attrs: battrs, img_attrs: attrs)
+end
+
 def expand_copyright(copyright)
     result = { :years => {} }
 
 def expand_copyright(copyright)
     result = { :years => {} }