diff --git a/examples/i2c_oled/bomb.h b/examples/i2c_oled/bomb.h new file mode 100644 index 0000000000000000000000000000000000000000..208d602109a3e8be6caf75f299b32375c834def7 --- /dev/null +++ b/examples/i2c_oled/bomb.h @@ -0,0 +1,17 @@ +/* +The bomb illustration has been drawn and provided by [DoubleWaffleCakes](https://www.reddit.com/user/DoubleWaffleCakes/). +*/ +const unsigned char bomb_i_stripped[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, + 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x48, 0x00, + 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x03, 0xfe, 0x00, + 0x00, 0x0f, 0xff, 0x80, 0x00, 0x1f, 0xff, 0xc0, 0x00, 0x1f, 0xff, 0xc0, + 0x00, 0x3f, 0xff, 0xe0, 0x00, 0x3f, 0xff, 0xe0, 0x00, 0x73, 0x9f, 0xf0, + 0x00, 0x73, 0x9f, 0xf0, 0x00, 0x73, 0x9f, 0xf0, 0x00, 0x73, 0x9f, 0xf0, + 0x00, 0x73, 0x9f, 0xf0, 0x00, 0x3f, 0xff, 0xe0, 0x00, 0x3f, 0xff, 0xe0, + 0x00, 0x1f, 0xff, 0xc0, 0x00, 0x1f, 0xff, 0xc0, 0x00, 0x0f, 0xff, 0x80, + 0x00, 0x13, 0xe0, 0x40, 0x00, 0x20, 0xc0, 0x20, 0x00, 0x7f, 0xff, 0xe0, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; +const unsigned int bomb_i_stripped_len = 128; diff --git a/examples/i2c_oled/i2c_oled.c b/examples/i2c_oled/i2c_oled.c index 94e6ce6390af94aa88c6d4020f01e71d1016b563..fd7a3bc3a2f88cf0dcd895d57a5469b1ea65bb7e 100644 --- a/examples/i2c_oled/i2c_oled.c +++ b/examples/i2c_oled/i2c_oled.c @@ -17,6 +17,8 @@ #include "ssd1306_i2c.h" #include "ssd1306.h" +#include "bomb.h" + int main() { // 48MHz internal clock @@ -42,7 +44,7 @@ int main() printf("Looping on test modes..."); while(1) { - for(uint8_t mode=0;mode<(SSD1306_H>32?8:7);mode++) + for(uint8_t mode=0;mode<(SSD1306_H>32?9:8);mode++) { // clear buffer for next mode ssd1306_setbuf(0); @@ -85,8 +87,11 @@ int main() else ssd1306_fillCircle(x, SSD1306_H/2, 15, 1); break; - case 4: + printf("Image\n\r"); + ssd1306_drawImage(0, 0, bomb_i_stripped, 32, 32, 0); + break; + case 5: printf("Unscaled Text\n\r"); ssd1306_drawstr(0,0, "This is a test", 1); ssd1306_drawstr(0,8, "of the emergency", 1); @@ -102,19 +107,19 @@ int main() ssd1306_xorrect(SSD1306_W/2, 0, SSD1306_W/2, SSD1306_W); break; - case 5: + case 6: printf("Scaled Text 1, 2\n\r"); ssd1306_drawstr_sz(0,0, "sz 8x8", 1, fontsize_8x8); ssd1306_drawstr_sz(0,16, "16x16", 1, fontsize_16x16); break; - case 6: + case 7: printf("Scaled Text 4\n\r"); ssd1306_drawstr_sz(0,0, "32x32", 1, fontsize_32x32); break; - case 7: + case 8: printf("Scaled Text 8\n\r"); ssd1306_drawstr_sz(0,0, "64", 1, fontsize_64x64); break; diff --git a/examples/i2c_oled/ssd1306.h b/examples/i2c_oled/ssd1306.h index 19ea88db1053ad211038656b1dbe1452f8f6e2bb..ea985d8d8a0108004beb495107b3c95570eb5b13 100644 --- a/examples/i2c_oled/ssd1306.h +++ b/examples/i2c_oled/ssd1306.h @@ -240,6 +240,77 @@ void ssd1306_xorPixel(uint8_t x, uint8_t y) ssd1306_buffer[addr] ^= (1<<(y&7)); } +/* + * draw a an image from an array, directly into to the display buffer + * the color modes allow for overwriting and even layering (sprites!) + */ +void ssd1306_drawImage(uint8_t x, uint8_t y, const unsigned char* input, uint8_t width, uint8_t height, uint8_t color_mode) { + uint8_t x_absolute; + uint8_t y_absolute; + uint8_t pixel; + uint8_t bytes_to_draw = width / 8; + uint16_t buffer_addr; + + for (uint8_t line = 0; line < height; line++) { + y_absolute = y + line; + if (y_absolute >= SSD1306_H) { + break; + } + + // SSD1306 is in vertical mode, yet we want to draw horizontally, which necessitates assembling the output bytes from the input data + // bitmask for current pixel in vertical (output) byte + uint8_t v_mask = 1 << (y_absolute & 7); + + for (uint8_t byte = 0; byte < bytes_to_draw; byte++) { + uint8_t input_byte = input[byte + line * bytes_to_draw]; + + for (pixel = 0; pixel < 8; pixel++) { + x_absolute = x + 8 * (bytes_to_draw - byte) + pixel; + if (x_absolute >= SSD1306_W) { + break; + } + // looking at the horizontal display, we're drawing bytes bottom to top, not left to right, hence y / 8 + buffer_addr = x_absolute + SSD1306_W * (y_absolute / 8); + // state of current pixel + uint8_t input_pixel = input_byte & (1 << pixel); + + switch (color_mode) { + case 0: + // write pixels as they are + ssd1306_buffer[buffer_addr] = (ssd1306_buffer[buffer_addr] & ~v_mask) | (input_pixel ? v_mask : 0); + break; + case 1: + // write pixels after inversion + ssd1306_buffer[buffer_addr] = (ssd1306_buffer[buffer_addr] & ~v_mask) | (!input_pixel ? v_mask : 0); + break; + case 2: + // 0 clears pixel + ssd1306_buffer[buffer_addr] &= input_pixel ? 0xFF : ~v_mask; + break; + case 3: + // 1 sets pixel + ssd1306_buffer[buffer_addr] |= input_pixel ? v_mask : 0; + break; + case 4: + // 0 sets pixel + ssd1306_buffer[buffer_addr] |= !input_pixel ? v_mask : 0; + break; + case 5: + // 1 clears pixel + ssd1306_buffer[buffer_addr] &= input_pixel ? ~v_mask : 0xFF; + break; + } + } + #if SSD1306_LOG_IMAGE == 1 + printf("%02x ", input_byte); + #endif + } + #if SSD1306_LOG_IMAGE == 1 + printf("\n\r"); + #endif + } +} + /* * fast vert line */