Alexandra Posta / Mbed OS ELEC2645_Race_Collision

Dependencies:   ELEC2645_JoystickLCD_LPC1768_2021

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers N5110.cpp Source File

N5110.cpp

00001 #include "mbed.h"
00002 #include "N5110.h"
00003 
00004 
00005 // overloaded constructor includes power pin - LCD Vcc connected to GPIO pin
00006 // this constructor works fine with LPC1768 - enough current sourced from GPIO
00007 // to power LCD. Doesn't work well with K64F.
00008 N5110::N5110(PinName const pwrPin,
00009              PinName const scePin,
00010              PinName const rstPin,
00011              PinName const dcPin,
00012              PinName const mosiPin,
00013              PinName const sclkPin,
00014              PinName const ledPin)
00015     :
00016     _spi(new SPI(mosiPin,NC,sclkPin)), // create new SPI instance and initialise
00017     _led(new DigitalOut(ledPin)),
00018     _pwr(new DigitalOut(pwrPin)),
00019     _sce(new DigitalOut(scePin)),
00020     _rst(new DigitalOut(rstPin)),
00021     _dc(new DigitalOut(dcPin))
00022 {}
00023 
00024 // overloaded constructor does not include power pin - LCD Vcc must be tied to +3V3
00025 // Best to use this with K64F as the GPIO hasn't sufficient output current to reliably
00026 // drive the LCD.
00027 N5110::N5110(PinName const scePin,
00028              PinName const rstPin,
00029              PinName const dcPin,
00030              PinName const mosiPin,
00031              PinName const sclkPin,
00032              PinName const ledPin)
00033     :
00034     _spi(new SPI(mosiPin,NC,sclkPin)), // create new SPI instance and initialise
00035     _led(new DigitalOut(ledPin)),
00036     _pwr(NULL), // pwr not needed so null it to be safe
00037     _sce(new DigitalOut(scePin)),
00038     _rst(new DigitalOut(rstPin)),
00039     _dc(new DigitalOut(dcPin))
00040 {}
00041 
00042 
00043 N5110::~N5110()
00044 {
00045     delete _spi;
00046 
00047     if(_pwr) {
00048         delete _pwr;
00049     }
00050 
00051     delete _led;
00052     delete _sce;
00053     delete _rst;
00054     delete _dc;
00055 }
00056 
00057 // initialise function - powers up and sends the initialisation commands
00058 void N5110::init()
00059 {
00060     turnOn();     // power up
00061     reset();      // reset LCD - must be done within 100 ms
00062     initSPI();    
00063     
00064     backLightOn();
00065     setContrast(0.55);  // this may need tuning (say 0.4 to 0.6)
00066     setBias(3);   // datasheet - 48:1 mux - don't mess with if you don't know what you're doing! (0 to 7)
00067     setTempCoefficient(0); // datasheet - may need increasing (range 0 to 3) at very low temperatures
00068     normalMode();  // normal video mode by default
00069     
00070     clearRAM();      // RAM is undefined at power-up so clear to be sure
00071     clear();   // clear buffer
00072 }
00073 
00074 // sets normal video mode (black on white)
00075 void N5110::normalMode()
00076 {
00077     sendCommand(0b00100000);   // basic instruction
00078     sendCommand(0b00001100);  // normal video mode- datasheet
00079 }
00080 
00081 // sets normal video mode (white on black)
00082 void N5110::inverseMode()
00083 {
00084     sendCommand(0b00100000);   // basic instruction
00085     sendCommand(0b00001101);   // inverse video mode - datasheet
00086 }
00087 
00088 // function to power up the LCD and backlight - only works when using GPIO to power
00089 void N5110::turnOn()
00090 {
00091     if (_pwr != NULL) {
00092         _pwr->write(1);  // apply power
00093     }
00094 }
00095 
00096 // function to power down LCD
00097 void N5110::turnOff()
00098 {
00099     clear(); // clear buffer
00100     refresh();
00101     backLightOff(); // turn backlight off
00102     clearRAM();   // clear RAM to ensure specified current consumption
00103     // send command to ensure we are in basic mode
00104     
00105     sendCommand(0b00100000); // basic mode
00106     sendCommand(0b00001000); // clear display
00107     sendCommand(0b00100001); // extended mode
00108     sendCommand(0b00100100); // power down
00109     
00110     // if we are powering the LCD using the GPIO then make it low to turn off
00111     if (_pwr != NULL) {
00112         wait_ms(10);  // small delay and then turn off the power pin
00113         _pwr->write(0);  // turn off power
00114     }
00115 
00116 }
00117 
00118 // function to change LED backlight brightness
00119 void N5110::backLightOn()
00120 {
00121     _led->write(1);
00122 }
00123 
00124 // function to change LED backlight brightness
00125 void N5110::backLightOff()
00126 {
00127     _led->write(0);
00128 }
00129 
00130 void N5110::setContrast(float contrast) {
00131     
00132     // enforce limits
00133     if (contrast > 1.0f)
00134         contrast = 1.0f;
00135     else if (contrast < 0.0f)
00136         contrast = 0.0;
00137     
00138     // convert to char in range 0 to 127 (i.e. 6 bits)
00139     char ic = char(contrast*127.0f);
00140     
00141     sendCommand(0b00100001);  // extended instruction set
00142     sendCommand(0b10000000 | ic);   // set Vop (which controls contrast)
00143     sendCommand(0b00100000);  // back to basic instruction set
00144 }
00145 
00146 void N5110::setTempCoefficient(char tc) {
00147     
00148     // enforce limits
00149     if (tc>3) {
00150         tc=3;
00151     }
00152     
00153     // temperature coefficient may need increasing at low temperatures
00154 
00155     sendCommand(0b00100001);  // extended instruction set
00156     sendCommand(0b00000100 | tc);
00157     sendCommand(0b00100000);  // back to basic instruction set
00158 }
00159     
00160 void N5110::setBias(char bias) {
00161     
00162     // from data sheet
00163     // bias      mux rate
00164     // 0        1:100
00165     // 1        1:80
00166     // 2        1:65
00167     // 3        1:48   (default)
00168     // 4        1:40/1:34
00169     // 5        1:24
00170     // 6        1:18/1:16
00171     // 7        1:10/1:9/1:8
00172     
00173     // enforce limits
00174     if (bias>7) {
00175         bias=7;
00176     }
00177         
00178     sendCommand(0b00100001);  // extended mode instruction
00179     sendCommand(0b00010000 | bias);  
00180     sendCommand(0b00100000); // end of extended mode instruction
00181 }
00182 
00183 // pulse the active low reset line
00184 void N5110::reset()
00185 {
00186     _rst->write(0);  // reset the LCD
00187     _rst->write(1);
00188 }
00189 
00190 // function to initialise SPI peripheral
00191 void N5110::initSPI()
00192 {
00193     _spi->format(8,1);    // 8 bits, Mode 1 - polarity 0, phase 1 - base value of clock is 0, data captured on falling edge/propagated on rising edge
00194     _spi->frequency(4000000);  // maximum of screen is 4 MHz
00195 }
00196 
00197 // send a command to the display
00198 void N5110::sendCommand(unsigned char command)
00199 {
00200     _dc->write(0);  // set DC low for command
00201     _sce->write(0); // set CE low to begin frame
00202     _spi->write(command);  // send command
00203     _dc->write(1);  // turn back to data by default
00204     _sce->write(1); // set CE high to end frame (expected for transmission of single byte)
00205 }
00206 
00207 // send data to the display at the current XY address
00208 // dc is set to 1 (i.e. data) after sending a command and so should
00209 // be the default mode.
00210 void N5110::sendData(unsigned char data)
00211 {
00212     _sce->write(0);   // set CE low to begin frame
00213     _spi->write(data);
00214     _sce->write(1);  // set CE high to end frame (expected for transmission of single byte)
00215 }
00216 
00217 // this function writes 0 to the 504 bytes to clear the RAM
00218 void N5110::clearRAM()
00219 {
00220     _sce->write(0);  //set CE low to begin frame
00221     for(int i = 0; i < WIDTH * HEIGHT; i++) { // 48 x 84 bits = 504 bytes
00222         _spi->write(0x00);  // send 0's
00223     }
00224     _sce->write(1); // set CE high to end frame
00225 }
00226 
00227 // function to set the XY address in RAM for subsequenct data write
00228 void N5110::setXYAddress(unsigned int const x,
00229                          unsigned int const y)
00230 {
00231     if (x<WIDTH && y<HEIGHT) {  // check within range
00232         sendCommand(0b00100000);  // basic instruction
00233         sendCommand(0b10000000 | x);  // send addresses to display with relevant mask
00234         sendCommand(0b01000000 | y);
00235     }
00236 }
00237 
00238 // These functions are used to set, clear and get the value of pixels in the display
00239 // Pixels are addressed in the range of 0 to 47 (y) and 0 to 83 (x).  The refresh()
00240 // function must be called after set and clear in order to update the display
00241 void N5110::setPixel(unsigned int const x,
00242                      unsigned int const y,
00243                      bool const         state)
00244 {
00245     if (x<WIDTH && y<HEIGHT) {  // check within range
00246         // calculate bank and shift 1 to required position in the data byte
00247         if(state) buffer[x][y/8] |= (1 << y%8);
00248         else      buffer[x][y/8] &= ~(1 << y%8);
00249     }
00250 }
00251 
00252 void N5110::clearPixel(unsigned int const x,
00253                        unsigned int const y)
00254 {
00255     if (x<WIDTH && y<HEIGHT) {  // check within range
00256         // calculate bank and shift 1 to required position (using bit clear)
00257         buffer[x][y/8] &= ~(1 << y%8);
00258     }
00259 }
00260 
00261 int N5110::getPixel(unsigned int const x,
00262                     unsigned int const y) const
00263 {
00264     if (x<WIDTH && y<HEIGHT) {  // check within range
00265         // return relevant bank and mask required bit
00266 
00267         int pixel = (int) buffer[x][y/8] & (1 << y%8);
00268 
00269         if (pixel)
00270             return 1;
00271         else
00272             return 0;
00273     }
00274 
00275     return 0;
00276 
00277 }
00278 
00279 // function to refresh the display
00280 void N5110::refresh()
00281 {
00282     setXYAddress(0,0);  // important to set address back to 0,0 before refreshing display
00283     // address auto increments after printing string, so buffer[0][0] will not coincide
00284     // with top-left pixel after priting string
00285 
00286     _sce->write(0);  //set CE low to begin frame
00287 
00288     for(int j = 0; j < BANKS; j++) {  // be careful to use correct order (j,i) for horizontal addressing
00289         for(int i = 0; i < WIDTH; i++) {
00290             _spi->write(buffer[i][j]);  // send buffer
00291         }
00292     }
00293     _sce->write(1); // set CE high to end frame
00294 
00295 }
00296 
00297 // fills the buffer with random bytes.  Can be used to test the display.
00298 // The rand() function isn't seeded so it probably creates the same pattern everytime
00299 void N5110::randomiseBuffer()
00300 {
00301     int i,j;
00302     for(j = 0; j < BANKS; j++) {  // be careful to use correct order (j,i) for horizontal addressing
00303         for(i = 0; i < WIDTH; i++) {
00304             buffer[i][j] = rand()%256;  // generate random byte
00305         }
00306     }
00307 
00308 }
00309 
00310 // function to print 5x7 font
00311 void N5110::printChar(char const          c,
00312                       unsigned int const  x,
00313                       unsigned int const  y)
00314 {
00315     if (y<BANKS) {  // check if printing in range of y banks
00316 
00317         for (int i = 0; i < 5 ; i++ ) {
00318             int pixel_x = x+i;
00319             if (pixel_x > WIDTH-1)  // ensure pixel isn't outside the buffer size (0 - 83)
00320                 break;
00321             buffer[pixel_x][y] = font5x7[(c - 32)*5 + i];
00322             // array is offset by 32 relative to ASCII, each character is 5 pixels wide
00323         }
00324 
00325     }
00326 }
00327 
00328 // function to print string at specified position
00329 void N5110::printString(const char         *str,
00330                         unsigned int const  x,
00331                         unsigned int const  y)
00332 {
00333     if (y<BANKS) {  // check if printing in range of y banks
00334 
00335         int n = 0 ; // counter for number of characters in string
00336         // loop through string and print character
00337         while(*str) {
00338 
00339             // writes the character bitmap data to the buffer, so that
00340             // text and pixels can be displayed at the same time
00341             for (int i = 0; i < 5 ; i++ ) {
00342                 int pixel_x = x+i+n*6;
00343                 if (pixel_x > WIDTH-1) // ensure pixel isn't outside the buffer size (0 - 83)
00344                     break;
00345                 buffer[pixel_x][y] = font5x7[(*str - 32)*5 + i];
00346             }
00347             str++;  // go to next character in string
00348             n++;    // increment index
00349         }
00350     }
00351 }
00352 
00353 // function to clear the screen buffer
00354 void N5110::clear()
00355 {
00356     memset(buffer,0,sizeof(buffer));
00357 }
00358 
00359 // function to plot array on display
00360 void N5110::plotArray(float const array[])
00361 {
00362     for (int i=0; i<WIDTH; i++) {  // loop through array
00363         // elements are normalised from 0.0 to 1.0, so multiply
00364         // by 47 to convert to pixel range, and subtract from 47
00365         // since top-left is 0,0 in the display geometry
00366         setPixel(i,47 - int(array[i]*47.0f),true);
00367     }
00368 
00369 }
00370 
00371 // function to draw circle
00372 void N5110:: drawCircle(unsigned int const x0,
00373                         unsigned int const y0,
00374                         unsigned int const radius,
00375                         FillType const     fill)
00376 {
00377     // from http://en.wikipedia.org/wiki/Midpoint_circle_algorithm
00378     int x = radius;
00379     int y = 0;
00380     int radiusError = 1-x;
00381 
00382     while(x >= y) {
00383 
00384         // if transparent, just draw outline
00385         if (fill == FILL_TRANSPARENT) {
00386             setPixel( x + x0,  y + y0,true);
00387             setPixel(-x + x0,  y + y0,true);
00388             setPixel( y + x0,  x + y0,true);
00389             setPixel(-y + x0,  x + y0,true);
00390             setPixel(-y + x0, -x + y0,true);
00391             setPixel( y + x0, -x + y0,true);
00392             setPixel( x + x0, -y + y0,true);
00393             setPixel(-x + x0, -y + y0,true);
00394         } else {  // drawing filled circle, so draw lines between points at same y value
00395 
00396             int type = (fill==FILL_BLACK) ? 1:0;  // black or white fill
00397 
00398             drawLine(x+x0,y+y0,-x+x0,y+y0,0,type);
00399             drawLine(y+x0,x+y0,-y+x0,x+y0,0,type);
00400             drawLine(y+x0,-x+y0,-y+x0,-x+y0,0,type);
00401             drawLine(x+x0,-y+y0,-x+x0,-y+y0,0,type);
00402         }
00403 
00404         y++;
00405         if (radiusError < 0) {
00406             radiusError += 2 * y + 1;
00407         } else {
00408             x--;
00409             radiusError += 2 * (y - x) + 1;
00410         }
00411     }
00412 
00413 }
00414 
00415 // function to draw ellipse
00416 void N5110:: drawEllipse(unsigned int const xc,
00417                          unsigned int const yc,
00418                          unsigned int const rx,
00419                          unsigned int const ry)
00420 {   
00421     int rx2 = rx*rx, ry2 = ry*ry;
00422     int x = 0, y = ry; //Starting point
00423 
00424     int incSW = ry2*2 + rx2*2;
00425 
00426     // Slopes deduced from incremental algorithm with the second-order logic
00427     int W = ry2*(-2*x + 3); 
00428     int S = rx2*(-2*y + 3);
00429     int SW = W + S;
00430 
00431     // Decision parameter of Region 1 and Region 2
00432     int p1 = ry2 - rx2*ry + rx2/4; 
00433     int p2 = ry2*(x - 0.5)*(x - 0.5) + rx2*(y - 1)*(y - 1) - rx2*ry2; 
00434 
00435     // Region 1
00436     while(rx2*(y-0.5) >= ry2*(-x-1)) {
00437         
00438         // Set points based on 4-way symmetry
00439         setPixel(-x+xc,-y+yc, true);
00440         setPixel(-x+xc, y+yc, true);
00441         setPixel( x+xc, y+yc, true); 
00442         setPixel( x+xc,-y+yc, true); 
00443         
00444         if(p1 > 0) {
00445             p1 += SW;
00446             W += ry2*2;
00447             SW += incSW;
00448             y--;
00449         }
00450         else {
00451             p1 += W;
00452             W += 2*ry2;
00453             SW += 2*ry2;
00454         }
00455         x--;
00456     }
00457 
00458     SW = ry2*(2 - 2*x) + rx2*(-2*y + 3);
00459 
00460     // Region 2
00461     while(y >= 0) {
00462         
00463         // Set points based on 4-way symmetry
00464         setPixel(-x+xc,-y+yc, true); 
00465         setPixel(-x+xc, y+yc, true);
00466         setPixel( x+xc, y+yc, true); 
00467         setPixel( x+xc,-y+yc, true); 
00468         
00469         if(p2 > 0) {
00470             p2 += S;
00471             S += rx2*2;
00472             SW += rx2*2;
00473         }
00474         else {
00475             p2 += SW;
00476             SW += incSW;
00477             S += rx2*2;
00478             x--;
00479         }
00480         y--;
00481     }
00482 }
00483 
00484 // take points on a curve, decide whether to draw them or not
00485 void N5110::drawCurve(std::vector<Vector2Df> curve_points, float offset, int dash_len, int type)
00486 {
00487     if(type == TYPE_SOLID){
00488         for(int i = 0; i < curve_points.size()-1; i++){
00489             // take the current and the following coordinates and draw a line between them
00490             drawLine(static_cast<int>(curve_points[i].x),static_cast<int>(curve_points[i].y), 
00491             static_cast<int>(curve_points[i+1].x),static_cast<int>(curve_points[i+1].y),0,1);
00492         }
00493     }
00494     if(type == TYPE_DOTTED){
00495         int counter = 0;
00496         for(int i = curve_points.size()-1; i > 0 ; i--){
00497             int x0 = static_cast<int>(curve_points[i].x);
00498             int x1 = static_cast<int>(curve_points[i-1].x);
00499             int y0 = static_cast<int>(curve_points[i].y);
00500             int y1 = static_cast<int>(curve_points[i-1].y);  
00501                 
00502             int const y_range = y0 - y1;
00503             int const x_range = x1 - x0;
00504     
00505             // ensure we loop from smallest to largest or else for-loop won't run as expected
00506             //unsigned int const start = y_range > 0 ? y0:y1;
00507             //unsigned int const stop =  y_range > 0 ? y1:y0;
00508             
00509             for (unsigned int y = y0; y <= y1 ; y++) {
00510                 // do linear interpolation
00511                 int const dy = y0 - y;
00512                 unsigned int const x = x0 + (x_range * (dy / (float)y_range));
00513     
00514                 // If the line type is '0', this will clear the pixel
00515                 // If it is '1' or '2', the pixel will be set
00516                 setPixel(x,y, fmod(pow(counter, 0.6) - fmod(offset, (2 * dash_len)), (2 * dash_len)) < dash_len);
00517                 counter++;
00518             }
00519         }
00520     }
00521 }   
00522 
00523 void N5110::drawLine(unsigned int const x0,
00524                      unsigned int const y0,
00525                      unsigned int const x1,
00526                      unsigned int const y1,
00527                      unsigned int const offset,
00528                      unsigned int const step)
00529 {
00530     // Note that the ranges can be negative so we have to turn the input values
00531     // into signed integers first
00532     int const y_range = static_cast<int>(y1) - static_cast<int>(y0);
00533     int const x_range = static_cast<int>(x1) - static_cast<int>(x0);
00534 
00535     // make sure we loop over the largest range to get the most pixels on the display
00536     // for instance, if drawing a vertical line (x_range = 0), we need to loop down the y pixels
00537     // or else we'll only end up with 1 pixel in the x column
00538     if ( abs(x_range) > abs(y_range) ) {
00539 
00540         // ensure we loop from smallest to largest or else for-loop won't run as expected
00541         unsigned int const start = x_range > 0 ? x0:x1;
00542         unsigned int const stop =  x_range > 0 ? x1:x0;
00543 
00544         // loop between x pixels
00545         for (unsigned int x = start; x<= stop ; x+=step) {
00546             // do linear interpolation
00547             int const dx = static_cast<int>(x) - static_cast<int>(x0);
00548             unsigned int const y = y0 + y_range * dx / x_range;
00549 
00550             // If the line type is '0', this will clear the pixel
00551             // If it is '1' or '2', the pixel will be set
00552             setPixel(x,y, FILL_BLACK);
00553         }
00554     } else {
00555 
00556         // ensure we loop from smallest to largest or else for-loop won't run as expected
00557         unsigned int const start = y_range > 0 ? y0:y1;
00558         unsigned int const stop =  y_range > 0 ? y1:y0;
00559 
00560         for (unsigned int y = start; y<= stop ; y+=step) {
00561             // do linear interpolation
00562             int const dy = static_cast<int>(y)-static_cast<int>(y0);
00563             unsigned int const x = x0 + x_range * dy / y_range;
00564 
00565             // If the line type is '0', this will clear the pixel
00566             // If it is '1' or '2', the pixel will be set
00567             setPixel(x,y, FILL_BLACK);
00568         }
00569     }
00570 
00571 }
00572 
00573 void N5110::drawRect(unsigned int const x0,
00574                      unsigned int const y0,
00575                      unsigned int const width,
00576                      unsigned int const height,
00577                      FillType const     fill)
00578 {
00579     if (fill == FILL_TRANSPARENT) { // transparent, just outline
00580         drawLine(x0,y0,x0+(width-1),y0,0,1);  // top
00581         drawLine(x0,y0+(height-1),x0+(width-1),y0+(height-1),0,1);  // bottom
00582         drawLine(x0,y0,x0,y0+(height-1),0,1);  // left
00583         drawLine(x0+(width-1),y0,x0+(width-1),y0+(height-1),0,1);  // right
00584     } else { // filled rectangle
00585         int step = (fill==FILL_BLACK) ? 1:0;  // black or white fill
00586         for (int y = y0; y<y0+height; y++) {  // loop through rows of rectangle
00587             drawLine(x0,y,x0+(width-1),y,0,step);  // draw line across screen
00588         }
00589     }
00590 }
00591 
00592 void N5110::drawSprite(int x0,
00593                        int y0,
00594                        int nrows,
00595                        int ncols,
00596                        int *sprite)
00597 {
00598     for (int i = 0; i < nrows; i++) {
00599         for (int j = 0 ; j < ncols ; j++) {
00600 
00601             int pixel = *((sprite+i*ncols)+j);
00602             setPixel(x0+j,y0+i, pixel);
00603         }
00604     }
00605 }