Writing C++ for the STM32F0 to talk to an LCD

Thread Starter

brbeardm

Joined Oct 26, 2016
9
very helpful advice, thanks all. I'm reworking my breadboard right now to get everything more organized and make more room for the LCD. Once I get all this up and get this code working on the chip, I'll post an update

Mr. Software, thanks for the education on // comments. I noticed STM32CubeMX generated code uses the /* format and I was going to research that.

Cheers, Brian
 

Thread Starter

brbeardm

Joined Oct 26, 2016
9
Hit a roadblock. I have gone over my code and defines and wiring on the board checking it over and over. No luck My original blinky LED's that I need the oscilloscope work still work... but I can't get the LCD to do anything. It doesn't flash or blink or nothing... even when I reflash the chip... the screen just stays the same backlit with no activity and I've adjusted the contrast each time after I flash just to make sure I'm not missing something...

could it be the lack of delays? Here's my code now:

Code:
#include "main.h"
#include "stm32f2xx_hal.h"

/* LCD Control */
#define     LCD_DATA_PORT         GPIOD /* LCD Data */
#define     LCD_CONTROL_PORT     GPIOB
#define     RS         GPIO_PIN_4
#define     RW         GPIO_PIN_6
#define     EN         GPIO_PIN_7
#define     BF         GPIO_PIN_7

/* Private function prototypes -----------------------------------------------*/
static void MX_GPIO_Init(void);

/* function prototypes -------------------------------------------------------*/
void LCD_init(void);
void LCD_command(uint16_t);
void LCD_data(uint16_t);
void LCD_ready(void);
/* USER CODE END PFP */

int main(void)
{
  /* MCU Configuration-Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
    LCD_init();

  /* Infinite loop */
  while (1)
  {
        LCD_data(0x41);    /* output 'A' */
        HAL_Delay(500);

        /* Mr_blinky lights */
        GPIOC ->BSRR |= (GPIO_BSRR_BS_0 | GPIO_BSRR_BR_3); /* Turn pin C0 on and turn pin C3 off */
        HAL_Delay(250);
        GPIOC ->BSRR |= (GPIO_BSRR_BR_0 | GPIO_BSRR_BS_3); /* Turn pin C0 off and turn pin C3 on */
        HAL_Delay(250);
  }
}

static void MX_GPIO_Init(void)
{
  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOB_CLK_ENABLE();
  __HAL_RCC_GPIOC_CLK_ENABLE();
  __HAL_RCC_GPIOD_CLK_ENABLE();

    /* Set Data Direction for MrBlinky - two LED lights testing GPIO */
    GPIOC->MODER |= (GPIO_MODER_MODER0_0 | GPIO_MODER_MODER3_0);                            // Set PortC pins C0 and C3 to Output mode

    /* Set Data Direction for LCD D0-D7 */
    LCD_DATA_PORT->MODER |= (GPIO_MODER_MODER0_0 | GPIO_MODER_MODER1_0 | GPIO_MODER_MODER2_0 | GPIO_MODER_MODER3_0 | GPIO_MODER_MODER4_0 | GPIO_MODER_MODER5_0 | GPIO_MODER_MODER6_0 | GPIO_MODER_MODER7_0);

    /* Set Data Direction for LCD RW, RS, EN control pins */
    LCD_CONTROL_PORT->MODER |= (GPIO_MODER_MODER4_0 | GPIO_MODER_MODER6_0 | GPIO_MODER_MODER7_0);                    /* Set PortB pins B4, B6, B7 to Output mode */
}

void LCD_init(void)
{
  LCD_command(0x38); // initialize 8-bit mode
  LCD_command(0x06); // increment mode
  LCD_command(0x0C); // cursor off
  LCD_command(0x10); // cursor right
  LCD_command(0x01); // clear screen
}

// wait for LCD ready
void LCD_ready(void)
{
  GPIO_PinState busy;
  LCD_DATA_PORT->MODER = 0;  /* set as input */
  HAL_GPIO_WritePin(LCD_CONTROL_PORT, RW, GPIO_PIN_SET);
  HAL_GPIO_WritePin(LCD_CONTROL_PORT, RS, GPIO_PIN_RESET);
  do
  {
    HAL_GPIO_WritePin(LCD_CONTROL_PORT, EN, GPIO_PIN_SET);
    busy = HAL_GPIO_ReadPin(LCD_DATA_PORT, BF);
    HAL_GPIO_WritePin(LCD_CONTROL_PORT, EN, GPIO_PIN_RESET);
  } while (busy);
    LCD_DATA_PORT->MODER = 0x0000AAAA; /* set as 8-bit output */
}

