ssd1329.c


1
//*****************************************************************************
2
//
3
// 128x96 oled display driver for ssd1329 controller
4
//
5
//*****************************************************************************
6
7
//*****************************************************************************
8
//
9
// PINS
10
//
11
//*****************************************************************************
12
//
13
// The SPI must already be configured before using this driver and
14
// the following pins must already be defined:
15
//
16
// SCK            SPI Clock
17
// MOSI           SPI Data
18
// CS_DISP        Oled chip select, active low
19
// RES_DISP       Oled reset, active low
20
// DC_DISP        Data/command selection, low = command, high = data
21
// OLED_CMD_PORT  Port where the CS_DISP, RES_DISP and DC_DISP lines are connected
22
//
23
//*****************************************************************************
24
25
#include <avr/io.h>
26
#include <util/delay.h>
27
#include <assert.h>
28
#include "hardware.h"
29
#include "ssd1329.h"
30
31
//*****************************************************************************
32
//
33
// Buffer for storing sequences of command and data for the display.
34
//
35
//*****************************************************************************
36
static unsigned char g_pucBuffer[8];
37
38
//*****************************************************************************
39
//
40
// Define the SSD1329 128x96x4 Remap Setting(s).  This will be used in
41
// several places in the code to switch between vertical and horizontal
42
// address incrementing.  Note that the controller support 128 rows while
43
// the RIT display only uses 96.
44
//
45
// The Remap Command (0xA0) takes one 8-bit parameter.  The parameter is
46
// defined as follows.
47
//
48
// Bit 7: Reserved
49
// Bit 6: Disable(0)/Enable(1) COM Split Odd Even
50
//        When enabled, the COM signals are split Odd on one side, even on
51
//        the other.  Otherwise, they are split 0-63 on one side, 64-127 on
52
//        the other.
53
// Bit 5: Reserved
54
// Bit 4: Disable(0)/Enable(1) COM Remap
55
//        When Enabled, ROW 0-127 map to COM 127-0 (that is, reverse row order)
56
// Bit 3: Reserved
57
// Bit 2: Horizontal(0)/Vertical(1) Address Increment
58
//        When set, data RAM address will increment along the column rather
59
//        than along the row.
60
// Bit 1: Disable(0)/Enable(1) Nibble Remap
61
//        When enabled, the upper and lower nibbles in the DATA bus for access
62
//        to the data RAM are swapped.
63
// Bit 0: Disable(0)/Enable(1) Column Address Remap
64
//        When enabled, DATA RAM columns 0-63 are remapped to Segment Columns
65
//        127-0.
66
//
67
//*****************************************************************************
68
#define SSD1329_INIT_REMAP      0x41 // was 0x52, app note says 0x51
69
#define SSD1329_INIT_OFFSET     0x00
70
static const unsigned char g_puc_SSD1329_VerticalInc[]   = { 0xA0, 0x56 };
71
static const unsigned char g_puc_SSD1329_HorizontalInc[] = { 0xA0, 0x52 };
72
73
#define OFFSET 2
74
75
//*****************************************************************************
76
//
77
// A 5x7 font (in a 6x8 cell, where the sixth column is omitted from this
78
// table) for displaying text on the OLED display.  The data is organized as
79
// bytes from the left column to the right column, with each byte containing
80
// the top row in the LSB and the bottom row in the MSB.
81
//
82
// Note:  This is the same font data that is used in the EK-LM3S811
83
// osram96x16x1 driver.  The single bit-per-pixel is expaned in the StringDraw
84
// function to the appropriate four bit-per-pixel gray scale format.
85
//
86
//*****************************************************************************
87
static const unsigned char g_pucFont[96][5] = {
88
89
    { 0x00, 0x00, 0x00, 0x00, 0x00 }, // " "
90
    { 0x00, 0x00, 0x4f, 0x00, 0x00 }, // !
91
    { 0x00, 0x07, 0x00, 0x07, 0x00 }, // "
92
    { 0x14, 0x7f, 0x14, 0x7f, 0x14 }, // #
93
    { 0x24, 0x2a, 0x7f, 0x2a, 0x12 }, // $
94
    { 0x23, 0x13, 0x08, 0x64, 0x62 }, // %
95
    { 0x36, 0x49, 0x55, 0x22, 0x50 }, // &
96
    { 0x00, 0x05, 0x03, 0x00, 0x00 }, // '
97
    { 0x00, 0x1c, 0x22, 0x41, 0x00 }, // (
98
    { 0x00, 0x41, 0x22, 0x1c, 0x00 }, // )
99
    { 0x14, 0x08, 0x3e, 0x08, 0x14 }, // *
100
    { 0x08, 0x08, 0x3e, 0x08, 0x08 }, // +
101
    { 0x00, 0x50, 0x30, 0x00, 0x00 }, // ,
102
    { 0x08, 0x08, 0x08, 0x08, 0x08 }, // -
103
    { 0x00, 0x60, 0x60, 0x00, 0x00 }, // .
104
    { 0x20, 0x10, 0x08, 0x04, 0x02 }, // /
105
    { 0x3e, 0x51, 0x49, 0x45, 0x3e }, // 0
106
    { 0x00, 0x42, 0x7f, 0x40, 0x00 }, // 1
107
    { 0x42, 0x61, 0x51, 0x49, 0x46 }, // 2
108
    { 0x21, 0x41, 0x45, 0x4b, 0x31 }, // 3
109
    { 0x18, 0x14, 0x12, 0x7f, 0x10 }, // 4
110
    { 0x27, 0x45, 0x45, 0x45, 0x39 }, // 5
111
    { 0x3c, 0x4a, 0x49, 0x49, 0x30 }, // 6
112
    { 0x01, 0x71, 0x09, 0x05, 0x03 }, // 7
113
    { 0x36, 0x49, 0x49, 0x49, 0x36 }, // 8
114
    { 0x06, 0x49, 0x49, 0x29, 0x1e }, // 9
115
    { 0x00, 0x36, 0x36, 0x00, 0x00 }, // :
116
    { 0x00, 0x56, 0x36, 0x00, 0x00 }, // ;
117
    { 0x08, 0x14, 0x22, 0x41, 0x00 }, // <
118
    { 0x14, 0x14, 0x14, 0x14, 0x14 }, // =
119
    { 0x00, 0x41, 0x22, 0x14, 0x08 }, // >
120
    { 0x02, 0x01, 0x51, 0x09, 0x06 }, // ?
121
    { 0x32, 0x49, 0x79, 0x41, 0x3e }, // @
122
    { 0x7e, 0x11, 0x11, 0x11, 0x7e }, // A
123
    { 0x7f, 0x49, 0x49, 0x49, 0x36 }, // B
124
    { 0x3e, 0x41, 0x41, 0x41, 0x22 }, // C
125
    { 0x7f, 0x41, 0x41, 0x22, 0x1c }, // D
126
    { 0x7f, 0x49, 0x49, 0x49, 0x41 }, // E
127
    { 0x7f, 0x09, 0x09, 0x09, 0x01 }, // F
128
    { 0x3e, 0x41, 0x49, 0x49, 0x7a }, // G
129
    { 0x7f, 0x08, 0x08, 0x08, 0x7f }, // H
130
    { 0x00, 0x41, 0x7f, 0x41, 0x00 }, // I
131
    { 0x20, 0x40, 0x41, 0x3f, 0x01 }, // J
132
    { 0x7f, 0x08, 0x14, 0x22, 0x41 }, // K
133
    { 0x7f, 0x40, 0x40, 0x40, 0x40 }, // L
134
    { 0x7f, 0x02, 0x0c, 0x02, 0x7f }, // M
135
    { 0x7f, 0x04, 0x08, 0x10, 0x7f }, // N
136
    { 0x3e, 0x41, 0x41, 0x41, 0x3e }, // O
137
    { 0x7f, 0x09, 0x09, 0x09, 0x06 }, // P
138
    { 0x3e, 0x41, 0x51, 0x21, 0x5e }, // Q
139
    { 0x7f, 0x09, 0x19, 0x29, 0x46 }, // R
140
    { 0x46, 0x49, 0x49, 0x49, 0x31 }, // S
141
    { 0x01, 0x01, 0x7f, 0x01, 0x01 }, // T
142
    { 0x3f, 0x40, 0x40, 0x40, 0x3f }, // U
143
    { 0x1f, 0x20, 0x40, 0x20, 0x1f }, // V
144
    { 0x3f, 0x40, 0x38, 0x40, 0x3f }, // W
145
    { 0x63, 0x14, 0x08, 0x14, 0x63 }, // X
146
    { 0x07, 0x08, 0x70, 0x08, 0x07 }, // Y
147
    { 0x61, 0x51, 0x49, 0x45, 0x43 }, // Z
148
    { 0x00, 0x7f, 0x41, 0x41, 0x00 }, // [
149
    { 0x02, 0x04, 0x08, 0x10, 0x20 }, // "\"
150
    { 0x00, 0x41, 0x41, 0x7f, 0x00 }, // ]
151
    { 0x04, 0x02, 0x01, 0x02, 0x04 }, // ^
152
    { 0x40, 0x40, 0x40, 0x40, 0x40 }, // _
153
    { 0x00, 0x01, 0x02, 0x04, 0x00 }, // `
154
    { 0x20, 0x54, 0x54, 0x54, 0x78 }, // a
155
    { 0x7f, 0x48, 0x44, 0x44, 0x38 }, // b
156
    { 0x38, 0x44, 0x44, 0x44, 0x20 }, // c
157
    { 0x38, 0x44, 0x44, 0x48, 0x7f }, // d
158
    { 0x38, 0x54, 0x54, 0x54, 0x18 }, // e
159
    { 0x08, 0x7e, 0x09, 0x01, 0x02 }, // f
160
    { 0x0c, 0x52, 0x52, 0x52, 0x3e }, // g
161
    { 0x7f, 0x08, 0x04, 0x04, 0x78 }, // h
162
    { 0x00, 0x44, 0x7d, 0x40, 0x00 }, // i
163
    { 0x20, 0x40, 0x44, 0x3d, 0x00 }, // j
164
    { 0x7f, 0x10, 0x28, 0x44, 0x00 }, // k
165
    { 0x00, 0x41, 0x7f, 0x40, 0x00 }, // l
166
    { 0x7c, 0x04, 0x18, 0x04, 0x78 }, // m
167
    { 0x7c, 0x08, 0x04, 0x04, 0x78 }, // n
168
    { 0x38, 0x44, 0x44, 0x44, 0x38 }, // o
169
    { 0x7c, 0x14, 0x14, 0x14, 0x08 }, // p
170
    { 0x08, 0x14, 0x14, 0x18, 0x7c }, // q
171
    { 0x7c, 0x08, 0x04, 0x04, 0x08 }, // r
172
    { 0x48, 0x54, 0x54, 0x54, 0x20 }, // s
173
    { 0x04, 0x3f, 0x44, 0x40, 0x20 }, // t
174
    { 0x3c, 0x40, 0x40, 0x20, 0x7c }, // u
175
    { 0x1c, 0x20, 0x40, 0x20, 0x1c }, // v
176
    { 0x3c, 0x40, 0x30, 0x40, 0x3c }, // w
177
    { 0x44, 0x28, 0x10, 0x28, 0x44 }, // x
178
    { 0x0c, 0x50, 0x50, 0x50, 0x3c }, // y
179
    { 0x44, 0x64, 0x54, 0x4c, 0x44 }, // z
180
    { 0x00, 0x08, 0x36, 0x41, 0x00 }, // {
181
    { 0x00, 0x00, 0x7f, 0x00, 0x00 }, // |
182
    { 0x00, 0x41, 0x36, 0x08, 0x00 }, // }
183
    { 0x02, 0x01, 0x02, 0x04, 0x02 }, // ~
184
    { 0x00, 0x00, 0x00, 0x00, 0x00 }
185
};
186
187
//*****************************************************************************
188
//
189
// The sequence of commands used to initialize the SSD1329 controller.  Each
190
// command is described as follows:  there is a byte specifying the number of
191
// bytes in the command sequence, followed by that many bytes of command data.
192
// Note:  This initialization sequence is derived from RIT App Note for
193
// the P14201.  Values used are from the RIT app note, except where noted.
194
//
195
//*****************************************************************************
196
static const unsigned char g_puc_SSD1329_Init[] = {
197
198
  //
199
  // Set column address
200
  //
201
  3, 0x15, 0, 63,
202
203
  //
204
  // Set row address
205
  //
206
  3, 0x75, 0, 127,
207
208
    //
209
    // Unlock commands
210
    //
211
    3, 0xFD, 0x12, 0xE3,
212
213
    //
214
    // Display off
215
    //
216
    2, 0xAE, 0xE3,
217
218
    //
219
    // Icon off
220
    //
221
    3, 0x94, 0, 0xE3,
222
223
    //
224
    // Multiplex ratio
225
    //
226
    3, 0xA8, 95, 0xE3,
227
228
    //
229
    // Contrast
230
    //
231
    3, 0x81, 0xB7, 0xE3,
232
233
    //
234
    // Pre-charge current
235
    //
236
    3, 0x82, 0x3F, 0xE3,
237
238
    //
239
    // Display Re-map
240
    //
241
    3, 0xA0, SSD1329_INIT_REMAP, 0xE3,
242
243
    //
244
    // Display Start Line
245
    //
246
    3, 0xA1, 0, 0xE3,
247
248
    //
249
    // Display Offset
250
    //
251
    3, 0xA2, SSD1329_INIT_OFFSET, 0xE3,
252
253
    //
254
    // Display Mode Normal
255
    //
256
    2, 0xA4, 0xE3,
257
258
    //
259
    // Phase Length
260
    // was 0x11
261
    3, 0xB1, 0x53, 0xE3,
262
263
    //
264
    // Frame frequency
265
    //
266
    3, 0xB2, 0x23, 0xE3,
267
268
    //
269
    // Front Clock Divider
270
    //
271
    3, 0xB3, 0xE2, 0xE3,
272
273
    //
274
    // Set gray scale table.  App note uses default command:
275
    // 2, 0xB7, 0xE3
276
    // This gray scale attempts some gamma correction to reduce
277
    // the brightness of the low levels.
278
    //
279
    17, 0xB8, 1, 2, 3, 4, 5, 6, 8, 10, 12, 14, 16, 19, 22, 26, 30, 0xE3,
280
281
    //
282
    // Second pre-charge period. App note uses value 0x04.
283
    //
284
    3, 0xBB, 0x01, 0xE3,
285
286
    //
287
    // Pre-charge voltage
288
    // was 0x3F
289
    3, 0xBC, 0x0F, 0xE3,
290
291
    //
292
    // Display ON
293
    //
294
    2, 0xAF, 0xE3,
295
};
296
297
//*****************************************************************************
298
//
299
//! \internal
300
//!
301
//! Write a sequence of command bytes to the SSD1329 controller.
302
//!
303
//! The data is written in a polled fashion; this function will not return
304
//! until the entire byte sequence has been written to the controller.
305
//!
306
//! \return None.
307
//
308
//*****************************************************************************
309
static void SSD1329_WriteCommand(const unsigned char *pucBuffer, unsigned long ulCount) {
310
311
    //
312
    // Clear the command/control bit to enable command mode.
313
    //
314
  OLED_CMD_PORT &= ~(1<<DC_DISP);
315
316
  //
317
  // Clear the chip select bit (enable)
318
  //
319
  // toggle it
320
  OLED_CMD_PORT &= ~(1<<CS_DISP);
321
  OLED_CMD_PORT |= (1<<CS_DISP);
322
  OLED_CMD_PORT &= ~(1<<CS_DISP);
323
324
    //
325
    // Loop while there are more bytes left to be transferred.
326
    //
327
    while(ulCount != 0) {
328
329
        //
330
        // Write the next byte to the controller.
331
        //
332
    SPDR = *pucBuffer++;
333
      // Wait for transmission complete
334
      while(!(SPSR & (1<<SPIF)));
335
336
        //
337
        // Decrement the BYTE counter.
338
        //
339
        ulCount--;
340
    }
341
342
  //
343
  // Set the chip select bit (disable)
344
  //
345
  OLED_CMD_PORT |= (1<<CS_DISP);
346
  
347
}
348
349
//*****************************************************************************
350
//
351
//! \internal
352
//!
353
//! Write a sequence of data bytes to the SSD1329 controller.
354
//!
355
//! The data is written in a polled fashion; this function will not return
356
//! until the entire byte sequence has been written to the controller.
357
//!
358
//! \return None.
359
//
360
//*****************************************************************************
361
static void SSD1329_WriteData(const unsigned char *pucBuffer, unsigned long ulCount) {
362
363
    //
364
    // Set the command/control bit to enable data mode.
365
    //
366
  OLED_CMD_PORT |= (1<<DC_DISP);
367
368
  //
369
  // Clear the chip select bit (enable)
370
  //
371
  // toggle it
372
  OLED_CMD_PORT &= ~(1<<CS_DISP);
373
  OLED_CMD_PORT |= (1<<CS_DISP);
374
  OLED_CMD_PORT &= ~(1<<CS_DISP);
375
376
    //
377
    // Loop while there are more bytes left to be transferred.
378
    //
379
    while(ulCount != 0) {
380
381
        //
382
        // Write the next byte to the controller.
383
        //
384
    SPDR = *pucBuffer++;
385
      // Wait for transmission complete
386
      while(!(SPSR & (1<<SPIF)));
387
388
        //
389
        // Decrement the BYTE counter.
390
        //
391
        ulCount--;
392
    }
393
394
  //
395
  // Set the chip select bit (disable)
396
  //
397
  // send_cmd(0xE3); (nop command)
398
  OLED_CMD_PORT |= (1<<CS_DISP);
399
}
400
401
//*****************************************************************************
402
//
403
//! Clears the OLED display.
404
//!
405
//! This function will clear the display RAM.  All pixels in the display will
406
//! be turned off.
407
//!
408
//! \return None.
409
//
410
//*****************************************************************************
411
void SSD1329_Clear(void) {
412
413
    //static const unsigned char pucCommand1[] = { 0x15, 0, 63 };
414
    //static const unsigned char pucCommand2[] = { 0x75, 0, 127 };
415
    unsigned long ulRow, ulColumn;
416
417
    //
418
    // Clear out the buffer used for sending bytes to the display.
419
    //
420
    *(unsigned long *)&g_pucBuffer[0] = 0;
421
    *(unsigned long *)&g_pucBuffer[4] = 0;
422
423
    //
424
    // Set the window to fill the entire display.
425
    //
426
    //SSD1329_WriteCommand(pucCommand1, sizeof(pucCommand1));
427
    //SSD1329_WriteCommand(pucCommand2, sizeof(pucCommand2));
428
    SSD1329_WriteCommand(g_puc_SSD1329_HorizontalInc, sizeof(g_puc_SSD1329_HorizontalInc));
429
430
    //
431
    // Loop through the rows
432
    //
433
    for(ulRow = 0; ulRow < 96; ulRow++) {
434
435
        //
436
        // Loop through the columns.  Each byte is two pixels,
437
        // and the buffer hold 8 bytes, so 16 pixels are cleared
438
        // at a time.
439
        //
440
        for(ulColumn = 0; ulColumn < 128; ulColumn += 8 * 2) {
441
442
            //
443
            // Write 8 clearing bytes to the display, which will
444
            // clear 16 pixels across.
445
            //
446
            //SSD1329_WriteData(g_pucBuffer, sizeof(g_pucBuffer));
447
      SSD1329_WriteData(g_pucBuffer, sizeof(g_pucBuffer));
448
        }
449
    }
450
}
451
452
//*****************************************************************************
453
//
454
//! Displays a string on the OLED display.
455
//!
456
//! \param pcStr is a pointer to the string to display.
457
//! \param ulX is the horizontal position to display the string, specified in
458
//! columns from the left edge of the display.
459
//! \param ulY is the vertical position to display the string, specified in
460
//! rows from the top edge of the display.
461
//! \param ucLevel is the 4-bit gray scale value to be used for displayed text.
462
//!
463
//! This function will draw a string on the display.  Only the ASCII characters
464
//! between 32 (space) and 126 (tilde) are supported; other characters will
465
//! result in random data being draw on the display (based on whatever appears
466
//! before/after the font in memory).  The font is mono-spaced, so characters
467
//! such as ``i'' and ``l'' have more white space around them than characters
468
//! such as ``m'' or ``w''.
469
//!
470
//! If the drawing of the string reaches the right edge of the display, no more
471
//! characters will be drawn.  Therefore, special care is not required to avoid
472
//! supplying a string that is ``too long'' to display.
473
//!
474
//! \note Because the OLED display packs 2 pixels of data in a single byte, the
475
//! parameter \e ulX must be an even column number (for example, 0, 2, 4, and
476
//! so on).
477
//!
478
//! \return None.
479
//
480
//*****************************************************************************
481
void SSD1329_StringDraw(const char *pcStr, unsigned long ulX,
482
                      unsigned long ulY, unsigned char ucLevel) {
483
484
    unsigned long ulIdx1, ulIdx2;
485
    unsigned char ucTemp;
486
487
    //
488
    // Check the arguments.
489
    //
490
    assert(ulX < 128);
491
    assert((ulX & 1) == 0);
492
    assert(ulY < 96);
493
    assert(ucLevel < 16);
494
495
    //
496
    // Setup a window starting at the specified column and row, ending
497
    // at the right edge of the display and 8 rows down (single character row).
498
    //
499
    g_pucBuffer[0] = 0x15;
500
    g_pucBuffer[1] = ulX / 2;
501
    g_pucBuffer[2] = 63;
502
    SSD1329_WriteCommand(g_pucBuffer, 3);
503
    g_pucBuffer[0] = 0x75;
504
    g_pucBuffer[1] = ulY;
505
    g_pucBuffer[2] = ulY + 7;
506
    SSD1329_WriteCommand(g_pucBuffer, 3);
507
    SSD1329_WriteCommand(g_puc_SSD1329_VerticalInc, sizeof(g_puc_SSD1329_VerticalInc));
508
509
    //
510
    // Loop while there are more characters in the string.
511
    //
512
    while(*pcStr != 0) {
513
514
        //
515
        // Get a working copy of the current character and convert to an
516
        // index into the character bit-map array.
517
        //
518
        ucTemp = *pcStr++ & 0x7f;
519
520
        if(ucTemp < ' ') {
521
522
            ucTemp = 0;
523
        
524
    } else {
525
526
            ucTemp -= ' ';
527
        }
528
529
        //
530
        // Build and display the character buffer.
531
        //
532
        for(ulIdx1 = 0; ulIdx1 < 6; ulIdx1 += 2) {
533
534
            //
535
            // Convert two columns of 1-bit font data into a single data
536
            // byte column of 4-bit font data.
537
            //
538
            for(ulIdx2 = 0; ulIdx2 < 8; ulIdx2++) {
539
540
                g_pucBuffer[ulIdx2] = 0;
541
                if(g_pucFont[ucTemp][ulIdx1] & (1 << ulIdx2)) {
542
543
                    g_pucBuffer[ulIdx2] = (ucLevel << 4) & 0xf0;
544
                }
545
                if((ulIdx1 < 4) && (g_pucFont[ucTemp][ulIdx1 + 1] & (1 << ulIdx2))) {
546
547
                    g_pucBuffer[ulIdx2] |= (ucLevel << 0) & 0x0f;
548
                }
549
            }
550
551
            //
552
            // Send this byte column to the display.
553
            //
554
            SSD1329_WriteData(g_pucBuffer, 8);
555
            ulX += 2;
556
557
            //
558
            // Return if the right side of the display has been reached.
559
            //
560
            if(ulX == 128) {
561
562
                return;
563
            }
564
        }
565
    }
566
}
567
568
//*****************************************************************************
569
//
570
//! Displays a double size string on the OLED display.
571
//
572
//*****************************************************************************
573
void SSD1329_DoubleStringDraw(const char *pcStr, unsigned long ulX,
574
                      unsigned long ulY, unsigned char ucLevel) {
575
576
    //unsigned long ulIdx1, ulIdx2;
577
  unsigned long zeilen, spalten;
578
    //unsigned char ucTemp;
579
  unsigned char character;
580
  // ulIdx1 = spalten
581
  // ulIdx2 = zeilen
582
583
584
    //
585
    // Check the arguments.
586
    //
587
    assert(ulX < 128);
588
    assert((ulX & 1) == 0);
589
    assert(ulY < 96);
590
    assert(ucLevel < 16);
591
592
    //
593
    // Setup a window starting at the specified column and row, ending
594
    // at the right edge of the display and 8 rows down (single character row).
595
    //
596
    g_pucBuffer[0] = 0x15;
597
    g_pucBuffer[1] = ulX / 2;
598
    g_pucBuffer[2] = 63;
599
    SSD1329_WriteCommand(g_pucBuffer, 3);
600
    g_pucBuffer[0] = 0x75;
601
    g_pucBuffer[1] = ulY;
602
    g_pucBuffer[2] = ulY + 7;
603
    SSD1329_WriteCommand(g_pucBuffer, 3);
604
    SSD1329_WriteCommand(g_puc_SSD1329_VerticalInc, sizeof(g_puc_SSD1329_VerticalInc));
605
606
    //
607
    // Loop while there are more characters in the string.
608
    //
609
    while(*pcStr != 0) {
610
611
        //
612
        // Get a working copy of the current character and convert to an
613
        // index into the character bit-map array.
614
        //
615
        character = *pcStr++ & 0x7f;
616
617
        if(character < ' ') {
618
619
            character = 0;
620
        
621
    } else {
622
623
            character -= ' ';
624
        }
625
626
        //
627
        // Build and display the character buffer.
628
        //
629
        for(spalten = 0; spalten < 6; spalten += 2) {
630
631
            //
632
            // Convert two columns of 1-bit font data into a single data
633
            // byte column of 4-bit font data.
634
            //
635
            for(zeilen = 0; zeilen < 8; zeilen++) {
636
637
                g_pucBuffer[zeilen] = 0;
638
                if(g_pucFont[character][spalten] & (1 << zeilen)) {
639
640
                    g_pucBuffer[zeilen] = (ucLevel << 4) & 0xf0;
641
                }
642
                if((spalten < 4) && (g_pucFont[character][spalten + 1] & (1 << zeilen))) {
643
644
                    g_pucBuffer[zeilen] |= (ucLevel << 0) & 0x0f;
645
                }
646
            }
647
648
            //
649
            // Send this byte column to the display.
650
            //
651
            SSD1329_WriteData(g_pucBuffer, 8);
652
            ulX += 2;
653
654
            //
655
            // Return if the right side of the display has been reached.
656
            //
657
            if(ulX == 128) {
658
659
                return;
660
            }
661
        }
662
    }
663
}
664
665
//*****************************************************************************
666
//
667
//! Displays an image on the OLED display.
668
//!
669
//! \param pucImage is a pointer to the image data.
670
//! \param ulX is the horizontal position to display this image, specified in
671
//! columns from the left edge of the display.
672
//! \param ulY is the vertical position to display this image, specified in
673
//! rows from the top of the display.
674
//! \param ulWidth is the width of the image, specified in columns.
675
//! \param ulHeight is the height of the image, specified in rows.
676
//!
677
//! This function will display a bitmap graphic on the display.  Because of the
678
//! format of the display RAM, the starting column (\e ulX) and the number of
679
//! columns (\e ulWidth) must be an integer multiple of two.
680
//!
681
//! The image data is organized with the first row of image data appearing left
682
//! to right, followed immediately by the second row of image data.  Each byte
683
//! contains the data for two columns in the current row, with the leftmost
684
//! column being contained in bits 7:4 and the rightmost column being contained
685
//! in bits 3:0.
686
//!
687
//! For example, an image six columns wide and seven scan lines tall would
688
//! be arranged as follows (showing how the twenty one bytes of the image would
689
//! appear on the display):
690
//!
691
//! \verbatim
692
//!     +-------------------+-------------------+-------------------+
693
//!     |      Byte 0       |      Byte 1       |      Byte 2       |
694
//!     +---------+---------+---------+---------+---------+---------+
695
//!     | 7 6 5 4 | 3 2 1 0 | 7 6 5 4 | 3 2 1 0 | 7 6 5 4 | 3 2 1 0 |
696
//!     +---------+---------+---------+---------+---------+---------+
697
//!     |      Byte 3       |      Byte 4       |      Byte 5       |
698
//!     +---------+---------+---------+---------+---------+---------+
699
//!     | 7 6 5 4 | 3 2 1 0 | 7 6 5 4 | 3 2 1 0 | 7 6 5 4 | 3 2 1 0 |
700
//!     +---------+---------+---------+---------+---------+---------+
701
//!     |      Byte 6       |      Byte 7       |      Byte 8       |
702
//!     +---------+---------+---------+---------+---------+---------+
703
//!     | 7 6 5 4 | 3 2 1 0 | 7 6 5 4 | 3 2 1 0 | 7 6 5 4 | 3 2 1 0 |
704
//!     +---------+---------+---------+---------+---------+---------+
705
//!     |      Byte 9       |      Byte 10      |      Byte 11      |
706
//!     +---------+---------+---------+---------+---------+---------+
707
//!     | 7 6 5 4 | 3 2 1 0 | 7 6 5 4 | 3 2 1 0 | 7 6 5 4 | 3 2 1 0 |
708
//!     +---------+---------+---------+---------+---------+---------+
709
//!     |      Byte 12      |      Byte 13      |      Byte 14      |
710
//!     +---------+---------+---------+---------+---------+---------+
711
//!     | 7 6 5 4 | 3 2 1 0 | 7 6 5 4 | 3 2 1 0 | 7 6 5 4 | 3 2 1 0 |
712
//!     +---------+---------+---------+---------+---------+---------+
713
//!     |      Byte 15      |      Byte 16      |      Byte 17      |
714
//!     +---------+---------+---------+---------+---------+---------+
715
//!     | 7 6 5 4 | 3 2 1 0 | 7 6 5 4 | 3 2 1 0 | 7 6 5 4 | 3 2 1 0 |
716
//!     +---------+---------+---------+---------+---------+---------+
717
//!     |      Byte 18      |      Byte 19      |      Byte 20      |
718
//!     +---------+---------+---------+---------+---------+---------+
719
//!     | 7 6 5 4 | 3 2 1 0 | 7 6 5 4 | 3 2 1 0 | 7 6 5 4 | 3 2 1 0 |
720
//!     +---------+---------+---------+---------+---------+---------+
721
//! \endverbatim
722
//!
723
//! \return None.
724
//
725
//*****************************************************************************
726
void SSD1329_ImageDraw(const unsigned char *pucImage,   // data to display
727
             unsigned long ulX,        // x-position
728
                       unsigned long ulY,         // y-position
729
             unsigned long ulWidth,      // width of the image
730
                       unsigned long ulHeight) {    // height of the image
731
732
    //
733
    // Check the arguments.
734
    //
735
    assert(ulX < 128);
736
    assert((ulX & 1) == 0);
737
    assert(ulY < 96);
738
    assert((ulX + ulWidth) <= 128);
739
    assert((ulY + ulHeight) <= 96);
740
    assert((ulWidth & 1) == 0);
741
742
    //
743
    // Setup a window starting at the specified column and row, and ending
744
    // at the column + width and row+height.
745
    //
746
    g_pucBuffer[0] = 0x15;
747
    g_pucBuffer[1] = ulX / 2;
748
    g_pucBuffer[2] = (ulX + ulWidth - 2) / 2;
749
    SSD1329_WriteCommand(g_pucBuffer, 3);
750
    g_pucBuffer[0] = 0x75;
751
    g_pucBuffer[1] = ulY;
752
    g_pucBuffer[2] = ulY + ulHeight - 1;
753
    SSD1329_WriteCommand(g_pucBuffer, 3);
754
    SSD1329_WriteCommand(g_puc_SSD1329_HorizontalInc, sizeof(g_puc_SSD1329_HorizontalInc));
755
756
    //
757
    // Loop while there are more rows to display.
758
    //
759
    while(ulHeight--) {
760
761
        //
762
        // Write this row of image data.
763
        //
764
        SSD1329_WriteData(pucImage, (ulWidth / 2));
765
766
    /*
767
        // Send this byte column to the display.
768
        //
769
        SSD1329_WriteData(g_pucBuffer, 8);
770
        ulX += 2;
771
    */
772
773
        //
774
        // Advance to the next row of the image.
775
        //
776
        pucImage += (ulWidth / 2);
777
    }
778
}
779
780
//*****************************************************************************
781
//
782
//! Initialize the OLED display.
783
//!
784
//! \param ulFrequency specifies the SSI Clock Frequency to be used.
785
//!
786
//! This function initializes the SSI interface to the OLED display and
787
//! configures the SSD1329 controller on the panel.
788
//!
789
//! \return None.
790
//
791
//*****************************************************************************
792
void SSD1329_Init() {
793
794
    unsigned long ulIdx;
795
796
  OLED_CMD_PORT &= ~(1<<RES_DISP);
797
  _delay_us(10);
798
  OLED_CMD_PORT |= (1<<RES_DISP);
799
800
    //
801
    // Clear the frame buffer.
802
    //
803
    SSD1329_Clear();
804
805
    //
806
    // Initialize the SSD1329 controller.  Loop through the initialization
807
    // sequence array, sending each command "string" to the controller.
808
    //
809
    for(ulIdx = 0; ulIdx < sizeof(g_puc_SSD1329_Init); ulIdx += g_puc_SSD1329_Init[ulIdx] + 1) {
810
811
        //
812
        // Send this command.
813
        //
814
        SSD1329_WriteCommand(g_puc_SSD1329_Init + ulIdx + 1, g_puc_SSD1329_Init[ulIdx] - 1);
815
    }
816
}