This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

How use NOKIA LCD5110 with TIVA C TM4C123GXL

Other Parts Discussed in Thread: ENERGIA

Hello, I need to use a Nokia 5110 display with a TM4C123GXL TIVA for a project.

I found a ready with the implementation code. I copied the code snippets for just a single file, compiled and no error appears, but nothing is shown on the display screen. The pin-out as shown in this code, have re-checked everything. But my difficulty is to understand the code that actually appear the test text on the screen.

The code that I got to adapt this at this link (users.ece.utexas.edu/.../arm) -> Ctrl + F -> 5110

#include <stdint.h>
#include <stdbool.h>
#include "driverlib/sysctl.h"
//#include "inc/hw_memmap.h"
//#include "inc/hw_types.h"
//#include "inc/hw_gpio.h"
//#include "driverlib/gpio.h"
//#include "inc/tm4c123gh6pm.h"
//#include "driverlib/pin_map.h" //Mapping of peripherals to pins for all parts. "GPIOPinTypeUART"
//#include "driverlib/uart.h"

/* *************************** Pinagem | Pinou***************************
// 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
 */

/*
SYSDIV2  Divisor  Clock (MHz)
 0        1       reserved
 1        2       reserved
 2        3       reserved
 3        4       reserved
 4        5       80.000
 5        6       66.667
 6        7       reserved
 7        8       50.000
 8        9       44.444
 9        10      40.000
 10       11      36.364
 11       12      33.333
 12       13      30.769
 13       14      28.571
 14       15      26.667
 15       16      25.000
 16       17      23.529
 17       18      22.222
 18       19      21.053
 19       20      20.000
 20       21      19.048
 21       22      18.182
 22       23      17.391
 23       24      16.667
 24       25      16.000
 25       26      15.385
 26       27      14.815
 27       28      14.286
 28       29      13.793
 29       30      13.333
 30       31      12.903
 31       32      12.500
 32       33      12.121
 33       34      11.765
 34       35      11.429
 35       36      11.111
 36       37      10.811
 37       38      10.526
 38       39      10.256
 39       40      10.000
 40       41      9.756
 41       42      9.524
 42       43      9.302
 43       44      9.091
 44       45      8.889
 45       46      8.696
 46       47      8.511
 47       48      8.333
 48       49      8.163
 49       50      8.000
 50       51      7.843
 51       52      7.692
 52       53      7.547
 53       54      7.407
 54       55      7.273
 55       56      7.143
 56       57      7.018
 57       58      6.897
 58       59      6.780
 59       60      6.667
 60       61      6.557
 61       62      6.452
 62       63      6.349
 63       64      6.250
 64       65      6.154
 65       66      6.061
 66       67      5.970
 67       68      5.882
 68       69      5.797
 69       70      5.714
 70       71      5.634
 71       72      5.556
 72       73      5.479
 73       74      5.405
 74       75      5.333
 75       76      5.263
 76       77      5.195
 77       78      5.128
 78       79      5.063
 79       80      5.000
 80       81      4.938
 81       82      4.878
 82       83      4.819
 83       84      4.762
 84       85      4.706
 85       86      4.651
 86       87      4.598
 87       88      4.545
 88       89      4.494
 89       90      4.444
 90       91      4.396
 91       92      4.348
 92       93      4.301
 93       94      4.255
 94       95      4.211
 95       96      4.167
 96       97      4.124
 97       98      4.082
 98       99      4.040
 99       100     4.000
 100      101     3.960
 101      102     3.922
 102      103     3.883
 103      104     3.846
 104      105     3.810
 105      106     3.774
 106      107     3.738
 107      108     3.704
 108      109     3.670
 109      110     3.636
 110      111     3.604
 111      112     3.571
 112      113     3.540
 113      114     3.509
 114      115     3.478
 115      116     3.448
 116      117     3.419
 117      118     3.390
 118      119     3.361
 119      120     3.333
 120      121     3.306
 121      122     3.279
 122      123     3.252
 123      124     3.226
 124      125     3.200
 125      126     3.175
 126      127     3.150
 127      128     3.125
 */


