2015-02-12 06:09 AM
Hi,
I'm trying to read the accelerometer (LIS302DL) in the STM32F4Discovery board using the I2C-Bus. Unfortunately, my aapproach is not working. When i (try to) configure the IC an read the ''Who_Am_I'' register, the return value is zero, but it should be 0b00111 Currently I have no oscilloscope or logic analyzer at hand and therefore cannot check the bus signals. Hopefully, somebody tried to read the accelerometer values in the past and can help me solve my problem. Thanks in advance! EDIT: I updated the code, see fourth comment!
#include ''stm32f4xx.h''
#include ''stm32f4xx_gpio.h''
#include ''stm32f4xx_rcc.h''
#include ''stm32f4xx_i2c.h''
#include <stdint.h>
void
initI2C()
{
// Use 168MHz
SystemInit();
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
I2C_InitTypeDef I2C_InitStructure;
// PA-Pins for I2C-Bus
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// PA6
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource5, GPIO_AF_I2C1);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource7, GPIO_AF_I2C1);
I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
I2C_InitStructure.I2C_ClockSpeed = 100000;
I2C_InitStructure.I2C_OwnAddress1 = 0;
I2C_Init(I2C1, &I2C_InitStructure);
I2C_Cmd(I2C1, ENABLE);
GPIO_ResetBits(GPIOA, GPIO_Pin_6);
}
// For procedure, see: stm32f4xx_i2c.h, line 303+
// i2cAdd: Address of slave in I2C-Bus
// regAdd: Register address of slave to write to
// data: Data to write
void
i2cSendByte(uint8_t i2cAdd, uint8_t regAdd, uint8_t data)
{
while
(I2C_GetFlagStatus(I2C1 , I2C_FLAG_BUSY));
// Generate Start Condition
I2C_GenerateSTART(I2C1, ENABLE);
while
(I2C_GetFlagStatus(I2C1 , I2C_EVENT_MASTER_MODE_SELECT));
// Send slave address
I2C_Send7bitAddress(I2C1, i2cAdd, I2C_Direction_Transmitter);
while
(I2C_GetFlagStatus(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
// Wait for SACK
// Transfer register address
I2C_SendData(I2C1, regAdd);
while
(I2C_GetFlagStatus(I2C1 , I2C_EVENT_MASTER_BYTE_TRANSMITTED));
// Wait for SACK
// Transfer data to register
I2C_SendData(I2C1, data);
while
(I2C_GetFlagStatus(I2C1 , I2C_EVENT_MASTER_BYTE_TRANSMITTED));
// Wait for SACK
I2C_GenerateSTOP(I2C1 , ENABLE);
}
int8_t i2cReceiveByte(uint8_t i2cAdd, uint8_t regAdd)
{
I2C_AcknowledgeConfig(I2C1, DISABLE);
while
(I2C_GetFlagStatus(I2C1 , I2C_FLAG_BUSY));
// Generate Start Condition
I2C_GenerateSTART(I2C1, ENABLE);
while
(I2C_GetFlagStatus(I2C1 , I2C_EVENT_MASTER_MODE_SELECT));
// Send slave address
I2C_Send7bitAddress(I2C1, i2cAdd, I2C_Direction_Transmitter);
while
(I2C_GetFlagStatus(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
// Wait for SACK
// Transfer register address
I2C_SendData(I2C1, regAdd);
while
(I2C_GetFlagStatus(I2C1 , I2C_EVENT_MASTER_BYTE_TRANSMITTED));
// Wait for SACK
// Generate Start Condition
I2C_GenerateSTART(I2C1, ENABLE);
while
(I2C_GetFlagStatus(I2C1 , I2C_EVENT_MASTER_MODE_SELECT));
// Send slave address
I2C_Send7bitAddress(I2C1, i2cAdd, I2C_Direction_Receiver);
while
(I2C_GetFlagStatus(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED ));
while
(I2C_GetFlagStatus(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED ));
// Wait for SACK
int8_t data = I2C_ReceiveData(I2C1);
I2C_GenerateSTOP(I2C1 , ENABLE);
I2C_AcknowledgeConfig(I2C1, ENABLE);
return
data;
}
int
main(
void
)
{
initI2C();
i2cSendByte(0b0011100<<1, 0x20, 0b11100111);
int8_t data;
while
(1)
{
data = i2cReceiveByte(0b0011100<<1, 0x0F);
//data = i2cReceiveByte(0b00111000, 0x29);
}
}
2015-02-12 06:28 AM
I presume you are using PA6 for accelerometer CS signal.
My reading of the LS303DL datasheet concludes that CS should be set for I2C, reset for SPI. Cheers, Hal2015-02-12 06:47 AM
Thanks for your answer.
Actually, I fogot to set the CS signal, it is connected to PE3. Despite that my problem still persists. PA6 is used to modify the I2C-address of the chip, see page 19 of the manual. ''Fixed'' code:#include ''stm32f4xx.h''
#include ''stm32f4xx_gpio.h''
#include ''stm32f4xx_rcc.h''
#include ''stm32f4xx_i2c.h''
#include <stdint.h>
void
initI2C()
{
// Use 168MHz
SystemInit();
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
I2C_InitTypeDef I2C_InitStructure;
// PA-Pins for I2C-Bus
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// PA6
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// PE3
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOE, &GPIO_InitStructure);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource5, GPIO_AF_I2C1);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource7, GPIO_AF_I2C1);
I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
I2C_InitStructure.I2C_ClockSpeed = 100000;
I2C_InitStructure.I2C_OwnAddress1 = 0;
I2C_Init(I2C1, &I2C_InitStructure);
I2C_Cmd(I2C1, ENABLE);
GPIO_ResetBits(GPIOA, GPIO_Pin_6);
// Select I2C Mode
GPIO_SetBits(GPIOE, GPIO_Pin_3);
}
// For procedure, see: stm32f4xx_i2c.h, line 303+
// i2cAdd: Address of slave in I2C-Bus
// regAdd: Register address of slave to write to
// data: Data to write
void
i2cSendByte(uint8_t i2cAdd, uint8_t regAdd, uint8_t data)
{
while
(I2C_GetFlagStatus(I2C1 , I2C_FLAG_BUSY));
// Generate Start Condition
I2C_GenerateSTART(I2C1, ENABLE);
while
(I2C_GetFlagStatus(I2C1 , I2C_EVENT_MASTER_MODE_SELECT));
// Send slave address
I2C_Send7bitAddress(I2C1, i2cAdd, I2C_Direction_Transmitter);
while
(I2C_GetFlagStatus(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
// Wait for SACK
// Transfer register address
I2C_SendData(I2C1, regAdd);
while
(I2C_GetFlagStatus(I2C1 , I2C_EVENT_MASTER_BYTE_TRANSMITTED));
// Wait for SACK
// Transfer data to register
I2C_SendData(I2C1, data);
while
(I2C_GetFlagStatus(I2C1 , I2C_EVENT_MASTER_BYTE_TRANSMITTED));
// Wait for SACK
I2C_GenerateSTOP(I2C1 , ENABLE);
}
int8_t i2cReceiveByte(uint8_t i2cAdd, uint8_t regAdd)
{
I2C_AcknowledgeConfig(I2C1, DISABLE);
while
(I2C_GetFlagStatus(I2C1 , I2C_FLAG_BUSY));
// Generate Start Condition
I2C_GenerateSTART(I2C1, ENABLE);
while
(I2C_GetFlagStatus(I2C1 , I2C_EVENT_MASTER_MODE_SELECT));
// Send slave address
I2C_Send7bitAddress(I2C1, i2cAdd, I2C_Direction_Transmitter);
while
(I2C_GetFlagStatus(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
// Wait for SACK
// Transfer register address
I2C_SendData(I2C1, regAdd);
while
(I2C_GetFlagStatus(I2C1 , I2C_EVENT_MASTER_BYTE_TRANSMITTED));
// Wait for SACK
// Generate Start Condition
I2C_GenerateSTART(I2C1, ENABLE);
while
(I2C_GetFlagStatus(I2C1 , I2C_EVENT_MASTER_MODE_SELECT));
// Send slave address
I2C_Send7bitAddress(I2C1, i2cAdd, I2C_Direction_Receiver);
while
(I2C_GetFlagStatus(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED ));
while
(I2C_GetFlagStatus(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED ));
// Wait for SACK
int8_t data = I2C_ReceiveData(I2C1);
I2C_GenerateSTOP(I2C1 , ENABLE);
I2C_AcknowledgeConfig(I2C1, ENABLE);
return
data;
}
int
main(
void
)
{
initI2C();
i2cSendByte(0b0011100<<1, 0x20, 0b11100111);
int8_t data;
while
(1)
{
data = i2cReceiveByte(0b0011100<<1, 0x0F);
//data = i2cReceiveByte(0b00111000, 0x29);
}
}
2015-02-12 03:04 PM
Check your peripheral clock command. Looks like wrong bus, wrong peripheral.
Cheers, Hal2015-02-13 04:07 AM
Yes, I used SPI for debugging and fogot to restore it.
After correcting this error, the program flow is stuck at line 72:while
(I2C_GetFlagStatus(I2C1 , I2C_FLAG_BUSY));
The ''bus is busy'' flag is always set.
According to my investigation, this seems to be a common problem. But so far i couldn't solve it.
#include ''stm32f4xx.h''
#include ''stm32f4xx_gpio.h''
#include ''stm32f4xx_rcc.h''
#include ''stm32f4xx_i2c.h''
#include <stdint.h>
void
initI2C()
{
// Use 168MHz
SystemInit();
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
I2C_InitTypeDef I2C_InitStructure;
// PA-Pins for I2C-Bus
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// PA6
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// PE3
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOE, &GPIO_InitStructure);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource5, GPIO_AF_I2C1);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource7, GPIO_AF_I2C1);
GPIO_ResetBits(GPIOA, GPIO_Pin_6);
// Select I2C mode
GPIO_SetBits(GPIOE, GPIO_Pin_3);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);
I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
I2C_InitStructure.I2C_ClockSpeed = 100000;
I2C_InitStructure.I2C_OwnAddress1 = 0;
I2C_Cmd(I2C1, ENABLE);
I2C_DeInit(I2C1);
I2C_Init(I2C1, &I2C_InitStructure);
}
// For procedure, see: stm32f4xx_i2c.h, line 303+
// i2cAdd: Address of slave in I2C-Bus
// regAdd: Register address of slave to write to
// data: Data to write
void
i2cSendByte(uint8_t i2cAdd, uint8_t regAdd, uint8_t data)
{
while
(I2C_GetFlagStatus(I2C1 , I2C_FLAG_BUSY));
// Generate Start Condition
I2C_GenerateSTART(I2C1, ENABLE);
while
(I2C_GetFlagStatus(I2C1 , I2C_EVENT_MASTER_MODE_SELECT));
// Send slave address
I2C_Send7bitAddress(I2C1, i2cAdd, I2C_Direction_Transmitter);
while
(I2C_GetFlagStatus(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
// Wait for SACK
// Transfer register address
I2C_SendData(I2C1, regAdd);
while
(I2C_GetFlagStatus(I2C1 , I2C_EVENT_MASTER_BYTE_TRANSMITTED));
// Wait for SACK
// Transfer data to register
I2C_SendData(I2C1, data);
while
(I2C_GetFlagStatus(I2C1 , I2C_EVENT_MASTER_BYTE_TRANSMITTED));
// Wait for SACK
I2C_GenerateSTOP(I2C1 , ENABLE);
}
int8_t i2cReceiveByte(uint8_t i2cAdd, uint8_t regAdd)
{
I2C_AcknowledgeConfig(I2C1, DISABLE);
while
(I2C_GetFlagStatus(I2C1 , I2C_FLAG_BUSY));
// Generate Start Condition
I2C_GenerateSTART(I2C1, ENABLE);
while
(I2C_GetFlagStatus(I2C1 , I2C_EVENT_MASTER_MODE_SELECT));
// Send slave address
I2C_Send7bitAddress(I2C1, i2cAdd, I2C_Direction_Transmitter);
while
(I2C_GetFlagStatus(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
// Wait for SACK
// Transfer register address
I2C_SendData(I2C1, regAdd);
while
(I2C_GetFlagStatus(I2C1 , I2C_EVENT_MASTER_BYTE_TRANSMITTED));
// Wait for SACK
// Generate Start Condition
I2C_GenerateSTART(I2C1, ENABLE);
while
(I2C_GetFlagStatus(I2C1 , I2C_EVENT_MASTER_MODE_SELECT));
// Send slave address
I2C_Send7bitAddress(I2C1, i2cAdd, I2C_Direction_Receiver);
while
(I2C_GetFlagStatus(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED ));
while
(I2C_GetFlagStatus(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED ));
// Wait for SACK
int8_t data = I2C_ReceiveData(I2C1);
I2C_GenerateSTOP(I2C1 , ENABLE);
I2C_AcknowledgeConfig(I2C1, ENABLE);
return
data;
}
int
main(
void
)
{
initI2C();
i2cSendByte(0b0011100<<1, 0x20, 0b11100111);
int8_t data;
while
(1)
{
data = i2cReceiveByte(0b0011100<<1, 0x0F);
//data = i2cReceiveByte(0b00111000, 0x29);
}
}
2015-02-13 03:04 PM
You have another SPI debugging leftover. You are still on the SPI pins which have no I2C function.
Most of the Discovery I2C pins are dedicated to on board function. Check my research, but I believe PB8 and PB11 are available for your use. Cheers, Hal2015-02-16 08:40 AM
It seems like there is no way to obtain the accelerometer values directly using the I2C-Bus, since the IC is connected to PA5 and PA7 on the PCB. I assumed the pins had this functionality, because the I2C mode of the accelerometer was selectable instead of being pulled to GND.
Let's see if I can make it work by bridging the relevant pins using jumper wires.