Subversion Repositories Projects

Rev

Rev 489 | Rev 519 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
331 cascade 1
/****************************************************************************
2
 *   Copyright (C) 2009 by Claas Anders "CaScAdE" Rathje                    *
3
 *   admiralcascade@gmail.com                                               *
4
 *   Project-URL: http://www.mylifesucks.de/oss/c-osd/                      *
5
 *                                                                          *
6
 *   This program is free software; you can redistribute it and/or modify   *
7
 *   it under the terms of the GNU General Public License as published by   *
8
 *   the Free Software Foundation; either version 2 of the License.         *
9
 *                                                                          *
10
 *   This program is distributed in the hope that it will be useful,        *
11
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of         *
12
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          *
13
 *   GNU General Public License for more details.                           *
14
 *                                                                          *
15
 *   You should have received a copy of the GNU General Public License      *
16
 *   along with this program; if not, write to the                          *
17
 *   Free Software Foundation, Inc.,                                        *
18
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.              *
19
 ****************************************************************************/
20
 
346 cascade 21
#include <avr/io.h>
22
#include <util/delay.h>
23
#include <avr/pgmspace.h> 
514 cascade 24
#include "main.h"
331 cascade 25
#include "max7456_software_spi.h"
26
 
27
/* ##########################################################################
28
 * MAX7456 SPI & Display stuff
29
 * ##########################################################################*/
30
 
31
/**
32
 * Send a byte through SPI
33
 */
34
void spi_send(uint8_t byte) {
35
    for (int8_t i = 7; i >= 0; i--) {
36
        if (((byte >> i) & 1)) {
37
            MAX_SDIN_HIGH
38
        } else {
39
            MAX_SDIN_LOW
40
        }
41
        MAX_SCLK_HIGH
42
        MAX_SCLK_LOW
43
    }
44
}
45
 
46
/**
47
 *  Send <byte> to <address> of MAX7456
48
 */
49
void spi_send_byte(uint8_t address, uint8_t byte) {
50
    // start sending
51
    MAX_CS_LOW
52
 
53
    spi_send(address);
54
    spi_send(byte);
55
 
56
    // end sending
57
    MAX_CS_HIGH
58
}
59
 
514 cascade 60
 
331 cascade 61
/**
62
 *  write a <character> to <address> of MAX7456 display memory
63
 */
64
void write_char(uint16_t address, char character) {
65
    spi_send_byte(0x05, (address & 0xFF00) >> 8); // DMAH
66
    spi_send_byte(0x06, (address & 0x00FF)); // DMAL
67
    spi_send_byte(0x07, character); // DMDI
68
}
69
 
514 cascade 70
 
331 cascade 71
/**
514 cascade 72
 *  clear display memory
73
 *  (also sets 8bit mode)
74
 */
75
void clear(void) {
76
    /*uint16_t memory_address = 0;
77
    for (unsigned int a = 0; a < 480; a++) {
78
        write_char(memory_address++, 0);
79
    }*/
80
        // clear all display-mem (DMM)
81
    spi_send_byte(0x04, 0b01000100);
82
 
83
    // clearing takes 12uS according to maxim so lets wait longer
84
    _delay_us(20);
85
}
86
 
87
 
88
/**
89
 * for testing write all chars to screen
90
 */
91
void write_all_chars() {
92
    uint16_t x = 3, y = 2, t = 0;
93
    while (t < 256) {
94
        write_char(x++ + y*30, t++);
95
        if (x > 25) {
96
            y++;
97
            x = 3;
98
        }
99
    }
100
}
101
 
102
#if !(ALLCHARSDEBUG|(WRITECHARS != -1))
103
 
104
/**
331 cascade 105
 *  write a character <attribute> to <address> of MAX7456 display memory
106
 */
107
void write_char_att(uint16_t address, char attribute) {
108
    // the only important part is that the DMAH[1] is set
109
    // so we add 2 which binary is the 2nd lowest byte
110
    spi_send_byte(0x05, ((address & 0xFF00) >> 8) | 2); // DMAH
111
    spi_send_byte(0x06, (address & 0x00FF)); // DMAL
112
    spi_send_byte(0x07, attribute); // DMDI
113
}
114
 
