LED screen snake as an example of 48x48 panelspace working.

Dependencies:   mbed

Committer:
rsavitski
Date:
Thu Mar 22 13:20:53 2012 +0000
Revision:
0:b38330b559d4

        

Who changed what in which revision?

UserRevisionLine numberNew contents of line
rsavitski 0:b38330b559d4 1 #include "mbed.h"
rsavitski 0:b38330b559d4 2
rsavitski 0:b38330b559d4 3 /*
rsavitski 0:b38330b559d4 4 collision detection
rsavitski 0:b38330b559d4 5 dot
rsavitski 0:b38330b559d4 6 scoring
rsavitski 0:b38330b559d4 7 growth currently at tail?
rsavitski 0:b38330b559d4 8
rsavitski 0:b38330b559d4 9
rsavitski 0:b38330b559d4 10 */
rsavitski 0:b38330b559d4 11
rsavitski 0:b38330b559d4 12 extern "C" void frameout(unsigned char dsVal[], unsigned char transformedSource[]);
rsavitski 0:b38330b559d4 13
rsavitski 0:b38330b559d4 14 class ledScreen {
rsavitski 0:b38330b559d4 15 public:
rsavitski 0:b38330b559d4 16 ledScreen();
rsavitski 0:b38330b559d4 17 ~ledScreen() {}
rsavitski 0:b38330b559d4 18
rsavitski 0:b38330b559d4 19 void transformFrame(unsigned char* imageSource);
rsavitski 0:b38330b559d4 20 void outputFrame();
rsavitski 0:b38330b559d4 21 void start(); // start outputting frames on an interrupt
rsavitski 0:b38330b559d4 22
rsavitski 0:b38330b559d4 23 private:
rsavitski 0:b38330b559d4 24
rsavitski 0:b38330b559d4 25 int MAX_PULSE_WIDTH; // constant: max enable pulse duration
rsavitski 0:b38330b559d4 26 int pulseLength; // length of current pulse (used in delta-sigma pwm)
rsavitski 0:b38330b559d4 27 int OP_TIME;
rsavitski 0:b38330b559d4 28
rsavitski 0:b38330b559d4 29 static const int XPANS = 3; // number of panels horizontally
rsavitski 0:b38330b559d4 30 static const int YUNITS = 1;
rsavitski 0:b38330b559d4 31 static const int YPANS = 3; // 3* YUNITS
rsavitski 0:b38330b559d4 32 static const int PIXPERPAN = 256;
rsavitski 0:b38330b559d4 33
rsavitski 0:b38330b559d4 34 int running;
rsavitski 0:b38330b559d4 35 int subFrameCtr;
rsavitski 0:b38330b559d4 36
rsavitski 0:b38330b559d4 37 Timeout nextFrameTimer; // timeout routine
rsavitski 0:b38330b559d4 38
rsavitski 0:b38330b559d4 39 // Buffers to hold the RGB data after rearranging to match the LED shifting pattern
rsavitski 0:b38330b559d4 40 unsigned char transformedSource[3*PIXPERPAN*XPANS*YPANS];
rsavitski 0:b38330b559d4 41
rsavitski 0:b38330b559d4 42 // Error values for all 256 brightness levels
rsavitski 0:b38330b559d4 43 unsigned int dsErr[256];
rsavitski 0:b38330b559d4 44 unsigned int ssdsErr[256];
rsavitski 0:b38330b559d4 45
rsavitski 0:b38330b559d4 46 // On/off state per sub-frame for all 256 brightness levels
rsavitski 0:b38330b559d4 47 unsigned char dsVal[256];
rsavitski 0:b38330b559d4 48
rsavitski 0:b38330b559d4 49 // Precomputed gamma for all 256 brightness levels
rsavitski 0:b38330b559d4 50 unsigned short gamma[256];
rsavitski 0:b38330b559d4 51
rsavitski 0:b38330b559d4 52
rsavitski 0:b38330b559d4 53 DigitalOut flatch; // data latch (for all connected panels in parallel)
rsavitski 0:b38330b559d4 54 DigitalOut MA0; // module address 0
rsavitski 0:b38330b559d4 55 DigitalOut MA1;
rsavitski 0:b38330b559d4 56 DigitalOut NREN; // active low enable for red channel (low -> LED on). Note: need to have enable high when latching data
rsavitski 0:b38330b559d4 57 DigitalOut Rdat0; // red data
rsavitski 0:b38330b559d4 58 DigitalOut Gdat0; // green data
rsavitski 0:b38330b559d4 59 DigitalOut Bdat0; // blue data
rsavitski 0:b38330b559d4 60 DigitalOut Rdat1; // red data
rsavitski 0:b38330b559d4 61 DigitalOut Gdat1; // green data
rsavitski 0:b38330b559d4 62 DigitalOut Bdat1; // blue data
rsavitski 0:b38330b559d4 63 DigitalOut Rdat2; // red data
rsavitski 0:b38330b559d4 64 DigitalOut Gdat2; // green data
rsavitski 0:b38330b559d4 65 DigitalOut Bdat2; // blue data
rsavitski 0:b38330b559d4 66 DigitalOut sclk; // clock
rsavitski 0:b38330b559d4 67
rsavitski 0:b38330b559d4 68 DigitalOut debug;
rsavitski 0:b38330b559d4 69
rsavitski 0:b38330b559d4 70 };
rsavitski 0:b38330b559d4 71
rsavitski 0:b38330b559d4 72 ledScreen::ledScreen() :
rsavitski 0:b38330b559d4 73 flatch(p10), // data latch (for all connected panels in parallel)
rsavitski 0:b38330b559d4 74 MA0(p23), // module address 0
rsavitski 0:b38330b559d4 75 MA1(p24),
rsavitski 0:b38330b559d4 76 NREN(p9), // active low enable for red channel (low -> LED on). Note: need to have enable high when latching data
rsavitski 0:b38330b559d4 77 Rdat0(p15), // red data
rsavitski 0:b38330b559d4 78 Gdat0(p16), // green data
rsavitski 0:b38330b559d4 79 Bdat0(p17), // blue data
rsavitski 0:b38330b559d4 80 Rdat1(p7), // red data
rsavitski 0:b38330b559d4 81 Gdat1(p6), // green data
rsavitski 0:b38330b559d4 82 Bdat1(p5), // blue data
rsavitski 0:b38330b559d4 83 Rdat2(p13), // red data
rsavitski 0:b38330b559d4 84 Gdat2(p12), // green data
rsavitski 0:b38330b559d4 85 Bdat2(p11), // blue data
rsavitski 0:b38330b559d4 86 sclk(p14),
rsavitski 0:b38330b559d4 87 debug(p27) { // clock
rsavitski 0:b38330b559d4 88
rsavitski 0:b38330b559d4 89 // precompute gamma for every possible RGB intensity value (0-255).
rsavitski 0:b38330b559d4 90 // Gamma correction with gamma = 3, downshifting by 8 to bring the range of values back to 0-65535
rsavitski 0:b38330b559d4 91 for (int i=0; i<256; i++) {
rsavitski 0:b38330b559d4 92 gamma[i] = pow(i, 2.2) * 0.33;//(i*i*i)>>8;
rsavitski 0:b38330b559d4 93 }
rsavitski 0:b38330b559d4 94
rsavitski 0:b38330b559d4 95 // initialising lines
rsavitski 0:b38330b559d4 96 flatch = 1;
rsavitski 0:b38330b559d4 97 NREN = 1;
rsavitski 0:b38330b559d4 98 sclk = 1;
rsavitski 0:b38330b559d4 99
rsavitski 0:b38330b559d4 100 // initialising values
rsavitski 0:b38330b559d4 101 MAX_PULSE_WIDTH = 512; //must currently be a power of 2, and when changing this, you must change the ssdsErr crossover masking
rsavitski 0:b38330b559d4 102 pulseLength = MAX_PULSE_WIDTH;
rsavitski 0:b38330b559d4 103 OP_TIME = 510; //Determined by scoping. Change this every time you change num screens
rsavitski 0:b38330b559d4 104 //NUM_PANELS = 3
rsavitski 0:b38330b559d4 105
rsavitski 0:b38330b559d4 106 running=0;
rsavitski 0:b38330b559d4 107 subFrameCtr=0;
rsavitski 0:b38330b559d4 108
rsavitski 0:b38330b559d4 109 // initialising errors for delta-sigma
rsavitski 0:b38330b559d4 110 for (int j=0; j<256; j++) {
rsavitski 0:b38330b559d4 111 dsErr[j] = 0;
rsavitski 0:b38330b559d4 112 ssdsErr[j] = 0;
rsavitski 0:b38330b559d4 113 }
rsavitski 0:b38330b559d4 114
rsavitski 0:b38330b559d4 115 }
rsavitski 0:b38330b559d4 116
rsavitski 0:b38330b559d4 117 void ledScreen::start() {
rsavitski 0:b38330b559d4 118 outputFrame();
rsavitski 0:b38330b559d4 119 }
rsavitski 0:b38330b559d4 120
rsavitski 0:b38330b559d4 121
rsavitski 0:b38330b559d4 122
rsavitski 0:b38330b559d4 123 void ledScreen::transformFrame(unsigned char* imageSource)
rsavitski 0:b38330b559d4 124 {
rsavitski 0:b38330b559d4 125 int i=0;
rsavitski 0:b38330b559d4 126 int panseqnum=0, t=0, out=0, x=0, y=0;
rsavitski 0:b38330b559d4 127
rsavitski 0:b38330b559d4 128 for (int q=0; q < 256*3*3*3; q+=3)
rsavitski 0:b38330b559d4 129 {
rsavitski 0:b38330b559d4 130 i = q/3;
rsavitski 0:b38330b559d4 131
rsavitski 0:b38330b559d4 132 x = i % (16*XPANS);
rsavitski 0:b38330b559d4 133 y = i / (16*XPANS);
rsavitski 0:b38330b559d4 134
rsavitski 0:b38330b559d4 135
rsavitski 0:b38330b559d4 136 int MA = (y/16) % 3;
rsavitski 0:b38330b559d4 137 panseqnum = x/16 + y/(16*3) * XPANS;
rsavitski 0:b38330b559d4 138
rsavitski 0:b38330b559d4 139 if (y%2 == 0)
rsavitski 0:b38330b559d4 140 {
rsavitski 0:b38330b559d4 141 t = (y%16)/2*0x20 + ((x%16)/8*0x10+(7-(x%16)%8));
rsavitski 0:b38330b559d4 142 }
rsavitski 0:b38330b559d4 143 else
rsavitski 0:b38330b559d4 144 {
rsavitski 0:b38330b559d4 145 t = 8 + (y%16)/2*0x20 + ((x%16)/8*0x10+(x%16)%8);
rsavitski 0:b38330b559d4 146 }
rsavitski 0:b38330b559d4 147
rsavitski 0:b38330b559d4 148 out = 3*(MA * YUNITS * XPANS * 256 + t * XPANS * YUNITS + panseqnum);
rsavitski 0:b38330b559d4 149
rsavitski 0:b38330b559d4 150 transformedSource[out] = imageSource[q];
rsavitski 0:b38330b559d4 151 transformedSource[out+1] = imageSource[q+1];
rsavitski 0:b38330b559d4 152 transformedSource[out+2] = imageSource[q+2];
rsavitski 0:b38330b559d4 153 }
rsavitski 0:b38330b559d4 154
rsavitski 0:b38330b559d4 155 }
rsavitski 0:b38330b559d4 156
rsavitski 0:b38330b559d4 157 // Output one frame and call itself after a period of time if running is set to true
rsavitski 0:b38330b559d4 158 void ledScreen::outputFrame() {
rsavitski 0:b38330b559d4 159
rsavitski 0:b38330b559d4 160 debug = 1;
rsavitski 0:b38330b559d4 161
rsavitski 0:b38330b559d4 162 NREN = 0; // turn off
rsavitski 0:b38330b559d4 163
rsavitski 0:b38330b559d4 164 if (subFrameCtr<=0) subFrameCtr=36;
rsavitski 0:b38330b559d4 165 subFrameCtr--;
rsavitski 0:b38330b559d4 166
rsavitski 0:b38330b559d4 167 if (subFrameCtr == 0) { // Every cycle of delta sigma we take a snapshot of the error that needs to be corrected by the short pulses.
rsavitski 0:b38330b559d4 168 for (int i = 0; i < 256; i++) { // This is required to eliminate visible flicker due to beat frequencies otherwise created.
rsavitski 0:b38330b559d4 169 dsErr[i] += ssdsErr[i] & 0xFE000000;
rsavitski 0:b38330b559d4 170 ssdsErr[i] %= 0x10000;
rsavitski 0:b38330b559d4 171 ssdsErr[i] += dsErr[i] % (512 * 0x10000);
rsavitski 0:b38330b559d4 172 dsErr[i] &= 0xFE000000;
rsavitski 0:b38330b559d4 173 }
rsavitski 0:b38330b559d4 174
rsavitski 0:b38330b559d4 175 // Doing delta sigma for the snapshot
rsavitski 0:b38330b559d4 176 for (int i = 0; i <= 9; i++) {
rsavitski 0:b38330b559d4 177 int lpl = 1<<i;
rsavitski 0:b38330b559d4 178
rsavitski 0:b38330b559d4 179 if (ssdsErr[i]/0x10000 & lpl)
rsavitski 0:b38330b559d4 180 ssdsErr[i]-=(0x10000-gamma[i])*lpl;
rsavitski 0:b38330b559d4 181 else
rsavitski 0:b38330b559d4 182 ssdsErr[i]+=gamma[i]*lpl;
rsavitski 0:b38330b559d4 183 }
rsavitski 0:b38330b559d4 184
rsavitski 0:b38330b559d4 185 }
rsavitski 0:b38330b559d4 186
rsavitski 0:b38330b559d4 187 // produce pulse lengths of 1, 2, 4, ... 256, spread throughout all subframes (only one in four are not MAX_PULSE_WIDTH long)
rsavitski 0:b38330b559d4 188 pulseLength = ((subFrameCtr%4)?MAX_PULSE_WIDTH:(1<<(subFrameCtr>>2)));
rsavitski 0:b38330b559d4 189
rsavitski 0:b38330b559d4 190 for (int i = 0; i < 256; i++) {
rsavitski 0:b38330b559d4 191 if (pulseLength == MAX_PULSE_WIDTH) {
rsavitski 0:b38330b559d4 192 // Delta-Sigma modulation with variable pulse length weighting
rsavitski 0:b38330b559d4 193 // Based on energy dimensions (time * amplitude)
rsavitski 0:b38330b559d4 194 if (dsErr[i] > (0x10000-gamma[i])*pulseLength) {
rsavitski 0:b38330b559d4 195 dsVal[i] = 0;//-1; Invert as we are using inverting buffers
rsavitski 0:b38330b559d4 196 dsErr[i]-=(0x10000-gamma[i])*pulseLength;
rsavitski 0:b38330b559d4 197 } else {
rsavitski 0:b38330b559d4 198 dsVal[i] = (unsigned char)-1;
rsavitski 0:b38330b559d4 199 dsErr[i]+=gamma[i]*pulseLength;
rsavitski 0:b38330b559d4 200 }
rsavitski 0:b38330b559d4 201 } else { // if short pulse
rsavitski 0:b38330b559d4 202 if (ssdsErr[i]/0x10000 & pulseLength) {
rsavitski 0:b38330b559d4 203 //Doing proper least significant delta sigma live still causes flicker (but only for dim pixels)
rsavitski 0:b38330b559d4 204 //ssdsErr[i]-=(0x10000-gamma[i])*pulseLength;
rsavitski 0:b38330b559d4 205 dsVal[i] = 0;
rsavitski 0:b38330b559d4 206 } else {
rsavitski 0:b38330b559d4 207 dsVal[i] = (unsigned char)-1;
rsavitski 0:b38330b559d4 208 }
rsavitski 0:b38330b559d4 209
rsavitski 0:b38330b559d4 210 }
rsavitski 0:b38330b559d4 211 }
rsavitski 0:b38330b559d4 212
rsavitski 0:b38330b559d4 213 // output data
rsavitski 0:b38330b559d4 214 for (int i = 0; i < 3; i++) {
rsavitski 0:b38330b559d4 215 MA0 = !(i&1);
rsavitski 0:b38330b559d4 216 MA1 = !(i&2);
rsavitski 0:b38330b559d4 217
rsavitski 0:b38330b559d4 218 frameout(dsVal, &transformedSource[i*256*3*3]);
rsavitski 0:b38330b559d4 219 }
rsavitski 0:b38330b559d4 220
rsavitski 0:b38330b559d4 221 NREN = 0; // need to have enables high before every latch, (in case we are on a long pulse)
rsavitski 0:b38330b559d4 222 flatch = 0; // latching all data to LEDs
rsavitski 0:b38330b559d4 223 flatch = 1;
rsavitski 0:b38330b559d4 224 NREN = 1; // turn on LEDs
rsavitski 0:b38330b559d4 225
rsavitski 0:b38330b559d4 226 if (pulseLength < 4) { // short pulses done through wait
rsavitski 0:b38330b559d4 227 wait_us(pulseLength);
rsavitski 0:b38330b559d4 228 NREN = 0; //Turn off LEDs
rsavitski 0:b38330b559d4 229 outputFrame(); //this will recurse only once due to the distrubution of pulses. pulseLength of the next instance will be attached.
rsavitski 0:b38330b559d4 230 }
rsavitski 0:b38330b559d4 231 else
rsavitski 0:b38330b559d4 232 {
rsavitski 0:b38330b559d4 233 // long waits done through attaching an interrupt that will turn off the LEDs at the start of next function call.
rsavitski 0:b38330b559d4 234 // Meanwhile, the main code can run between the interrupts.
rsavitski 0:b38330b559d4 235 nextFrameTimer.attach_us(this, &ledScreen::outputFrame, pulseLength);
rsavitski 0:b38330b559d4 236 debug = 0;
rsavitski 0:b38330b559d4 237 }
rsavitski 0:b38330b559d4 238 }