sample code of stm32 to initialize LCD(newhaven display)
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-2html
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 acontrol 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=199KHz.''
);
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);
}