// *************************** Tamanho da tela | WINDOWS SIZE ***************************
#define SCREENW     84
#define SCREENH     48
// *************************** Definições | DEFINES ***************************
#define DC                      (*((volatile uint32_t *)0x40004100))
#define DC_COMMAND              0
#define DC_DATA                 0x40
#define RESET                   (*((volatile uint32_t *)0x40004200))
#define RESET_LOW               0
#define RESET_HIGH              0x80
#define GPIO_PORTA_DIR_R        (*((volatile uint32_t *)0x40004400))
#define GPIO_PORTA_AFSEL_R      (*((volatile uint32_t *)0x40004420))
#define GPIO_PORTA_DEN_R        (*((volatile uint32_t *)0x4000451C))
#define GPIO_PORTA_AMSEL_R      (*((volatile uint32_t *)0x40004528))
#define GPIO_PORTA_PCTL_R       (*((volatile uint32_t *)0x4000452C))
#define SSI0_CR0_R              (*((volatile uint32_t *)0x40008000))
#define SSI0_CR1_R              (*((volatile uint32_t *)0x40008004))
#define SSI0_DR_R               (*((volatile uint32_t *)0x40008008))
#define SSI0_SR_R               (*((volatile uint32_t *)0x4000800C))
#define SSI0_CPSR_R             (*((volatile uint32_t *)0x40008010))
#define SSI0_CC_R               (*((volatile uint32_t *)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 uint32_t *)0x400FE104))
#define SYSCTL_RCGC2_R          (*((volatile uint32_t *)0x400FE108))
#define SYSCTL_RCGC1_SSI0       0x00000010  // SSI0 Clock Gating Control
#define SYSCTL_RCGC2_GPIOA      0x00000001  // port A Clock Gating Control

// *************************** Definições Nokia5110.h | MORE DEFINES ***************************
#define MAX_X                   84
#define MAX_Y                   48
#define CONTRAST                0xB1

// *************************** Definições PLL | DEFINES PLL ***************************
#define SYSCTL_RIS_R            (*((volatile uint32_t *)0x400FE050))
#define SYSCTL_RIS_PLLLRIS      0x00000040  // PLL Lock Raw Interrupt Status
#define SYSCTL_RCC_R            (*((volatile uint32_t *)0x400FE060))
#define SYSCTL_RCC_XTAL_M       0x000007C0  // Crystal Value
#define SYSCTL_RCC_XTAL_6MHZ    0x000002C0  // 6 MHz Crystal
#define SYSCTL_RCC_XTAL_8MHZ    0x00000380  // 8 MHz Crystal
#define SYSCTL_RCC_XTAL_16MHZ   0x00000540  // 16 MHz Crystal
#define SYSCTL_RCC2_R           (*((volatile uint32_t *)0x400FE070))
#define SYSCTL_RCC2_USERCC2     0x80000000  // Use RCC2
#define SYSCTL_RCC2_DIV400      0x40000000  // Divide PLL as 400 MHz vs. 200
// MHz
#define SYSCTL_RCC2_SYSDIV2_M   0x1F800000  // System Clock Divisor 2
#define SYSCTL_RCC2_SYSDIV2LSB  0x00400000  // Additional LSB for SYSDIV2
#define SYSCTL_RCC2_PWRDN2      0x00002000  // Power-Down PLL 2
#define SYSCTL_RCC2_BYPASS2     0x00000800  // PLL Bypass 2
#define SYSCTL_RCC2_OSCSRC2_M   0x00000070  // Oscillator Source 2
#define SYSCTL_RCC2_OSCSRC2_MO  0x00000000  // MOSC

#define SYSDIV2 7
// *************************** Definições usadas no Exemplo ***************************
#define PIN_SCE   7 //Pin 3 on LCD
#define PIN_RESET 6 //Pin 4 on LCD
#define PIN_DC    5 //Pin 5 on LCD
#define PIN_SDIN  4 //Pin 6 on LCD
#define PIN_SCLK  3 //Pin 7 on LCD

