diff --git a/examples/i2c_oled/README.md b/examples/i2c_oled/README.md index 91b8118ff10dbe83249c597b35e460f2d513f405..facc372c93fcf37bdaaaa47a73731e704bc6cd08 100644 --- a/examples/i2c_oled/README.md +++ b/examples/i2c_oled/README.md @@ -1,10 +1,10 @@ # I2C OLED demonstration This example code demonstrates use of the CH32V003 I2C peripheral with an SSD1306 -OLED (128x32 pixel type). It provides a generic I2C port initialization and -transmit (write-only) low level interface and a high-level graphics driver with -pixels, lines, circles, rectangles and 8x8 character font rendering. Out of the -box this demo cycles through a few different graphic screens to test out the -various drawing primitives. +OLED. Three different OLED sizes are supported - 64x32, 128x32, and 128x64. +It provides a generic I2C port initialization and transmit (write-only) low level +interface and a high-level graphics driver with pixels, lines, circles, rectangles +and 8x8 character font rendering. Out of the box this demo cycles through a few +different graphic screens to test out the various drawing primitives. https://user-images.githubusercontent.com/1132011/230734071-dee305de-5aad-4ca0-a422-5fb31d2bb0e0.mp4 @@ -27,13 +27,23 @@ mysterious effects and less error checking. * IRQ_DIAG - enables timing analysis via GPIO toggling. Don't enable this unless you know what you're doing. +There are a few build-time options in the oled.h source: +* OLED_ADDR - the I2C address of your OLED display. The default is 0x3c which +should work for most devices. Use 0x3d if you've pulled the SA0 line high. +* OLED_PSZ - the number of bytes to send per I2C data packet. The default value +of 32 seems to work well. Smaller values are allowed but may result in slower +refresh rates. +* OLED_64X32, OLED_128X32, OLED_128X64 - choose only one of these depending on +the type of OLED you've got. + ## Use Connect an SSD1306-based OLED in I2C interface mode to pins PC1 (SDA) and PC2 (SCL) of the CH32V003 with proper I2C pullup resistors and observe the various graphic images that cycle at approximately 2 second intervals. -Note - I used an Adafruit 0.91" 128x32 OLED breakout (stock #4440) for my testing -and found that the built-in 10k pullup resistors were too weak for reliable I2C -bus transactions. I had to add 2.2k resistors to the SCL and SDA pads to allow -proper operation. +Note - for part of my testing I used an Adafruit 0.91" 128x32 OLED breakout +(stock #4440) and found that the built-in 10k pullup resistors were too weak for +reliable I2C bus transactions. I had to add 2.2k resistors to the SCL and SDA +pads to allow proper operation. Generic OLED boards from ebay had stronger pullups +and did not need modification. diff --git a/examples/i2c_oled/i2c_oled.c b/examples/i2c_oled/i2c_oled.c index da23988c8a373ab6374780621e6ea4ee303266d7..f2f43ff5d9a8035ba87538ca63ec60f890f76b7a 100644 --- a/examples/i2c_oled/i2c_oled.c +++ b/examples/i2c_oled/i2c_oled.c @@ -31,7 +31,7 @@ int main() printf("Looping on test modes..."); while(1) { - for(uint8_t mode=0;mode<=6;mode++) + for(uint8_t mode=0;mode<(OLED_H>32?8:7);mode++) { // clear buffer for next mode oled_setbuf(0); @@ -39,53 +39,75 @@ int main() switch(mode) { case 0: + printf("buffer fill with binary\n\r"); for(int i=0;i<sizeof(oled_buffer);i++) oled_buffer[i] = i; break; case 1: + printf("pixel plots\n\r"); for(int i=0;i<OLED_W;i++) { - oled_drawPixel(i, i>>2, 1); - oled_drawPixel(i, OLED_H-1-(i>>2), 1); + oled_drawPixel(i, i/(OLED_W/OLED_H), 1); + oled_drawPixel(i, OLED_H-1-(i/(OLED_W/OLED_H)), 1); } break; case 2: { + printf("Line plots\n\r"); uint8_t y= 0; for(uint8_t x=0;x<OLED_W;x+=16) { oled_drawLine(x, 0, OLED_W, y, 1); oled_drawLine(OLED_W-x, OLED_H, 0, OLED_H-y, 1); - y+= 4; + y+= OLED_H/8; } } break; case 3: + printf("Circles empty and filled\n\r"); for(uint8_t x=0;x<OLED_W;x+=16) if(x<64) - oled_drawCircle(x,16, 15, 1); + oled_drawCircle(x, OLED_H/2, 15, 1); else - oled_fillCircle(x,16, 15, 1); + oled_fillCircle(x, OLED_H/2, 15, 1); break; case 4: + printf("Unscaled Text\n\r"); oled_drawstr(0,0, "This is a test", 1); oled_drawstr(0,8, "of the emergency", 1); oled_drawstr(0,16,"broadcasting", 1); oled_drawstr(0,24,"system.",1); - - oled_xorrect(64, 0, 64, 32); + if(OLED_H>32) + { + oled_drawstr(0,32, "Lorem ipsum", 1); + oled_drawstr(0,40, "dolor sit amet,", 1); + oled_drawstr(0,48,"consectetur", 1); + oled_drawstr(0,56,"adipiscing",1); + } + oled_xorrect(OLED_W/2, 0, OLED_W/2, OLED_W); break; + case 5: + printf("Scaled Text 1, 2\n\r"); oled_drawstr_sz(0,0, "sz 8x8", 1, fontsize_8x8); oled_drawstr_sz(0,16, "16x16", 1, fontsize_16x16); break; + case 6: + printf("Scaled Text 4\n\r"); oled_drawstr_sz(0,0, "32x32", 1, fontsize_32x32); break; + + + case 7: + printf("Scaled Text 8\n\r"); + oled_drawstr_sz(0,0, "64", 1, fontsize_64x64); + break; + default: break; } diff --git a/examples/i2c_oled/oled.h b/examples/i2c_oled/oled.h index b4dcff039af313b9664ec3aff026e0ac4be28286..378a27db98063cc95b6a60f0c6b81dfa59b389ea 100644 --- a/examples/i2c_oled/oled.h +++ b/examples/i2c_oled/oled.h @@ -14,6 +14,35 @@ // OLED I2C address #define OLED_ADDR 0x3c +// comfortable I2C packet size for this OLED +#define OLED_PSZ 32 + +// what type of OLED - uncomment just one +//#define OLED_64X32 +#define OLED_128X32 +//#define OLED_128X64 + +// characteristics of each type +#ifdef OLED_64X32 +#define OLED_W 64 +#define OLED_H 32 +#define OLED_FULLUSE +#define OLED_OFFSET 32 +#endif + +#ifdef OLED_128X32 +#define OLED_W 128 +#define OLED_H 32 +#define OLED_OFFSET 0 +#endif + +#ifdef OLED_128X64 +#define OLED_W 128 +#define OLED_H 64 +#define OLED_FULLUSE +#define OLED_OFFSET 0 +#endif + /* * send OLED command byte */ @@ -81,7 +110,11 @@ const uint8_t oled_init_array[] = SSD1306_SETDISPLAYCLOCKDIV, // 0xD5 0x80, // the suggested ratio 0x80 SSD1306_SETMULTIPLEX, // 0xA8 - 0x3F, // different for tiny +#ifdef OLED_64X32 + 0x1F, // for 64-wide displays +#else + 0x3F, // for 128-wide displays +#endif SSD1306_SETDISPLAYOFFSET, // 0xD3 0x00, // no offset SSD1306_SETSTARTLINE | 0x0, // 0x40 | line @@ -92,7 +125,7 @@ const uint8_t oled_init_array[] = SSD1306_SEGREMAP | 0x1, // 0xA0 | bit SSD1306_COMSCANDEC, SSD1306_SETCOMPINS, // 0xDA - 0x12, + 0x12, // SSD1306_SETCONTRAST, // 0x81 0x8F, SSD1306_SETPRECHARGE, // 0xd9 @@ -104,11 +137,9 @@ const uint8_t oled_init_array[] = SSD1306_DISPLAYON, // 0xAF --turn on oled panel SSD1306_TERMINATE_CMDS // 0xFF --fake command to mark end }; -#define OLED_W 128 -#define OLED_H 32 // the display buffer -uint8_t oled_buffer[128*32/8]; +uint8_t oled_buffer[OLED_W*OLED_H/8]; /* * set the buffer to a color @@ -118,6 +149,7 @@ void oled_setbuf(uint8_t color) memset(oled_buffer, color ? 0xFF : 0x00, sizeof(oled_buffer)); } +#ifndef OLED_FULLUSE /* * expansion array for OLED with every other row unused */ @@ -128,24 +160,24 @@ const uint8_t expand[16] = 0x80,0x82,0x88,0x8a, 0xa0,0xa2,0xa8,0xaa, }; +#endif /* * Send the frame buffer */ -#define OLED_PSZ 32 // comfortable I2C packet size for this OLED void oled_refresh(void) { uint16_t i; oled_cmd(SSD1306_COLUMNADDR); - oled_cmd(0); // Column start address (0 = reset) - oled_cmd(OLED_W-1); // Column end address (127 = reset) + oled_cmd(OLED_OFFSET); // Column start address (0 = reset) + oled_cmd(OLED_OFFSET+OLED_W-1); // Column end address (127 = reset) oled_cmd(SSD1306_PAGEADDR); oled_cmd(0); // Page start address (0 = reset) oled_cmd(7); // Page end address -#if 0 +#ifdef OLED_FULLUSE /* for fully used rows just plow thru everything */ for(i=0;i<sizeof(oled_buffer);i+=OLED_PSZ) { @@ -489,7 +521,8 @@ void oled_drawstr(uint8_t x, uint8_t y, char *str, uint8_t color) typedef enum { fontsize_8x8 = 1, fontsize_16x16 = 2, - fontsize_32x32 = 4 + fontsize_32x32 = 4, + fontsize_64x64 = 8, } font_size_t; /*