|
|
1.1 ! root 1: /* ! 2: * SSD0303 OLED controller with OSRAM Pictiva 96x16 display. ! 3: * ! 4: * Copyright (c) 2006-2007 CodeSourcery. ! 5: * Written by Paul Brook ! 6: * ! 7: * This code is licenced under the GPL. ! 8: */ ! 9: ! 10: /* The controller can support a variety of different displays, but we only ! 11: implement one. Most of the commends relating to brightness and geometry ! 12: setup are ignored. */ ! 13: #include "hw.h" ! 14: #include "i2c.h" ! 15: #include "console.h" ! 16: ! 17: //#define DEBUG_SSD0303 1 ! 18: ! 19: #ifdef DEBUG_SSD0303 ! 20: #define DPRINTF(fmt, args...) \ ! 21: do { printf("ssd0303: " fmt , ##args); } while (0) ! 22: #define BADF(fmt, args...) \ ! 23: do { fprintf(stderr, "ssd0303: error: " fmt , ##args); exit(1);} while (0) ! 24: #else ! 25: #define DPRINTF(fmt, args...) do {} while(0) ! 26: #define BADF(fmt, args...) \ ! 27: do { fprintf(stderr, "ssd0303: error: " fmt , ##args);} while (0) ! 28: #endif ! 29: ! 30: /* Scaling factor for pixels. */ ! 31: #define MAGNIFY 4 ! 32: ! 33: enum ssd0303_mode ! 34: { ! 35: SSD0303_IDLE, ! 36: SSD0303_DATA, ! 37: SSD0303_CMD ! 38: }; ! 39: ! 40: enum ssd0303_cmd { ! 41: SSD0303_CMD_NONE, ! 42: SSD0303_CMD_SKIP1 ! 43: }; ! 44: ! 45: typedef struct { ! 46: i2c_slave i2c; ! 47: DisplayState *ds; ! 48: int row; ! 49: int col; ! 50: int start_line; ! 51: int mirror; ! 52: int flash; ! 53: int enabled; ! 54: int inverse; ! 55: int redraw; ! 56: enum ssd0303_mode mode; ! 57: enum ssd0303_cmd cmd_state; ! 58: uint8_t framebuffer[132*8]; ! 59: } ssd0303_state; ! 60: ! 61: static int ssd0303_recv(i2c_slave *i2c) ! 62: { ! 63: BADF("Reads not implemented\n"); ! 64: return -1; ! 65: } ! 66: ! 67: static int ssd0303_send(i2c_slave *i2c, uint8_t data) ! 68: { ! 69: ssd0303_state *s = (ssd0303_state *)i2c; ! 70: enum ssd0303_cmd old_cmd_state; ! 71: switch (s->mode) { ! 72: case SSD0303_IDLE: ! 73: DPRINTF("byte 0x%02x\n", data); ! 74: if (data == 0x80) ! 75: s->mode = SSD0303_CMD; ! 76: else if (data == 0x40) ! 77: s->mode = SSD0303_DATA; ! 78: else ! 79: BADF("Unexpected byte 0x%x\n", data); ! 80: break; ! 81: case SSD0303_DATA: ! 82: DPRINTF("data 0x%02x\n", data); ! 83: if (s->col < 132) { ! 84: s->framebuffer[s->col + s->row * 132] = data; ! 85: s->col++; ! 86: s->redraw = 1; ! 87: } ! 88: break; ! 89: case SSD0303_CMD: ! 90: old_cmd_state = s->cmd_state; ! 91: s->cmd_state = SSD0303_CMD_NONE; ! 92: switch (old_cmd_state) { ! 93: case SSD0303_CMD_NONE: ! 94: DPRINTF("cmd 0x%02x\n", data); ! 95: s->mode = SSD0303_IDLE; ! 96: switch (data) { ! 97: case 0x00 ... 0x0f: /* Set lower colum address. */ ! 98: s->col = (s->col & 0xf0) | (data & 0xf); ! 99: break; ! 100: case 0x10 ... 0x20: /* Set higher column address. */ ! 101: s->col = (s->col & 0x0f) | ((data & 0xf) << 4); ! 102: break; ! 103: case 0x40 ... 0x7f: /* Set start line. */ ! 104: s->start_line = 0; ! 105: break; ! 106: case 0x81: /* Set contrast (Ignored). */ ! 107: s->cmd_state = SSD0303_CMD_SKIP1; ! 108: break; ! 109: case 0xa0: /* Mirror off. */ ! 110: s->mirror = 0; ! 111: break; ! 112: case 0xa1: /* Mirror off. */ ! 113: s->mirror = 1; ! 114: break; ! 115: case 0xa4: /* Entire display off. */ ! 116: s->flash = 0; ! 117: break; ! 118: case 0xa5: /* Entire display on. */ ! 119: s->flash = 1; ! 120: break; ! 121: case 0xa6: /* Inverse off. */ ! 122: s->inverse = 0; ! 123: break; ! 124: case 0xa7: /* Inverse on. */ ! 125: s->inverse = 1; ! 126: break; ! 127: case 0xa8: /* Set multipled ratio (Ignored). */ ! 128: s->cmd_state = SSD0303_CMD_SKIP1; ! 129: break; ! 130: case 0xad: /* DC-DC power control. */ ! 131: s->cmd_state = SSD0303_CMD_SKIP1; ! 132: break; ! 133: case 0xae: /* Display off. */ ! 134: s->enabled = 0; ! 135: break; ! 136: case 0xaf: /* Display on. */ ! 137: s->enabled = 1; ! 138: break; ! 139: case 0xb0 ... 0xbf: /* Set Page address. */ ! 140: s->row = data & 7; ! 141: break; ! 142: case 0xc0 ... 0xc8: /* Set COM output direction (Ignored). */ ! 143: break; ! 144: case 0xd3: /* Set display offset (Ignored). */ ! 145: s->cmd_state = SSD0303_CMD_SKIP1; ! 146: break; ! 147: case 0xd5: /* Set display clock (Ignored). */ ! 148: s->cmd_state = SSD0303_CMD_SKIP1; ! 149: break; ! 150: case 0xd8: /* Set color and power mode (Ignored). */ ! 151: s->cmd_state = SSD0303_CMD_SKIP1; ! 152: break; ! 153: case 0xd9: /* Set pre-charge period (Ignored). */ ! 154: s->cmd_state = SSD0303_CMD_SKIP1; ! 155: break; ! 156: case 0xda: /* Set COM pin configuration (Ignored). */ ! 157: s->cmd_state = SSD0303_CMD_SKIP1; ! 158: break; ! 159: case 0xdb: /* Set VCOM dselect level (Ignored). */ ! 160: s->cmd_state = SSD0303_CMD_SKIP1; ! 161: break; ! 162: case 0xe3: /* no-op. */ ! 163: break; ! 164: default: ! 165: BADF("Unknown command: 0x%x\n", data); ! 166: } ! 167: break; ! 168: case SSD0303_CMD_SKIP1: ! 169: DPRINTF("skip 0x%02x\n", data); ! 170: break; ! 171: } ! 172: break; ! 173: } ! 174: return 0; ! 175: } ! 176: ! 177: static void ssd0303_event(i2c_slave *i2c, enum i2c_event event) ! 178: { ! 179: ssd0303_state *s = (ssd0303_state *)i2c; ! 180: switch (event) { ! 181: case I2C_FINISH: ! 182: s->mode = SSD0303_IDLE; ! 183: break; ! 184: case I2C_START_RECV: ! 185: case I2C_START_SEND: ! 186: case I2C_NACK: ! 187: /* Nothing to do. */ ! 188: break; ! 189: } ! 190: } ! 191: ! 192: static void ssd0303_update_display(void *opaque) ! 193: { ! 194: ssd0303_state *s = (ssd0303_state *)opaque; ! 195: uint8_t *dest; ! 196: uint8_t *src; ! 197: int x; ! 198: int y; ! 199: int line; ! 200: char *colors[2]; ! 201: char colortab[MAGNIFY * 8]; ! 202: int dest_width; ! 203: uint8_t mask; ! 204: ! 205: if (s->redraw) { ! 206: switch (s->ds->depth) { ! 207: case 0: ! 208: return; ! 209: case 15: ! 210: dest_width = 2; ! 211: break; ! 212: case 16: ! 213: dest_width = 2; ! 214: break; ! 215: case 24: ! 216: dest_width = 3; ! 217: break; ! 218: case 32: ! 219: dest_width = 4; ! 220: break; ! 221: default: ! 222: BADF("Bad color depth\n"); ! 223: return; ! 224: } ! 225: dest_width *= MAGNIFY; ! 226: memset(colortab, 0xff, dest_width); ! 227: memset(colortab + dest_width, 0, dest_width); ! 228: if (s->flash) { ! 229: colors[0] = colortab; ! 230: colors[1] = colortab; ! 231: } else if (s->inverse) { ! 232: colors[0] = colortab; ! 233: colors[1] = colortab + dest_width; ! 234: } else { ! 235: colors[0] = colortab + dest_width; ! 236: colors[1] = colortab; ! 237: } ! 238: dest = s->ds->data; ! 239: for (y = 0; y < 16; y++) { ! 240: line = (y + s->start_line) & 63; ! 241: src = s->framebuffer + 132 * (line >> 3) + 36; ! 242: mask = 1 << (line & 7); ! 243: for (x = 0; x < 96; x++) { ! 244: memcpy(dest, colors[(*src & mask) != 0], dest_width); ! 245: dest += dest_width; ! 246: src++; ! 247: } ! 248: for (x = 1; x < MAGNIFY; x++) { ! 249: memcpy(dest, dest - dest_width * 96, dest_width * 96); ! 250: dest += dest_width * 96; ! 251: } ! 252: } ! 253: } ! 254: dpy_update(s->ds, 0, 0, 96 * MAGNIFY, 16 * MAGNIFY); ! 255: } ! 256: ! 257: static void ssd0303_invalidate_display(void * opaque) ! 258: { ! 259: ssd0303_state *s = (ssd0303_state *)opaque; ! 260: s->redraw = 1; ! 261: } ! 262: ! 263: void ssd0303_init(DisplayState *ds, i2c_bus *bus, int address) ! 264: { ! 265: ssd0303_state *s; ! 266: ! 267: s = (ssd0303_state *)i2c_slave_init(bus, address, sizeof(ssd0303_state)); ! 268: s->ds = ds; ! 269: s->i2c.event = ssd0303_event; ! 270: s->i2c.recv = ssd0303_recv; ! 271: s->i2c.send = ssd0303_send; ! 272: graphic_console_init(ds, ssd0303_update_display, ssd0303_invalidate_display, ! 273: NULL, s); ! 274: dpy_resize(s->ds, 96 * MAGNIFY, 16 * MAGNIFY); ! 275: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.