9 tile screen working with one image space, platform for development

Dependencies:   mbed

Committer:
rsavitski
Date:
Tue Mar 06 19:58:34 2012 +0000
Revision:
0:8b26631e8c70

        

Who changed what in which revision?

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