//The DC pin tells the LCD if we are sending a command or data
#define LCD_COMMAND 0
#define LCD_DATA  1

//You may find a different size screen, but this one is 84 by 48 pixels
#define LCD_X     84
#define LCD_Y     48
// *************************** Enumerações, Constantes e Variáveis | ENUMS, CONSTANTS AND VARIABLES***************************
enum typeOfWrite{
	COMMAND,                              // the transmission is an LCD command
	DATA                                  // the transmission is data
};

// This table contains the hex values that represent pixels
// for a font that is 5 pixels wide and 8 pixels high
static const uint8_t ASCII[][5] = {
		{0x00, 0x00, 0x00, 0x00, 0x00} // 20
		,{0x00, 0x00, 0x5f, 0x00, 0x00} // 21 !
		,{0x00, 0x07, 0x00, 0x07, 0x00} // 22 "
		,{0x14, 0x7f, 0x14, 0x7f, 0x14} // 23 #
		,{0x24, 0x2a, 0x7f, 0x2a, 0x12} // 24 $
		,{0x23, 0x13, 0x08, 0x64, 0x62} // 25 %
		,{0x36, 0x49, 0x55, 0x22, 0x50} // 26 &
		,{0x00, 0x05, 0x03, 0x00, 0x00} // 27 '
		,{0x00, 0x1c, 0x22, 0x41, 0x00} // 28 (
		,{0x00, 0x41, 0x22, 0x1c, 0x00} // 29 )
		,{0x14, 0x08, 0x3e, 0x08, 0x14} // 2a *
		,{0x08, 0x08, 0x3e, 0x08, 0x08} // 2b +
		,{0x00, 0x50, 0x30, 0x00, 0x00} // 2c ,
		,{0x08, 0x08, 0x08, 0x08, 0x08} // 2d -
		,{0x00, 0x60, 0x60, 0x00, 0x00} // 2e .
		,{0x20, 0x10, 0x08, 0x04, 0x02} // 2f /
		,{0x3e, 0x51, 0x49, 0x45, 0x3e} // 30 0
		,{0x00, 0x42, 0x7f, 0x40, 0x00} // 31 1
		,{0x42, 0x61, 0x51, 0x49, 0x46} // 32 2
		,{0x21, 0x41, 0x45, 0x4b, 0x31} // 33 3
		,{0x18, 0x14, 0x12, 0x7f, 0x10} // 34 4
		,{0x27, 0x45, 0x45, 0x45, 0x39} // 35 5
		,{0x3c, 0x4a, 0x49, 0x49, 0x30} // 36 6
		,{0x01, 0x71, 0x09, 0x05, 0x03} // 37 7
		,{0x36, 0x49, 0x49, 0x49, 0x36} // 38 8
		,{0x06, 0x49, 0x49, 0x29, 0x1e} // 39 9
		,{0x00, 0x36, 0x36, 0x00, 0x00} // 3a :
		,{0x00, 0x56, 0x36, 0x00, 0x00} // 3b ;
		,{0x08, 0x14, 0x22, 0x41, 0x00} // 3c <
		,{0x14, 0x14, 0x14, 0x14, 0x14} // 3d =
		,{0x00, 0x41, 0x22, 0x14, 0x08} // 3e >
		,{0x02, 0x01, 0x51, 0x09, 0x06} // 3f ?
		,{0x32, 0x49, 0x79, 0x41, 0x3e} // 40 @
		,{0x7e, 0x11, 0x11, 0x11, 0x7e} // 41 A
		,{0x7f, 0x49, 0x49, 0x49, 0x36} // 42 B
		,{0x3e, 0x41, 0x41, 0x41, 0x22} // 43 C
		,{0x7f, 0x41, 0x41, 0x22, 0x1c} // 44 D
		,{0x7f, 0x49, 0x49, 0x49, 0x41} // 45 E
		,{0x7f, 0x09, 0x09, 0x09, 0x01} // 46 F
		,{0x3e, 0x41, 0x49, 0x49, 0x7a} // 47 G
		,{0x7f, 0x08, 0x08, 0x08, 0x7f} // 48 H
		,{0x00, 0x41, 0x7f, 0x41, 0x00} // 49 I
		,{0x20, 0x40, 0x41, 0x3f, 0x01} // 4a J
		,{0x7f, 0x08, 0x14, 0x22, 0x41} // 4b K
		,{0x7f, 0x40, 0x40, 0x40, 0x40} // 4c L
		,{0x7f, 0x02, 0x0c, 0x02, 0x7f} // 4d M
		,{0x7f, 0x04, 0x08, 0x10, 0x7f} // 4e N
		,{0x3e, 0x41, 0x41, 0x41, 0x3e} // 4f O
		,{0x7f, 0x09, 0x09, 0x09, 0x06} // 50 P
		,{0x3e, 0x41, 0x51, 0x21, 0x5e} // 51 Q
		,{0x7f, 0x09, 0x19, 0x29, 0x46} // 52 R
		,{0x46, 0x49, 0x49, 0x49, 0x31} // 53 S
		,{0x01, 0x01, 0x7f, 0x01, 0x01} // 54 T
		,{0x3f, 0x40, 0x40, 0x40, 0x3f} // 55 U
		,{0x1f, 0x20, 0x40, 0x20, 0x1f} // 56 V
		,{0x3f, 0x40, 0x38, 0x40, 0x3f} // 57 W
		,{0x63, 0x14, 0x08, 0x14, 0x63} // 58 X
		,{0x07, 0x08, 0x70, 0x08, 0x07} // 59 Y
		,{0x61, 0x51, 0x49, 0x45, 0x43} // 5a Z
		,{0x00, 0x7f, 0x41, 0x41, 0x00} // 5b [
		,{0x02, 0x04, 0x08, 0x10, 0x20} // 5c '\'
		,{0x00, 0x41, 0x41, 0x7f, 0x00} // 5d ]
		,{0x04, 0x02, 0x01, 0x02, 0x04} // 5e ^
		,{0x40, 0x40, 0x40, 0x40, 0x40} // 5f _
		,{0x00, 0x01, 0x02, 0x04, 0x00} // 60 `
		,{0x20, 0x54, 0x54, 0x54, 0x78} // 61 a
		,{0x7f, 0x48, 0x44, 0x44, 0x38} // 62 b
		,{0x38, 0x44, 0x44, 0x44, 0x20} // 63 c
		,{0x38, 0x44, 0x44, 0x48, 0x7f} // 64 d
		,{0x38, 0x54, 0x54, 0x54, 0x18} // 65 e
		,{0x08, 0x7e, 0x09, 0x01, 0x02} // 66 f
		,{0x0c, 0x52, 0x52, 0x52, 0x3e} // 67 g
		,{0x7f, 0x08, 0x04, 0x04, 0x78} // 68 h
		,{0x00, 0x44, 0x7d, 0x40, 0x00} // 69 i
		,{0x20, 0x40, 0x44, 0x3d, 0x00} // 6a j
		,{0x7f, 0x10, 0x28, 0x44, 0x00} // 6b k
		,{0x00, 0x41, 0x7f, 0x40, 0x00} // 6c l
		,{0x7c, 0x04, 0x18, 0x04, 0x78} // 6d m
		,{0x7c, 0x08, 0x04, 0x04, 0x78} // 6e n
		,{0x38, 0x44, 0x44, 0x44, 0x38} // 6f o
		,{0x7c, 0x14, 0x14, 0x14, 0x08} // 70 p
		,{0x08, 0x14, 0x14, 0x18, 0x7c} // 71 q
		,{0x7c, 0x08, 0x04, 0x04, 0x08} // 72 r
		,{0x48, 0x54, 0x54, 0x54, 0x20} // 73 s
		,{0x04, 0x3f, 0x44, 0x40, 0x20} // 74 t
		,{0x3c, 0x40, 0x40, 0x20, 0x7c} // 75 u
		,{0x1c, 0x20, 0x40, 0x20, 0x1c} // 76 v
		,{0x3c, 0x40, 0x30, 0x40, 0x3c} // 77 w
		,{0x44, 0x28, 0x10, 0x28, 0x44} // 78 x
		,{0x0c, 0x50, 0x50, 0x50, 0x3c} // 79 y
		,{0x44, 0x64, 0x54, 0x4c, 0x44} // 7a z
		,{0x00, 0x08, 0x36, 0x41, 0x00} // 7b {
		,{0x00, 0x00, 0x7f, 0x00, 0x00} // 7c |
		,{0x00, 0x41, 0x36, 0x08, 0x00} // 7d }
		,{0x10, 0x08, 0x08, 0x10, 0x08} // 7e ~
		//  ,{0x78, 0x46, 0x41, 0x46, 0x78} // 7f DEL
		,{0x1f, 0x24, 0x7c, 0x24, 0x1f} // 7f UT sign
};