115
/**
116
 *  write a <character> at <x>/<y> to MAX7456 display memory
117
 */
118
void write_char_xy(uint8_t x, uint8_t y, char character) {
119
    uint16_t address = y * 30 + x;
120
    write_char(address, character);
121
}
122
 
123
/**
124
 *  write a  character <attribute> at <x>/<y> to MAX7456 display memory
125
 */
126
void write_char_att_xy(uint8_t x, uint8_t y, char attribute) {
127
    uint16_t address = y * 30 + x;
128
    write_char_att(address, attribute);
129
}
130
 
131
/**
514 cascade 132
 * let the MAX7456 learn a new character at <number>
133
 * with <data>.
331 cascade 134
 */
514 cascade 135
void learn_char(uint8_t number, unsigned char* data) {
136
    // select character to write (CMAH)
137
    spi_send_byte(0x09, number);
404 cascade 138
 
514 cascade 139
    for (uint8_t i = 0; i < 54; i++) {
140
        // select 4pixel byte of char (CMAL)
141
        spi_send_byte(0x0A, i);
142
 
143
        // write 4pixel byte of char (CMDI)
144
        spi_send_byte(0x0B, data[i]);
145
    }
146
 
147
    // write to the NVM array from the shadow RAM (CMM)
148
    spi_send_byte(0x08, 0b10100000);
149
 
150
    // according to maxim writing to nvram takes about 12ms, lets wait longer
151
    _delay_ms(120);
331 cascade 152
}
153
 
154
/**
155
 *  write an ascii <character> to <address> of MAX7456 display memory
156
 */
157
void write_ascii_char(uint16_t address, char c) {
158
    if (c == 32) c = 0; // remap space
159
    else if (c > 48 && c <= 57) c -= 48; // remap numbers
160
    else if (c == '0') c = 10; // remap zero
161
    else if (c >= 65 && c <= 90) c -= 54; // remap big letters
162
    else if (c >= 97 && c <= 122) c -= 60; // remap small letters
163
    else if (c == '(') c = 63; // remap
164
    else if (c == ')') c = 64; // remap
165
    else if (c == '.') c = 65; // remap
166
    else if (c == '?') c = 66; // remap
167
    else if (c == ';') c = 67; // remap
168
    else if (c == ':') c = 68; // remap
169
    else if (c == ',') c = 69; // remap
170
    else if (c == '\'') c = 70; // remap
171
    else if (c == '/') c = 71; // remap
172
    else if (c == '"') c = 72; // remap
173
    else if (c == '-') c = 73; // remap minus
174
    else if (c == '<') c = 74; // remap
175
    else if (c == '>') c = 75; // remap
176
    else if (c == '@') c = 76; // remap
177
    write_char(address, c);
178
}
179
 
180
/**
181
 *  write an ascii <string> at <x>/<y> to MAX7456 display memory
182
 */
183
void write_ascii_string(uint8_t x, uint8_t y, char *string) {
184
    while (*string) {
185
        write_ascii_char(((x++)+(y * 30)), *string);
186
        string++;
187
    }
188
}
189
 
190
/**
346 cascade 191
 *  write an ascii <string> from progmen at <x>/<y> to MAX7456 display memory
192
 */
489 woggle 193
void write_ascii_string_pgm(uint8_t x, uint8_t y, const char *string) {
346 cascade 194
        while (pgm_read_byte(string) != 0x00)
195
                write_ascii_char(((x++)+(y * 30)), pgm_read_byte(string++));
196
}
197
 
198
/**
379 cascade 199
 *  write an <string> from progmen at <x>/<y> downwards to MAX7456 display memory
200
 */
489 woggle 201
void write_string_pgm_down(uint8_t x, uint8_t y, const char *string, uint8_t length) {
379 cascade 202
        while (length--)
203
                write_char((x+(y++ * 30)), pgm_read_byte(string++));
204
}
205
 
206
/**
349 cascade 207
 * Write only some digits of a unsigned <number> at <x>/<y> to MAX7456 display memory
208
 * <num> represents the largest multiple of 10 that will still be displayable as
209
 * the first digit, so num = 10 will be 0-99 and so on
210
 * <pad> = 1 will cause blank spaced to be filled up with zeros e.g. 007 instead of   7
331 cascade 211
 */
