diff --git a/microcode-eeprom-programmer/microcode-eeprom-programmer.ino b/microcode-eeprom-programmer/microcode-eeprom-programmer.ino index 032cb65..57aecb0 100644 --- a/microcode-eeprom-programmer/microcode-eeprom-programmer.ino +++ b/microcode-eeprom-programmer/microcode-eeprom-programmer.ino @@ -49,8 +49,13 @@ uint16_t data[] = { * Output the address bits and outputEnable signal using shift registers. */ void setAddress(int address, bool outputEnable) { - shiftOut(SHIFT_DATA, SHIFT_CLK, MSBFIRST, (address >> 8) | (outputEnable ? 0x00 : 0x80)); - shiftOut(SHIFT_DATA, SHIFT_CLK, MSBFIRST, address); + address = address & 0x7FFF; + + byte msb = (address >> 8) | (outputEnable ? 0x00 : 0x80); + shiftOut(SHIFT_DATA, SHIFT_CLK, MSBFIRST, msb); + + byte lsb = address & 0xFF; + shiftOut(SHIFT_DATA, SHIFT_CLK, MSBFIRST, lsb); digitalWrite(SHIFT_LATCH, LOW); digitalWrite(SHIFT_LATCH, HIGH); @@ -67,7 +72,7 @@ byte readEEPROM(int address) { } setAddress(address, /*outputEnable*/ true); - byte data = 0; + byte data = 0x00; for (int pin = EEPROM_D7; pin >= EEPROM_D0; pin -= 1) { data = (data << 1) + digitalRead(pin); } @@ -94,24 +99,77 @@ void writeEEPROM(int address, byte data) { delay(10); } +/** + * Clear out the entire EEPROM + */ +void eraseEEPROM() +{ + Serial.println("Erasing EEPROM"); + for (int address = 0x0000; address < 0x0800; address++) { + writeEEPROM(address, 0xff); + + if (address % 0x40 == 0x00) { + Serial.print("."); + } + } + Serial.println("Erasing EEPROM -- Done."); + Serial.println(); +} + + +void programEEPROM(byte data[], int length) +{ + Serial.println("Programming EEPROM"); + for (int address = 0x0000; address < length; address++) { + writeEEPROM(address, data[address]); + + if (address % 0x40 == 0x00) { + Serial.print("."); + } + } + Serial.println(" Done."); + Serial.println(); +} + + +void programEEPROM(uint16_t data[], int offset, int length, bool highByte) +{ + Serial.println("Programming EEPROM"); + for (int address = 0x0000; address < length; address++){ + byte value = data[address] >> (highByte ? 8 : 0); + writeEEPROM(address + offset, value); + + if (address % 0x40 == 0x00) { + Serial.print("."); + } + } + Serial.println(" Done."); + Serial.println(); +} + /* * Read the contents of the EEPROM and print them to the serial monitor. */ -void printContents() { - for (int base = 0; base <= 255; base += 16) { - byte data[16]; - for (int offset = 0; offset <= 15; offset += 1) { - data[offset] = readEEPROM(base + offset); +void printContents(int address) { + for (int base = 0x0000; base < 0x0100; base += 0x10) { + char buf[20]; + sprintf(buf, "0x%04x: ", address + base); + Serial.print(buf); + for (int offset = 0; offset < 0x10; offset += 0x01) { + byte data = readEEPROM(address + base + offset); + sprintf(buf, "%02x ", data); + Serial.print(buf); + + if (offset == 0x07) { + Serial.print(" "); + } } - char buf[80]; - sprintf(buf, "%03x: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x", - base, data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7], - data[8], data[9], data[10], data[11], data[12], data[13], data[14], data[15]); - - Serial.println(buf); + Serial.println(); } + + Serial.println(); } @@ -124,33 +182,18 @@ void setup() { pinMode(WRITE_EN, OUTPUT); Serial.begin(57600); - // Program data bytes - Serial.print("Programming EEPROM"); - - // Program the 8 high-order bits of microcode into the first 128 bytes of EEPROM - for (int address = 0; address < sizeof(data)/sizeof(data[0]); address += 1) { - writeEEPROM(address, data[address] >> 8); - - if (address % 64 == 0) { - Serial.print("."); - } - } + // eraseEEPROM(); - // Program the 8 low-order bits of microcode into the second 128 bytes of EEPROM - for (int address = 0; address < sizeof(data)/sizeof(data[0]); address += 1) { - writeEEPROM(address + 128, data[address]); - - if (address % 64 == 0) { - Serial.print("."); - } - } - - Serial.println(" done"); + // Program data bytes + // Program the 8 high-order bits of microcode into the first 0x80 bytes of EEPROM + programEEPROM(data, 0x00, sizeof data / sizeof data[0], true); + // Program the 8 low-order bits of microcode into the second 0x80 bytes of EEPROM + programEEPROM(data, 0x80, sizeof data / sizeof data[0], false); // Read and print out the contents of the EERPROM Serial.println("Reading EEPROM"); - printContents(); + printContents(0x0000); } diff --git a/multiplexed-display.tests/.gitattributes b/multiplexed-display.tests/.gitattributes new file mode 100644 index 0000000..1ff0c42 --- /dev/null +++ b/multiplexed-display.tests/.gitattributes @@ -0,0 +1,63 @@ +############################################################################### +# Set default behavior to automatically normalize line endings. +############################################################################### +* text=auto + +############################################################################### +# Set default behavior for command prompt diff. +# +# This is need for earlier builds of msysgit that does not have it on by +# default for csharp files. +# Note: This is only used by command line +############################################################################### +#*.cs diff=csharp + +############################################################################### +# Set the merge driver for project and solution files +# +# Merging from the command prompt will add diff markers to the files if there +# are conflicts (Merging from VS is not affected by the settings below, in VS +# the diff markers are never inserted). Diff markers may cause the following +# file extensions to fail to load in VS. An alternative would be to treat +# these files as binary and thus will always conflict and require user +# intervention with every merge. To do so, just uncomment the entries below +############################################################################### +#*.sln merge=binary +#*.csproj merge=binary +#*.vbproj merge=binary +#*.vcxproj merge=binary +#*.vcproj merge=binary +#*.dbproj merge=binary +#*.fsproj merge=binary +#*.lsproj merge=binary +#*.wixproj merge=binary +#*.modelproj merge=binary +#*.sqlproj merge=binary +#*.wwaproj merge=binary + +############################################################################### +# behavior for image files +# +# image files are treated as binary by default. +############################################################################### +#*.jpg binary +#*.png binary +#*.gif binary + +############################################################################### +# diff behavior for common document formats +# +# Convert binary document formats to text before diffing them. This feature +# is only available from the command line. Turn it on by uncommenting the +# entries below. +############################################################################### +#*.doc diff=astextplain +#*.DOC diff=astextplain +#*.docx diff=astextplain +#*.DOCX diff=astextplain +#*.dot diff=astextplain +#*.DOT diff=astextplain +#*.pdf diff=astextplain +#*.PDF diff=astextplain +#*.rtf diff=astextplain +#*.RTF diff=astextplain diff --git a/multiplexed-display.tests/.gitignore b/multiplexed-display.tests/.gitignore new file mode 100644 index 0000000..3c4efe2 --- /dev/null +++ b/multiplexed-display.tests/.gitignore @@ -0,0 +1,261 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ + +# Visual Studio 2015 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# DNX +project.lock.json +project.fragment.lock.json +artifacts/ + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# TODO: Comment the next line if you want to checkin your web deploy settings +# but database connection strings (with potential passwords) will be unencrypted +#*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/packages/* +# except build/, which is used as an MSBuild target. +!**/packages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/packages/repositories.config +# NuGet v3's project.json files produces more ignoreable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +node_modules/ +orleans.codegen.cs + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +*.mdf +*.ldf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# JetBrains Rider +.idea/ +*.sln.iml + +# CodeRush +.cr/ + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc \ No newline at end of file diff --git a/multiplexed-display.tests/multiplexed-display.tests.sln b/multiplexed-display.tests/multiplexed-display.tests.sln new file mode 100644 index 0000000..4cbe344 --- /dev/null +++ b/multiplexed-display.tests/multiplexed-display.tests.sln @@ -0,0 +1,22 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.26430.15 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "multiplexed-display.tests", "multiplexed-display.tests\multiplexed-display.tests.csproj", "{9D7E2F34-856F-453F-839C-91741F8F0781}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {9D7E2F34-856F-453F-839C-91741F8F0781}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9D7E2F34-856F-453F-839C-91741F8F0781}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9D7E2F34-856F-453F-839C-91741F8F0781}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9D7E2F34-856F-453F-839C-91741F8F0781}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/multiplexed-display.tests/multiplexed-display.tests/DisplayTests.cs b/multiplexed-display.tests/multiplexed-display.tests/DisplayTests.cs new file mode 100644 index 0000000..7541157 --- /dev/null +++ b/multiplexed-display.tests/multiplexed-display.tests/DisplayTests.cs @@ -0,0 +1,209 @@ +// +// Copyright 2017-2020 Greg Eakin +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at: +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +using Microsoft.VisualStudio.TestTools.UnitTesting; +using System; +using System.Collections.Generic; + +namespace multiplexed_display.tests +{ + [TestClass] + public class DisplayTests + { + private readonly char[] _digits = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; + private const char Blank = ' '; + private const char MinusSign = '-'; + private const char HexSigh = 'h'; + + private static string Display(int i, IReadOnlyList data) + { + return $"{data[0x300 + i]}{data[0x200 + i]}{data[0x100 + i]}{data[0x000 + i]}"; + } + + [TestMethod] + public void UnsignedTest() + { + var data = new char[0x400]; + + for (var i = 0; i < 0x100; i++) + { + var d2 = i / 100 % 10; // 2nd 7segment display (hundreds) + var d3 = i / 10 % 10; // 3rd 7segment display (tenths) + data[i + 0x300] = Blank; // clear first 7segment display + data[i + 0x200] = d2 == 0 ? Blank : _digits[d2]; // write the digit or clear if 0 + data[i + 0x100] = d2 == 0 && d3 == 0 ? Blank : _digits[d3]; // write the digit or clear if d3 and d2 are 0 + data[i + 0x000] = _digits[i % 10]; // write the digit even 0 + } + + Assert.AreEqual(" 0", Display(0, data)); + Assert.AreEqual(" 7", Display(7, data)); + Assert.AreEqual(" 16", Display(16, data)); + Assert.AreEqual(" 100", Display(100, data)); + Assert.AreEqual(" 255", Display(255, data)); + } + + [TestMethod] + public void HexTest() + { + var data = new char[0x400]; + + for (var i = 0; i < 0x100; i++) + { + var d2 = i >> 4; + var d3 = i & 0x0F; + data[i + 0x300] = Blank; + data[i + 0x200] = _digits[d2]; + data[i + 0x100] = _digits[d3]; + data[i + 0x000] = HexSigh; + } + + Assert.AreEqual(" 00h", Display(0x00, data)); + Assert.AreEqual(" 07h", Display(0x07, data)); + Assert.AreEqual(" 1ch", Display(0x1C, data)); + Assert.AreEqual(" 64h", Display(0x64, data)); + Assert.AreEqual(" ffh", Display(0xFF, data)); + } + + [TestMethod] + public void TwosComplementTest() + { + var data = new char[0x400]; + + for (var i = 0; i < 0x100; i++) + { + if (i < 0x80) + { + var d2 = i / 100 % 10; // 2nd 7segment display (hundreds) + var d3 = i / 10 % 10; // 3rd 7segment display (tenths) + data[i + 0x300] = Blank; // clear first 7segment display + data[i + 0x200] = d2 == 0 ? Blank : _digits[d2]; // write the digit or clear if 0 + data[i + 0x100] = d2 == 0 && d3 == 0 ? Blank : _digits[d3]; // write the digit or clear if d3 and d2 are 0 + data[i + 0x000] = _digits[i % 10]; // write the digit even 0 + } + else + { + // Example + // d1 d2 d3 d4 + // - 1 2 3 + // - 4 2 + // - 7 + + var value = i - 0x100; //real value as two's complement + var d2 = Math.Abs(value) / 100 % 10; //hundreds + var d3 = Math.Abs(value) / 10 % 10; //tenths + var d4 = Math.Abs(value) % 10; //ones + + //first 7segment display + data[i + 0x300] = d2 == 0 ? Blank : MinusSign; //write a minus sign to the first 7segment display if the second 7segment display isn't clear + + //second 7segment display + if (d2 == 0 && d3 == 0) + { // if the minus sign is further right + data[i + 0x200] = Blank; // clear second 7segment display + } + else + { + data[i + 0x200] = d2 == 0 ? MinusSign : _digits[d2]; + } + + // third 7segment display + data[i + 0x100] = d2 == 0 && d3 == 0 ? MinusSign : _digits[d3]; // write a minus sign if both the second and the third 7segment display are clear + + // last 7segment display + data[i + 0x000] = _digits[d4]; // always write the last digit (ones) + } + } + + Assert.AreEqual(" 0", Display(0, data)); + Assert.AreEqual(" 16", Display(16, data)); + Assert.AreEqual(" 127", Display(127, data)); + Assert.AreEqual("-128", Display(128, data)); + Assert.AreEqual(" -10", Display(246, data)); + Assert.AreEqual(" -1", Display(255, data)); + } + + private static uint BinaryToGray(uint num) + { + return num ^ (num >> 1); + } + + private static uint GrayToBinary32(uint num) + { + num = num ^ (num >> 16); + num = num ^ (num >> 8); + num = num ^ (num >> 4); + num = num ^ (num >> 2); + num = num ^ (num >> 1); + return num; + } + + [TestMethod] + public void GrayTest() + { + var data = new char[0x400]; + + for (var gray = 0x000; gray < 0x100; gray++) + { + var binary = GrayToBinary32((uint)gray); + + var d2 = binary / 100 % 10; // 2nd 7segment display (hundreds) + var d3 = binary / 10 % 10; // 3rd 7segment display (tenths) + data[gray + 0x300] = Blank; // clear first 7segment display + data[gray + 0x200] = d2 == 0 ? Blank : _digits[d2]; // write the digit or clear if 0 + data[gray + 0x100] = d2 == 0 && d3 == 0 ? Blank : _digits[d3]; // write the digit or clear if d3 and d2 are 0 + data[gray + 0x000] = _digits[binary % 10]; // write the digit even 0 + } + + for (var binary = 0x000; binary < 0x100; binary++) + { + var gray = BinaryToGray((uint)binary); + Assert.AreEqual($"{binary,4:##0}", Display((int)gray, data)); + } + } + + [TestMethod] + public void BcdTest() + { + var data = new char[0x400]; + + for (var i = 0; i < 0x100; i++) + { + var d3 = i >> 4; + var d4 = i & 0x0F; + + if (d3 > 9 || d4 > 9) + { + data[i + 0x300] = MinusSign; + data[i + 0x200] = MinusSign; + data[i + 0x100] = MinusSign; + data[i + 0x000] = MinusSign; + continue; + } + + data[i + 0x300] = Blank; + data[i + 0x200] = Blank; + data[i + 0x100] = d3 == 0 ? Blank : _digits[d3]; + data[i + 0x000] = _digits[d4]; + } + + Assert.AreEqual(" 0", Display(0x00, data)); + Assert.AreEqual(" 7", Display(0x07, data)); + Assert.AreEqual(" 26", Display(0x26, data)); + Assert.AreEqual(" 99", Display(0x99, data)); + Assert.AreEqual("----", Display(0x0A, data)); + Assert.AreEqual("----", Display(0xA0, data)); + } + } +} diff --git a/multiplexed-display.tests/multiplexed-display.tests/Properties/AssemblyInfo.cs b/multiplexed-display.tests/multiplexed-display.tests/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..404e5e0 --- /dev/null +++ b/multiplexed-display.tests/multiplexed-display.tests/Properties/AssemblyInfo.cs @@ -0,0 +1,20 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +[assembly: AssemblyTitle("multiplexed-display.tests")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("multiplexed-display.tests")] +[assembly: AssemblyCopyright("Copyright © 2017")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +[assembly: ComVisible(false)] + +[assembly: Guid("9d7e2f34-856f-453f-839c-91741f8f0781")] + +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/multiplexed-display.tests/multiplexed-display.tests/multiplexed-display.tests.csproj b/multiplexed-display.tests/multiplexed-display.tests/multiplexed-display.tests.csproj new file mode 100644 index 0000000..feef6f5 --- /dev/null +++ b/multiplexed-display.tests/multiplexed-display.tests/multiplexed-display.tests.csproj @@ -0,0 +1,67 @@ + + + + + Debug + AnyCPU + {9D7E2F34-856F-453F-839C-91741F8F0781} + Library + Properties + multiplexed_display.tests + multiplexed-display.tests + v4.5.2 + 512 + {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + 15.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages + False + UnitTest + + + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\packages\MSTest.TestFramework.2.1.2\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.dll + + + ..\packages\MSTest.TestFramework.2.1.2\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.Extensions.dll + + + + + + + + + + + + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + + \ No newline at end of file diff --git a/multiplexed-display.tests/multiplexed-display.tests/packages.config b/multiplexed-display.tests/multiplexed-display.tests/packages.config new file mode 100644 index 0000000..506206f --- /dev/null +++ b/multiplexed-display.tests/multiplexed-display.tests/packages.config @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/multiplexed-display/multiplexed-display.ino b/multiplexed-display/multiplexed-display.ino index cc018d6..336e58a 100644 --- a/multiplexed-display/multiplexed-display.ino +++ b/multiplexed-display/multiplexed-display.ino @@ -1,6 +1,6 @@ /** - * This sketch is specifically for programming the EEPROM used in the 8-bit - * decimal display decoder described in https://youtu.be/dLh1n2dErzE + * This sketch is specifically for programming the EEPROM used in the 8-bit + * decimal display decoder described in https://youtu.be/dLh1n2dErzE */ #define SHIFT_DATA 2 #define SHIFT_CLK 3 @@ -9,13 +9,21 @@ #define EEPROM_D7 12 #define WRITE_EN 13 + /* Output the address bits and outputEnable signal using shift registers. */ void setAddress(int address, bool outputEnable) { - shiftOut(SHIFT_DATA, SHIFT_CLK, MSBFIRST, (address >> 8) | (outputEnable ? 0x00 : 0x80)); - shiftOut(SHIFT_DATA, SHIFT_CLK, MSBFIRST, address); + address = address & 0x7FFF; + + // Shift the data out, via the shift register clock + byte msb = (address >> 8) | (outputEnable ? 0x00 : 0x80); + shiftOut(SHIFT_DATA, SHIFT_CLK, MSBFIRST, msb); + + byte lsb = address & 0xFF; + shiftOut(SHIFT_DATA, SHIFT_CLK, MSBFIRST, lsb); + // Shift-register data is stored in the storage register. digitalWrite(SHIFT_LATCH, LOW); digitalWrite(SHIFT_LATCH, HIGH); digitalWrite(SHIFT_LATCH, LOW); @@ -31,7 +39,7 @@ byte readEEPROM(int address) { } setAddress(address, /*outputEnable*/ true); - byte data = 0; + byte data = 0x00; for (int pin = EEPROM_D7; pin >= EEPROM_D0; pin -= 1) { data = (data << 1) + digitalRead(pin); } @@ -59,84 +67,148 @@ void writeEEPROM(int address, byte data) { } +/** + * Clear out the entire EEPROM + */ +void eraseEEPROM(int address, int length) +{ + char data[80]; + sprintf(data, "Erasing EEPROM, Start 0x%04x, Length 0x%04x", address, length); + Serial.println(data); + for (int offset = 0x0000; offset < length; offset++) { + writeEEPROM(address + offset, 0xff); + + if (offset % 0x40 == 0x00) { + Serial.print("."); + } + } + Serial.println(); + Serial.println("Erasing EEPROM -- Done."); + Serial.println(); +} + + /* Read the contents of the EEPROM and print them to the serial monitor. */ -void printContents() { - for (int base = 0; base <= 255; base += 16) { - byte data[16]; - for (int offset = 0; offset <= 15; offset += 1) { - data[offset] = readEEPROM(base + offset); +void printContents(int address) { + for (int base = 0x0000; base < 0x0100; base += 0x10) + { + char buf[20]; + sprintf(buf, "0x%04x: ", address + base); + Serial.print(buf); + for (int offset = 0x00; offset < 0x10; offset += 1) + { + byte data = readEEPROM(address + base + offset); + sprintf(buf, "%02x ", data); + Serial.print(buf); + + if (offset == 7) + Serial.print(" "); + } + Serial.println(); + } + Serial.println(); +} + + +byte digits[] = {0x7e, 0x30, 0x6d, 0x79, 0x33, 0x5b, 0x5f, 0x70, 0x7f, 0x7b, 0x77, 0x1f, 0x4e, 0x3d, 0x4f, 0x47}; +byte minusSign = 0x01; +byte blank = 0x00; + +/* + Using Indeximal's idea to remove the leading zeros, and use blank space instead. +*/ +void programEEPROM() +{ + // loop over all possible inputs + for (int i = 0x0000; i < 0x0100; i++) + { + if (i % 0x10 == 0x00) + { + Serial.print((i / 256.0) * 100.0); + Serial.println("%"); } - char buf[80]; - sprintf(buf, "%03x: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x", - base, data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7], - data[8], data[9], data[10], data[11], data[12], data[13], data[14], data[15]); + // unsigned byte as decimal + { + int d2 = (i / 100) % 10; // 2nd 7segment display (hundreds) + int d3 = (i / 10) % 10; // 3rd 7segment display (tenths) + writeEEPROM(i + 0x0300, blank); // clear first 7segment display + writeEEPROM(i + 0x0200, (d2 == 0) ? blank : digits[d2]); // write the digit or clear if 0 + writeEEPROM(i + 0x0100, (d2 == 0 && d3 == 0) ? blank : digits[d3]); // write the digit or clear if d3 and d2 are 0 + writeEEPROM(i + 0x0000, digits[i % 10]); // write the digit even 0 + } - Serial.println(buf); + // Two's complement + if (i < 0x80) + { + // positive numbers, same as above + int d2 = (i / 100) % 10; // 2nd 7segment display (hundreds) + int d3 = (i / 10) % 10; // 3rd 7segment display (tenths) + writeEEPROM(i + 0x0700, blank); // clear first 7segment display + writeEEPROM(i + 0x0600, (d2 == 0) ? blank : digits[d2]); // write the digit or clear if 0 + writeEEPROM(i + 0x0500, (d2 == 0 && d3 == 0) ? blank : digits[d3]); // write the digit or clear if d3 and d2 are 0 + writeEEPROM(i + 0x0400, digits[i % 10]); // write the digit including 0 + } + else + { + // Example + // d1 d2 d3 d4 + // - 1 2 3 + // - 4 2 + // - 7 + + int value = i - 0x0100; //real value as two's complement + int d2 = (abs(value) / 100) % 10; //hundreds + int d3 = (abs(value) / 10) % 10; //tenths + int d4 = abs(value) % 10; //ones + + //first 7segment display + writeEEPROM(i + 0x0700, d2 == 0 ? blank : minusSign); //write a minus sign to the first 7segment display if the second 7segment display isn't clear + + //second 7segment display + if (d2 == 0 && d3 == 0) { // if the minus sign is further right + writeEEPROM(i + 0x0600, blank); // clear second 7segment display + } else { + writeEEPROM(i + 0x0600, d2 == 0 ? minusSign : digits[d2]); + } + + // third 7segment display + writeEEPROM(i + 0x0500, (d2 == 0 && d3 == 0) ? minusSign : digits[d3]); // write a minus sign if both the second and the third 7segment display are clear + + // last 7segment display + writeEEPROM(i + 0x0400, digits[d4]); // always write the last digit (ones) + } } } void setup() { - // put your setup code here, to run once: + // put your setup code here, to run once: pinMode(SHIFT_DATA, OUTPUT); pinMode(SHIFT_CLK, OUTPUT); + + digitalWrite(SHIFT_LATCH, LOW); pinMode(SHIFT_LATCH, OUTPUT); + digitalWrite(WRITE_EN, HIGH); pinMode(WRITE_EN, OUTPUT); - Serial.begin(57600); - - - // Bit patterns for the digits 0..9 - byte digits[] = { 0x7e, 0x30, 0x6d, 0x79, 0x33, 0x5b, 0x5f, 0x70, 0x7f, 0x7b }; - - Serial.println("Programming ones place"); - for (int value = 0; value <= 255; value += 1) { - writeEEPROM(value, digits[value % 10]); - } - Serial.println("Programming tens place"); - for (int value = 0; value <= 255; value += 1) { - writeEEPROM(value + 256, digits[(value / 10) % 10]); - } - Serial.println("Programming hundreds place"); - for (int value = 0; value <= 255; value += 1) { - writeEEPROM(value + 512, digits[(value / 100) % 10]); - } - Serial.println("Programming sign"); - for (int value = 0; value <= 255; value += 1) { - writeEEPROM(value + 768, 0); - } - Serial.println("Programming ones place (twos complement)"); - for (int value = -128; value <= 127; value += 1) { - writeEEPROM((byte)value + 1024, digits[abs(value) % 10]); - } - Serial.println("Programming tens place (twos complement)"); - for (int value = -128; value <= 127; value += 1) { - writeEEPROM((byte)value + 1280, digits[abs(value / 10) % 10]); - } - Serial.println("Programming hundreds place (twos complement)"); - for (int value = -128; value <= 127; value += 1) { - writeEEPROM((byte)value + 1536, digits[abs(value / 100) % 10]); - } - Serial.println("Programming sign (twos complement)"); - for (int value = -128; value <= 127; value += 1) { - if (value < 0) { - writeEEPROM((byte)value + 1792, 0x01); - } else { - writeEEPROM((byte)value + 1792, 0); - } - } + Serial.begin(57600); + // Clear and program the EEPROM + // eraseEEPROM(0x0600, 0x0100); + programEEPROM(); + + // Read and print out the contents of the EERPROM Serial.println("Reading EEPROM"); - printContents(); + for (int address = 0x0000; address < 0x0800; address += 0x0100) + printContents(address); } - void loop() { // put your main code here, to run repeatedly: - } +