forked from KhaledMohamed118/Connect4Simulation
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathVirtualNokia5110.c
More file actions
1045 lines (985 loc) · 44.4 KB
/
Copy pathVirtualNokia5110.c
File metadata and controls
1045 lines (985 loc) · 44.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
// VirtualNokia5110.c
// Runs on LM4F120/TM4C123
// This virtual Nokia project only runs on the real board,
// Instead of having a real Nokia, this driver sends Nokia
// commands out the UART to TExaSdisplay
// The Nokia5110 is 48x84 black and white
// pixel LCD to display text, images, or other information.
// Daniel Valvano and Jonathan Valvano
// Font table, initialization, and other functions based
// off of Nokia_5110_Example from Spark Fun:
// 7-17-2011
// Spark Fun Electronics 2011
// Nathan Seidle
// http://dlnmh9ip6v2uc.cloudfront.net/datasheets/LCD/Monochrome/Nokia_5110_Example.pde
// December 28, 2014
/* This example accompanies the book
"Embedded Systems: Introduction to ARM Cortex M Microcontrollers"
ISBN: 978-1469998749, Jonathan Valvano, copyright (c) 2014
Copyright 2015 by Jonathan W. Valvano, valvano@mail.utexas.edu
You may use, edit, run or distribute this file
as long as the above copyright notice remains
THIS SOFTWARE IS PROVIDED "AS IS". NO WARRANTIES, WHETHER EXPRESS, IMPLIED
OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE.
VALVANO SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL,
OR CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
For more information about my classes, my research, and my books, see
http://users.ece.utexas.edu/~valvano/
*/
// Hardware
// VIRTUAL_NOKIA=0 means LaunchPad connected to a real Nokia 5110 LCD
// VIRTUAL_NOKIA=1 means LaunchPad connected to PC through debugging USB cable, TExaSdisplay running on PC with COM port open
#define VIRTUAL_NOKIA 0
#if VIRTUAL_NOKIA
#include "Nokia5110.h"
// UART2.c
// Runs on LM4F120/TM4C123
// Use UART0 to implement bidirectional data transfer to and from a
// computer running HyperTerminal. This time, interrupts and FIFOs
// are used.
// Daniel Valvano
// September 11, 2013
// Modified by EE345L students Charlie Gough && Matt Hawk
// Modified by EE345M students Agustinus Darmawan && Mingjie Qiu
/* This example accompanies the book
"Embedded Systems: Real Time Interfacing to Arm Cortex M Microcontrollers",
ISBN: 978-1463590154, Jonathan Valvano, copyright (c) 2013
Program 5.11 Section 5.6, Program 3.10
Copyright 2013 by Jonathan W. Valvano, valvano@mail.utexas.edu
You may use, edit, run or distribute this file
as long as the above copyright notice remains
THIS SOFTWARE IS PROVIDED "AS IS". NO WARRANTIES, WHETHER EXPRESS, IMPLIED
OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE.
VALVANO SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL,
OR CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
For more information about my classes, my research, and my books, see
http://users.ece.utexas.edu/~valvano/
*/
// U0Rx (VCP receive) connected to PA0
// U0Tx (VCP transmit) connected to PA1
// FIFO.h
// Runs on any computer
// Provide functions that initialize a FIFO, put data in, get data out,
// and return the current size. The file includes a transmit FIFO
// using index implementation and a receive FIFO using pointer
// implementation. Other index or pointer implementation FIFOs can be
// created using the macros supplied at the end of the file.
// Daniel Valvano
// June 16, 2011
/* This example accompanies the book
"Embedded Systems: Real Time Interfacing to the Arm Cortex M3",
ISBN: 978-1463590154, Jonathan Valvano, copyright (c) 2011
Programs 3.7, 3.8., 3.9 and 3.10 in Section 3.7
Copyright 2011 by Jonathan W. Valvano, valvano@mail.utexas.edu
You may use, edit, run or distribute this file
as long as the above copyright notice remains
THIS SOFTWARE IS PROVIDED "AS IS". NO WARRANTIES, WHETHER EXPRESS, IMPLIED
OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE.
VALVANO SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL,
OR CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
For more information about my classes, my research, and my books, see
http://users.ece.utexas.edu/~valvano/
*/
// macro to create an index FIFO
#define AddIndexFifo(NAME,SIZE,TYPE,SUCCESS,FAIL) \
unsigned long volatile NAME ## PutI; \
unsigned long volatile NAME ## GetI; \
TYPE static NAME ## Fifo [SIZE]; \
void NAME ## Fifo_Init(void){ long sr; \
sr = StartCritical(); \
NAME ## PutI = NAME ## GetI = 0; \
EndCritical(sr); \
} \
int NAME ## Fifo_Put (TYPE data){ \
if(( NAME ## PutI - NAME ## GetI ) & ~(SIZE-1)){ \
return(FAIL); \
} \
NAME ## Fifo[ NAME ## PutI &(SIZE-1)] = data; \
NAME ## PutI ## ++; \
return(SUCCESS); \
} \
int NAME ## Fifo_Get (TYPE *datapt){ \
if( NAME ## PutI == NAME ## GetI ){ \
return(FAIL); \
} \
*datapt = NAME ## Fifo[ NAME ## GetI &(SIZE-1)]; \
NAME ## GetI ## ++; \
return(SUCCESS); \
} \
unsigned short NAME ## Fifo_Size (void){ \
return ((unsigned short)( NAME ## PutI - NAME ## GetI )); \
}
// e.g.,
// AddIndexFifo(Tx,32,unsigned char, 1,0)
// SIZE must be a power of two
// creates TxFifo_Init() TxFifo_Get() and TxFifo_Put()
// macro to create a pointer FIFO
#define AddPointerFifo(NAME,SIZE,TYPE,SUCCESS,FAIL) \
TYPE volatile *NAME ## PutPt; \
TYPE volatile *NAME ## GetPt; \
TYPE static NAME ## Fifo [SIZE]; \
void NAME ## Fifo_Init(void){ long sr; \
sr = StartCritical(); \
NAME ## PutPt = NAME ## GetPt = &NAME ## Fifo[0]; \
EndCritical(sr); \
} \
int NAME ## Fifo_Put (TYPE data){ \
TYPE volatile *nextPutPt; \
nextPutPt = NAME ## PutPt + 1; \
if(nextPutPt == &NAME ## Fifo[SIZE]){ \
nextPutPt = &NAME ## Fifo[0]; \
} \
if(nextPutPt == NAME ## GetPt ){ \
return(FAIL); \
} \
else{ \
*( NAME ## PutPt ) = data; \
NAME ## PutPt = nextPutPt; \
return(SUCCESS); \
} \
} \
int NAME ## Fifo_Get (TYPE *datapt){ \
if( NAME ## PutPt == NAME ## GetPt ){ \
return(FAIL); \
} \
*datapt = *( NAME ## GetPt ## ++); \
if( NAME ## GetPt == &NAME ## Fifo[SIZE]){ \
NAME ## GetPt = &NAME ## Fifo[0]; \
} \
return(SUCCESS); \
} \
unsigned short NAME ## Fifo_Size (void){\
if( NAME ## PutPt < NAME ## GetPt ){ \
return ((unsigned short)( NAME ## PutPt - NAME ## GetPt + (SIZE*sizeof(TYPE)))/sizeof(TYPE)); \
} \
return ((unsigned short)( NAME ## PutPt - NAME ## GetPt )/sizeof(TYPE)); \
}
// e.g.,
// AddPointerFifo(Rx,32,unsigned char, 1,0)
// SIZE can be any size
// creates RxFifo_Init() RxFifo_Get() and RxFifo_Put()
#define NVIC_EN0_INT5 0x00000020 // Interrupt 5 enable
#define NVIC_EN0_R (*((volatile unsigned long *)0xE000E100)) // IRQ 0 to 31 Set Enable Register
#define NVIC_PRI1_R (*((volatile unsigned long *)0xE000E404)) // IRQ 4 to 7 Priority Register
#define GPIO_PORTA_AFSEL_R (*((volatile unsigned long *)0x40004420))
#define GPIO_PORTA_DEN_R (*((volatile unsigned long *)0x4000451C))
#define GPIO_PORTA_AMSEL_R (*((volatile unsigned long *)0x40004528))
#define GPIO_PORTA_PCTL_R (*((volatile unsigned long *)0x4000452C))
#define UART0_DR_R (*((volatile unsigned long *)0x4000C000))
#define UART0_FR_R (*((volatile unsigned long *)0x4000C018))
#define UART0_IBRD_R (*((volatile unsigned long *)0x4000C024))
#define UART0_FBRD_R (*((volatile unsigned long *)0x4000C028))
#define UART0_LCRH_R (*((volatile unsigned long *)0x4000C02C))
#define UART0_CTL_R (*((volatile unsigned long *)0x4000C030))
#define UART0_IFLS_R (*((volatile unsigned long *)0x4000C034))
#define UART0_IM_R (*((volatile unsigned long *)0x4000C038))
#define UART0_RIS_R (*((volatile unsigned long *)0x4000C03C))
#define UART0_ICR_R (*((volatile unsigned long *)0x4000C044))
#define UART_FR_RXFF 0x00000040 // UART Receive FIFO Full
#define UART_FR_TXFF 0x00000020 // UART Transmit FIFO Full
#define UART_FR_RXFE 0x00000010 // UART Receive FIFO Empty
#define UART_LCRH_WLEN_8 0x00000060 // 8 bit word length
#define UART_LCRH_FEN 0x00000010 // UART Enable FIFOs
#define UART_CTL_UARTEN 0x00000001 // UART Enable
#define UART_IFLS_RX1_8 0x00000000 // RX FIFO >= 1/8 full
#define UART_IFLS_TX1_8 0x00000000 // TX FIFO <= 1/8 full
#define UART_IM_RTIM 0x00000040 // UART Receive Time-Out Interrupt
// Mask
#define UART_IM_TXIM 0x00000020 // UART Transmit Interrupt Mask
#define UART_IM_RXIM 0x00000010 // UART Receive Interrupt Mask
#define UART_RIS_RTRIS 0x00000040 // UART Receive Time-Out Raw
// Interrupt Status
#define UART_RIS_TXRIS 0x00000020 // UART Transmit Raw Interrupt
// Status
#define UART_RIS_RXRIS 0x00000010 // UART Receive Raw Interrupt
// Status
#define UART_ICR_RTIC 0x00000040 // Receive Time-Out Interrupt Clear
#define UART_ICR_TXIC 0x00000020 // Transmit Interrupt Clear
#define UART_ICR_RXIC 0x00000010 // Receive Interrupt Clear
#define SYSCTL_RCGC1_R (*((volatile unsigned long *)0x400FE104))
#define SYSCTL_RCGC2_R (*((volatile unsigned long *)0x400FE108))
#define SYSCTL_RCGC1_UART0 0x00000001 // UART0 Clock Gating Control
#define SYSCTL_RCGC2_GPIOA 0x00000001 // port A Clock Gating Control
void DisableInterrupts(void); // Disable interrupts
void EnableInterrupts(void); // Enable interrupts
long StartCritical (void); // previous I bit, disable interrupts
void EndCritical(long sr); // restore I bit to previous value
void WaitForInterrupt(void); // low power mode
#define RXFIFOSIZE 16 // size of the FIFOs (must be power of 2)
#define TXFIFOSIZE 512 // size of the FIFOs (must be power of 2)
#define FIFOSUCCESS 1 // return value on success
#define FIFOFAIL 0 // return value on failure
// create index implementation FIFO (see FIFO.h)
AddIndexFifo(Rx, RXFIFOSIZE, char, FIFOSUCCESS, FIFOFAIL)
AddIndexFifo(Tx, TXFIFOSIZE, char, FIFOSUCCESS, FIFOFAIL)
// Initialize UART0
// Baud rate is 115200 bits/sec
void UART_Init(void){
SYSCTL_RCGC1_R |= SYSCTL_RCGC1_UART0; // activate UART0
SYSCTL_RCGC2_R |= SYSCTL_RCGC2_GPIOA; // activate port A
RxFifo_Init(); // initialize empty FIFOs
TxFifo_Init();
UART0_CTL_R &= ~UART_CTL_UARTEN; // disable UART
UART0_IBRD_R = 43; // IBRD = int(80,000,000 / (16 * 115,200)) = int(43.4027)
UART0_FBRD_R = 26; // FBRD = round(0.4027 * 64) = 26
// 8 bit word length (no parity bits, one stop bit, FIFOs)
UART0_LCRH_R = (UART_LCRH_WLEN_8|UART_LCRH_FEN);
UART0_IFLS_R &= ~0x3F; // clear TX and RX interrupt FIFO level fields
// configure interrupt for TX FIFO <= 1/8 full
// configure interrupt for RX FIFO >= 1/8 full
UART0_IFLS_R += (UART_IFLS_TX1_8|UART_IFLS_RX1_8);
// enable TX and RX FIFO interrupts and RX time-out interrupt
UART0_IM_R |= (UART_IM_RXIM|UART_IM_TXIM|UART_IM_RTIM);
UART0_CTL_R |= UART_CTL_UARTEN; // enable UART
GPIO_PORTA_AFSEL_R |= 0x03; // enable alt funct on PA1-0
GPIO_PORTA_DEN_R |= 0x03; // enable digital I/O on PA1-0
// configure PA1-0 as UART
GPIO_PORTA_PCTL_R = (GPIO_PORTA_PCTL_R&0xFFFFFF00)+0x00000011;
GPIO_PORTA_AMSEL_R = 0; // disable analog functionality on PA
// UART0=priority 2
NVIC_PRI1_R = (NVIC_PRI1_R&0xFFFF00FF)|0x00004000; // bits 13-15
NVIC_EN0_R = NVIC_EN0_INT5; // enable interrupt 5 in NVIC
}
// copy from hardware RX FIFO to software RX FIFO
// stop when hardware RX FIFO is empty or software RX FIFO is full
void static copyHardwareToSoftware(void){
char letter;
while(((UART0_FR_R&UART_FR_RXFE) == 0) && (RxFifo_Size() < (RXFIFOSIZE - 1))){
letter = UART0_DR_R;
RxFifo_Put(letter);
}
}
// copy from software TX FIFO to hardware TX FIFO
// stop when software TX FIFO is empty or hardware TX FIFO is full
void static copySoftwareToHardware(void){
char letter;
while(((UART0_FR_R&UART_FR_TXFF) == 0) && (TxFifo_Size() > 0)){
TxFifo_Get(&letter);
UART0_DR_R = letter;
}
}
// input ASCII character from UART
// spin if RxFifo is empty
unsigned char UART_InChar(void){
char letter;
while(RxFifo_Get(&letter) == FIFOFAIL){};
return(letter);
}
// output ASCII character to UART
// spin if TxFifo is full
void UART_OutChar(unsigned char data){
while(TxFifo_Put(data) == FIFOFAIL){};
UART0_IM_R &= ~UART_IM_TXIM; // disable TX FIFO interrupt
copySoftwareToHardware();
UART0_IM_R |= UART_IM_TXIM; // enable TX FIFO interrupt
}
// at least one of three things has happened:
// hardware TX FIFO goes from 3 to 2 or less items
// hardware RX FIFO goes from 1 to 2 or more items
// UART receiver has timed out
void UART0_Handler(void){
if(UART0_RIS_R&UART_RIS_TXRIS){ // hardware TX FIFO <= 2 items
UART0_ICR_R = UART_ICR_TXIC; // acknowledge TX FIFO
// copy from software TX FIFO to hardware TX FIFO
copySoftwareToHardware();
if(TxFifo_Size() == 0){ // software TX FIFO is empty
UART0_IM_R &= ~UART_IM_TXIM; // disable TX FIFO interrupt
}
}
if(UART0_RIS_R&UART_RIS_RXRIS){ // hardware RX FIFO >= 2 items
UART0_ICR_R = UART_ICR_RXIC; // acknowledge RX FIFO
// copy from hardware RX FIFO to software RX FIFO
copyHardwareToSoftware();
}
if(UART0_RIS_R&UART_RIS_RTRIS){ // receiver timed out
UART0_ICR_R = UART_ICR_RTIC; // acknowledge receiver time out
// copy from hardware RX FIFO to software RX FIFO
copyHardwareToSoftware();
}
}
// Maximum dimensions of the LCD
#define MAX_X 84
#define MAX_Y 48
// Communication protocol
// message data action caused by
// 1 clear buffer, Nokia5110_ClearBuffer,
// 2,n set cursor, Y=bits 6-4(0-5),X=bits 3-0(0-11),Nokia5110_SetCursor
// 3,... draw full screen, 504 bytes are sent, Nokia5110_DrawFullImage
// 4,m,t,s,... send a BMP image first time, Nokia5110_PrintBMP
// 5,m,x,y redraw BMP image into buffer, Nokia5110_PrintBMP
// 6 punch up buffer onto display, Nokia5110_DisplayBuffer
// 7 clear LCD, Nokia5110_Clear
// 20-7F print that ASCII as 5 wide by 8 high, Nokia5110_OutChar
// definitions in the message protocol
// n is the cursor location from top left, Y=bits 6-4(0-5),X=bits 3-0(0-11)
// m is the BMP number from 0 to 255 representing which BMP is being sent, each BMP has a unique number
// x is the horizontal position of bottom left corner of image, columns from the left edge
// must be less than 84
// 0 is on the left; 82 is near the right
// y is the vertical position of bottom left corner of image, rows from the top edge
// t is the threshold grayscale colors above this number make corresponding pixel 'on'
// 0 to 14
// 0 is fine for ships, explosions, projectiles, and bunkers
// s is the number of words (4 bytes/word) in the 16-color BMP image including preamble
unsigned char *BMPtable[256]; // zero means unused, a pointer means this BMP has been previously sent
//********Nokia5110_Init*****************
// Initialize Nokia 5110 48x84 LCD by sending the proper
// commands to the PCD8544 driver.
// SSI baud clock must be less than 4 MHz, maximum of the Nokia 5110.
// inputs: none
// outputs: none
// assumes: system clock rate of 80 MHz
void Nokia5110_Init(void){unsigned long m;
UART_Init(); // UART0, 115200 bits/sec, interrupts
for(m=0; m<256; m++){
BMPtable[m] = (unsigned char *)0; // zero means entry is unused
}
}
//********Nokia5110_OutChar*****************
// Print a character to the Nokia 5110 48x84 LCD. The
// character will be printed at the current cursor position,
// the cursor will automatically be updated, and it will
// wrap to the next row or back to the top if necessary.
// One blank column of pixels will be printed on either side
// of the character for readability. Since characters are 8
// pixels tall and 5 pixels wide, 12 characters fit per row,
// and there are six rows.
// inputs: data character to print
// outputs: none
// assumes: LCD is in default horizontal addressing mode (V = 0)
void Nokia5110_OutChar(unsigned char data){
if((data>=0x20)&&(data<=0x7F)){
UART_OutChar(data); // pass printable ASCII character to PC
}
}
//********Nokia5110_OutString*****************
// Print a string of characters to the Nokia 5110 48x84 LCD.
// The string will automatically wrap, so padding spaces may
// be needed to make the output look optimal.
// inputs: ptr pointer to NULL-terminated ASCII string
// outputs: none
// assumes: LCD is in default horizontal addressing mode (V = 0)
void Nokia5110_OutString(char *ptr){
while(*ptr){
Nokia5110_OutChar((unsigned char)*ptr);
ptr = ptr + 1;
}
}
//********Nokia5110_OutUDec*****************
// Output a 16-bit number in unsigned decimal format with a
// fixed size of five right-justified digits of output.
// Inputs: n 16-bit unsigned number
// Outputs: none
// assumes: LCD is in default horizontal addressing mode (V = 0)
void Nokia5110_OutUDec(unsigned short n){
if(n < 10){
Nokia5110_OutString(" ");
Nokia5110_OutChar(n+'0'); /* n is between 0 and 9 */
} else if(n<100){
Nokia5110_OutString(" ");
Nokia5110_OutChar(n/10+'0'); /* tens digit */
Nokia5110_OutChar(n%10+'0'); /* ones digit */
} else if(n<1000){
Nokia5110_OutString(" ");
Nokia5110_OutChar(n/100+'0'); /* hundreds digit */
n = n%100;
Nokia5110_OutChar(n/10+'0'); /* tens digit */
Nokia5110_OutChar(n%10+'0'); /* ones digit */
}
else if(n<10000){
Nokia5110_OutChar(' ');
Nokia5110_OutChar(n/1000+'0'); /* thousands digit */
n = n%1000;
Nokia5110_OutChar(n/100+'0'); /* hundreds digit */
n = n%100;
Nokia5110_OutChar(n/10+'0'); /* tens digit */
Nokia5110_OutChar(n%10+'0'); /* ones digit */
}
else {
Nokia5110_OutChar(n/10000+'0'); /* ten-thousands digit */
n = n%10000;
Nokia5110_OutChar(n/1000+'0'); /* thousands digit */
n = n%1000;
Nokia5110_OutChar(n/100+'0'); /* hundreds digit */
n = n%100;
Nokia5110_OutChar(n/10+'0'); /* tens digit */
Nokia5110_OutChar(n%10+'0'); /* ones digit */
}
}
//********Nokia5110_SetCursor*****************
// Move the cursor to the desired X- and Y-position. The
// next character will be printed here. X=0 is the leftmost
// column. Y=0 is the top row.
// inputs: newX new X-position of the cursor (0<=newX<=11)
// newY new Y-position of the cursor (0<=newY<=5)
// outputs: none
void Nokia5110_SetCursor(unsigned char newX, unsigned char newY){
if((newX > 11) || (newY > 5)){ // bad input
return; // do nothing
}
// multiply newX by 7 because each character is 7 columns wide
// lcdwrite(COMMAND, 0x80|(newX*7)); // setting bit 7 updates X-position
// lcdwrite(COMMAND, 0x40|newY); // setting bit 6 updates Y-position
UART_OutChar(2); // set cursor command
UART_OutChar((newY<<4)|newX);
// bits 6,5,4 are Y(0 to 5), bits 3,2,1,0 are X (0 to 11)
}
//********Nokia5110_Clear*****************
// Clear the LCD by writing zeros to the entire screen and
// reset the cursor to (0,0) (top left corner of screen).
// inputs: none
// outputs: none
void Nokia5110_Clear(void){
UART_OutChar(7); // clear LCD command
Nokia5110_SetCursor(0, 0);
}
//********Nokia5110_DrawFullImage*****************
// Fill the whole screen by drawing a 48x84 bitmap image.
// inputs: ptr pointer to 504 byte bitmap
// outputs: none
// assumes: LCD is in default horizontal addressing mode (V = 0)
void Nokia5110_DrawFullImage(const char *ptr){
int i;
// TExaSdisplay will place image onto screen, no need for Nokia5110_SetCursor(0, 0);
UART_OutChar(3); // draw full image command
for(i=0; i<(MAX_X*MAX_Y/8); i=i+1){ // 504 bytes
UART_OutChar(ptr[i]);
}
}
//char Screen[SCREENW*SCREENH/8]; // buffer stores the next image to be printed on the screen
//********Nokia5110_PrintBMP*****************
// Bitmaps defined above were created for the LM3S1968 or
// LM3S8962's 4-bit grayscale OLED display. They also
// still contain their header data and may contain padding
// to preserve 4-byte alignment. This function takes a
// bitmap in the previously described format and puts its
// image data in the proper location in the buffer so the
// image will appear on the screen after the next call to
// Nokia5110_DisplayBuffer();
// The interface and operation of this process is modeled
// after RIT128x96x4_BMP(x, y, image);
// inputs: xpos horizontal position of bottom left corner of image, columns from the left edge
// must be less than 84
// 0 is on the left; 82 is near the right
// ypos vertical position of bottom left corner of image, rows from the top edge
// must be less than 48
// 2 is near the top; 47 is at the bottom
// ptr pointer to a 16 color BMP image
// threshold grayscale colors above this number make corresponding pixel 'on'
// 0 to 14
// 0 is fine for ships, explosions, projectiles, and bunkers
// outputs: none
void Nokia5110_PrintBMP(unsigned char xpos, unsigned char ypos, const unsigned char *ptr, unsigned char threshold){
long width = ptr[18], height = ptr[22], i, s, m;
// check for clipping
if((height <= 0) || // bitmap is unexpectedly encoded in top-to-bottom pixel order
((width%2) != 0) || // must be even number of columns
((xpos + width) > SCREENW) || // right side cut off
(ypos < (height - 1)) || // top cut off
(ypos > SCREENH)) { // bottom cut off
return;
}
if(threshold > 14){
threshold = 14; // only full 'on' turns pixel on
}
// next check to see if this BMP has been drawn before?
for(m=0; m<256 ; m++){
if(BMPtable[m]==ptr){ // matches previous transmission
UART_OutChar(5); // 5,m,x,y redraw BMP image into buffer
UART_OutChar(m);
UART_OutChar(xpos);
UART_OutChar(ypos);
return;
}
}
// first time for this BMP so log it in BMPtable
m = 0; // find first free empty space (over write entry 255 if needed)
while((m<255)&&BMPtable[m]){
m++;
}
BMPtable[m] = (unsigned char *)ptr; // log it in table
s = ptr[10]; // byte 10 contains the offset where image data can be found
for(i=1; i<=(width*height/2); i=i+1){
s = s + 1;
if((i%(width/2)) == 0){ // at the end of a row
// bitmaps are 32-bit word aligned
switch((width/2)%4){ // skip any padding
case 0: s = s + 0; break;
case 1: s = s + 3; break;
case 2: s = s + 2; break;
case 3: s = s + 1; break;
}
}
}
if(s>1020){
return; // max BMP size is 254 bytes
}
s = ((s+3)/4)*4; // round up to multiple of 4
UART_OutChar(4); // 4,m,t,s,... send a BMP image first time,
UART_OutChar(m);
UART_OutChar(threshold);
UART_OutChar(s/4); // size in words
for(i=0; i<s; i=i+1){
UART_OutChar(ptr[i]); // BMP data, still encoded
}
UART_OutChar(5); // 5,m,x,y redraw BMP image into buffer
UART_OutChar(m);
UART_OutChar(xpos);
UART_OutChar(ypos);
}
/*
void Nokia5110_PrintBMP_RealOne(unsigned char xpos, unsigned char ypos, const unsigned char *ptr, unsigned char threshold){
long width = ptr[18], height = ptr[22], i, j;
unsigned short screenx, screeny;
unsigned char mask;
// check for clipping
if((height <= 0) || // bitmap is unexpectedly encoded in top-to-bottom pixel order
((width%2) != 0) || // must be even number of columns
((xpos + width) > SCREENW) || // right side cut off
(ypos < (height - 1)) || // top cut off
(ypos > SCREENH)) { // bottom cut off
return;
}
if(threshold > 14){
threshold = 14; // only full 'on' turns pixel on
}
// bitmaps are encoded backwards, so start at the bottom left corner of the image
screeny = ypos/8;
screenx = xpos + SCREENW*screeny;
mask = ypos%8; // row 0 to 7
mask = 0x01<<mask; // now stores a mask 0x01 to 0x80
j = ptr[10]; // byte 10 contains the offset where image data can be found
for(i=1; i<=(width*height/2); i=i+1){
// the left pixel is in the upper 4 bits
if(((ptr[j]>>4)&0xF) > threshold){
Screen[screenx] |= mask;
} else{
Screen[screenx] &= ~mask;
}
screenx = screenx + 1;
// the right pixel is in the lower 4 bits
if((ptr[j]&0xF) > threshold){
Screen[screenx] |= mask;
} else{
Screen[screenx] &= ~mask;
}
screenx = screenx + 1;
j = j + 1;
if((i%(width/2)) == 0){ // at the end of a row
if(mask > 0x01){
mask = mask>>1;
} else{
mask = 0x80;
screeny = screeny - 1;
}
screenx = xpos + SCREENW*screeny;
// bitmaps are 32-bit word aligned
switch((width/2)%4){ // skip any padding
case 0: j = j + 0; break;
case 1: j = j + 3; break;
case 2: j = j + 2; break;
case 3: j = j + 1; break;
}
}
}
}
*/
// There is a buffer in RAM that holds one screen
// This routine clears this buffer
void Nokia5110_ClearBuffer(void){
UART_OutChar(1); // clear buffer command
}
//********Nokia5110_DisplayBuffer*****************
// Fill the whole screen by drawing a 48x84 screen image.
// inputs: none
// outputs: none
// assumes: LCD is in default horizontal addressing mode (V = 0)
void Nokia5110_DisplayBuffer(void){
UART_OutChar(6); // punch up buffer onto LCD
}
#else
// Nokia5110.c
// Runs on LM4F120/TM4C123
// Use SSI0 to send an 8-bit code to the Nokia5110 48x84
// pixel LCD to display text, images, or other information.
// Daniel Valvano
// September 16, 2013
// Font table, initialization, and other functions based
// off of Nokia_5110_Example from Spark Fun:
// 7-17-2011
// Spark Fun Electronics 2011
// Nathan Seidle
// http://dlnmh9ip6v2uc.cloudfront.net/datasheets/LCD/Monochrome/Nokia_5110_Example.pde
/* This example accompanies the book
"Embedded Systems: Introduction to ARM Cortex M Microcontrollers",
ISBN: 978-1469998749, Jonathan Valvano, copyright (c) 2014
Copyright 2014 by Jonathan W. Valvano, valvano@mail.utexas.edu
You may use, edit, run or distribute this file
as long as the above copyright notice remains
THIS SOFTWARE IS PROVIDED "AS IS". NO WARRANTIES, WHETHER EXPRESS, IMPLIED
OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE.
VALVANO SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL,
OR CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
For more information about my classes, my research, and my books, see
http://users.ece.utexas.edu/~valvano/
*/
// Blue Nokia 5110
// ---------------
// Signal (Nokia 5110) LaunchPad pin
// Reset (RST, pin 1) connected to PA7
// SSI0Fss (CE, pin 2) connected to PA3
// Data/Command (DC, pin 3) connected to PA6
// SSI0Tx (Din, pin 4) connected to PA5
// SSI0Clk (Clk, pin 5) connected to PA2
// 3.3V (Vcc, pin 6) power
// back light (BL, pin 7) not connected, consists of 4 white LEDs which draw ~80mA total
// Ground (Gnd, pin 8) ground
// Red SparkFun Nokia 5110 (LCD-10168)
// -----------------------------------
// Signal (Nokia 5110) LaunchPad pin
// 3.3V (VCC, pin 1) power
// Ground (GND, pin 2) ground
// SSI0Fss (SCE, pin 3) connected to PA3
// Reset (RST, pin 4) connected to PA7
// Data/Command (D/C, pin 5) connected to PA6
// SSI0Tx (DN, pin 6) connected to PA5
// SSI0Clk (SCLK, pin 7) connected to PA2
// back light (LED, pin 8) not connected, consists of 4 white LEDs which draw ~80mA total
#include "Nokia5110.h"
#define DC (*((volatile unsigned long *)0x40004100))
#define DC_COMMAND 0
#define DC_DATA 0x40
#define RESET (*((volatile unsigned long *)0x40004200))
#define RESET_LOW 0
#define RESET_HIGH 0x80
#define GPIO_PORTA_DIR_R (*((volatile unsigned long *)0x40004400))
#define GPIO_PORTA_AFSEL_R (*((volatile unsigned long *)0x40004420))
#define GPIO_PORTA_DEN_R (*((volatile unsigned long *)0x4000451C))
#define GPIO_PORTA_AMSEL_R (*((volatile unsigned long *)0x40004528))
#define GPIO_PORTA_PCTL_R (*((volatile unsigned long *)0x4000452C))
#define SSI0_CR0_R (*((volatile unsigned long *)0x40008000))
#define SSI0_CR1_R (*((volatile unsigned long *)0x40008004))
#define SSI0_DR_R (*((volatile unsigned long *)0x40008008))
#define SSI0_SR_R (*((volatile unsigned long *)0x4000800C))
#define SSI0_CPSR_R (*((volatile unsigned long *)0x40008010))
#define SSI0_CC_R (*((volatile unsigned long *)0x40008FC8))
#define SSI_CR0_SCR_M 0x0000FF00 // SSI Serial Clock Rate
#define SSI_CR0_SPH 0x00000080 // SSI Serial Clock Phase
#define SSI_CR0_SPO 0x00000040 // SSI Serial Clock Polarity
#define SSI_CR0_FRF_M 0x00000030 // SSI Frame Format Select
#define SSI_CR0_FRF_MOTO 0x00000000 // Freescale SPI Frame Format
#define SSI_CR0_DSS_M 0x0000000F // SSI Data Size Select
#define SSI_CR0_DSS_8 0x00000007 // 8-bit data
#define SSI_CR1_MS 0x00000004 // SSI Master/Slave Select
#define SSI_CR1_SSE 0x00000002 // SSI Synchronous Serial Port
// Enable
#define SSI_SR_BSY 0x00000010 // SSI Busy Bit
#define SSI_SR_TNF 0x00000002 // SSI Transmit FIFO Not Full
#define SSI_CPSR_CPSDVSR_M 0x000000FF // SSI Clock Prescale Divisor
#define SSI_CC_CS_M 0x0000000F // SSI Baud Clock Source
#define SSI_CC_CS_SYSPLL 0x00000000 // Either the system clock (if the
// PLL bypass is in effect) or the
// PLL output (default)
#define SYSCTL_RCGC1_R (*((volatile unsigned long *)0x400FE104))
#define SYSCTL_RCGC2_R (*((volatile unsigned long *)0x400FE108))
#define SYSCTL_RCGC1_SSI0 0x00000010 // SSI0 Clock Gating Control
#define SYSCTL_RCGC2_GPIOA 0x00000001 // port A Clock Gating Control
enum typeOfWrite{
COMMAND, // the transmission is an LCD command
DATA // the transmission is data
};
// The Data/Command pin must be valid when the eighth bit is
// sent. The SSI module has hardware input and output FIFOs
// that are 8 locations deep. Based on the observation that
// the LCD interface tends to send a few commands and then a
// lot of data, the FIFOs are not used when writing
// commands, and they are used when writing data. This
// ensures that the Data/Command pin status matches the byte
// that is actually being transmitted.
// The write command operation waits until all data has been
// sent, configures the Data/Command pin for commands, sends
// the command, and then waits for the transmission to
// finish.
// The write data operation waits until there is room in the
// transmit FIFO, configures the Data/Command pin for data,
// and then adds the data to the transmit FIFO.
// This is a helper function that sends an 8-bit message to the LCD.
// inputs: type COMMAND or DATA
// message 8-bit code to transmit
// outputs: none
// assumes: SSI0 and port A have already been initialized and enabled
void static lcdwrite(enum typeOfWrite type, char message){
if(type == COMMAND){
// wait until SSI0 not busy/transmit FIFO empty
while((SSI0_SR_R&SSI_SR_BSY)==SSI_SR_BSY){};
DC = DC_COMMAND;
SSI0_DR_R = message; // command out
// wait until SSI0 not busy/transmit FIFO empty
while((SSI0_SR_R&SSI_SR_BSY)==SSI_SR_BSY){};
} else{
while((SSI0_SR_R&SSI_SR_TNF)==0){}; // wait until transmit FIFO not full
DC = DC_DATA;
SSI0_DR_R = message; // data out
}
}
//********Nokia5110_Init*****************
// Initialize Nokia 5110 48x84 LCD by sending the proper
// commands to the PCD8544 driver. One new feature of the
// LM4F120 is that its SSIs can get their baud clock from
// either the system clock or from the 16 MHz precision
// internal oscillator.
// inputs: none
// outputs: none
// assumes: system clock rate of 80 MHz
void Nokia5110_Init(void){
volatile unsigned long delay;
SYSCTL_RCGC1_R |= SYSCTL_RCGC1_SSI0; // activate SSI0
SYSCTL_RCGC2_R |= SYSCTL_RCGC2_GPIOA; // activate port A
delay = SYSCTL_RCGC2_R; // allow time to finish activating
GPIO_PORTA_DIR_R |= 0xC0; // make PA6,7 out
GPIO_PORTA_AFSEL_R |= 0x2C; // enable alt funct on PA2,3,5
GPIO_PORTA_AFSEL_R &= ~0xC0; // disable alt funct on PA6,7
GPIO_PORTA_DEN_R |= 0xEC; // enable digital I/O on PA2,3,5,6,7
// configure PA2,3,5 as SSI
GPIO_PORTA_PCTL_R = (GPIO_PORTA_PCTL_R&0xFF0F00FF)+0x00202200;
// configure PA6,7 as GPIO
GPIO_PORTA_PCTL_R = (GPIO_PORTA_PCTL_R&0x00FFFFFF)+0x00000000;
GPIO_PORTA_AMSEL_R &= ~0xEC; // disable analog functionality on PA2,3,5,6,7
SSI0_CR1_R &= ~SSI_CR1_SSE; // disable SSI
SSI0_CR1_R &= ~SSI_CR1_MS; // master mode
// configure for system clock/PLL baud clock source
SSI0_CC_R = (SSI0_CC_R&~SSI_CC_CS_M)+SSI_CC_CS_SYSPLL;
// clock divider for 3.33 MHz SSIClk (80 MHz PLL/24)
// SysClk/(CPSDVSR*(1+SCR))
// 80/(24*(1+0)) = 3.33 MHz (slower than 4 MHz)
SSI0_CPSR_R = (SSI0_CPSR_R&~SSI_CPSR_CPSDVSR_M)+24; // must be even number
SSI0_CR0_R &= ~(SSI_CR0_SCR_M | // SCR = 0 (3.33 Mbps data rate)
SSI_CR0_SPH | // SPH = 0
SSI_CR0_SPO); // SPO = 0
// FRF = Freescale format
SSI0_CR0_R = (SSI0_CR0_R&~SSI_CR0_FRF_M)+SSI_CR0_FRF_MOTO;
// DSS = 8-bit data
SSI0_CR0_R = (SSI0_CR0_R&~SSI_CR0_DSS_M)+SSI_CR0_DSS_8;
SSI0_CR1_R |= SSI_CR1_SSE; // enable SSI
RESET = RESET_LOW; // reset the LCD to a known state
for(delay=0; delay<10; delay=delay+1);// delay minimum 100 ns
RESET = RESET_HIGH; // negative logic
lcdwrite(COMMAND, 0x21); // chip active; horizontal addressing mode (V = 0); use extended instruction set (H = 1)
// set LCD Vop (contrast), which may require some tweaking:
lcdwrite(COMMAND, CONTRAST); // try 0xB1 (for 3.3V red SparkFun), 0xB8 (for 3.3V blue SparkFun), 0xBF if your display is too dark, or 0x80 to 0xFF if experimenting
lcdwrite(COMMAND, 0x04); // set temp coefficient
lcdwrite(COMMAND, 0x14); // LCD bias mode 1:48: try 0x13 or 0x14
lcdwrite(COMMAND, 0x20); // we must send 0x20 before modifying the display control mode
lcdwrite(COMMAND, 0x0C); // set display control to normal mode: 0x0D for inverse
}
//********Nokia5110_OutChar*****************
// Print a character to the Nokia 5110 48x84 LCD. The
// character will be printed at the current cursor position,
// the cursor will automatically be updated, and it will
// wrap to the next row or back to the top if necessary.
// One blank column of pixels will be printed on either side
// of the character for readability. Since characters are 8
// pixels tall and 5 pixels wide, 12 characters fit per row,
// and there are six rows.
// inputs: data character to print
// outputs: none
// assumes: LCD is in default horizontal addressing mode (V = 0)
void Nokia5110_OutChar(unsigned char data){
int i;
lcdwrite(DATA, 0x00); // blank vertical line padding
for(i=0; i<5; i=i+1){
lcdwrite(DATA, ASCII[data - 0x20][i]);
}
lcdwrite(DATA, 0x00); // blank vertical line padding
}
//********Nokia5110_OutString*****************
// Print a string of characters to the Nokia 5110 48x84 LCD.
// The string will automatically wrap, so padding spaces may
// be needed to make the output look optimal.
// inputs: ptr pointer to NULL-terminated ASCII string
// outputs: none
// assumes: LCD is in default horizontal addressing mode (V = 0)
void Nokia5110_OutString(char *ptr){
while(*ptr){
Nokia5110_OutChar((unsigned char)*ptr);
ptr = ptr + 1;
}
}
//********Nokia5110_OutUDec*****************
// Output a 16-bit number in unsigned decimal format with a
// fixed size of five right-justified digits of output.
// Inputs: n 16-bit unsigned number
// Outputs: none
// assumes: LCD is in default horizontal addressing mode (V = 0)
void Nokia5110_OutUDec(unsigned short n){
if(n < 10){
Nokia5110_OutString(" ");
Nokia5110_OutChar(n+'0'); /* n is between 0 and 9 */
} else if(n<100){
Nokia5110_OutString(" ");
Nokia5110_OutChar(n/10+'0'); /* tens digit */
Nokia5110_OutChar(n%10+'0'); /* ones digit */
} else if(n<1000){
Nokia5110_OutString(" ");
Nokia5110_OutChar(n/100+'0'); /* hundreds digit */
n = n%100;
Nokia5110_OutChar(n/10+'0'); /* tens digit */
Nokia5110_OutChar(n%10+'0'); /* ones digit */
}
else if(n<10000){
Nokia5110_OutChar(' ');
Nokia5110_OutChar(n/1000+'0'); /* thousands digit */
n = n%1000;
Nokia5110_OutChar(n/100+'0'); /* hundreds digit */
n = n%100;
Nokia5110_OutChar(n/10+'0'); /* tens digit */
Nokia5110_OutChar(n%10+'0'); /* ones digit */
}
else {
Nokia5110_OutChar(n/10000+'0'); /* ten-thousands digit */
n = n%10000;
Nokia5110_OutChar(n/1000+'0'); /* thousands digit */
n = n%1000;
Nokia5110_OutChar(n/100+'0'); /* hundreds digit */
n = n%100;
Nokia5110_OutChar(n/10+'0'); /* tens digit */
Nokia5110_OutChar(n%10+'0'); /* ones digit */
}
}
//********Nokia5110_SetCursor*****************
// Move the cursor to the desired X- and Y-position. The
// next character will be printed here. X=0 is the leftmost
// column. Y=0 is the top row.
// inputs: newX new X-position of the cursor (0<=newX<=11)
// newY new Y-position of the cursor (0<=newY<=5)
// outputs: none
void Nokia5110_SetCursor(unsigned char newX, unsigned char newY){
if((newX > 11) || (newY > 5)){ // bad input
return; // do nothing
}
// multiply newX by 7 because each character is 7 columns wide
lcdwrite(COMMAND, 0x80|(newX*7)); // setting bit 7 updates X-position
lcdwrite(COMMAND, 0x40|newY); // setting bit 6 updates Y-position
}
//********Nokia5110_Clear*****************
// Clear the LCD by writing zeros to the entire screen and
// reset the cursor to (0,0) (top left corner of screen).
// inputs: none
// outputs: none
void Nokia5110_Clear(void){
int i;
for(i=0; i<(MAX_X*MAX_Y/8); i=i+1){
lcdwrite(DATA, 0x00);
}
Nokia5110_SetCursor(0, 0);
}
//********Nokia5110_DrawFullImage*****************
// Fill the whole screen by drawing a 48x84 bitmap image.
// inputs: ptr pointer to 504 byte bitmap
// outputs: none
// assumes: LCD is in default horizontal addressing mode (V = 0)
void Nokia5110_DrawFullImage(const char *ptr){
int i;
Nokia5110_SetCursor(0, 0);
for(i=0; i<(MAX_X*MAX_Y/8); i=i+1){
lcdwrite(DATA, ptr[i]);
}
}
char Screen[SCREENW*SCREENH/8]; // buffer stores the next image to be printed on the screen
//********Nokia5110_PrintBMP*****************
// Bitmaps defined above were created for the LM3S1968 or
// LM3S8962's 4-bit grayscale OLED display. They also
// still contain their header data and may contain padding
// to preserve 4-byte alignment. This function takes a
// bitmap in the previously described format and puts its
// image data in the proper location in the buffer so the
// image will appear on the screen after the next call to
// Nokia5110_DisplayBuffer();
// The interface and operation of this process is modeled
// after RIT128x96x4_BMP(x, y, image);
// inputs: xpos horizontal position of bottom left corner of image, columns from the left edge
// must be less than 84
// 0 is on the left; 82 is near the right
// ypos vertical position of bottom left corner of image, rows from the top edge
// must be less than 48
// 2 is near the top; 47 is at the bottom
// ptr pointer to a 16 color BMP image
// threshold grayscale colors above this number make corresponding pixel 'on'
// 0 to 14
// 0 is fine for ships, explosions, projectiles, and bunkers
// outputs: none
void Nokia5110_PrintBMP(unsigned char xpos, unsigned char ypos, const unsigned char *ptr, unsigned char threshold){
long width = ptr[18], height = ptr[22], i, j;
unsigned short screenx, screeny;
unsigned char mask;
// check for clipping
if((height <= 0) || // bitmap is unexpectedly encoded in top-to-bottom pixel order
((width%2) != 0) || // must be even number of columns
((xpos + width) > SCREENW) || // right side cut off
(ypos < (height - 1)) || // top cut off
(ypos > SCREENH)) { // bottom cut off
return;
}
if(threshold > 14){
threshold = 14; // only full 'on' turns pixel on
}
// bitmaps are encoded backwards, so start at the bottom left corner of the image
screeny = ypos/8;
screenx = xpos + SCREENW*screeny;
mask = ypos%8; // row 0 to 7
mask = 0x01<<mask; // now stores a mask 0x01 to 0x80
j = ptr[10]; // byte 10 contains the offset where image data can be found
for(i=1; i<=(width*height/2); i=i+1){
// the left pixel is in the upper 4 bits
if(((ptr[j]>>4)&0xF) > threshold){
Screen[screenx] |= mask;
} else{
Screen[screenx] &= ~mask;
}
screenx = screenx + 1;