Mirror with some correction
Dependencies: mbed FastIO FastPWM USBDevice
Diff: main.cpp
- Revision:
- 26:cb71c4af2912
- Parent:
- 25:e22b88bd783a
- Child:
- 29:582472d0bc57
--- a/main.cpp Tue Sep 01 04:27:15 2015 +0000 +++ b/main.cpp Wed Sep 23 05:06:39 2015 +0000 @@ -137,6 +137,15 @@ // but with a slight practical need for a handful of extra ports (I'm using the // cutting-edge 10-contactor setup, so my real LedWiz is full!). // +// - Enhanced LedWiz emulation with TLC5940 PWM controller chips. You can attach +// external PWM controller chips for controlling device outputs, instead of using +// the limited LedWiz emulation through the on-board GPIO ports as described above. +// The software can control a set of daisy-chained TLC5940 chips, which provide +// 16 PWM outputs per chip. Two of these chips give you the full complement +// of 32 output ports of an actual LedWiz, and four give you 64 ports, which +// should be plenty for nearly any virtual pinball project. +// +// // The on-board LED on the KL25Z flashes to indicate the current device status: // // two short red flashes = the device is powered but hasn't successfully @@ -214,6 +223,7 @@ #include "tsl1410r.h" #include "FreescaleIAP.h" #include "crc32.h" +#include "TLC5940.h" // our local configuration file #define DECL_EXTERNS @@ -226,6 +236,12 @@ // number of elements in an array #define countof(x) (sizeof(x)/sizeof((x)[0])) +// floating point square of a number +inline float square(float x) { return x*x; } + +// floating point rounding +inline float round(float x) { return x > 0 ? floor(x + 0.5) : ceil(x - 0.5); } + // --------------------------------------------------------------------------- // USB device vendor ID, product ID, and version. @@ -309,6 +325,13 @@ // // On-board RGB LED elements - we use these for diagnostic displays. // +// Note that LED3 (the blue segment) is hard-wired on the KL25Z to PTD1, +// so PTD1 shouldn't be used for any other purpose (e.g., as a keyboard +// input or a device output). (This is kind of unfortunate in that it's +// one of only two ports exposed on the jumper pins that can be muxed to +// SPI0 SCLK. This effectively limits us to PTC5 if we want to use the +// SPI capability.) +// DigitalOut ledR(LED1), ledG(LED2), ledB(LED3); @@ -316,20 +339,77 @@ // // LedWiz emulation // +// There are two modes for this feature. The default mode uses the on-board +// GPIO ports to implement device outputs - each LedWiz software port is +// connected to a physical GPIO pin on the KL25Z. The KL25Z only has 10 +// PWM channels, so in this mode only 10 LedWiz ports will be dimmable; the +// rest are strictly on/off. The KL25Z also has a limited number of GPIO +// ports overall - not enough for the full complement of 32 LedWiz ports +// and 24 VP joystick inputs, so it's necessary to trade one against the +// other if both features are to be used. +// +// The alternative, enhanced mode uses external TLC5940 PWM controller +// chips to control device outputs. In this mode, each LedWiz software +// port is mapped to an output on one of the external TLC5940 chips. +// Two 5940s is enough for the full set of 32 LedWiz ports, and we can +// support even more chips for even more outputs (although doing so requires +// breaking LedWiz compatibility, since the LedWiz USB protocol is hardwired +// for 32 outputs). Every port in this mode has full PWM support. +// +// Current starting output index for "PBA" messages from the PC (using +// the LedWiz USB protocol). Each PBA message implicitly uses the +// current index as the starting point for the ports referenced in +// the message, and increases it (by 8) for the next call. static int pbaIdx = 0; -// LedWiz output pin interface. We create a cover class to virtualize -// digital vs PWM outputs and give them a common interface. The KL25Z -// unfortunately doesn't have enough hardware PWM channels to support -// PWM on all 32 LedWiz outputs, so we provide as many PWM channels as -// we can (10), and fill out the rest of the outputs with plain digital -// outs. +// Generic LedWiz output port interface. We create a cover class to +// virtualize digital vs PWM outputs, and on-board KL25Z GPIO vs external +// TLC5940 outputs, and give them all a common interface. class LwOut { public: + // Set the output intensity. 'val' is 0.0 for fully off, 1.0 for + // fully on, and fractional values for intermediate intensities. virtual void set(float val) = 0; }; + + +#ifdef ENABLE_TLC5940 + +// The TLC5940 interface object. +TLC5940 tlc5940(TLC5940_SCLK, TLC5940_SIN, TLC5940_GSCLK, TLC5940_BLANK, + TLC5940_XLAT, TLC5940_NCHIPS); + +// LwOut class for TLC5940 outputs. These are fully PWM capable. +// The 'idx' value in the constructor is the output index in the +// daisy-chained TLC5940 array. 0 is output #0 on the first chip, +// 1 is #1 on the first chip, 15 is #15 on the first chip, 16 is +// #0 on the second chip, 32 is #0 on the third chip, etc. +class Lw5940Out: public LwOut +{ +public: + Lw5940Out(int idx) : idx(idx) { prv = -1; } + virtual void set(float val) + { + if (val != prv) + tlc5940.set(idx, (int)(val * 4095)); + } + int idx; + float prv; +}; + +#else // ENABLE_TLC5940 + +// +// Default LedWiz mode - using on-board GPIO ports. In this mode, we +// assign a KL25Z GPIO port to each LedWiz output. We have to use a +// mix of PWM-capable and Digital-Only ports in this configuration, +// since the KL25Z hardware only has 10 PWM channels, which isn't +// enough to fill out the full complement of 32 LedWiz outputs. +// + +// LwOut class for a PWM-capable GPIO port class LwPwmOut: public LwOut { public: @@ -342,6 +422,8 @@ PwmOut p; float prv; }; + +// LwOut class for a Digital-Only (Non-PWM) GPIO port class LwDigOut: public LwOut { public: @@ -354,6 +436,17 @@ DigitalOut p; float prv; }; + +#endif // ENABLE_TLC5940 + +// LwOut class for unmapped ports. The LedWiz protocol is hardwired +// for 32 ports, but we might not want to assign all 32 software ports +// to physical output pins - the KL25Z has a limited number of GPIO +// ports, so we might not have enough available GPIOs to fill out the +// full LedWiz complement after assigning GPIOs for other functions. +// This class is used to populate the LedWiz mapping array for ports +// that aren't connected to physical outputs; it simply ignores value +// changes. class LwUnusedOut: public LwOut { public: @@ -361,7 +454,11 @@ virtual void set(float val) { } }; -// output pin array +// Array of output assignments. This array is indexed by the LedWiz +// output port number; that protocol is hardwired for 32 ports, so we +// need 32 elements in the array. Each element is an LwOut object +// that provides the mapping to the physical output corresponding to +// the software port. static LwOut *lwPin[32]; // initialize the output pin array @@ -369,6 +466,18 @@ { for (int i = 0 ; i < countof(lwPin) ; ++i) { +#ifdef ENABLE_TLC5940 + // Set up a TLC5940 output. If the output is within range of + // the connected number of chips (16 outputs per chip), assign it + // to the current index, otherwise leave it unattached. + if (i < TLC5940_NCHIPS*16) + lwPin[i] = new Lw5940Out(i); + else + lwPin[i] = new LwUnusedOut(); + +#else // ENABLE_TLC5940 + // Set up the GPIO pin, according to whether it's PWM-capable or + // digital-only, and whether or not it's assigned at all. PinName p = (i < countof(ledWizPortMap) ? ledWizPortMap[i].pin : NC); if (p == NC) lwPin[i] = new LwUnusedOut(); @@ -376,6 +485,9 @@ lwPin[i] = new LwPwmOut(p); else lwPin[i] = new LwDigOut(p); + +#endif // ENABLE_TLC5940 + } } @@ -601,14 +713,6 @@ }; // --------------------------------------------------------------------------- -// -// Some simple math service routines -// - -inline float square(float x) { return x*x; } -inline float round(float x) { return x > 0 ? floor(x + 0.5) : ceil(x - 0.5); } - -// --------------------------------------------------------------------------- // // Accelerometer (MMA8451Q) //