/* send command to LCD instruction register */
void LCD_command(uint16_t ch)
{
  LCD_ready();
  LCD_DATA_PORT->ODR  = ch;
    HAL_GPIO_WritePin(LCD_CONTROL_PORT, (RS | RW), GPIO_PIN_RESET);
    HAL_GPIO_WritePin(LCD_CONTROL_PORT, EN, GPIO_PIN_SET);
    HAL_GPIO_WritePin(LCD_CONTROL_PORT, EN, GPIO_PIN_RESET);
}

void LCD_data(uint16_t ch)
{
  LCD_ready();
  LCD_DATA_PORT->ODR  = ch;  /* write data */
  HAL_GPIO_WritePin(LCD_CONTROL_PORT, RS, GPIO_PIN_SET);
    HAL_GPIO_WritePin(LCD_CONTROL_PORT, RW, GPIO_PIN_RESET);
    HAL_GPIO_WritePin(LCD_CONTROL_PORT, EN, GPIO_PIN_SET);
    HAL_GPIO_WritePin(LCD_CONTROL_PORT, EN, GPIO_PIN_RESET);
}
Youtube of the activity
 
Last edited:

MrChips

Joined Oct 2, 2009
35,040
Make sure you have a 0.1μF ceramic capacitor and a 10μF electrolytic capacitor across VDD and VSS at the LCD end of the cabling.

For now, temporarily replace the LCD_ready( ) statement with HAL_Delay(2) in the LCD_command( ) and LCD_data( ) functions.

Add HAL_Delay(200) as the last statement in the LCD_init( ) function.

Go back to using your old GPIO_init( ) function modified for using your new port assignments.

Code:
void GPIO_init()
{
    GPIO_InitTypeDef GPIO_InitStructure;

  __HAL_RCC_GPIOB_CLK_ENABLE();
  __HAL_RCC_GPIOC_CLK_ENABLE();
  __HAL_RCC_GPIOD_CLK_ENABLE();

    GPIO_InitStructure.Pin = RS | RW | EN;
    GPIO_InitStructure.Speed = GPIO_SPEED_HIGH;
    GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
    HAL_GPIO_Init(LCD_CONTROL_PORT, &GPIO_InitStructure);

    GPIO_InitStructure.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 | GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7;
    GPIO_InitStructure.Speed = GPIO_SPEED_HIGH;
    GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
    HAL_GPIO_Init(LCD_DATA_PORT, &GPIO_InitStructure);
}
 

dannyf

Joined Sep 13, 2015
2,197
I think you will find it much helpful to learn to write code the right way. Go back to the basics by reading the data sheet on how to initialize the LCD and then write code to initialize the LCD.
 

dannyf

Joined Sep 13, 2015
2,197
let me make this a little bit easier for you:

Code:
//gpio.c/.h

#define IO_SET(port, pins)  port->BSRR = (pins)  //set pins
#define IO_CLR(port, pins) port->BRR = (pins) //clear pins
then code your lcd.c/.h modules utilizing IO_SET/CLR

Code:
[LIST=1]
[*]/* send command to LCD instruction register */
[*]void LCD_command(uint16_t ch)
[*]{
[*]  LCD_ready();
[*]  LCD_OUT(ch);  //LCD_DATA_PORT->ODR  = ch;
[*]    IO_CLR(LCD_CONTROL_PORT, RS | RW);  //clear RS/RW  //HAL_GPIO_WritePin(LCD_CONTROL_PORT, (RS | RW), GPIO_PIN_RESET);
[*]    IO_SET(LCD_CONTROL_PORT, EN); //set en  //HAL_GPIO_WritePin(LCD_CONTROL_PORT, EN, GPIO_PIN_SET);
[*]    IO_CLR(LCD_CONTROL_PORT, EN); //clear en  //HAL_GPIO_WritePin(LCD_CONTROL_PORT, EN, GPIO_PIN_RESET);
[*]}
[*]
[/LIST]
you will need to write the LCD_OUT() routine/macro.

Always write your code to a logic port with logic pins. No hardware specific information in your user code.
 

Thread Starter

brbeardm

Joined Oct 26, 2016
9
Success! works great. I modified the code and added a function to send a string of characters to the display.


Mr. Chips, I got the LCD_Ready() function working by changing the LCD_DATA_PORT->MODER = 0x00005555; //for 8-bit output. after studying the data sheet. So I took out the two HAL_Delay(2); functions.
upload_2016-11-7_19-34-55.png
 
Last edited:

MrChips

Joined Oct 2, 2009
35,040
Well done! Pat yourself on the back for finding my silly mistake. I incorrectly had set the MODE bits to 10 instead of 01.
Note that you only need to change pin-7 from output to input and back to output, i.e., only bit-14 needs to be toggled between 1 and 0 and 1 again.
 
Top