/* * Initialize LCD controller and flash "HELLO" on LCD * * The LCD controller of EduBase board is connected to * a shift register. * SCLK - PA5 * MOSI - PA7 * PA12 is used for slave select of the shift register. * * The connections between the shift register and LCD are * Bit 0 - RS (register select) * Bit 1 - E (enable) * * Bit 4 - Data 4 * Bit 5 - Data 5 * Bit 6 - Data 6 * Bit 7 - Data 7 * * For simplicity, all delay below 1 ms uses 1 ms. */ #include "stm32f4xx.h" #define RS 1 /* BIT0 mask for reg select */ #define EN 2 /* BIT1 mask for E */ void delayMs(int n); void LCD_nibble_write(char data, unsigned char control); void LCD_command(unsigned char command); void LCD_data(char data); void LCD_init(void); void SPI1_write(unsigned char data); int main(void) { /* initialize SPI1 that connects to the shift registers */ LCD_init(); while(1) { /* Write "HELLO" on LCD */ LCD_data('H'); LCD_data('E'); LCD_data('L'); LCD_data('L'); LCD_data('O'); delayMs(1000); /* clear LCD display */ LCD_command(1); delayMs(1000); } } /* configure SPI1 and the associated GPIO pins */ void LCD_init(void) { RCC->AHB1ENR |= 1; /* enable GPIOA clock */ RCC->AHB1ENR |= 4; /* enable GPIOC clock */ RCC->APB2ENR |= 0x1000; /* enable SPI1 clock */ /* PORTA 5, 7 for SPI1 MOSI and SCLK */ GPIOA->MODER &= ~0x0000CC00; /* clear pin mode */ GPIOA->MODER |= 0x00008800; /* set pin alternate mode */ GPIOA->AFR[0] &= ~0xF0F00000; /* clear alt mode */ GPIOA->AFR[0] |= 0x50500000; /* set alt mode SPI1 */ /* PA12 as GPIO output for SPI slave select */ GPIOA->MODER &= ~0x03000000; /* clear pin mode */ GPIOA->MODER |= 0x01000000; /* set pin output mode */ /* initialize SPI1 module */ SPI1->CR1 = 0x31F; SPI1->CR2 = 0; SPI1->CR1 |= 0x40; /* enable SPI1 module */ /* LCD controller reset sequence */ delayMs(20); LCD_nibble_write(0x30, 0); delayMs(5); LCD_nibble_write(0x30, 0); delayMs(1); LCD_nibble_write(0x30, 0); delayMs(1); LCD_nibble_write(0x20, 0); /* use 4-bit data mode */ delayMs(1); LCD_command(0x28); /* set 4-bit data, 2-line, 5x7 font */ LCD_command(0x06); /* move cursor right */ LCD_command(0x01); /* clear screen, move cursor to home */ LCD_command(0x0F); /* turn on display, cursor blinking */ } void LCD_nibble_write(char data, unsigned char control) { data &= 0xF0; /* clear lower nibble for control */ control &= 0x0F; /* clear upper nibble for data */ SPI1_write (data | control); /* RS = 0, R/W = 0 */ SPI1_write (data | control | EN); /* pulse E */ delayMs(0); SPI1_write (data); } void LCD_command(unsigned char command) { LCD_nibble_write(command & 0xF0, 0); /* upper nibble first */ LCD_nibble_write(command << 4, 0); /* then lower nibble */ if (command < 4) delayMs(2); /* command 1 and 2 needs up to 1.64ms */ else delayMs(1); /* all others 40 us */ } void LCD_data(char data) { LCD_nibble_write(data & 0xF0, RS); /* upper nibble first */ LCD_nibble_write(data << 4, RS); /* then lower nibble */ delayMs(1); } /* This function enables slave select, writes one byte to SPI1, */ /* wait for transmit complete and deassert slave select. */ void SPI1_write(unsigned char data) { while (!(SPI1->SR & 2)) {} /* wait until Transfer buffer Empty */ GPIOA->BSRR = 0x10000000; /* assert slave select */ SPI1->DR = data; /* write data */ while (SPI1->SR & 0x80) {} /* wait for transmission done */ GPIOA->BSRR = 0x00001000; /* deassert slave select */ } /* 16 MHz SYSCLK */ void delayMs(int n) { int i; for (; n > 0; n--) for (i = 0; i < 3195; i++) ; }