uint8_t Screen[SCREENW*SCREENH/8]; // buffer stores the next image to be printed on the screen
const unsigned char Masks[8]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80}; //usado na função Nokia5110_ClrPxl

// *************************** Protótipos Funções ***************************
void static lcdwrite(enum typeOfWrite type, uint8_t message);
void static lcddatawrite(uint8_t data);
void Nokia5110_Init(void);
void Nokia5110_OutChar(char data);
void Nokia5110_OutString(char *ptr);
void Nokia5110_OutUDec(uint16_t n);
void Nokia5110_SetCursor(uint8_t newX, uint8_t newY);
void Nokia5110_Clear(void);
void Nokia5110_DrawFullImage(const uint8_t *ptr);
void Nokia5110_PrintBMP(uint8_t xpos, uint8_t ypos, const uint8_t *ptr, uint8_t threshold);
void Nokia5110_ClearBuffer(void);
void Nokia5110_DisplayBuffer(void);
void Nokia5110_ClrPxl(uint32_t i, uint32_t j);
void Nokia5110_SetPxl(uint32_t i, uint32_t j);
void PLL_Init(void);

// *************************** exemplo main.c ***************************
int main(void){
	uint32_t count = 0;
	PLL_Init();                           // set system clock to 50 MHz
	Nokia5110_Init();
	count = 0;
	Nokia5110_Clear();
	Nokia5110_OutString("************* LCD Test *************Letter: Num:------- ---- ");
	Nokia5110_OutChar(127);               // print UT sign
	while(1){
		Nokia5110_SetCursor(5, 5);          // five leading spaces, bottom row
		Nokia5110_OutChar((count%26)+'A');
		Nokia5110_OutChar(' ');
		Nokia5110_OutUDec(count);
		SysCtlDelay(103333333);                     // delay ~0.5 sec at 50 MHz
		count = count + 1;
	}
}

