{"id":61,"date":"2024-12-05T18:00:56","date_gmt":"2024-12-05T21:00:56","guid":{"rendered":"https:\/\/blog.feche.ar\/?p=61"},"modified":"2024-12-15T16:12:57","modified_gmt":"2024-12-15T19:12:57","slug":"source-code-of-cluster-vmmj08mh-9-00-needle-led-sweep","status":"publish","type":"post","link":"https:\/\/blog.feche.ar\/?p=61","title":{"rendered":"Source code of cluster VMMJ08MH 9.00 Needle\/Led sweep"},"content":{"rendered":"\n<h2 class=\"wp-block-heading\">Introduction.<\/h2>\n\n\n\n<p>Hey there,<\/p>\n\n\n\n<p>In this blog-post, I will be sharing the source code of the needle sweep patch made for cluster <strong>VMMJ08MH 9.00<\/strong>, including a brief explanation on how this works.<\/p>\n\n\n\n<p>This is useful for <em>new developers<\/em> or if you want to learn how to make a patch code for these clusters &#8211; once you manage to control it, you can create infinite amounts of codes and\/or fixes for the cluster.<\/p>\n\n\n\n<p>I won&#8217;t go into full detail here, these clusters have a <strong>W65C816 MCU<\/strong> that controls the entire cluster, and you write code in W65C816 assembler opcodes to give instructions on what to do &#8211; this is basically programming the MCU.<\/p>\n\n\n\n<p>The MCU model that this cluster uses is a <strong>Micronas CDVV 1304<\/strong>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">&nbsp;The code.<\/h2>\n\n\n\n<blockquote class=\"wp-block-quote has-background is-layout-flow wp-block-quote-is-layout-flow\" style=\"background-color:#ffffe5;font-size:14px\">\n<p class=\"has-background\" style=\"background-color:#ffffe5;font-size:18px\"><strong>DISCLAIMER<\/strong>: this code is licensed under the GNU LGPL v3.0 or later, see the <strong><em>LICENSE <\/em><\/strong>tab for more details.<\/p>\n<\/blockquote>\n\n\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-avrasm\" data-line=\"\">; Needle and led sweep for cluster VMMJ08MH 9.00\n; Made by Feche\n; https:\/\/feche.ar\/\n\n    .org    $0E8F\n    \nMaxSweepProgress = $55\nMaxDelayProgress = $60\n\nsub_5587:\n    ; Check if cluster in on\n    JSR     $6027\n    BCC     ResetSweep\n    \n    ; Check if needles are homed\n    JSR     IsHomed\n    BCS     ResetSweep\n    \n    ; If sweep is done, branch\n    JSR     Progress\n    BCS     Continue\n    \n    JSR     NeedleSweep\n    JSR     LightSweep\n    \nContinue:\n    JSR     CheckLeds\n    \n    LDA     $81\n    JMP     $558A\n    \nResetSweep:\n    STZ     DelayProgress\n    STZ     SweepProgress\n    STZ     EnableLeds\n    \n    BCC     Continue\n    ; Disable delay if not homed\n    LDA     #MaxDelayProgress\n    STA     DelayProgress\n    BRA     Continue\n\n; NeedleSweep ------------------------------------------------------------------\nNeedleSweep:\n    LDA     SweepProgress\n    CMP     #(MaxSweepProgress\/2)\n    BCS     ZeroOutNeedles\n    \n    ; Do needle sweep!\n    LDA     #$5      \n    STA     $26D                \n    STA     $273\n    \n    LDA     #$80\n    STA     $272\n    STA     $26C\n    \n    LDA     #$0F\n    STA     $26F                \n    STA     $271\n    \n    LDA     #$B0\n    STA     $270\n    STA     $26E\n\n    RTS\n    \nZeroOutNeedles:\n    ; Set needles to zero\n    LDX     #$0\nLoop:\n    STZ     $26C, X\n    INX\n    CPX     #8\n    BNE     Loop\n    \n    RTS\n    \n; LightSweep ------------------------------------------------------------------\nLightSweep:\n    PHX\n    PHY\n    \n    STZ     $ACD\n    STZ     $ACE\n    \n    ; Load speedometer\n    LDX     #$E7\n    ; Get needle position\n    LDY     7, X\n    LDA     LedSweepData, Y\n    \n    LDY     SweepProgress\n    CPY     #(MaxSweepProgress\/2)\n    BCS     NeedleDown\n\n    TSB     LedData\n    BRA     LightContinue\n    \nNeedleDown:\n    TRB     LedData\n\nLightContinue:\n    LDA     LedData\n    STA     $ACE\n    \n    LDA     #$CD\n    STA     0\n    LDA     #$A\n    STA     1\n    \n    ; this function turns on\/off leds\n    JSR     $65D9\n    \n    PLY\n    PLX\n    RTS\n    \n; Progress ---------------------------------------------------------------------\nProgress:\n    ; Check if we need to apply delay\n    LDA     DelayProgress\n    CMP     #MaxDelayProgress\n    ; Delay done\n    BEQ     DelayDone\n    \n    ; Increment delay counter\n    SEC\n    INC     DelayProgress\n    JSR     ZeroOutNeedles\n    RTS\n    \nDelayDone:\n    ; Increment progress counter\n    SEC\n    LDA     SweepProgress\n    CMP     #MaxSweepProgress\n    ; Progress done!\n    BEQ     ProgressDone\n    \n    CLC\n    INC     SweepProgress\n    RTS\n    \nProgressDone:\n    ; Enable leds after we finish the sweep\n    LDA     #1\n    STA     EnableLeds\n    ;STZ     SweepProgress ; Loop!\n    RTS\n\n; CheckLeds --------------------------------------------------------------------\nCheckLeds:\n    LDA     EnableLeds\n    CMP     #0\n    BEQ     DisableLed\n    RTS\n    \nDisableLed:\n    LDA     #1\n    TSB     $A56\n    RTS\n    \n; IsHomed ----------------------------------------------------------------------\nIsHomed:\n    LDA     $B41\n    CMP     #$1E\n    BEQ     HomedTrue\n    CMP     #$10\n    BEQ     HomedTrue\nHomedFalse:\n    SEC\n    RTS\nHomedTrue:\n    CLC\n    RTS\n;                     0    1    2    3    4    5    6    7    8    9\nLedSweepData:   .byte $00, $80, $00, $01, $00, $40, $00, $04, $00, $02\n                .byte $00, $00, $20, $00, $08, $00, $00, $00, $00, $00\n                .byte $00, $00, $00, $00, $00, $00, $00\n                \nDelayProgress:  .byte $00\nSweepProgress:  .byte $00\nEnableLeds:     .byte $00\nLedData:        .byte $00<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Explanation.<\/h2>\n\n\n\n<p>I&#8217;ve included comments in the code to understand it better, but in a quick glance:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>We call routine <em><strong>$6027<\/strong><\/em> to check if cluster is on\/off. (<em>ignition on\/off<\/em>)<\/li>\n\n\n\n<li>We call routine <em><strong>IsHomed() <\/strong><\/em>to check if the needles are in the homed position. (<em>needles ready<\/em>)<\/li>\n\n\n\n<li>If <em>one <\/em>of the both are <strong>false<\/strong>, the needle sweep resets back to zero and this process repeats until both checks are <strong>true<\/strong>.<\/li>\n\n\n\n<li>Now that we are ready, we call <em><strong>Progress()<\/strong><\/em> routine to increment the progress variable used as reference for <em><strong>start &#8211; end &#8211; stop<\/strong> <\/em>cycle of the sweep.<\/li>\n\n\n\n<li>Inside <strong><em>Progress()<\/em> <\/strong>routine, we check for delay &#8211; a delay is needed when the <em>needle is already homed<\/em>, caused by a rapid on\/off of the ignition switch. If the needle is not homed, the cluster constantly checks the needles until it is ready &#8211; this process produces a delay, and this is the <em>delay <\/em>we simulate to keep both sweeps (homed\/not homed) having the same duration.<\/li>\n\n\n\n<li>Once the delay is done, the <strong><em>DelayProgress<\/em> <\/strong>variable starts to increment until <em><strong>MaxSweepProgress<\/strong><\/em> is reached, once reached the sweep is done.<\/li>\n\n\n\n<li>If the sweep is not done yet, we move the needles\/leds upwards until <em><strong>MaxSweepProgress\/2<\/strong><\/em>, beyond that the needles need to go down, the &#8216;zero-out&#8217; position.<\/li>\n<\/ul>\n\n\n\n<p><\/p>\n\n\n\n<p>The code can then be compiled in any <strong>W65C816 <\/strong>compiler, there is an online compiler version above in &#8216;useful links&#8217;.<\/p>\n\n\n\n<p>This is programming in <em>low-level language<\/em>, and in order to fully understand it you will need previous knowledge on bitwise operations, memory addressing, stack pointer, etc.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Useful links.<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"http:\/\/6502.org\/tutorials\/65c816opcodes.html\">W65C816 opcode list<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/feche.ar\/f\/DSA-363978.pdf\">MCU datasheet<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/feche.ar\/w65c816\">Online W65C816 compiler<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/github.com\/gmenounos\/vwcluster\/tree\/main\">https:\/\/github.com\/gmenounos\/vwcluster\/tree\/main<\/a><\/li>\n<\/ul>\n\n\n\n<p>Happy coding \ud83d\ude42<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p><strong>UPDATES<\/strong>: <\/p>\n\n\n\n<p><em>09\/12\/24<\/em><br>&#8211; Fixed an issue with the temperature needle not being zeroed correctly.<br>&#8211; Reduced initial sweep delay.<\/p>\n<\/blockquote>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Introduction. Hey there, In this blog-post, I will be sharing the source code of the [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[4],"tags":[],"class_list":["post-61","post","type-post","status-publish","format-standard","hentry","category-tutorials-others"],"_links":{"self":[{"href":"https:\/\/blog.feche.ar\/index.php?rest_route=\/wp\/v2\/posts\/61","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.feche.ar\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.feche.ar\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.feche.ar\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.feche.ar\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=61"}],"version-history":[{"count":26,"href":"https:\/\/blog.feche.ar\/index.php?rest_route=\/wp\/v2\/posts\/61\/revisions"}],"predecessor-version":[{"id":155,"href":"https:\/\/blog.feche.ar\/index.php?rest_route=\/wp\/v2\/posts\/61\/revisions\/155"}],"wp:attachment":[{"href":"https:\/\/blog.feche.ar\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=61"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.feche.ar\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=61"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.feche.ar\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=61"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}