/** Quick test for sending some visible data to a SSD1306 display connected via I2C. This means not to test the display, but the I2C implementation. To run this test, add this line to board or printer config.h: #define I2C With this done, a welcome message should appear on the display. Without these additions, the binary size should be as small as the commit before. */ #ifdef I2C_TEST #include #include "config_wrapper.h" #include "i2c.h" #define DISPLAY_I2C_ADDRESS (0x3C << 1) const uint8_t PROGMEM display_init[] = { 0x00, // Command marker. 0xAE, // Display off. 0xD5, 0x80, // Display clock divider (reset). 0xA8, 0x1F, // 1/32 duty. 0x40 | 0x00, // Start line (reset). 0x20, 0x02, // Page addressing mode (reset). 0x22, 0x00, 0x03, // Start and end page in horiz./vert. addressing mode[1]. 0x21, 0x00, 0x7F, // Start and end column in horiz./vert. addressing mode. 0xA0 | 0x00, // No segment remap (reset). 0xC0 | 0x00, // Normal com pins mapping (reset). 0xDA, 0x02, // Sequental without remap com pins. 0x81, 0x7F, // Contrast (reset). 0xDB, 0x20, // Vcomh (reset). 0xD9, 0xF1, // Precharge period. 0x8D, 0x14, // Charge pump. 0xA6, // Positive display. 0xA4, // Resume display. 0xAF // Display on. }; // [1] Do not set this to 0x00..0x07 on a 32 pixel high display, or vertical // addressing mode will mess up. 32 pixel high displays have only 4 pages // (0..3), still addressing logic accepts, but can't deal with the 0..7 // meant for 64 pixel high displays. typedef struct { uint8_t columns; uint8_t data[4]; } SYMBOL; const SYMBOL PROGMEM font_8x4[] = { {2, {0x00, 0x00, 0x00, 0x00}}, /* space */ {3, {0x0C, 0x5E, 0x0C, 0x00}}, /* excl_mark */ {3, {0x03, 0x00, 0x03, 0x00}}, /* quot_mark */ {4, {0x74, 0x2E, 0x74, 0x2E}}, /* num_sign */ {4, {0x24, 0xCA, 0x53, 0x24}}, /* dlr_sign */ {4, {0x44, 0x30, 0x0C, 0x22}}, /* prc_sign */ {4, {0x33, 0x4D, 0x22, 0x00}}, /* ampersand */ {2, {0x02, 0x01, 0x00, 0x00}}, /* apostrophe */ {2, {0x3E, 0x41, 0x00, 0x00}}, /* lparent */ {2, {0x41, 0x3E, 0x00, 0x00}}, /* rparent */ {3, {0x14, 0x3E, 0x14, 0x00}}, /* asterisk */ {3, {0x08, 0x1C, 0x08, 0x00}}, /* plus_sign */ {2, {0x40, 0x20, 0x00, 0x00}}, /* comma */ {3, {0x08, 0x08, 0x08, 0x00}}, /* minus_sign */ {1, {0x20, 0x00, 0x00, 0x00}}, /* dot */ {3, {0x30, 0x0C, 0x03, 0x00}}, /* solidus */ {4, {0x3E, 0x41, 0x41, 0x3E}}, /* num_0 */ {3, {0x44, 0x7F, 0x40, 0x00}}, /* num_1 */ {4, {0x62, 0x51, 0x49, 0x46}}, /* num_2 */ {4, {0x22, 0x49, 0x49, 0x36}}, /* num_3 */ {4, {0x0F, 0x08, 0x08, 0x7E}}, /* num_4 */ {4, {0x27, 0x45, 0x45, 0x39}}, /* num_5 */ {4, {0x3E, 0x45, 0x45, 0x38}}, /* num_6 */ {4, {0x01, 0x71, 0x09, 0x07}}, /* num_7 */ {4, {0x36, 0x49, 0x49, 0x36}}, /* num_8 */ {4, {0x26, 0x49, 0x49, 0x3E}}, /* num_9 */ {1, {0x24, 0x00, 0x00, 0x00}}, /* colon */ {2, {0x40, 0x24, 0x00, 0x00}}, /* semicolon */ {3, {0x08, 0x14, 0x22, 0x00}}, /* less_sign */ {3, {0x14, 0x14, 0x14, 0x00}}, /* equal_sign */ {3, {0x22, 0x14, 0x08, 0x00}}, /* great_sign */ {3, {0x02, 0x51, 0x0E, 0x00}}, /* ques_mark */ {4, {0x7E, 0x99, 0xA5, 0x3E}}, /* at */ {3, {0x7E, 0x11, 0x7F, 0x00}}, /* a_cap */ {3, {0x7F, 0x49, 0x36, 0x00}}, /* b_cap */ {3, {0x3E, 0x41, 0x22, 0x00}}, /* c_cap */ {3, {0x7F, 0x41, 0x3E, 0x00}}, /* d_cap */ {3, {0x7F, 0x49, 0x41, 0x00}}, /* e_cap */ {3, {0x7F, 0x09, 0x01, 0x00}}, /* f_cap */ {3, {0x3E, 0x41, 0x71, 0x00}}, /* g_cap */ {3, {0x7F, 0x08, 0x7F, 0x00}}, /* h_cap */ {3, {0x41, 0x7F, 0x41, 0x00}}, /* i_cap */ {3, {0x40, 0x41, 0x3F, 0x00}}, /* j_cap */ {3, {0x7F, 0x0C, 0x73, 0x00}}, /* k_cap */ {3, {0x7F, 0x40, 0x40, 0x00}}, /* l_cap */ {3, {0x7F, 0x06, 0x7F, 0x00}}, /* m_cap */ {3, {0x7F, 0x3C, 0x7F, 0x00}}, /* n_cap */ {3, {0x3E, 0x41, 0x3E, 0x00}}, /* o_cap */ {3, {0x7F, 0x11, 0x0E, 0x00}}, /* p_cap */ {3, {0x3E, 0x41, 0xBE, 0x00}}, /* q_cap */ {3, {0x7F, 0x11, 0x6E, 0x00}}, /* r_cap */ {3, {0x46, 0x49, 0x31, 0x00}}, /* s_cap */ {3, {0x01, 0x7F, 0x01, 0x00}}, /* t_cap */ {3, {0x3F, 0x40, 0x7F, 0x00}}, /* u_cap */ {3, {0x3F, 0x40, 0x3F, 0x00}}, /* v_cap */ {3, {0x7F, 0x30, 0x7F, 0x00}}, /* w_cap */ {3, {0x73, 0x0C, 0x73, 0x00}}, /* x_cap */ {3, {0x0F, 0x70, 0x0F, 0x00}}, /* y_cap */ {3, {0x61, 0x5D, 0x47, 0x00}}, /* z_cap */ {2, {0x7F, 0x41, 0x00, 0x00}}, /* lq_bracket */ {3, {0x06, 0x18, 0x60, 0x00}}, /* rev_solidus */ {2, {0x41, 0x7F, 0x00, 0x00}}, /* rq_bracket */ {3, {0x02, 0x01, 0x02, 0x00}}, /* circumflex_accent */ {3, {0x40, 0x40, 0x40, 0x00}}, /* low_line */ {2, {0x01, 0x02, 0x00, 0x00}}, /* grave_accent */ {3, {0x30, 0x48, 0x78, 0x00}}, /* a_sml */ {3, {0x7E, 0x48, 0x30, 0x00}}, /* b_sml */ {3, {0x30, 0x48, 0x48, 0x00}}, /* c_sml */ {3, {0x30, 0x48, 0x7E, 0x00}}, /* d_sml */ {3, {0x30, 0x58, 0x58, 0x00}}, /* e_sml */ {2, {0x7C, 0x12, 0x00, 0x00}}, /* f_sml */ {3, {0x10, 0xA8, 0x70, 0x00}}, /* g_sml */ {3, {0x7E, 0x08, 0x70, 0x00}}, /* h_sml */ {1, {0x74, 0x00, 0x00, 0x00}}, /* i_sml */ {2, {0x80, 0x7A, 0x00, 0x00}}, /* j_sml */ {3, {0x7E, 0x10, 0x68, 0x00}}, /* k_sml */ {2, {0x3E, 0x40, 0x00, 0x00}}, /* l_sml */ {3, {0x78, 0x38, 0x70, 0x00}}, /* m_sml */ {3, {0x78, 0x08, 0x70, 0x00}}, /* n_sml */ {3, {0x30, 0x48, 0x30, 0x00}}, /* o_sml */ {3, {0xF8, 0x48, 0x30, 0x00}}, /* p_sml */ {3, {0x30, 0x48, 0xF8, 0x00}}, /* q_sml */ {2, {0x70, 0x08, 0x00, 0x00}}, /* r_sml */ {3, {0x50, 0x58, 0x28, 0x00}}, /* s_sml */ {2, {0x3E, 0x44, 0x00, 0x00}}, /* t_sml */ {3, {0x38, 0x40, 0x78, 0x00}}, /* u_sml */ {3, {0x38, 0x40, 0x38, 0x00}}, /* v_sml */ {3, {0x78, 0x60, 0x78, 0x00}}, /* w_sml */ {3, {0x68, 0x10, 0x68, 0x00}}, /* x_sml */ {3, {0x18, 0xA0, 0x78, 0x00}}, /* y_sml */ {3, {0x68, 0x68, 0x58, 0x00}}, /* z_sml */ {3, {0x08, 0x36, 0x41, 0x00}}, /* left_curly_bracket */ {1, {0x7F, 0x00, 0x00, 0x00}}, /* vertical_line */ {3, {0x41, 0x36, 0x08, 0x00}}, /* rigth_curly_bracket */ {4, {0x02, 0x01, 0x02, 0x01}}, /* tilde */ {4, {0x00, 0x00, 0x00, 0x00}} /* del */ }; #define FONT_SYMBOLS_SPACE 1 static void i2c_test(void) { uint16_t i; const char* message = "Welcome to Teacup"; for (i = 0; i < sizeof(display_init); i++) { // Send last byte with 'last_byte' set. i2c_write(pgm_read_byte(&display_init[i]), (i == sizeof(display_init) - 1)); } /** Clear the screen. As this display supports many sophisticated commands, but not a simple 'clear', we have to overwrite the entire memory with zeros, byte by byte. */ // Set horizontal adressing mode. i2c_write(0x00, 0); i2c_write(0x20, 0); i2c_write(0x00, 1); // Write 512 zeros. i2c_write(0x40, 0); for (i = 0; i < 512; i++) { i2c_write(0x00, (i == 511)); } // Return to page adressing mode. i2c_write(0x00, 0); i2c_write(0x20, 0); i2c_write(0x02, 1); /** Setup cursor on display. "Welcome to Teacup" is 64 pixel columns wide, entire display is 128 columns, so we offset by 32 columns to get it to the center. */ i2c_write(0x00, 0); // Line 1. i2c_write(0xB0 | 1, 0); // Column 32. i2c_write(0x00 | (32 & 0x0F), 0); i2c_write(0x10 | ((32 >> 4) & 0x0F), 1); // Render text to bitmap to display. i2c_write(0x40, 0); while (*message) { uint8_t index = (uint8_t)*message - 0x20; // Send the character bitmap. for (i = 0; i < pgm_read_byte(&font_8x4[index].columns); i++) { i2c_write(pgm_read_byte(&font_8x4[index].data[i]), 0); } // Send space between characters. for (i = 0; i < FONT_SYMBOLS_SPACE; i++) { i2c_write(0x00, 0); } message++; } // Send another space for transmission end. i2c_write(0x00, 1); } #endif /* I2C_TEST */