//********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_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 }
/** * prints C string data on LCD, this function is doing some simple * interpretation of some special characters in string, like \n \r or * backspace. Every carriage return or return character will move cursor * to line below current one and backspace character will move cursor to the * left until it reaches first character of the line. If string is longer, than * what LCD is capable to display, cursor wraps around and print will overwrite * existing text. * * @param LcdData_t* lcd handler structure address * @param char* data 0 terinated string * @return u8 bytes written * */ u8 lcdprint(LcdData_t *lcd, const char *data) { int i = 0; while (i < (lcd->organization.columns * lcd->organization.rows) && data[i]) { if (data[i] == '\n' || data[i] == '\r') { if (lcd->organization.rows > 1) //For one-liners we do not reset column //counter lcd->column = 0; lcd->row = (lcd->row + 1) % lcd->organization.rows; i++; continue; } else if (data[i] == 0x08) //BS { if (lcd->column > 0) lcd->column -= 1; i++; continue; } lcdcommand(lcd, LCD_DDRAM_SET | PTOMEMADDR(lcd, lcd->column, lcd->row)); lcdwrite(lcd, data[i]); i++; lcd->column = (lcd->column + 1) % lcd->organization.columns; if (lcd->column == 0) lcd->row = (lcd->row + 1) % lcd->organization.rows; } return (lcd->column + (lcd->row * lcd->organization.columns)); }
//********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]); } }
//********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); }
static ssize_t lcdi2c_char(struct device* dev, struct device_attribute* attr, const char* buf, size_t count) { u8 memaddr; CRIT_BEG(data, ERESTARTSYS); if (buf && count > 0) { memaddr = (1 + data->column + (data->row * data->organization.columns)) % LCD_BUFFER_SIZE; lcdwrite(data, buf[0]); data->column = (memaddr % data->organization.columns); data->row = (memaddr / data->organization.columns); lcdsetcursor(data, data->column, data->row); } CRIT_END(data); return 1; }
//********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 }
static long lcdi2c_ioctl(struct file *file, unsigned int ioctl_num, unsigned long arg) { char *buffer = (char*)arg, ccb[10]; u8 memaddr, i, ch; long status = SUCCESS; CRIT_BEG(data, EAGAIN); switch (ioctl_num) { case LCD_IOCTL_SETCHAR: get_user(ch, buffer); memaddr = (1 + data->column + (data->row * data->organization.columns)) % LCD_BUFFER_SIZE; lcdwrite(data, ch); data->column = (memaddr % data->organization.columns); data->row = (memaddr / data->organization.columns); lcdsetcursor(data, data->column, data->row); break; case LCD_IOCTL_GETCHAR: memaddr = (data->column + (data->row * data->organization.columns)) % LCD_BUFFER_SIZE; ch = data->buffer[memaddr]; put_user(ch, buffer); break; case LCD_IOCTL_GETPOSITION: printk(KERN_INFO "GETPOSITION called\n"); put_user(data->column, buffer); put_user(data->row, buffer+1); break; case LCD_IOCTL_SETPOSITION: get_user(data->column, buffer); get_user(data->row, buffer+1); lcdsetcursor(data, data->column, data->row); break; case LCD_IOCTL_RESET: get_user(ch, buffer); if (ch == '1') lcdinit(data, data->organization.topology); break; case LCD_IOCTL_HOME: printk(KERN_INFO "HOME called\n"); get_user(ch, buffer); if (ch == '1') lcdhome(data); break; case LCD_IOCTL_GETCURSOR: put_user(data->cursor ? '1' : '0', buffer); break; case LCD_IOCTL_SETCURSOR: get_user(ch, buffer); lcdcursor(data, (ch == '1')); break; case LCD_IOCTL_GETBLINK: put_user(data->blink ? '1' : '0', buffer); break; case LCD_IOCTL_SETBLINK: get_user(ch, buffer); lcdblink(data, (ch == '1')); break; case LCD_IOCTL_GETBACKLIGHT: put_user(data->backlight ? '1' : '0', buffer); break; case LCD_IOCTL_SETBACKLIGHT: get_user(ch, buffer); lcdsetbacklight(data, (ch == '1')); break; case LCD_IOCTL_SCROLLHZ: get_user(ch, buffer); lcdscrollhoriz(data, ch - '0'); break; case LCD_IOCTL_GETCUSTOMCHAR: get_user(ch, buffer); for (i=0; i<8; i++) put_user(data->customchars[ch][i], buffer + i + 1); break; case LCD_IOCTL_SETCUSTOMCHAR: for (i = 0; i < 9; i++) get_user(ccb[i], buffer + i); lcdcustomchar(data, ccb[0], ccb+1); break; case LCD_IOCTL_CLEAR: get_user(ch, buffer); if (ch == '1') lcdclear(data); break; default: printk(KERN_INFO "Unknown IOCTL\n"); break; } CRIT_END(data); return status; }