AnsweredAssumed Answered

sample code of stm32 to initialize LCD(newhaven display)

Question asked by mao on Oct 29, 2015
Latest reply on Nov 22, 2017 by James Armstrong

I have been using LCD (glass on chip) made by newhaven display for a while. They provided sample code to initialize. However the code is mostly for microchip, not for STM32 hal drive.
Some people have been stuck on it. After I figured it out, I got the tricky skill to initialize it.
Here I post it on forum. Hope some people can benifit from it.

LCD is NHD-C0216CiZ-FN-FBW-3V, http://www.newhavendisplay.com/nhdc0216cizfnfbw3v-p-2301.html
Keil 5.16a, DFP2.6.

Code is generated by stm32cubemx, in which trigger is NOT used for i2c. Therefore the code is for polling mode(or blocking mode). I believe the trigger mode or DMA mode should work as long as you switch the transmit function.
Here is the tricky thing.

Initialization For ST7032i *  

*****************************************************/  
void init_LCD()  
{  
I2C_Start();  
I2C_out(0x7C);  
I2C_out(0x00);  
I2C_out(0x38);  
delay(10);  
I2C_out(0x39);  
delay(10);  
I2C_out(0x14);  
I2C_out(0x78);  
I2C_out(0x5E);  
I2C_out(0x6D);  
I2C_out(0x0C);  
I2C_out(0x01);  
I2C_out(0x06);  
delay(10);  
I2C_stop();  
}  
/*****************************************************/

 

The sample code first initialize the i2c bus, and then send many commands, and finally close the bus, I2c_stop().
While in STM32, the transmit function to send a data to the i2c will complete the whole loop(i2c start, i2c stop).
The tricky thing is that once you close the loop, you have to send a control byte again before you send an actual command. Therefore you have to send two byte(one is control byte and the other is command byte)together each time you send a command to the LCD. If you understand this, you have the key for LCD.

here is typical code to send a command:

// send one command char to the i2c.  
// it is very important that command control byte must be sent first to indicate the following byte is a command  
uint32_t SendOneByteCommandToI2C(uint8_t commandChar,  uint8_t i2c_address) 
    uint32_t rnt; 
    uint8_t command[2];  //send two bytes, one is to prepare command write, followed by lcd_clear command 
    command[0]=LCDcmdControlByte; //indicating for command writing. it is 0x00 for newhaven lcd 
    command[1]=commandChar;//followed by command char 
    rnt= SendCommandToI2C(command,2,LCDi2cAddr);TM_DelayMicros(5); 
    return rnt; 
}

I attached the complete code for LCD initialization.

uint32_t SendCommandToI2C(uint8_t *pData, uint16_t size, uint8_t i2c_address) 
    if(HAL_I2C_Master_Transmit(&hi2c1, (uint16_t)i2c_address, pData, size, 5000)!= HAL_OK) 
    
    /* Error_Handler() function is called when Timeout error occurs. 
       When Acknowledge failure occurs (Slave don't acknowledge it's address) 
       Master restarts communication */ 
    if (HAL_I2C_GetError(&hi2c1) != HAL_I2C_ERROR_AF) 
    
             errorcode=HAL_I2C_GetError(&hi2c1); 
            sprintf(errormsg,"Error occurs for LCD_clear. code=%d",errorcode); 
      Error_Handler(errormsg); 
            return errorcode; 
    
  
    return 0; 
    
// send one command char to the i2c.  
// it is very important that command control byte must be sent first to indicate the following byte is a command  
uint32_t SendOneByteCommandToI2C(uint8_t commandChar,  uint8_t i2c_address) 
    uint32_t rnt; 
    uint8_t command[2];  //send two bytes, one is to prepare command write, followed by lcd_clear command 
    command[0]=LCDcmdControlByte; //indicating for command writing 
    command[1]=commandChar;//followed by command char 
    rnt= SendCommandToI2C(command,2,LCDi2cAddr);TM_DelayMicros(5); 
    return rnt; 
    
// **************************** i2c polling definition ************** 
//LCD Display Section (for NHD-C0216CiZ-FN-FBW-3V) 
    
    
/*****************************************************/ 
//********************************************************* 
/* write a byte to the LCD in 8 bit mode */ 
    