349 cascade 212
void write_ndigit_number_u(uint8_t x, uint8_t y, uint16_t number, int16_t num, uint8_t pad) {
213
                // if number is largar than 99[..]9 we must decrease it
214
                while (number >= (num * 10)) {
215
                        number -= num * 10;
216
                }
331 cascade 217
 
349 cascade 218
                uint8_t started = 0;
331 cascade 219
 
349 cascade 220
                while (num > 0) {
221
                        uint8_t b = number / num;
222
                        if (b > 0 || started || num == 1) {
223
                            write_ascii_char((x++)+(y * 30), '0' + b);
224
                            started = 1;
225
                        } else {
226
                                if (pad) write_ascii_char((x++)+(y * 30), '0');
227
                                else write_ascii_char((x++)+(y * 30), 0);
228
                        }
229
                        number -= b * num;
230
 
231
                        num /= 10;
232
                }
331 cascade 233
}
234
 
235
/**
349 cascade 236
 * Write only some digits of a signed <number> at <x>/<y> to MAX7456 display memory
237
 * <num> represents the largest multiple of 10 that will still be displayable as
238
 * the first digit, so num = 10 will be 0-99 and so on
239
 * <pad> = 1 will cause blank spaced to be filled up with zeros e.g. 007 instead of   7
331 cascade 240
 */
349 cascade 241
void write_ndigit_number_s(uint8_t x, uint8_t y, int16_t number, int16_t num, uint8_t pad) {
242
    if (((uint16_t) number) > 32767) {
243
        number = number - 65536;
244
                num *= -1;
331 cascade 245
 
349 cascade 246
                // if number is smaller than -99[..]9 we must increase it
247
                while (number <= (num * 10)) {
248
                        number -= num * 10;
249
                }
331 cascade 250
 
349 cascade 251
                uint8_t started = 0;
331 cascade 252
 
349 cascade 253
                while (num < 0) {
254
                        uint8_t b = number / num;
255
                        if (pad) write_ascii_char((x)+(y * 30), '0');
256
                        if (b > 0 || started || num == 1) {
257
                                if (!started) write_char((x - 1)+(y * 30), 0x49);
258
                            write_ascii_char((x++)+(y * 30), '0' + b);
259
                            started = 1;
260
                        } else {
261
                                write_ascii_char((x++)+(y * 30), 0);
262
                        }
263
                        number -= b * num;
331 cascade 264
 
349 cascade 265
                        num /= 10;
266
                }
267
        } else {
268
        write_char((x)+(y * 30), 0);
269
        write_ndigit_number_u(x, y, number, num, pad);
331 cascade 270
    }
271
}
272
 
273
/**
349 cascade 274
 * Write only some digits of a unsigned <number> at <x>/<y> to MAX7456 display memory
275
 * as /10th of the value
276
 * <num> represents the largest multiple of 10 that will still be displayable as
277
 * the first digit, so num = 10 will be 0-99 and so on
278
 * <pad> = 1 will cause blank spaced to be filled up with zeros e.g. 007 instead of   7
331 cascade 279
 */
349 cascade 280
void write_ndigit_number_u_10th(uint8_t x, uint8_t y, uint16_t number, int16_t num, uint8_t pad) {
281
                // if number is largar than 99[..]9 we must decrease it
282
                while (number >= (num * 10)) {
283
                        number -= num * 10;
284
                }
285
 
331 cascade 286
 
349 cascade 287
                uint8_t started = 0;
288
                while (num > 0) {
289
                        uint8_t b = number / num;
290
                        if (b > 0 || started || num == 1) {
291
                                if ((num / 10) == 0) {
292
                                        if (!started) write_ascii_char((x - 1)+(y * 30), '0');
293
                                        write_char((x++)+(y * 30), 65); // decimal point
294
                                }
295
                                write_ascii_char((x++)+(y * 30), '0' + b);
296
                            started = 1;
297
                        } else {
298
                                if (pad) write_ascii_char((x++)+(y * 30), '0');
299
                                else write_ascii_char((x++)+(y * 30), ' ');
300
                        }
301
                        number -= b * num;
331 cascade 302
 
349 cascade 303
                        num /= 10;
304
                }
331 cascade 305
}
306
 
