derived from Aidafruit SSD1306 library

Dependents:   Test_SSD1306 L152RE_OLED_SSD1306 EcranZumo

Fork of SSD1306 by Jonathan Gaul

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers ssd1306.cpp Source File

ssd1306.cpp

00001 
00002 #include "mbed.h"
00003 #include "ssd1306.h"
00004 
00005 #include <stdarg.h>
00006 
00007 #define pgm_read_byte(addr) (*(const unsigned char *)(addr))
00008 
00009 SSD1306::SSD1306(PinName cs, PinName rs, PinName dc, PinName clk, PinName data)
00010     : _spi(data, NC, clk), 
00011       _cs(cs), 
00012       _reset(rs), 
00013       _dc(dc),
00014       _cursor_x(0),
00015       _cursor_y(0)
00016 {
00017 }
00018 
00019 void SSD1306::off()
00020 {
00021     _send_command(0xAE);
00022 }
00023 
00024 void SSD1306::on()
00025 {
00026     _send_command(0xAF);
00027 }
00028 
00029 void SSD1306::sleep()
00030 {
00031     _send_command(0xAE);
00032 }
00033 
00034 void SSD1306::wake()
00035 {
00036     _send_command(0xAF);
00037 }
00038 
00039 void SSD1306::set_inverse(unsigned char value)
00040 {
00041     _send_command(value ? 0xA7 : 0xA6);
00042 }
00043 
00044 void SSD1306::set_display_offset(unsigned char value)
00045 {
00046     _send_command(0xD3);
00047     _send_command(value & 0x3F); 
00048 }
00049 
00050 void SSD1306::set_contrast(unsigned char value) 
00051 {
00052     _send_command(0x81);
00053     _send_command(value);
00054 }
00055 
00056 void SSD1306::set_display_start_line(unsigned char value)
00057 {
00058     _send_command(0x40 | value);
00059 }
00060 
00061 void SSD1306::set_segment_remap(unsigned char value)
00062 {
00063     _send_command(value ? 0xA1 : 0xA0);
00064 }
00065 
00066 void SSD1306::set_multiplex_ratio(unsigned char value)
00067 {
00068     _send_command(0xA8);
00069     _send_command(value & 0x3F);
00070 }
00071 
00072 void SSD1306::set_com_output_scan_direction(unsigned char value)
00073 {
00074     _send_command(value ? 0xC8 : 0xC0);
00075 }
00076 
00077 void SSD1306::set_com_pins_hardware_configuration(unsigned char sequential, unsigned char lr_remap)
00078 {
00079     _send_command(0xDA);
00080     _send_command(0x02 | ((sequential & 1) << 4) | ((lr_remap & 1) << 5));
00081 }
00082 
00083 void SSD1306::start_horizontal_scroll(unsigned char direction, unsigned char start, unsigned char end, unsigned char interval) 
00084 {
00085     _send_command(direction ? 0x27 : 0x26);
00086     _send_command(0x00);
00087     _send_command(start & 0x07);
00088     switch (interval) {
00089         case   2: _send_command(0x07); break; // 111b
00090         case   3: _send_command(0x04); break; // 100b
00091         case   4: _send_command(0x05); break; // 101b
00092         case   5: _send_command(0x00); break; // 000b
00093         case  25: _send_command(0x06); break; // 110b
00094         case  64: _send_command(0x01); break; // 001b
00095         case 128: _send_command(0x02); break; // 010b
00096         case 256: _send_command(0x03); break; // 011b
00097         default:
00098             // default to 2 frame interval
00099             _send_command(0x07); break;
00100     }
00101     _send_command(end & 0x07);
00102     _send_command(0x00);
00103     _send_command(0xFF);
00104     
00105     // activate scroll
00106     _send_command(0x2F);
00107 }
00108 
00109 void SSD1306::start_vertical_and_horizontal_scroll(unsigned char direction, unsigned char start, unsigned char end, unsigned char interval, unsigned char vertical_offset)
00110 {
00111     _send_command(direction ? 0x2A : 0x29);
00112     _send_command(0x00);
00113     _send_command(start & 0x07);
00114     switch (interval) {
00115         case   2: _send_command(0x07); break; // 111b
00116         case   3: _send_command(0x04); break; // 100b
00117         case   4: _send_command(0x05); break; // 101b
00118         case   5: _send_command(0x00); break; // 000b
00119         case  25: _send_command(0x06); break; // 110b
00120         case  64: _send_command(0x01); break; // 001b
00121         case 128: _send_command(0x02); break; // 010b
00122         case 256: _send_command(0x03); break; // 011b
00123         default:
00124             // default to 2 frame interval
00125             _send_command(0x07); break;
00126     }
00127     _send_command(end & 0x07);
00128     _send_command(vertical_offset);    
00129     
00130     // activate scroll
00131     _send_command(0x2F);
00132 }
00133 
00134 void SSD1306::stop_scroll()
00135 {
00136     // all scroll configurations are removed from the display when executing this command.
00137     _send_command(0x2E);
00138 }
00139 
00140 void SSD1306::pam_set_start_address(unsigned char address)
00141 {
00142     // "Set Lower Column Start Address for Page Addressing Mode"
00143     _send_command(address & 0x0F);
00144     
00145     // "Set Higher Column Start Address for Page Addressing Mode"
00146     _send_command((address << 4) & 0x0F);
00147 }
00148 
00149 void SSD1306::set_memory_addressing_mode(unsigned char mode)
00150 {
00151     _send_command(0x20);
00152     _send_command(mode & 0x3);
00153 }
00154 
00155 void SSD1306::hv_set_column_address(unsigned char start, unsigned char end)
00156 {
00157     _send_command(0x21);
00158     _send_command(start & 0x7F);
00159     _send_command(end & 0x7F);
00160 }
00161 
00162 void SSD1306::hv_set_page_address(unsigned char start, unsigned char end)
00163 {
00164     _send_command(0x22);
00165     _send_command(start & 0x07);
00166     _send_command(end & 0x07);
00167 }
00168 
00169 void SSD1306::pam_set_page_start(unsigned char address)
00170 {
00171     _send_command(0xB0 | (address & 0x07));
00172 }
00173 
00174 void SSD1306::set_display_clock_ratio_and_frequency(unsigned char ratio, unsigned char frequency)
00175 {
00176     _send_command(0xD5);
00177     _send_command((ratio & 0x0F) | ((frequency & 0x0F) << 4));
00178 }
00179 
00180 void SSD1306::set_precharge_period(unsigned char phase1, unsigned char phase2)
00181 {
00182     _send_command(0xD9);
00183     _send_command((phase1 & 0x0F) | ((phase2 & 0x0F ) << 4));
00184 }
00185 
00186 void SSD1306::set_vcomh_deselect_level(unsigned char level)
00187 {
00188     _send_command(0xDB);
00189     _send_command((level & 0x03) << 4);
00190 }
00191 
00192 void SSD1306::nop()
00193 {
00194     _send_command(0xE3);
00195 }
00196 
00197 void SSD1306::set_charge_pump_enable(unsigned char enable)
00198 {
00199     _send_command(0x8D);
00200     _send_command(enable ? 0x14 : 0x10);
00201 }
00202 
00203 void SSD1306::initialise()
00204 {
00205     // Init
00206     _reset = 1;
00207     wait(0.01);
00208     _reset = 0;
00209     wait(0.10);
00210     _reset = 1;
00211     
00212     off();
00213 
00214     set_display_clock_ratio_and_frequency(0, 8);
00215     set_multiplex_ratio(0x3F); // 1/64 duty
00216     set_precharge_period(0xF, 0x01);
00217     set_display_offset(0);    
00218     set_display_start_line(0);  
00219     set_charge_pump_enable(1);    
00220     set_memory_addressing_mode(0); // horizontal addressing mode; across then down
00221     set_segment_remap(1);
00222     set_com_output_scan_direction(1);
00223     set_com_pins_hardware_configuration(1, 0);
00224     set_contrast(0xFF);
00225     set_vcomh_deselect_level(1);
00226     
00227     wake();
00228     set_inverse(0);
00229     
00230     hv_set_column_address(0, 127);
00231     hv_set_page_address(0, 7);
00232     
00233     pam_set_start_address(0);
00234     pam_set_page_start(0);
00235     
00236     // set_precharge_period(2, 2);
00237 }
00238 
00239 void SSD1306::update()
00240 {
00241     hv_set_column_address(0, 127);
00242     hv_set_page_address(0, 7);
00243     
00244     for (int i = 0; i < 1024; i++)
00245         _send_data(_screen[i]);
00246 }
00247 
00248 void SSD1306::drawBitmap(int x, int y,
00249                   const unsigned char *bitmap, int w, int h, int color) {
00250   int16_t i, j, byteWidth = (w + 7) / 8;
00251 
00252   for(j=0; j<h; j++) {
00253     for(i=0; i<w; i++ ) {
00254       if(pgm_read_byte(bitmap + j * byteWidth + i / 8) & (128 >> (i & 7))) {
00255         color? set_pixel(x+i, y+j): clear_pixel(x+i, y+j);
00256       }
00257     }
00258   }
00259 }
00260 
00261 void SSD1306::set_pixel(int x, int y)
00262 {
00263     if (x >= SSD1306_LCDWIDTH || y >= SSD1306_LCDHEIGHT) return;
00264     
00265     _screen[x + (y / 8) * 128] |= 1 << (y % 8);
00266 }
00267 
00268 void SSD1306::clear_pixel(int x, int y)
00269 {
00270     if (x >= SSD1306_LCDWIDTH || y >= SSD1306_LCDHEIGHT) return;
00271     
00272     _screen[x + (y / 8) * 128] &= ~(1 << (y % 8));
00273 }
00274 
00275 void SSD1306::line(int x0, int y0, int x1, int y1) {
00276   int steep = abs(y1 - y0) > abs(x1 - x0);
00277   int t;
00278   
00279   if (steep) {
00280     t = x0; x0 = y0; y0 = t;
00281     t = x1; x1 = y1; y1 = t;
00282   }
00283 
00284   if (x0 > x1) {
00285     t = x0; x0 = x1; x1 = t;
00286     t = y0; y0 = y1; y1 = t;
00287   }
00288 
00289   int dx, dy;
00290   
00291   dx = x1 - x0;
00292   dy = abs(y1 - y0);
00293 
00294   int err = dx / 2;
00295   int ystep;
00296 
00297   if (y0 < y1) {
00298     ystep = 1;
00299   } else {
00300     ystep = -1;}
00301 
00302   for (; x0<x1; x0++) {
00303     if (steep) {
00304       set_pixel(y0, x0);
00305     } else {
00306       set_pixel(x0, y0);
00307     }
00308     err -= dy;
00309     if (err < 0) {
00310       y0 += ystep;
00311       err += dx;
00312     }
00313   }
00314 }
00315 
00316 void SSD1306::set_font(unsigned char *font, unsigned int width)
00317 {
00318     _console_font_data = font;
00319     _console_font_width = width;
00320 }
00321 
00322 void SSD1306::set_double_height_text(unsigned int double_height)
00323 {
00324     _double_height_text = double_height;
00325 }
00326 
00327 void SSD1306::putc(unsigned char c)
00328 {
00329     while (_cursor_x >= (128 / _console_font_width))
00330     {
00331         _cursor_x -= (128 / _console_font_width);
00332         _cursor_y++;            
00333     }
00334 
00335     while (_cursor_y > 7)
00336     {
00337         scroll_up();            
00338     }
00339 
00340     switch (c)
00341     {
00342     case '\n':
00343         _cursor_y++;
00344         break;
00345         
00346     case '\r':
00347         _cursor_x = 0;
00348         break;
00349         
00350     case '\t':
00351         _cursor_x = (_cursor_x + 4) % 4;
00352         break;
00353         
00354     default:
00355         for (int b = 0; b < _console_font_width; b++)
00356         {
00357             _screen[_cursor_x * _console_font_width + _cursor_y * 128 + b] = _console_font_data[(c - FONT_START) * _console_font_width + b];
00358         }
00359         
00360         _cursor_x++;
00361     }            
00362 }
00363 
00364 void SSD1306::scroll_up()
00365 {
00366     for (int y = 1; y <= 7; y++)
00367     {
00368         for (int x = 0; x < 128; x++)
00369         {
00370             _screen[x + 128 * (y - 1)] = _screen[x + 128 * y];
00371         }
00372     }
00373     
00374     for (int x = 0; x < 128; x++)
00375     {
00376         _screen[x + 128 * 7] = 0;
00377     }    
00378 
00379     _cursor_y--;
00380 }
00381 
00382 void SSD1306::printf(const char *format, ...)
00383 {
00384     static char buffer[128];
00385     
00386     va_list args;
00387     va_start(args, format);
00388     vsprintf(buffer, format, args);
00389     va_end(args);
00390     
00391     char *c = (char *)&buffer;
00392     while (*c != 0)
00393     {
00394         putc(*c++);
00395     }
00396 }
00397 
00398 void SSD1306::clear()
00399 {
00400     for (int i = 0; i < 1024; i++)
00401         _screen[i] = 0;
00402         
00403     _cursor_x = 0;
00404     _cursor_y = 0;
00405 }
00406 
00407 void SSD1306::_send_command(unsigned char code)
00408 {
00409     _cs = 1;
00410     _dc = 0;
00411     _cs = 0;
00412     _spi.write(code);
00413     _cs = 1;
00414 }
00415 
00416 void SSD1306::_send_data(unsigned char value)
00417 {
00418     _cs = 1;
00419     _dc = 1;
00420     _cs = 0;
00421     _spi.write(value);
00422     _cs = 1;
00423 }