2015-10-29 02:47 PM
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);
}
2017-01-31 02:39 AM
I am trying to go through code, I think there is a mistake in the function void
lcd_goto().
You have given start address in DDRAM as 0x80, when I checked ur LCD data sheet, the first line start address is 0x00 and the second line start address is 0x40.
Please verify if possible.
Thanks,
2017-01-31 04:48 AM
I have an LCD based on ST7036i controller. The LCD is NHD-C0220BIZ-FS(RGB)-FBW-3VM.
http://www.newhavendisplay.com/specs/NHD-C0220BiZ-FSRGB-FBW-3VM.pdf
Following is the code so far:
#define LCD_ADDRESS 0x78
uint8_t commands[2] = { 0x00, 0x00 };uint8_t data[2] = { 0x40, 0x00};HAL_StatusTypeDef halstatus = 0;
void Init_LCD()
{ HAL_GPIO_WritePin(GPIOB,GPIO_PIN_5, GPIO_PIN_SET); // make LCD_RST high to start LCD module HAL_Delay(60); halstatus = HAL_I2C_IsDeviceReady(&hi2c1,LCD_ADDRESS,2,100); printf('halstatus1 = %d\r\n',halstatus); commands[1] = 0x38; halstatus = HAL_I2C_Master_Transmit(&hi2c1, LCD_ADDRESS, commands, 2, 100); printf('halstatus2 = %d\r\n',halstatus); //HAL_Delay(20); HAL_Delay(60); commands[1] = 0x39; halstatus = HAL_I2C_Master_Transmit(&hi2c1,LCD_ADDRESS, commands, 2, 100); printf('halstatus3 = %d\r\n',halstatus); HAL_Delay(60); commands[1] = 0x14; halstatus = HAL_I2C_Master_Transmit(&hi2c1, LCD_ADDRESS, commands, 2, 100); printf('halstatus4 = %d\r\n', halstatus); HAL_Delay(60); commands[1] = 0x78; halstatus = HAL_I2C_Master_Transmit(&hi2c1, LCD_ADDRESS, commands, 2, 100); printf('halstatus5 = %d\r\n', halstatus); HAL_Delay(60); commands[1] = 0x5e; halstatus = HAL_I2C_Master_Transmit(&hi2c1, LCD_ADDRESS, commands, 2, 100); printf('halstatus6 = %d\r\n', halstatus); //HAL_Delay(2); HAL_Delay(60); commands[1] = 0x6d; halstatus = HAL_I2C_Master_Transmit(&hi2c1, LCD_ADDRESS, commands, 2, 100); printf('halstatus7 = %d\r\n', halstatus); HAL_Delay(60); commands[1] = 0x0c; halstatus = HAL_I2C_Master_Transmit(&hi2c1, LCD_ADDRESS, commands, 2, 100); printf('halstatus8= %d\r\n', halstatus); //HAL_Delay(2); HAL_Delay(60); commands[1] = 0x01; halstatus = HAL_I2C_Master_Transmit(&hi2c1, LCD_ADDRESS, commands, 2, 100); printf('halstatus9 = %d\r\n',halstatus); HAL_Delay(60); commands[1] = 0x06; halstatus = HAL_I2C_Master_Transmit(&hi2c1, LCD_ADDRESS, commands, 2, 100); printf('halstatus10 = %d\r\n', halstatus); HAL_Delay(60); } void Show_LCD() {commands[1] = 0x80; // First character position of first Line halstatus = HAL_I2C_Master_Transmit(&hi2c1, LCD_ADDRESS, commands, 2, 100); printf('halstatus11 = %d\r\n',halstatus); HAL_Delay(60); data[1] = 'a'; // 'a' character. halstatus = HAL_I2C_Master_Transmit(&hi2c1, LCD_ADDRESS, data, 2, 100); printf('halstatus12 = %d\r\n', halstatus); HAL_Delay(60); }void main()
{
// HAL initializations here
Init_LCD();
Show_LCD();while(1)
{ }
}
I was looking to see a character 'a' (0x61 in hex) in the second line start position.
It does not up anything..
The output of the program is:
halstatus1 = 0
halstatus2 = 0
halstatus3 = 1
halstatus4= 0
halstatus5= 0
halstatus6= 0
halstatus7= 1
halstatus8= 0
halstatus9= 1
halstatus10= 0
halstatus11= 0
halstatus12= 1
I am getting HAL_ERROR or 1 value at 0x39 byte, 0x6d byte, 0x01 byte and 0x61 byte.
Why I am getting this error, please let me know.
Edit: The problem is now solved, I edited the above code to a working model. Although some command seem to fail, I am getting character 'a' at the first digit position of the first line, which it should be.
Thanks,
2017-01-31 05:55 PM
the reason it is 0x80 is that The highest bit is always 1 when set DDRAM, page 7 of manual.
2017-01-31 06:14 PM
I believe your problem is initialization.
it needs some delay for the fist three command.
I would recommend just copying my code to test because those codes are in using with me. Very reliable.
Of course, you need to change i2c address.
If you didnt see anything on LCD, step in to check what is wrong.
Hardware: check every pin to make sure it is solid connection. Very often, the weird thing you may encounter actually comes from the hardware bug. For example, sometime ago, the power supply in one board not able to provide enough current. But I didn't notice that. The thing is that the code works. But after I add one more trival sentence somewhere the program completely changed,out of logic. It looks it is caused by software, actually not. After I fixed the power supply problem, the problem in software is gone.
I have some bad experience for LCD too. The connection looks OK but not really good.
Check the power supply of the LCD. supply voltage in your case is 3.3v.
Then software problem. Do you have a working code for i2c? Suppose i2c is not really hard to use. If it is not i2c problem, step in and debug.
2017-11-21 03:19 PM
Ok, for those that have used the NHD-C0220Biz-FS(RGB)-FBW-3VM I have a stupid question. My display is not working and I verified the STM32 code is correct and even probe all the i2c addresses and see my i/o expander but never the display. I was verifying everything and I initially thought it was odd the numbering on the LCD is 8..1 from left to right instead of 1..8. So, I have RST on the far right pin and C1- on the far left pin. I am thinking the manufacture documentation is wrong. I found a schematic symbol and matching footprint on EasyEDA for the same display and it has C1- on the far right (opposite from what the manf. documentation shows). Can someone verify the pin layout on this display?