307
/**
349 cascade 308
 * Write only some digits of a signed <number> at <x>/<y> to MAX7456 display memory
309
 * as /10th of the value
310
 * <num> represents the largest multiple of 10 that will still be displayable as
311
 * the first digit, so num = 10 will be 0-99 and so on
312
 * <pad> = 1 will cause blank spaced to be filled up with zeros e.g. 007 instead of   7
331 cascade 313
 */
349 cascade 314
void write_ndigit_number_s_10th(uint8_t x, uint8_t y, int16_t number, int16_t num, uint8_t pad) {
315
    if (((uint16_t) number) > 32767) {
316
        number = number - 65536;
317
                num *= -1;
331 cascade 318
 
349 cascade 319
                // if number is smaller than -99[..]9 we must increase it
320
                while (number <= (num * 10)) {
321
                        number -= num * 10;
322
                }
331 cascade 323
 
349 cascade 324
                uint8_t started = 0;
331 cascade 325
 
349 cascade 326
                while (num < 0) {
327
                        uint8_t b = number / num;
328
                        if (pad) write_ascii_char((x)+(y * 30), '0');
329
                        if (b > 0 || started || num == 1) {
330
                                if ((num / 10) == 0) {
331
                                        if (!started) {
332
                                                write_ascii_char((x - 2)+(y * 30), '-');
333
                                                write_ascii_char((x - 1)+(y * 30), '0');
334
                                        }
335
                                        write_char((x++)+(y * 30), 65); // decimal point
336
                                } else if (!started) {
337
                                        write_char((x - 1)+(y * 30), 0x49); // minus
338
                                }
339
                            write_ascii_char((x++)+(y * 30), '0' + b);
340
                            started = 1;
341
                        } else {
342
                                write_ascii_char((x++)+(y * 30), 0);
343
                        }
344
                        number -= b * num;
345
 
346
                        num /= 10;
347
                }
348
        } else {
331 cascade 349
        write_char((x)+(y * 30), 0);
349 cascade 350
        write_ndigit_number_u_10th(x, y, number, num, pad);
331 cascade 351
    }
352
}
353
 
354
/**
355
 *  write <seconds> as human readable time at <x>/<y> to MAX7456 display mem
356
 */
357
void write_time(uint8_t x, uint8_t y, uint16_t seconds) {
358
    uint16_t min = seconds / 60;
359
    seconds -= min * 60;
349 cascade 360
    write_ndigit_number_u(x, y, min, 100, 0);
331 cascade 361
    write_char_xy(x + 3, y, 68);
349 cascade 362
    write_ndigit_number_u(x + 4, y, seconds, 10, 1);
331 cascade 363
}
364
 
365
/**
412 cascade 366
 * wirte a <position> at <x>/<y> assuming it is a gps position for long-/latitude
367
 */
368
void write_gps_pos(uint8_t x, uint8_t y, int32_t position) {
489 woggle 369
        if (position < 0) {
370
                position ^= ~0;
431 cascade 371
                position++;
412 cascade 372
                write_char_xy(x++, y, 0x49); // minus
373
        } else {
374
                write_char_xy(x++, y, 0); // clear ('+' would be nice, maybe later)
375
        }
376
        write_ndigit_number_u(x, y, (uint16_t) (position / (int32_t) 10000000), 100, 1);
377
        write_char_xy(x + 3, y, 65); // decimal point
378
        position = position - ((position / (int32_t) 10000000) * (int32_t) 10000000);
379
        write_ndigit_number_u(x + 4, y, (uint16_t) (position / (int32_t) 1000), 1000, 1);
380
        position = position - ((uint16_t) (position / (int32_t) 1000) * (int32_t) 1000);
381
        write_ndigit_number_u(x + 8, y, (uint16_t) position, 100, 1);
382
        write_char_xy(x + 11, y, 0xD0); // degree symbol
383
}
514 cascade 384
 
385
#endif