2011-08-17 06:57 AM
Hi,
I have been trying now for longer than i care to admit at getting my development board ( STM32F103R ) to talk to a sensor ( HMC5843 ) via I2C. I have gone through the STM32 code examples but they were frankly kind of useless.
I have put in the following code which i pasted together from pages of this forum and what little understanding of this peripheral i have.:
♯♯♯♯♯♯♯♯♯&sharpSTART CODE♯♯♯♯♯♯♯♯♯♯♯♯
&sharpinclude ''stm32f10x.h''
&sharpinclude ''Libs.h''
u16 loop1 = 0,loop2 = 0,loop3 = 0, Loop_Delay = 0; //loops for 1ms interrupts
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
&sharpdefine I2C1_SLAVE_ADDRESS7 0x1E // EEPROM I2C Address
&sharpdefine ClockSpeed 50000 // 50 KHz
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
u8 i2c_var = 123;
/* Private function prototypes -----------------------------------------------*/
void Delay(u16);
void I2C_Setup(void);
void Transmit (void);
void Recieve(void);
int main(void)
{
Setup ();
//ADCconfig();
//PWMinit();
USART_Setup();
I2C_Setup();
while(1)
{
if (loop1>=100)
{
Transmit();
SendData(1,i2c_var);
loop1=0;
GPIOB->BSRR |= GPIO_Pin_8 | GPIO_Pin_9 ; // switch of LED's
Recieve();
}
}
}//end main
void Transmit (void)
{
/* Send I2C1 START condition */
I2C_GenerateSTART(I2C1, ENABLE);
/* Test on I2C1 EV5 and clear it */
// while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));
/* Send EEPROM slave Address for write */
I2C_Send7bitAddress(I2C1, I2C1_SLAVE_ADDRESS7, I2C_Direction_Transmitter);
/* Test on I2C1 EV6 and clear it */
// while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
/* Send I2C1 EEPROM internal address */
I2C_SendData(I2C1, 0x02); // 0x02 is config register
/* Test on I2C1 EV8 and clear it */
// while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
/* Send I2C1 EEPROM data */
I2C_SendData(I2C1, 0x00);//puts config register into continious measurement mode.
/* Test on I2C1 EV8 and clear it */
// while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
/* Send I2C1 STOP Condition */
I2C_GenerateSTOP(I2C1, ENABLE);
}
void I2C_Setup(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
I2C_InitTypeDef I2C_InitStructure;
/* GPIOB Periph clock enable */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
/* I2C1 and I2C2 Periph clock enable */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);
/* Configure I2C1 pins: SCL and SDA ----------------------------------------*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD; // Open Drain, I2C bus pulled high externally
GPIO_Init(GPIOB, &GPIO_InitStructure);
/* Enable I2C1 -------------------------------------------------------------*/
I2C_Cmd(I2C1, ENABLE);
/* I2C1 configuration ------------------------------------------------------*/
I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
I2C_InitStructure.I2C_OwnAddress1 = I2C1_SLAVE_ADDRESS7;
I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
I2C_InitStructure.I2C_ClockSpeed = ClockSpeed;
I2C_Init(I2C1, &I2C_InitStructure);
}
void Recieve(void)
{
/* Send I2C1 START condition */
I2C_GenerateSTART(I2C1, ENABLE);
/* Test on I2C1 EV5 and clear it */
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));
/* Send EEPROM slave Address for write */
I2C_Send7bitAddress(I2C1, I2C1_SLAVE_ADDRESS7, I2C_Direction_Receiver);
i2c_var = I2C_ReceiveData(I2C1);//puts config register into continious measurement mode.
/* Send I2C1 STOP Condition */
I2C_GenerateSTOP(I2C1, ENABLE);
}
//Increment function called by Systick every 1ms
inline void Increment (void)
{
loop1++;
loop2++;
loop3++;
Loop_Delay++;
}
void Delay(u16 count)
{
Loop_Delay=0;
while (Loop_Delay <= count)
{
asm(''nop'');
}
}//end Delay
♯♯♯♯♯♯♯♯&sharpEND CODE♯♯♯♯♯♯♯♯♯♯
The Libs.h file just contains some setup functions for setting up the USART and GPIOS. i made sure i called the I2C setup after my setups just incase it was setting some ports incorrectly.
All i am trying to do is read data from the sensors registers , any of them!
if i uncomment the while check events then it hangs on all of them. if i comment them all out and then run the code it just returns ''31'' to serial , which is the number i am putting into the DR register in the first place. so im figuring that whatever im putting into the register is just sitting there and not being sent anywhere.
any help in pointing out my stupidity would be appreciated :\
Thanks in advance.
#stm32 #i2c #i2c #i2c2011-08-19 03:12 AM
Hello!
> sensor ( HMC5843 ) via I2C.> #define I2C1_SLAVE_ADDRESS7 0x1E // EEPROM I2C Address
> I2C_Send7bitAddress(I2C1, I2C1_SLAVE_ADDRESS7, I2C_Direction_Transmitter);
Watch to shift the given 7-bit address left before using. See doc to the chip and I2C in general.I2C_Send7bitAddress(I2C1, I2C1_SLAVE_ADDRESS7 << 1, I2C_Direction_Transmitter);
2011-08-19 09:22 AM
Thankyou for your reply,
I tried shifting the address left as you suggested on both the transmit and receive functions but its the same as before.If i leave the while checks in it hangs on any/all of them and if i take them all out it will just keep printing ''61'' back to the usart. which is what im sending into it in the first place.2011-08-19 09:24 AM
2011-08-26 04:08 AM
Hi,
I recently got an hmc5843 from Sparkfun and I cannot figure out how to make it work(my mcu is stm32f103). I also have a wii motion plus gyro device on I2C and it is working fine. I have the same problem as Darren: the error checking functions are not passed. Did anybody had success in interfacing this sensor to stm32? Regards, Andrei2011-08-28 08:49 AM
Andrei,
Thats interesting , so either its a coincidence and we both have incorrect code/broken sensors or they in fact don't work with the STM32.Over the next week or so i will get hold of some other I2C devices and try to communicate with them. I will let you know what i find and if my code was correct. Then we will know its more likely to be an issue with the sensor.Thanks,2011-09-01 11:32 AM
I'm sad to say i think it is in fact incorrect code, i managed to get hold of a logic analyser so i could actually see what was going on. The hmc5843 IS returning an ACK bit when it should so it seems to be functioning correctly.
I still haven't got it returning anything useful yet but i am working on it and am fairly sure i can get it working soon. Once i do i will post the code here.Darren.2011-09-06 12:47 PM
Ok so I managed to get hold of a maple board and loaded the code that sparkfun gives on there site onto it and just like that the HMC5843 worked , it gave all 3 axis readings and responded to being moved and so on.
I captured the transfer of data between the maple and the sensor on a logic analyser so i know exactly what it should look like. i then wired it all back onto the STM32 to see what the difference was. as it turns out what i thought were ACK bits are in fact erroneous spikes. in every 8bit transfer there is at least 1 small spike ranging from 1 - 3 micro sec long. The clock is set to 100khz so the clock width is 10micro secs meaning these spikes dont fit at all into the clocking sequence. iv messed around with the setup of the I2C on the STM32 with different configurations but no joy , it always still gives me these random spikes which im fairly certain is causing the issues.I dont suppose anyone has an I2C setup function they would be willing to share? so i could compare it to mine.Darren.2011-09-09 07:51 AM
Ok the issue is solved finally, Below is the pasted code. Its not neat or overly pretty and im certain you could do it in better ways , but it works on the HMC5843.
Just callI2C_Setup(); <-- this configures the peripheral init_sens(); <-- this writes to the registers to set it in continuous conversion mode.data sheet says to let it settle for a while here , 10ms or so.then call: Recieve(0x1E,0x03);where 0x1E is the address of the sensor and 0x03 is the register start position. It will then read all of the registers and load them into global variables X,Y,Z. As i said its not perfect but it works and should be fairly easy to follow and improve upon.here are the functions:void I2C_Setup(void){ GPIO_InitTypeDef GPIO_InitStructure; I2C_InitTypeDef I2C_InitStructure; /*enable I2C*/ I2C_Cmd(I2C1,ENABLE); /* I2C1 clock enable */ RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE); /* I2C1 SDA and SCL configuration */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD; GPIO_Init(GPIOB, &GPIO_InitStructure); //SCL is pin06 and SDA is pin 07 for I2C1 /* I2C1 configuration */ I2C_InitStructure.I2C_Mode = I2C_Mode_SMBusHost; I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2; I2C_InitStructure.I2C_OwnAddress1 = 0x00; I2C_InitStructure.I2C_Ack = I2C_Ack_Enable; I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit; I2C_InitStructure.I2C_ClockSpeed = I2C_SPEED ; I2C_Init(I2C1, &I2C_InitStructure); /*!< Enable SMBus Alert interrupt */ I2C_ITConfig(I2C1, I2C_IT_ERR, ENABLE); //dont think this is necessary}void init_sens(void){ I2C_GenerateSTART(I2C1, ENABLE); while(!I2C_GetFlagStatus(I2C1, I2C_FLAG_SB)); // start bit flag I2C_SendData(I2C1, 0x3C); //send write command to chip while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)); //while(!I2C_GetFlagStatus(I2C1, I2C_FLAG_TXE)); I2C_SendData(I2C1, 0x02); //mode register while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED)); I2C_SendData(I2C1, 0x00); //continious conversion mode while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED)); I2C_GenerateSTOP(I2C1, ENABLE); while(I2C_GetFlagStatus(I2C1, I2C_FLAG_STOPF)); // stop bit flag}void Recieve(u8 Address, u8 Register){ /*left align address*/ Address = Address<<1; /*re-enable ACK bit incase it was disabled last call*/ I2C_AcknowledgeConfig(I2C1, ENABLE); /* Test on BUSY Flag */ while (I2C_GetFlagStatus(I2C1,I2C_FLAG_BUSY)); /* Enable the I2C peripheral */ I2C_GenerateSTART(I2C1, ENABLE); /* Test on SB Flag */ while (!I2C_GetFlagStatus(I2C1,I2C_FLAG_SB)); /* Send device address for write */ I2C_Send7bitAddress(I2C1, Address, I2C_Direction_Transmitter); /* Test on ADDR Flag */ while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)); /* Send the device's internal address to write to */ I2C_SendData(I2C1,Register); /* Test on TXE FLag (data sent) */ while (!I2C_GetFlagStatus(I2C1,I2C_FLAG_TXE)); /* Send START condition a second time (Re-Start) */ I2C_GenerateSTART(I2C1, ENABLE); /* Test on SB Flag */ while (!I2C_GetFlagStatus(I2C1,I2C_FLAG_SB)); /* Send address for read */ I2C_Send7bitAddress(I2C1, Address, I2C_Direction_Receiver); /* Test on ADDR Flag */ while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED)); /* load in 5 of 6 registers */ XMSB = I2C_ReceiveData(I2C1); while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED)); XMSB = I2C_ReceiveData(I2C1); while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED)); YMSB = I2C_ReceiveData(I2C1); while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED)); YMSB = I2C_ReceiveData(I2C1); while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED)); ZMSB = I2C_ReceiveData(I2C1); while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED)); /*enable NACK bit on next read and read final register*/ I2C_NACKPositionConfig(I2C1, I2C_NACKPosition_Current); I2C_AcknowledgeConfig(I2C1, DISABLE); ZLSB = I2C_ReceiveData(I2C1); /* Send STOP Condition */ I2C_GenerateSTOP(I2C1, ENABLE); while(I2C_GetFlagStatus(I2C1, I2C_FLAG_STOPF)); // stop bit flag /*sort into 3 variables*/ X = ((XMSB<<8) | XLSB); Y = ((YMSB<<8) | YLSB); Z = ((ZMSB<<8) | ZLSB);}Hope this helps!Darren.2011-09-11 11:45 AM
Hi Darren,
I'm having a similar issue with my STM32F103. Can you tell me where can i find de description of this function: I2C_NACKPositionConfig(I2C1, I2C_NACKPosition_Current); Thanks Marcos