diff --git a/.cproject b/.cproject
index fcbaddd..6c5be4d 100644
--- a/.cproject
+++ b/.cproject
@@ -53,6 +53,10 @@
+
+
+
+
@@ -416,6 +420,10 @@
+
+
+
+
diff --git a/.project b/.project
index 2a8cde2..6f14074 100644
--- a/.project
+++ b/.project
@@ -31,7 +31,7 @@
org.eclipse.cdt.make.core.buildLocation
- ${workspace_loc:/SIMMProgrammer/Debug}
+ ${workspace_loc:/SIMMProgrammer/Release}
org.eclipse.cdt.make.core.cleanBuildTarget
diff --git a/external_mem.c b/external_mem.c
index eae8e3c..0ae6327 100644
--- a/external_mem.c
+++ b/external_mem.c
@@ -6,72 +6,55 @@
*/
#include "external_mem.h"
-#include "mcp23s17.h"
+#include "ports.h"
#include
-// SIMM control signals on port B
-#define SIMM_WE (1 << 6)
-#define SIMM_OE (1 << 5)
-#define SIMM_CS (1 << 4)
-
-static bool ExternalMem_Inited = false;
+#define NUM_ADDRESS_LINES 20
+// Allow this to be initialized more than once.
+// In case we mess with the port settings,
+// re-initializing ExternalMem should reset everything
+// to sensible defaults.
void ExternalMem_Init(void)
{
- // If it has already been initialized, no need to do it again.
- if (ExternalMem_Inited)
- {
- return;
- }
+ // Initialize the ports connected to address/data/control lines
+ Ports_Init();
- // This module depends on the MCP23S17
- MCP23S17_Init();
+ // Disable all pull-ups, on both the address and data lines. They aren't needed
+ // for normal operation.
+ Ports_AddressPullups_RMW(0, (1UL << (NUM_ADDRESS_LINES - 1)) - 1);
+ Ports_DataPullups_RMW(0, 0xFFFFFFFFUL);
- // Configure address lines as outputs
- DDRA = 0xFF; // A0-A7
- DDRC = 0xFF; // A8-A15
- DDRD |= 0x73; // A16-A20
+ // Configure all address lines as outputs
+ Ports_SetAddressDDR((1UL << (NUM_ADDRESS_LINES - 1)) - 1);
- // Sensible defaults for address and data lines
- ExternalMem_SetAddress(0);
- ExternalMem_SetDataAsInput();
+ // Sensible defaults for address and data lines:
+ // Write out address zero
+ Ports_SetAddressOut(0);
- // Control lines
- DDRB |= SIMM_WE | SIMM_OE | SIMM_CS;
+ // Set all data lines as inputs (with no pullups! we turned them off)
+ Ports_SetDataDDR(0);
- // Default all the control lines to high (de-asserted)
- PORTB |= SIMM_WE | SIMM_OE | SIMM_CS;
+ // Control lines (I'm cheating and manipulating the bits directly here)
+ Ports_SetCSDDR(1);
+ Ports_SetOEDDR(1);
+ Ports_SetWEDDR(1);
- // All done!
- ExternalMem_Inited = true;
+ // Default all control lines to high (de-asserted)
+ ExternalMem_DeassertCS();
+ ExternalMem_DeassertOE();
+ ExternalMem_DeassertWE();
}
void ExternalMem_SetAddress(uint32_t address)
{
- PORTA = (address & 0xFF); // A0-A7
- PORTC = ((address >> 8) & 0xFF); // A8-A15
-
- // A16-A20 are special because they are split up...(We use PORTD pins 0, 1, 4, 5, 6)
- uint8_t tmp = (address >> 16) & 0xFF;
- tmp = (tmp & 0x03) | ((tmp & 0x1C) << 2);
-
- // Now, turn off the pins we have to turn off, and turn on the pins we have to turn on
- // (without affecting other pins [2, 3, and 7] that we aren't supposed to touch)
- PORTD &= (0x8C | tmp); // This should turn off all '0' bits in tmp.
- PORTD |= tmp; // This should turn on all '1' bits in tmp
+ Ports_SetAddressOut(address);
}
void ExternalMem_SetData(uint32_t data)
{
- // Set as outputs
- MCP23S17_SetDDR(0xFFFF); // D0-D15
- DDRE = 0xFF; // D16-D23
- DDRF = 0xFF; // D24-D31
-
- // Set the actual outputted values
- MCP23S17_SetPins(data & 0xFFFF); // D0-D15
- PORTE = ((data >> 16) & 0xFF); // D16-D23
- PORTF = ((data >> 24) & 0xFF); // D24-D31
+ Ports_SetDataDDR(0xFFFFFFFFUL);
+ Ports_SetDataOut(data);
}
void ExternalMem_SetAddressAndData(uint32_t address, uint32_t data)
@@ -82,44 +65,40 @@ void ExternalMem_SetAddressAndData(uint32_t address, uint32_t data)
void ExternalMem_SetDataAsInput(void)
{
- MCP23S17_SetDDR(0x0000); // D0-D15
- DDRE = 0; // D16-D23
- DDRF = 0; // D24-D31
+ Ports_SetDataDDR(0);
}
uint32_t ExternalMem_ReadData(void)
{
- return ((uint32_t)MCP23S17_ReadPins()) |
- (((uint32_t)PORTE) << 16) |
- (((uint32_t)PORTF) << 24);
+ return Ports_ReadData();
}
void ExternalMem_AssertCS(void)
{
- PORTB &= ~SIMM_CS;
+ Ports_SetCSOut(0);
}
void ExternalMem_DeassertCS(void)
{
- PORTB |= SIMM_CS;
+ Ports_SetCSOut(1);
}
void ExternalMem_AssertWE(void)
{
- PORTB &= ~SIMM_WE;
+ Ports_SetWEOut(0);
}
void ExternalMem_DeassertWE(void)
{
- PORTB |= SIMM_WE;
+ Ports_SetWEOut(1);
}
void ExternalMem_AssertOE(void)
{
- PORTB &= ~SIMM_OE;
+ Ports_SetOEOut(0);
}
void ExternalMem_DeassertOE(void)
{
- PORTB |= SIMM_OE;
+ Ports_SetOEOut(1);
}
diff --git a/mcp23s17.c b/mcp23s17.c
index d6624b0..f07ac03 100644
--- a/mcp23s17.c
+++ b/mcp23s17.c
@@ -113,6 +113,22 @@ void MCP23S17_SetPullups(uint16_t pullups)
MCP23S17_WriteBothRegs(MCP23S17_GPPUA, pullups);
}
+// Determines the output values of output pins without reading any input pins
+uint16_t MCP23S17_GetOutputs(void)
+{
+ return MCP23S17_ReadBothRegs(MCP23S17_OLATA);
+}
+
+uint16_t MCP23S17_GetDDR(void)
+{
+ return MCP23S17_ReadBothRegs(MCP23S17_IODIRA);
+}
+
+uint16_t MCP23S17_GetPullups(void)
+{
+ return MCP23S17_ReadBothRegs(MCP23S17_GPPUA);
+}
+
void MCP23S17_WriteBothRegs(uint8_t addrA, uint16_t value)
{
// addrA should contain the address of the "A" register.
diff --git a/mcp23s17.h b/mcp23s17.h
index 11a5cb2..df541e0 100644
--- a/mcp23s17.h
+++ b/mcp23s17.h
@@ -15,5 +15,8 @@ void MCP23S17_SetDDR(uint16_t ddr);
void MCP23S17_SetPins(uint16_t data);
uint16_t MCP23S17_ReadPins(void);
void MCP23S17_SetPullups(uint16_t pullups);
+uint16_t MCP23S17_GetOutputs(void);
+uint16_t MCP23S17_GetDDR(void);
+uint16_t MCP23S17_GetPullups(void);
#endif /* MCP23S17_H_ */
diff --git a/ports.c b/ports.c
new file mode 100644
index 0000000..e5b4b2e
--- /dev/null
+++ b/ports.c
@@ -0,0 +1,338 @@
+/*
+ * ports.c
+ *
+ * Created on: Nov 26, 2011
+ * Author: Doug
+ */
+
+#include "ports.h"
+#include "mcp23s17.h"
+#include
+
+// SIMM control signals on port B
+#define SIMM_WE (1 << 6)
+#define SIMM_OE (1 << 5)
+#define SIMM_CS (1 << 4)
+
+void Ports_Init(void)
+{
+ // This module depends on the MPC23S17
+ MCP23S17_Init();
+}
+
+void Ports_SetAddressOut(uint32_t data)
+{
+ // NOTE: If any of PORTA or PORTC or PORTD pins 0, 1, 4, 5, or 6 are set as
+ // inputs, this function might mess with their pull-up resistors.
+ // Only use it under normal operation when all the address pins are being
+ // used as outputs
+
+ PORTA = (data & 0xFF); // A0-A7
+ PORTC = ((data >> 8) & 0xFF); // A8-A15
+
+ // A16-A20 are special because they are split up...(We use PORTD pins 0, 1, 4, 5, 6)
+ uint8_t tmp = (data >> 16) & 0xFF;
+ tmp = (tmp & 0x03) | ((tmp & 0x1C) << 2);
+
+ // Now, turn off the pins we have to turn off, and turn on the pins we have to turn on
+ // (without affecting other pins [2, 3, and 7] that we aren't supposed to touch)
+ PORTD &= (0x8C | tmp); // This should turn off all '0' bits in tmp.
+ PORTD |= tmp; // This should turn on all '1' bits in tmp
+}
+
+void Ports_AddressOut_RMW(uint32_t data, uint32_t modifyMask)
+{
+ uint32_t modifiedDataOn = data & modifyMask;
+ uint32_t modifiedDataOff = data | ~modifyMask;
+
+ // Turn on/off requested bits in the PORT register.
+ PORTA |= ((modifiedDataOn >> 0) & 0xFF);
+ PORTA &= ((modifiedDataOff >> 0) & 0xFF);
+ PORTC |= ((modifiedDataOn >> 8) & 0xFF);
+ PORTC &= ((modifiedDataOff >> 8) & 0xFF);
+
+ // A16-A20 are special because they are split up...(We use PORTD pins 0, 1, 4, 5, 6)
+ uint8_t tmp = (modifiedDataOn >> 16) & 0xFF;
+ tmp = (tmp & 0x03) | ((tmp & 0x1C) << 2);
+
+ PORTD |= tmp;
+ PORTD &= (0x8C | tmp);
+}
+
+void Ports_SetDataOut(uint32_t data)
+{
+ // NOTE: If any pins of PORTE or PORTF are set as inputs, this
+ // function might mess with their pull-up resistors.
+ // Only use it under normal operation when all the address pins are being
+ // used as outputs
+
+ // Set the actual outputted values
+ MCP23S17_SetPins(data & 0xFFFF); // D0-D15
+ PORTE = ((data >> 16) & 0xFF); // D16-D23
+ PORTF = ((data >> 24) & 0xFF); // D24-D31
+}
+
+void Ports_DataOut_RMW(uint32_t data, uint32_t modifyMask)
+{
+ uint32_t modifiedDataOn = data & modifyMask;
+ uint32_t modifiedDataOff = data | ~modifyMask;
+
+ // Read what's in it first...
+ uint16_t outputLatches = MCP23S17_GetOutputs();
+ outputLatches |= (modifiedDataOn) & 0xFFFF;
+ outputLatches &= modifiedDataOff & 0xFFFF;
+ MCP23S17_SetPins(outputLatches);
+
+ // Turn on/off requested bits in the PORT register.
+ PORTE |= ((modifiedDataOn >> 16) & 0xFF);
+ PORTE &= ((modifiedDataOff >> 16) & 0xFF);
+ PORTF |= ((modifiedDataOn >> 24) & 0xFF);
+ PORTF &= ((modifiedDataOff >> 24) & 0xFF);
+}
+
+void Ports_SetCSOut(bool data)
+{
+ if (data)
+ {
+ PORTB |= SIMM_CS;
+ }
+ else
+ {
+ PORTB &= ~SIMM_CS;
+ }
+}
+
+void Ports_SetOEOut(bool data)
+{
+ if (data)
+ {
+ PORTB |= SIMM_OE;
+ }
+ else
+ {
+ PORTB &= ~SIMM_OE;
+ }
+}
+
+void Ports_SetWEOut(bool data)
+{
+ if (data)
+ {
+ PORTB |= SIMM_WE;
+ }
+ else
+ {
+ PORTB &= ~SIMM_WE;
+ }
+}
+
+void Ports_SetAddressDDR(uint32_t ddr)
+{
+ PORTA = (ddr & 0xFF); // A0-A7
+ PORTC = ((ddr >> 8) & 0xFF); // A8-A15
+
+ // A16-A20 are special because they are split up...(We use PORTD pins 0, 1, 4, 5, 6)
+ uint8_t tmp = (ddr >> 16) & 0xFF;
+ tmp = (tmp & 0x03) | ((tmp & 0x1C) << 2);
+
+ // Now, turn off the DDR bits we have to turn off,
+ // and turn on the DDR bits we have to turn on
+ // (without affecting other bits [2, 3, and 7]
+ // that we aren't supposed to touch)
+ DDRD &= (0x8C | tmp); // This should turn off all '0' bits in tmp.
+ DDRD |= tmp; // This should turn on all '1' bits in tmp
+}
+
+void Ports_AddressDDR_RMW(uint32_t ddr, uint32_t modifyMask)
+{
+ uint32_t modifiedDataOn = ddr & modifyMask;
+ uint32_t modifiedDataOff = ddr | ~modifyMask;
+
+ // Turn on/off requested bits in the DDR register.
+ DDRA |= ((modifiedDataOn >> 0) & 0xFF);
+ DDRA &= ((modifiedDataOff >> 0) & 0xFF);
+ DDRC |= ((modifiedDataOn >> 8) & 0xFF);
+ DDRC &= ((modifiedDataOff >> 8) & 0xFF);
+
+ // A16-A20 are special because they are split up...(We use PORTD pins 0, 1, 4, 5, 6)
+ uint8_t tmp = (modifiedDataOn >> 16) & 0xFF;
+ tmp = (tmp & 0x03) | ((tmp & 0x1C) << 2);
+
+ DDRD |= tmp;
+ DDRD &= (0x8C | tmp);
+}
+
+void Ports_SetDataDDR(uint32_t ddr)
+{
+ MCP23S17_SetDDR(ddr & 0xFFFF); // D0-D15
+ DDRE = ((ddr >> 16) & 0xFF); // D16-D23
+ DDRF = ((ddr >> 24) & 0xFF); // D24-D31
+}
+
+void Ports_DataDDR_RMW(uint32_t ddr, uint32_t modifyMask)
+{
+ uint32_t modifiedDataOn = ddr & modifyMask;
+ uint32_t modifiedDataOff = ddr | ~modifyMask;
+
+ // If we can get away with it, don't bother reading back...
+ if ((modifyMask & 0xFFFF) == 0xFFFF)
+ {
+ MCP23S17_SetDDR(modifiedDataOn & 0xFFFF);
+ }
+ else // Otherwise, we have to read what's in it first...(unless I decide to keep a local cached copy)
+ {
+ uint16_t outputLatches = MCP23S17_GetDDR();
+ outputLatches |= (modifiedDataOn) & 0xFFFF;
+ outputLatches &= modifiedDataOff & 0xFFFF;
+ MCP23S17_SetDDR(outputLatches);
+ }
+
+ // Turn on/off requested bits in the DDR register.
+ DDRE |= ((modifiedDataOn >> 16) & 0xFF);
+ DDRE &= ((modifiedDataOff >> 16) & 0xFF);
+ DDRF |= ((modifiedDataOn >> 24) & 0xFF);
+ DDRF &= ((modifiedDataOff >> 24) & 0xFF);
+}
+
+void Ports_SetCSDDR(bool ddr)
+{
+ if (ddr)
+ {
+ DDRB |= SIMM_CS;
+ }
+ else
+ {
+ DDRB &= ~SIMM_CS;
+ }
+}
+
+void Ports_SetOEDDR(bool ddr)
+{
+ if (ddr)
+ {
+ DDRB |= SIMM_OE;
+ }
+ else
+ {
+ DDRB &= ~SIMM_OE;
+ }
+}
+
+void Ports_SetWEDDR(bool ddr)
+{
+ if (ddr)
+ {
+ DDRB |= SIMM_WE;
+ }
+ else
+ {
+ DDRB &= ~SIMM_WE;
+ }
+}
+
+void Ports_AddressPullups_RMW(uint32_t pullups, uint32_t modifyMask)
+{
+ // Pull-ups are set by writing to the data register when in input mode.
+ // MAKE SURE THE PINS ARE SET AS INPUTS FIRST!
+ Ports_AddressOut_RMW(pullups, modifyMask);
+}
+
+void Ports_DataPullups_RMW(uint32_t pullups, uint32_t modifyMask)
+{
+ // Pull-ups here are a little more tricky because the MCP23S17 has
+ // separate registers for pull-up enable.
+ uint32_t modifiedDataOn = pullups & modifyMask;
+ uint32_t modifiedDataOff = pullups | ~modifyMask;
+
+ // If we can get away with it, don't bother reading back...
+ if ((modifyMask & 0xFFFF) == 0xFFFF)
+ {
+ MCP23S17_SetPullups(modifiedDataOn & 0xFFFF);
+ }
+ else // Otherwise, we have to read what's in it first...(unless I decide to keep a local cached copy)
+ {
+ uint16_t outputLatches = MCP23S17_GetPullups();
+ outputLatches |= (modifiedDataOn) & 0xFFFF;
+ outputLatches &= modifiedDataOff & 0xFFFF;
+ MCP23S17_SetPullups(outputLatches);
+ }
+
+ // Turn on/off requested bits in the PORT register for the other 16 bits.
+ PORTE |= ((modifiedDataOn >> 16) & 0xFF);
+ PORTE &= ((modifiedDataOff >> 16) & 0xFF);
+ PORTF |= ((modifiedDataOn >> 24) & 0xFF);
+ PORTF &= ((modifiedDataOff >> 24) & 0xFF);
+}
+
+void Ports_SetCSPullup(bool pullup)
+{
+ if (pullup)
+ {
+ PORTB |= SIMM_CS;
+ }
+ else
+ {
+ PORTB &= ~SIMM_CS;
+ }
+}
+
+void Ports_SetOEPullup(bool pullup)
+{
+ if (pullup)
+ {
+ PORTB |= SIMM_OE;
+ }
+ else
+ {
+ PORTB &= ~SIMM_OE;
+ }
+}
+
+void Ports_SetWEPullup(bool pullup)
+{
+ if (pullup)
+ {
+ PORTB |= SIMM_WE;
+ }
+ else
+ {
+ PORTB &= ~SIMM_WE;
+ }
+}
+
+
+uint32_t Ports_ReadAddress(void)
+{
+ uint32_t result = PINA;
+ result |= (((uint32_t)PINC) << 8);
+ uint8_t tmp = (PIND & 0x03) | ((PIND & 0x70) >> 2);
+ result |= (((uint32_t)tmp) << 16);
+
+ return result;
+}
+
+uint32_t Ports_ReadData(void)
+{
+ uint32_t result = (uint32_t)MCP23S17_ReadPins();
+
+ // Turn on/off requested bits in the PORT register.
+ result |= (((uint32_t)PINE) << 16);
+ result |= (((uint32_t)PINF) << 24);
+
+ return result;
+}
+
+bool Ports_ReadCSInData(void)
+{
+ return (PINB & SIMM_CS) != 0;
+}
+
+bool Ports_ReadOEInData(void)
+{
+ return (PINB & SIMM_OE) != 0;
+}
+
+bool Ports_ReadWEInData(void)
+{
+ return (PINB & SIMM_WE) != 0;
+}
diff --git a/ports.h b/ports.h
new file mode 100644
index 0000000..dd97795
--- /dev/null
+++ b/ports.h
@@ -0,0 +1,60 @@
+/*
+ * ports.h
+ *
+ * Created on: Nov 26, 2011
+ * Author: Doug
+ */
+
+#ifndef PORTS_H_
+#define PORTS_H_
+
+#include
+#include
+
+// Under normal operation, we will only be using the address pins as outputs.
+// The data pins will switch back and forth between all inputs and all outputs.
+// The CS/OE/WE pins will always be outputs.
+// The pullups will all be turned off.
+// So you should use Ports_SetAddressOut(),
+// Ports_SetDataOut(),
+// Ports_SetAddressDDR() [once at the beginning]
+// Ports_SetDataDDR(),
+// and Ports_ReadDataInData
+//
+// The reason I have implemented all this functionality is to give me complete
+// control over all the pins for other use cases, such as a SIMM electrical test.
+// By playing with pull-ups and inputs and outputs, I should be able to detect
+// many shorted output/input scenarios. So even though these functions are overkill,
+// they will be useful for diagnostics.
+
+void Ports_Init(void);
+
+void Ports_SetAddressOut(uint32_t data);
+void Ports_AddressOut_RMW(uint32_t data, uint32_t modifyMask);
+void Ports_SetDataOut(uint32_t data);
+void Ports_DataOut_RMW(uint32_t data, uint32_t modifyMask);
+void Ports_SetCSOut(bool data);
+void Ports_SetOEOut(bool data);
+void Ports_SetWEOut(bool data);
+
+void Ports_SetAddressDDR(uint32_t ddr);
+void Ports_AddressDDR_RMW(uint32_t ddr, uint32_t modifyMask);
+void Ports_SetDataDDR(uint32_t ddr);
+void Ports_DataDDR_RMW(uint32_t ddr, uint32_t modifyMask);
+void Ports_SetCSDDR(bool ddr);
+void Ports_SetOEDDR(bool ddr);
+void Ports_SetWEDDR(bool ddr);
+
+void Ports_AddressPullups_RMW(uint32_t pullups, uint32_t modifyMask);
+void Ports_DataPullups_RMW(uint32_t pullups, uint32_t modifyMask);
+void Ports_SetCSPullup(bool pullup);
+void Ports_SetOEPullup(bool pullup);
+void Ports_SetWEPullup(bool pullup);
+
+uint32_t Ports_ReadAddress(void);
+uint32_t Ports_ReadData(void);
+bool Ports_ReadCS(void);
+bool Ports_ReadOE(void);
+bool Ports_ReadWE(void);
+
+#endif /* PORTS_H_ */
diff --git a/tests/simm_electrical_test.c b/tests/simm_electrical_test.c
new file mode 100644
index 0000000..adb46b0
--- /dev/null
+++ b/tests/simm_electrical_test.c
@@ -0,0 +1,16 @@
+/*
+ * simm_electrical_test.c
+ *
+ * Created on: Nov 26, 2011
+ * Author: Doug
+ */
+
+#include "simm_electrical_test.h"
+
+int SIMMElectricalTest_Run(void)
+{
+ // Returns number of errors found
+ int numErrors = 0;
+
+ return numErrors;
+}
diff --git a/tests/simm_electrical_test.h b/tests/simm_electrical_test.h
new file mode 100644
index 0000000..15e3d3b
--- /dev/null
+++ b/tests/simm_electrical_test.h
@@ -0,0 +1,12 @@
+/*
+ * simm_electrical_test.h
+ *
+ * Created on: Nov 26, 2011
+ * Author: Doug
+ */
+
+#ifndef SIMM_ELECTRICAL_TEST_H_
+#define SIMM_ELECTRICAL_TEST_H_
+
+
+#endif /* SIMM_ELECTRICAL_TEST_H_ */