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 | }
|