/* *************************** main.c ***************************

 */


// *************************** Implementação Funções | Implementation of functions ***************************
// 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, uint8_t 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
	}
}
void static lcddatawrite(uint8_t data){
	while((SSI0_SR_R&0x00000002)==0){}; // wait until transmit FIFO not full
	DC = DC_DATA;
	SSI0_DR_R = data;                // 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 uint32_t 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(char data){int i;
lcddatawrite(0x00);        // blank vertical line padding
for(i=0; i<5; i=i+1){
	lcddatawrite(ASCII[data - 0x20][i]);
}
lcddatawrite(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(uint16_t 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(uint8_t newX, uint8_t 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){
		lcddatawrite(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 uint8_t *ptr){
	int i;
	Nokia5110_SetCursor(0, 0);
	for(i=0; i<(MAX_X*MAX_Y/8); i=i+1){
		lcddatawrite(ptr[i]);
	}
}
uint8_t 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(uint8_t xpos, uint8_t ypos, const uint8_t *ptr, uint8_t threshold){
	int32_t width = ptr[18], height = ptr[22], i, j;
	uint16_t screenx, screeny;
	uint8_t 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){int i;
for(i=0; i<SCREENW*SCREENH/8; i=i+1){
	Screen[i] = 0;              // clear buffer
}
}

//********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){
	Nokia5110_DrawFullImage(Screen);
}

//------------Nokia5110_ClrPxl------------
// Clear the Image pixel at (i, j), turning it dark.
// Input: i  the row index  (0 to 47 in this case),    y-coordinate
//        j  the column index  (0 to 83 in this case), x-coordinate
// Output: none
void Nokia5110_ClrPxl(uint32_t i, uint32_t j){
	Screen[84*(i>>3) + j] &= ~Masks[i&0x07];
}
//------------Nokia5110_SetPxl------------
// Set the Image pixel at (i, j), turning it on.
// Input: i  the row index  (0 to 47 in this case),    y-coordinate
//        j  the column index  (0 to 83 in this case), x-coordinate
// Output: none
void Nokia5110_SetPxl(uint32_t i, uint32_t j){
	Screen[84*(i>>3) + j] |= Masks[i&0x07];
}

// configure the system to get its clock from the PLL
void PLL_Init(void){
	// 0) configure the system to use RCC2 for advanced features
	//    such as 400 MHz PLL and non-integer System Clock Divisor
	SYSCTL_RCC2_R |= SYSCTL_RCC2_USERCC2;
	// 1) bypass PLL while initializing
	SYSCTL_RCC2_R |= SYSCTL_RCC2_BYPASS2;
	// 2) select the crystal value and oscillator source
	SYSCTL_RCC_R &= ~SYSCTL_RCC_XTAL_M;   // clear XTAL field
	SYSCTL_RCC_R += SYSCTL_RCC_XTAL_16MHZ;// configure for 16 MHz crystal
	SYSCTL_RCC2_R &= ~SYSCTL_RCC2_OSCSRC2_M;// clear oscillator source field
	SYSCTL_RCC2_R += SYSCTL_RCC2_OSCSRC2_MO;// configure for main oscillator source
	// 3) activate PLL by clearing PWRDN
	SYSCTL_RCC2_R &= ~SYSCTL_RCC2_PWRDN2;
	// 4) set the desired system divider and the system divider least significant bit
	SYSCTL_RCC2_R |= SYSCTL_RCC2_DIV400;  // use 400 MHz PLL
	SYSCTL_RCC2_R = (SYSCTL_RCC2_R&~0x1FC00000) // clear system clock divider field
                		  + (SYSDIV2<<22);      // configure for 80 MHz clock
	// 5) wait for the PLL to lock by polling PLLLRIS
	while((SYSCTL_RIS_R&SYSCTL_RIS_PLLLRIS)==0){};
	// 6) enable use of PLL by clearing BYPASS
	SYSCTL_RCC2_R &= ~SYSCTL_RCC2_BYPASS2;
}

  • Hi john,

    I actually got a Nokia 5510 working a few days ago.
    I used a Energia library. Adapted to C (from C++) and changed the energia specific functions.

    I saw that one you are using but I hate the fact that it's in direct register access. Having 1 easy to use in hand I kicked that one right out.
    Do you usually use direct register access? Me and some users here do to like to encourage users to avoid that. The Tivaware libraries will do for 90% of the applications and make it so much easier for you to get help! I look at that and suddenly reading the 100 pages I have to read on BJTs seems like something much more pleasing to do (seriously, sorry but I am not gonna read all those lines!).

    The library uses bit-banging. The library is not my making so I would be happy to share it. If you make any improvements like adding methods (drawing circles and stuff like that) or adding functions to manage the strings in C I would appreciate if you come share it here :)
    So would you like to have it?
  • To the community:

    Does not the "horror" of forcing new users to employ, "Only or mostly" Direct Register program coding land solidly here - now? 

    Who (beyond Amit) of sound mind would review those hundreds of lines of, "arcane, immensely critical and spectacularly detailed" DRM code? 

    And - would any (future) employer be "pleased" to have the "new hire" - take ten times as long - yet produce NO usable results - and then present this "mass of patently unclear code" to a senior programmer/engineer for "rescue?"    Really - on what planet?

    The futility of this "DRM emphasized approach" is immensely magnified by the ready ease, speed-up, unlimited "function reach" and "time tested" results produced under the clear alternative, "API!"

    Might something in the "education" process be sadly/wildly, "out of whack?"    Some "awareness" of Register content & usage proves useful - but "over focus" upon DRM - at the neglect of the proven, "Problem Solving Efficiencies" provided by the API - causes grave concern!

  • I just had a discussion kinda DRM vs driver libraries with a friend... We too learn to use a MCU at the 4th year but with DRM only!! He will go there next year (probably). I will be in 1 or 2 years... and it's with PIC only... (I'm gonna cry in the corner if I have to learn that and never use it again)

    Says that the libraries prevent you from learning the hardware... I would say the opposite! Libraries allow for more time to focus in the interesting part of the hardware instead of losing time with those "basics". I hope the point I make here is clear. Basically you will have the code working fast with the libraries for the most part. When you need a advanced feature or some DRM only tricks (missing function, faster code) you can take time to learn that (with the time you saved) or learn some advanced features that the hardware allows you more quickly... Instead of reading register maps you will be reading features and implement them with driver libraries much faster. (repetition much? just 1 point here)
  • Let's look again at the wondrous DRM "code dump" those here are asked to "wade thru."

    #define GPIO_PORTA_DIR_R        (*((volatile uint32_t *)0x40004400))
    #define GPIO_PORTA_AFSEL_R      (*((volatile uint32_t *)0x40004420))
    #define GPIO_PORTA_DEN_R        (*((volatile uint32_t *)0x4000451C))
    #define GPIO_PORTA_AMSEL_R      (*((volatile uint32_t *)0x40004528))
    #define GPIO_PORTA_PCTL_R       (*((volatile uint32_t *)0x4000452C))
    #define SSI0_CR0_R              (*((volatile uint32_t *)0x40008000))
    #define SSI0_CR1_R              (*((volatile uint32_t *)0x40008004))

    I've cut/pasted 7 lines - not a single comment appears!   If - and only if - the MCU manual is open - and the "register du jour" is examined (assuming that its 32 bits of register description - fit comfortably upon a single page - not guaranteed) - then the line of uncommented code "may" make some sense.   But what's been learned?

    Do not facts in evidence show that such method is exhausting - eats time & effort - poster is too tired/distracted to, "attend to comments" OR the comments would require substantial direct "import" from the MCU manual - to fully define and/or (almost) clarify?     Really - what's been learned?

    Should the project change - be expanded - or an entirely new project begun - how much (if any) of this cryptographic code presentation may (safely) be reused?    Clearly such DRM focus provides little "speed-up" and "safety" for future reuse!   

    Can the single, DRM code line's, "32 potential command/control bits" possibly be remembered, or even described, w/out great & unwarranted, "extra time/effort!"    And this holds true for "each/every" line of DRM code! 

    Why has this, "Not been learned?"   It's obvious - is it not? 

    Time, funds and energy are limited - does not the clear "over-focus" upon Register "minutiae" seriously degrade the ability of the student/user to effectively deploy this/other MCUs in the real world?   Does not burying oneself in exhausting "register bit scrutiny" shift focus FAR from the real problem - which the MCU is tasked to solve?

    A far better method - the API - sits on the shelf - receives (apparently) too little, no, or after-thought mention.   Can this be good?

    To the poster: none of this is targeted at you - you're hapless/blameless - yet if "unsaid" - and you deliver such "cryptographic work product" while freshly, "on the job" - I cannot imagine too many of your co-workers being, "pleased."   Perhaps part of "education" should address, "Survival on the job!"

  • Hey Luis, I'd like to use the energia library for the Nokia5110. Can you post a link? I don't see it on your git hub or google page. THanks.