OK, for what it’s worth here’s the code and a few additional words of explanation. If you are wondering why go to the trouble of pulling the shift register IC on the controller and then directly connecting to the Panda’s parallel port, it greatly simplifies the Panda coding. The original Arduino board did not have as many IO pins available as are on the Panda so the C code sent the setup data in nibbles instead of bytes - it’s just simpler and faster to use the Panda parallel port function.
Much more detail on how the motor controller is designed along with schematics can be found here:
http://www.ladyada.net/make/mshield/
https://docs.google.com/document/pub?id=1OdGS0QHKCdbrbAs_x62gmfSx_UdUPFPgZjwZnVDVHDg
/* ****************************************************************************
* PII_AFMC (Panda II AdaFruit Motor Controller) This code adapts an L293D Motor Drive Shield
* originally designed for an Arduino Duemilanove Mega to be pin compatible with a Panda II.
*The shield can drive 4 DC motors and 2 servos, or two steppers and 2 servos, but this
* version of the code is only for 4 DC motors and is set up to demonstrate operation by
* cycling though the operation of four motors sequentially (forward - reverse - stop).
*
* Compatibility with a Panda II was achieved by removing the 8 bit shift register IC (74HCT595N)
* on the motor controllere and directly connecting the Panda II parallel port pins to
* the empty IC socket. Since the controller also expected 2 PWM outputs where they are not
* available on the Panda, the code substituted 2 OutputCompare pins for PWM pins. The remaining
* PWM pins matched existing Panda PWM outputs so they were used as is. Rotational control uses
* an array of bit masks to toggle the appropriate bits of the parallel port which are connected
* directly via the empty shift register socket to the L293D dual H-bridge drivers input pins.
*
* The mask array, "mcbyte[]", is used in the method "sendMcb" with an OR and AND operation to
* set and clear bits in the variable "mcstatus" - the first of each pair is the OR value and
* the second is the AND. "mckey" is a number that points to the first paired value in mcbyte and
* mckey is set by using a descriptive variable name such as m1f (motor 1 forward)
* to turn motors on or off and select direction. Motor speed is set by PWM for motors 3&4
* and by OutputCompare for 1 & 2. Other combined masks could be used
* for additional and faster control options.
*
******************************************************************************
*/
using System;
using System.Threading;
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;
using GHIElectronics.NETMF.FEZ;
using GHIElectronics.NETMF.Hardware;
namespace PII_AFMC
{
public class Program
{
public static void Main()
{
byte i = 0; // initialize a counter used to pass data to the port
OutputPort led = new OutputPort((Cpu.Pin)FEZ_Pin.Digital.Di23, false); // led used to indicate a write command to the port
// mcstatus is the control byte that determines the current state of the L293D inputs less the enable inputs which are set via PWM or OoutputCompare
byte[] mcstatus = new byte[1] { 0 };
// mcbyte is an array containg the bit mask pairs for the OR and AND operations that set forward, reverse, or off for each motor
byte[] mcbyte = new byte[26] {0,0,1,253,2,254,0,252,8,251,4,247,0,243,16,223,32,239,0,207,128,191,64,127,0,63};
// next line creates recognizeable variables for motor control - not utilized in the demo version
byte alloff = 0, m1f = 2, m1r = 4, m1o = 6, m2f = 8, m2r = 10, m2o = 12, m3f = 14, m3r = 16, m3o = 18, m4f = 20, m4r = 22, m4o = 24;
byte mckey; // set which byte pair to use for a mask
mckey = alloff;
// Derfine the PWM used by motors 3 and 4 to set speed
GHIElectronics.NETMF.Hardware.PWM M3pwm = new PWM(PWM.Pin.PWM5);
M3pwm.Set(true);
M3pwm.SetPulse(100000000, 10000000);
GHIElectronics.NETMF.Hardware.PWM M4pwm = new PWM(PWM.Pin.PWM6);
M4pwm.Set(true);
M4pwm.SetPulse(100000000, 10000000);
// set up the OutputCompare pins (instead of PWMs) used by motors 1 and 2 to set speed
uint[] timings = new uint[2];
uint period = 1000, lowtimem1 = 500, lowtimem2 = 200;
// When going beyond this demo program this can be extracted to a method that is just called with a motor # and lowtime to set speed
//use a frequency of 1KHz = period = 1000 us or 1 ms & initially set off time to half the period - later the low time can be changed to control speed
uint highTime = (uint)(period - lowtimem1);
timings[0] = highTime;
timings[1] = 1000 - highTime;
OutputCompare _ocm1;
_ocm1 = new OutputCompare((Cpu.Pin)FEZ_Pin.Digital.Di11, false, timings.Length);
_ocm1.Set(true, timings, 0, 2, true); //start the waveform//frequency 1KHz
// Now repeat the process for motor 2
OutputCompare _ocm2;
highTime = (uint)(period - lowtimem2);
timings[0] = highTime;
timings[1] = 1000 - highTime;
_ocm2 = new OutputCompare((Cpu.Pin)FEZ_Pin.Digital.Di3, false, timings.Length);
_ocm2.Set(true, timings, 0, 2, true); //start the waveform//frequency 1KHz
// end PWM & OC set up
// Create an array of digital I/O pins called "pins" that determines which pins are to be used
// to create the parallel port. "(Cpu.Pin) is a required cast for the "Fez_Pin". Note
// that these specific pins are hardwired to provide faster data updates than other I/O pins.
Cpu.Pin[] pins;
pins = new Cpu.Pin[8] {
(Cpu.Pin)FEZ_Pin.Digital.Di51,
(Cpu.Pin)FEZ_Pin.Digital.Di50,
(Cpu.Pin)FEZ_Pin.Digital.Di49,
(Cpu.Pin)FEZ_Pin.Digital.Di48,
(Cpu.Pin)FEZ_Pin.Digital.Di47,
(Cpu.Pin)FEZ_Pin.Digital.Di46,
(Cpu.Pin)FEZ_Pin.Digital.Di45,
(Cpu.Pin)FEZ_Pin.Digital.Di44,
};
// Create the port called "mtrpins". GPIO_NONE is used because this port will not be read
// and is only set up for writing. Again note the cast required for the FEZ_Pin.
ParallelPort mtrpins;
mtrpins = new ParallelPort(pins, (Cpu.Pin)FEZ_Pin.Digital.Di24, (Cpu.Pin.GPIO_NONE));
// NEXT SECTION SEnds control byte to sendMcb method where byte is written to the parallel port.
while (true)
{
while (i < 26)
{
mckey = i;
sendMcb(mtrpins, mcstatus, mcbyte, mckey);
Debug.Print("i= " + i.ToString());
i = (byte)(i + 2);
Thread.Sleep(2000);
}
// Reset I and start over
i = 0;
}
}
public static void sendMcb(ParallelPort mtrpins, byte[] mcstatus, byte[] mcbyte, int mckey)
{
Debug.Print("mcstatus[0]= " + mcstatus[0].ToString());
mcstatus[0] = (byte)(mcstatus[0] | mcbyte[mckey]);
Debug.Print("mcstatus[0] post OR= " + mcstatus[0].ToString());
mcstatus[0] = (byte)(mcstatus[0] & mcbyte[mckey+1]);
Debug.Print("mcstatus[0] post AND = " + mcstatus[0].ToString());
mtrpins.Write( mcstatus, 0 ,1);
}
}
}