/* p3_2.c: Initialize and blink "HELLO" on the LCD using 8-bit data mode. * Polling of the busy bit of the LCD status register is used. * * Data pins use Port B07-00, control pins use Port A06-04. * * Tested with Atmel Studio 7 v7.0.1006 and Keil MDK-ARM v5.21a */ #include "samd21.h" #define RS 0x10 /* PA04 mask for Register Select*/ #define RW 0x20 /* PA05 mask for Read/Write */ #define EN 0x40 /* PA06 mask for Enable */ void delayMs(int n); void LCD_command(unsigned char command); void LCD_command_noPoll(unsigned char command); void LCD_data(unsigned char data); void LCD_init(void); void LCD_ready(void); int main(void) { LCD_init(); for(;;) { LCD_command(1); /* clear display */ delayMs(500); LCD_command(0x80); /* set cursor at beginning of first line */ LCD_data('H'); /* write the word "HELLO" */ LCD_data('E'); LCD_data('L'); LCD_data('L'); LCD_data('O'); delayMs(500); } } void LCD_init(void) { int i; unsigned char* ARRAY_PORT_PINCFG1 = (unsigned char*)®_PORT_PINCFG1; REG_PORT_DIRSET0 = RS | RW | EN; /* make PA06-04 pins output for control */ REG_PORT_DIRSET1 = 0x000000FF; /* make PB07-00 pins output for data */ for (i = 0; i < 8; i++) ARRAY_PORT_PINCFG1[i] |= 2; /* enable PB07-00 input buffer */ delayMs(30); /* initialization sequence */ LCD_command_noPoll(0x30); /* LCD does not respond to status poll yet */ delayMs(5); LCD_command_noPoll(0x30); delayMs(1); LCD_command_noPoll(0x30); /* busy flag cannot be polled before this command */ LCD_command(0x38); /* set 8-bit data, 2-line, 5x7 font */ LCD_command(0x06); /* move cursor right after each char */ LCD_command(0x01); /* clear screen, move cursor to home */ LCD_command(0x0F); /* turn on display, cursor blinking */ } /* This function waits until LCD controller is ready to * accept a new command/data before returns. * It polls the busy bit of the status register of the LCD controller. * In order to read the status register, the data port of the * microcontroller has to switch direction to input before reading * the LCD. The data port of the microcontroller is returned to * output port before the end of this function. */ void LCD_ready(void) { char status; /* change to read configuration to poll the status register */ REG_PORT_DIRCLR1 = 0x000000FF; /* make PB7-0 pins input */ REG_PORT_OUTCLR0 = RS; /* RS = 0 */ REG_PORT_OUTSET0 = RW; /* R/W = 1 */ do { /* stay in the loop until it is not busy */ REG_PORT_OUTSET0 = EN; /* pulse E high */ delayMs(0); status = REG_PORT_IN1; /* read status */ REG_PORT_OUTCLR0 = EN; /* clear E */ delayMs(0); } while (status & 0x80); /* check busy bit */ /* return to default write configuration */ REG_PORT_OUTCLR0 = RW; /* R/W = 1 */ REG_PORT_DIRSET1 = 0x000000FF; /* make PB7-0 pins output */ } /* This function waits for LCD controller ready before issuing * the next command. */ void LCD_command(unsigned char command) { LCD_ready(); /* wait for LCD controller ready */ REG_PORT_OUTCLR0 = (RS | RW); /* RS = 0, R/W = 0 */ REG_PORT_OUTCLR1 = 0xFF; /* clear data bus */ REG_PORT_OUTSET1 = command; /* put command on data bus */ REG_PORT_OUTSET0 = EN; /* pulse E high */ delayMs(0); REG_PORT_OUTCLR0 = EN; /* clear E */ } /* This function is used at the beginning of the initialization * when the busy bit of the status register is not readable. */ void LCD_command_noPoll(unsigned char command) { REG_PORT_OUTCLR0 = (RS | RW); /* RS = 0, R/W = 0 */ REG_PORT_OUTCLR1 = 0xFF; /* clear data bus */ REG_PORT_OUTSET1 = command; /* put command on data bus */ REG_PORT_OUTSET0 = EN; /* pulse E high */ delayMs(0); REG_PORT_OUTCLR0 = EN; /* clear E */ } /* This function waits for LCD controller ready before issuing * the next data. */ void LCD_data(unsigned char data) { LCD_ready(); /* wait for LCD controller ready */ REG_PORT_OUTSET0 = RS; /* RS = 1 */ REG_PORT_OUTCLR0 = RW; /* R/W = 0 */ REG_PORT_OUTCLR1 = 0xFF; /* clear data bus */ REG_PORT_OUTSET1 = data; /* put command on data bus */ REG_PORT_OUTSET0 = EN; /* pulse E high */ delayMs(0); REG_PORT_OUTCLR0 = EN; /* clear E */ } /* millisecond delay based on 1 MHz system clock */ void delayMs(int n) { int i; for (; n > 0; n--) for (i = 0; i < 199; i++) __asm("nop"); }