2014-02-12 06:07 AM
Hello,
I'm trying to interface the STM32L152 Discovery with an LCD display (NHD-C0220BiZ-FSW-FBW-3V3M) through I2C. I'm finding a problem when trying to write the first command to the LCD the code gets stuck on the EV6 check:while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
From the LCD I have SDA connected to PB7 and SCL connected to PB6. This lines have 4.7K pull up resistors connected to them.
Any ideas why this is happening?
The I2C driver's code is the following:
void i2c_init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
// NVIC_InitTypeDef NVIC_InitStructure;
I2C_InitTypeDef I2C_InitStructure;
//I2C_DeInit(I2Cx);
/*!< I2C Periph clock enable */
RCC_APB1PeriphClockCmd(I2Cx_CLK, ENABLE);
/*!< SDA GPIO clock enable */
RCC_AHBPeriphClockCmd(I2Cx_SDA_GPIO_CLK, ENABLE);
/*!< SCL GPIO clock enable */
RCC_AHBPeriphClockCmd(I2Cx_SCL_GPIO_CLK, ENABLE);
/* Connect PXx to I2C_SCL */
GPIO_PinAFConfig(I2Cx_SCL_GPIO_PORT, I2Cx_SCL_SOURCE, GPIO_AF_I2C1);
/* Connect PXx to I2C_SDA */
GPIO_PinAFConfig(I2Cx_SDA_GPIO_PORT, I2Cx_SDA_SOURCE, GPIO_AF_I2C1);
/*!< Configure I2C SCL pin */
GPIO_InitStructure.GPIO_Pin = I2Cx_SCL_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_40MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(I2Cx_SCL_GPIO_PORT, &GPIO_InitStructure);
/*!< Configure I2C SDA pin */
GPIO_InitStructure.GPIO_Pin = I2Cx_SDA_PIN;
GPIO_Init(I2Cx_SDA_GPIO_PORT, &GPIO_InitStructure);
// /* Configure the I2C event priority */
// NVIC_InitStructure.NVIC_IRQChannel = I2Cx_EV_IRQn;
// NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
// NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
// NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
// NVIC_Init(&NVIC_InitStructure);
// /* Configure I2C error interrupt to have the higher priority */
// NVIC_InitStructure.NVIC_IRQChannel = I2Cx_ER_IRQn;
// NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;
// NVIC_Init(&NVIC_InitStructure);
I2C_DeInit(I2Cx);
/*!< I2C Struct Initialize */
I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
I2C_InitStructure.I2C_DutyCycle = I2C_DUTYCYCLE;
I2C_InitStructure.I2C_OwnAddress1 = 0x60;
I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
I2C_InitStructure.I2C_ClockSpeed = I2C_SPEED1;
I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
/*!< I2C Initialize */
I2C_Init(I2Cx, &I2C_InitStructure);
// /* Enable Error Interrupt */
// I2C_ITConfig(I2Cx, I2C_IT_ERR , ENABLE);
/* I2C ENABLE */
I2C_Cmd(I2Cx, ENABLE);
}
/*******************************************************************************
* Function Name : I2C_ByteWrite
* Description : write a Byte to I2C Bus
* Input : deviceAddr is the I2C address of the device
* WriteAddr is the register address you want to write to
* pBuffer contains bytes to write
* Output : None
* Return : None
*******************************************************************************/
void I2C_ByteWrite(uint8_t pBuffer, uint8_t deviceAddress, uint8_t WriteAddr) {
/* Send START condition */
I2C_GenerateSTART(I2Cx, ENABLE);
/* Test on EV5 and clear it */
while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_MODE_SELECT));
/* Send EEPROM address for write */
I2C_Send7bitAddress(I2Cx, deviceAddress, I2C_Direction_Transmitter);
/* Test on EV6 and clear it */
while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
/* Send the EEPROM's internal address to write to : only one byte Address */
I2C_SendData(I2Cx, WriteAddr);
/* Test on EV8 and clear it */
while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
/* Send the byte to be written */
I2C_SendData(I2Cx, pBuffer);
/* Test on EV8 and clear it */
while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
/* Send STOP condition */
I2C_GenerateSTOP(I2Cx, ENABLE);
}
I call i2c_init(); successfully, the problem arises in the first I2C_ByteWrite inside the call to init_lcd();
This looks as follows:
void init_lcd(void)
{
RESET_RST; //RST = 0, reset
delay(2);
SET_RST; //RST = 1, end reset
delay(20);
I2C_ByteWrite(FUNC_SET_TBL0, LCD_ADDR, 0x00);
delay(10);
I2C_ByteWrite(FUNC_SET_TBL1, LCD_ADDR, 0x00);
delay(10);
I2C_ByteWrite(BIAS, LCD_ADDR, 0x00); // Set BIAS - 1/5
I2C_ByteWrite(CONTRAST, LCD_ADDR, 0x00); // Set contrast low byte
I2C_ByteWrite(BOOSTER, LCD_ADDR, 0x00); // ICON disp on, Booster on, Contrast high byte
I2C_ByteWrite(FOLLOWER, LCD_ADDR, 0x00); // Follower circuit (internal), amp ratio (6)
I2C_ByteWrite(DISPLAY_ON, LCD_ADDR, 0x00); // Display on
I2C_ByteWrite(CLEAR_DISPLAY, LCD_ADDR, 0x00); // Clear display
I2C_ByteWrite(ENTRY_MODE, LCD_ADDR, 0x00); //Entry mode set - increment
delay(10);
}
I would really appreciate any help and suggestions.
Thank you.
#ev6 #stm32l #discovery #i2c
2014-02-12 06:20 AM
Hi
''I'm trying to interface the STM32L152 Discovery with an LCD display (NHD-C0220BiZ-FSW-FBW-3V3M) through I2C. I'm finding a problem when trying to write the first command to the LCD'' Question : How is the LCD powered?Is it getting it's power off the Discovery board? What does''delay(20);
'' do?
How long is this delay?
Can you look at what is happening with an oscilloscope?
FYI - The STM32 can boot up in micro seconds - usually faster than some external peripherals can (or be ready) so it is never a good idea to try to go straight into peripheral initialisation code if the CPU is not in control (reset of ) the peripheral.
2014-02-13 01:41 AM
Hi,
Yes, the LCD gets its power from the Discovery. delay(20) takes about 0.2ms. I also have a 0.1ms delay in between the call to i2c_init() and lcd_init(). In addition, I don't think this should be a problem because I'm currently stepping on each statement, so this should give enough time for the uC to properly reset the LCD.When I look at the oscilloscope, this is what I see after the call to I2C_Send7bitAddress(I2Cx, deviceAddress, I2C_Direction_Transmitter);Where yellow is the SCLK, blue is SDA and purple is the active low reset of the LCD (in the screenshot high, since this is after the reset). Any guidance on this would be very helpful.Thank you.2014-02-13 02:19 AM
Hi
The trace only shows 2 bits being transmitted. not sure what is going on. Try running the code upto ''/* Send EEPROM address for write */
I2C_Send7bitAddress(I2Cx, deviceAddress, I2C_Direction_Transmitter);
/* Test on EV6 and clear it */
while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
''
Stop on the while, this should allow the start and the transmission of the address and w/r bit.
What is the value for ''
I2C_EVENT_MASTER_BYTE_TRANSMITTED
'' ?
2014-02-13 02:35 AM
I believe that until the while the configuration is correct. Here is a screenshot of the registers.
Are you asking about the value defined forI2C_EVENT_MASTER_BYTE_TRANSMITTED,
if that's the case it is defined as I2C_EVENT_MASTER_BYTE_TRANSMITTED ((uint32_t)0x00070084)Thanks!2014-02-13 02:59 AM
Hi
As I said before I cannot tell what is going on until I see the start bit and address byte being transmitted. The trace only showed 2 bits transmitted - very strange! And then a stop bit. ''is defined as I2C_EVENT_MASTER_BYTE_TRANSMITTED ((uint32_t)0x00070084)'' Try #define I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED ((uint32_t)0x00070082) /* BUSY, MSL, ADDR, TXE and TRA flags */2014-02-13 03:10 AM
What you are suggesting for I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED is what I actually have on the stm32l1xx_i2c.h file.
The screenshot that I sent from the scope is after the I2C_Send7BitAddress...2014-02-13 03:21 AM
''The screenshot that I sent from the scope is after the I2C_Send7BitAddress...''
Then something is very wrong. The trace only shows 2 bits being sent (only 2 SCLK cycles) and then what looks like a stop bit. Try to capture the whole 9 bits of the address byte!2014-02-13 04:22 AM
Is this likely that speed being too high locks the I2C IP ?
The capture shows that freq of SCL is near 700KHz, which is way over the 400 KHz max.2014-02-13 05:31 AM
I'm not sure how to get the entire clock sequence. I switched to ports 8 and 9 (clk and sda respectively), but still the same issue. I also changed the GPIO speed for both of them to 400KHz.Nevertheless, the frequency shown on the scope is still 700KHz, how can I change this?