//****************************************** 
//  Clear and home the LCD 
void lcd_clear(void
    SendOneByteCommandToI2C(0x01,LCDi2cAddr);TM_DelayMicros(5); 
    
//*************************************** 
//  Go to the specified position 
void lcd_goto(unsigned char pos) 
    uint8_t command[2];  //send two bytes, one is to prepare command write, followed by lcd_clear command 
    command[0]=LCDcmdControlByte; //indicating for command writing 
    command[1]=0x80+pos;    //for pos<=15    
    if(pos>15)  command[1]=0xC0+pos-16;//2nd line. the first letter of 2nd line is 0xC0=0x80+0x40  
    SendCommandToI2C(command,2,LCDi2cAddr);TM_DelayMicros(5); 
    
//******************************************* 
// write a string of chars to the LCD  
void lcd_puts(const char * s, unsigned char pos) 
    
    lcd_goto(pos); //go to the starting point 
    
    while(*s) 
    
        if(pos >31) break//can't be larger than 31 
        if(pos == 16)  
        {     
       lcd_goto(pos);         
    }   //go to the second line. 
        lcdwritech(*s++); 
        pos++;  //cursor needs to update because it will shift when key in one char. 
    
    TM_DelayMillis(1); 
    
//*************************************** 
//write a single char 
void lcdwritech(const unsigned char ch) 
    uint8_t command[2];  //send two bytes, one is to prepare command write, followed by lcd_clear command 
    command[0]=LCDDataControlByte; //indicating for command writing 
    command[1]=(uint8_t)ch; 
    SendCommandToI2C(command,2,LCDi2cAddr);TM_DelayMicros(5); 
    
/**************************************************** 
*           Initialization For ST7032i              * 
*****************************************************/ 
    
void InitNHDLCD()   
{  
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_SET); //enable the LCD. We use PB0 to control the reset pin of LCD 
// 
TM_DelayMillis(60);  // *************** highly required, because it requires a little bit for booting up 
    
SendOneByteCommandToI2C(0x38,LCDi2cAddr); //wake up 
TM_DelayMillis(20);  
SendOneByteCommandToI2C(0x39,LCDi2cAddr); // Function set; 8 bit, 2 lines, Instruction table 1 
TM_DelayMillis(20);  
SendOneByteCommandToI2C(0x14,LCDi2cAddr);TM_DelayMillis(2);  // Bias Set; BS 1/5; 2 lines 
SendOneByteCommandToI2C(0x70,LCDi2cAddr);TM_DelayMillis(2);  //contrast 
SendOneByteCommandToI2C(0x5E,LCDi2cAddr);TM_DelayMillis(2);   
SendOneByteCommandToI2C(0x6D,LCDi2cAddr); TM_DelayMillis(2); // Voltage follower and gain share  
TM_DelayMillis(1); 
SendOneByteCommandToI2C(0x0c ,LCDi2cAddr);  TM_DelayMillis(2);  
    
//SendOneByteCommandToI2C(0x70, LCDi2cAddr);    // contrast  . maximum light 
SendOneByteCommandToI2C(0x01,LCDi2cAddr); TM_DelayMillis(2);  
SendOneByteCommandToI2C(0x06,LCDi2cAddr); TM_DelayMillis(2);  
    
//the following is for testing only. it works 
strcpy(displayBuffer,"UltrasonicNozzleFreq=1952.9KHz."); 
lcd_puts(displayBuffer,0); //initial value 
    
}  
//************************************** 
// Hide Cursor. Indicating the display mode 
void HideCursor(void
    SendOneByteCommandToI2C(0x0c,LCDi2cAddr); 
    
//*************************************** 
// Show cursor. Indicating the edit mode 
void ShowCursor(unsigned char cursor) 
{    
        SendOneByteCommandToI2C(0x0F,LCDi2cAddr); 
}

Also I attached the code for i2c initialization.
Actually not did anything revision. It was created by cubemx.

Low level Initialization of i2c defined in hal_map.c

/* USER CODE BEGIN I2C1_MspInit 0 */ 
/* USER CODE END I2C1_MspInit 0 */ 
    
  /**I2C1 GPIO Configuration     
  PB6     ------> I2C1_SCL 
  PB7     ------> I2C1_SDA  
  */ 
      //original setting 
          
  GPIO_InitStruct.Pin = GPIO_PIN_6|GPIO_PIN_7; 
  GPIO_InitStruct.Mode = GPIO_MODE_AF_OD; //open drain, needs pull up resistor 
  GPIO_InitStruct.Pull = GPIO_NOPULL;// GPIO_PULLUP is also OK. We have a pull up resistor connected outside, so either one is OK 
  GPIO_InitStruct.Speed = GPIO_SPEED_HIGH; 
  GPIO_InitStruct.Alternate = GPIO_AF4_I2C1; 
  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); 
  // Peripheral clock enable 
__I2C1_CLK_ENABLE();

initialization code defined in main.c

/* I2C1 init function */ 
void MX_I2C1_Init(void
    
  hi2c1.Instance = I2C1; 
  hi2c1.Init.ClockSpeed = 100000; 
  hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2; 
  hi2c1.Init.OwnAddress1 = 20; 
  hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT; 
  hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLED; 
  hi2c1.Init.OwnAddress2 = 0; 
  hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLED; 
  hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLED; 
  HAL_I2C_Init(&hi2c1); 
    
}

Outcomes