In the second section of the fourteenth part of I2C BSP, we shall develop functions that will communicate with slave devices to write/read to/from MPU9250.
In this guide, we shall cover the following:
- Updating the header file.
- Updating the source file.
- Main code.
- Results.
1. Updating the header file:
In i2c_bps.h header file, include the following three functions.
The first function:
I2C_StatusTypedef BSP_I2C_Write(I2C_TypeDef *i2c, uint8_t address, uint8_t *data,uint16_t length, uint32_t timeout);
The function takes five parameters as following:
- I2C_Typedef to indicate which i2c to be used.
- The address of the slave device.
- Array that holds the data to be written to the slave device.
- Length of the data to be written.
- Timeout for time management.
Also, the function will return the I2C status as following:
- Success
- Failed.
- Timeout
The second function:
I2C_StatusTypedef BSP_I2C_Read_Memory(I2C_TypeDef *i2c, uint8_t address,uint8_t MemAddr, uint8_t *data,uint16_t length, uint32_t timeout);
This function will send the memory address to be read . It takes six parameters:
- I2C_Typedef to indicate which i2c to be used.
- The address of the slave device.
- The memory address within the slave.
- Array which holds the data to be read.
- Length of the data to be read.
- Timeout for time management.
The function will return the status of I2C as mentioned earlier.
The third and final function as following:
I2C_StatusTypedef BSP_I2C_Read(I2C_TypeDef *i2c, uint8_t address, uint8_t *data,uint16_t lenght, uint32_t timeout);
This function will read the slave directly without sending the memory to read first.
Hence, the update header file as following:
#ifndef I2C_BSP_H_ #define I2C_BSP_H_ #include "stm32f4xx.h" #include "stdint.h" #include "bsp_debug.h" #include "bsp.h" #define __I2C1_CLOCK_ENABLE() RCC->APB1ENR|=RCC_APB1ENR_I2C1EN #define __I2C2_CLOCK_ENABLE() RCC->APB1ENR|=RCC_APB1ENR_I2C2EN #define __I2C3_CLOCK_ENABLE() RCC->APB1ENR|=RCC_APB1ENR_I2C3EN typedef enum { standardSpeed=0, fastMode=1 }I2C_MasterModeTypedef; typedef enum { Duty_2=0, Duty_16_9=1 }I2C_DutyModeTypedef; typedef enum { i2c_success=0, i2c_failed=1, i2c_timeOut=2 }I2C_StatusTypedef; typedef struct { uint8_t PeripheralFrequency; uint8_t MasterMode; uint8_t DutyMode; uint16_t RiseTime; uint16_t Clock; }I2C_ConfigTypedef; void BSP_I2C_Init(I2C_TypeDef *i2c, I2C_ConfigTypedef *config); void BSP_I2C_Bus_Scan(I2C_TypeDef *i2c); I2C_StatusTypedef BSP_I2C_Write(I2C_TypeDef *i2c, uint8_t address, uint8_t *data ,uint16_t length, uint32_t timeout); I2C_StatusTypedef BSP_I2C_Read_Memory(I2C_TypeDef *i2c, uint8_t address,uint8_t MemAddr, uint8_t *data,uint16_t length, uint32_t timeout); I2C_StatusTypedef BSP_I2C_Read(I2C_TypeDef *i2c, uint8_t address, uint8_t *data,uint16_t lenght, uint32_t timeout); #endif /* I2C_BSP_H_ */
2. Updating the source file:
Before heading into updating the source file, please refer to these two guide:
The write function as following:
I2C_StatusTypedef BSP_I2C_Write(I2C_TypeDef *i2c, uint8_t address, uint8_t *data,uint16_t length, uint32_t timeout) { uint32_t start_timer=BSP_Get_Ticks(); while (i2c->SR2 & I2C_SR2_BUSY) //wait until bus not busy { if (BSP_Get_Ticks()- start_timer>timeout) { return i2c_timeOut; } } i2c->CR1 |= I2C_CR1_START; //generate start while (!(i2c->SR1 & I2C_SR1_SB)) //wait until start is generated { if (BSP_Get_Ticks()- start_timer>timeout) { return i2c_timeOut; } } i2c->DR = address<< 1; // Send slave address while (!(i2c->SR1 & I2C_SR1_ADDR)) //wait until address flag is set { if (BSP_Get_Ticks()- start_timer>timeout) { return i2c_timeOut; } } (void) i2c->SR2; //Clear SR2 while (!(i2c->SR1 & I2C_SR1_TXE)) //Wait until Data register empty { if (BSP_Get_Ticks()- start_timer>timeout) { return i2c_timeOut; } } for (uint16_t i=0;i<length;i++) { i2c->DR=data[i]; //filling buffer with command or data while (!(i2c->SR1 & I2C_SR1_BTF)) { if (BSP_Get_Ticks()- start_timer>timeout) { return i2c_timeOut; } } } i2c->CR1 |= I2C_CR1_STOP; return i2c_success; }
For the read from memory address:
I2C_StatusTypedef BSP_I2C_Read_Memory(I2C_TypeDef *i2c, uint8_t address,uint8_t MemAddr, uint8_t *data,uint16_t length, uint32_t timeout) { uint32_t start_timer=BSP_Get_Ticks(); while (i2c->SR2 & I2C_SR2_BUSY) { if (BSP_Get_Ticks()- start_timer>timeout) { return i2c_timeOut; } } i2c->CR1|=I2C_CR1_START; while(!(i2c->SR1 & I2C_SR1_SB)) { if (BSP_Get_Ticks()- start_timer>timeout) { return i2c_timeOut; } } i2c->DR=address<<1; while(!(i2c->SR1 & I2C_SR1_ADDR)) { if (BSP_Get_Ticks()- start_timer>timeout) { return i2c_timeOut; } } (void)i2c->SR2; while(!(i2c->SR1&I2C_SR1_TXE)) { if (BSP_Get_Ticks()- start_timer>timeout) { return i2c_timeOut; } } i2c->DR = MemAddr; while(!(i2c->SR1&I2C_SR1_TXE)) { if (BSP_Get_Ticks()- start_timer>timeout) { return i2c_timeOut; } } i2c->CR1|=I2C_CR1_START; while(!(i2c->SR1 & I2C_SR1_SB)) { if (BSP_Get_Ticks()- start_timer>timeout) { return i2c_timeOut; } } i2c->DR=address<<1|1; while(!(i2c->SR1 & I2C_SR1_ADDR)) { if (BSP_Get_Ticks()- start_timer>timeout) { return i2c_timeOut; } } (void)i2c->SR2; i2c->CR1|=I2C_CR1_ACK; while(length>0U) { if(length==1U) { i2c->CR1&=~I2C_CR1_ACK; i2c->CR1|=I2C_CR1_STOP; while(!(i2c->SR1&I2C_SR1_RXNE)) { if (BSP_Get_Ticks()- start_timer>timeout) { return i2c_timeOut; } } *data++=i2c->DR; break; } else { while(!(i2c->SR1&I2C_SR1_RXNE)) { if (BSP_Get_Ticks()- start_timer>timeout) { return i2c_timeOut; } } (*data++)=i2c->DR; length--; } } return i2c_success; }
For reading the i2c slave only without memory:
I2C_StatusTypedef BSP_I2C_Read(I2C_TypeDef *i2c, uint8_t address, uint8_t *data, uint16_t length, uint32_t timeout) { uint32_t start_timer=BSP_Get_Ticks(); while (i2c->SR2 & I2C_SR2_BUSY) { if (BSP_Get_Ticks()- start_timer>timeout) { return i2c_timeOut; } } i2c->CR1|=I2C_CR1_START; while(!(i2c->SR1 & I2C_SR1_SB)) { if (BSP_Get_Ticks()- start_timer>timeout) { return i2c_timeOut; } } i2c->DR=address<<1|1; while(!(i2c->SR1 & I2C_SR1_ADDR)) { if (BSP_Get_Ticks()- start_timer>timeout) { return i2c_timeOut; } } (void)i2c->SR2; i2c->CR1|=I2C_CR1_ACK; while(length>0U) { if(length==1U) { i2c->CR1&=~I2C_CR1_ACK; i2c->CR1|=I2C_CR1_STOP; while(!(i2c->SR1&I2C_SR1_RXNE)) { if (BSP_Get_Ticks()- start_timer>timeout) { return i2c_timeOut; } } *data++=i2c->DR; break; } else { while(!(i2c->SR1&I2C_SR1_RXNE)) { if (BSP_Get_Ticks()- start_timer>timeout) { return i2c_timeOut; } } (*data++)=i2c->DR; length--; } } return i2c_success; }
Hence, the updated source file as following:
#include "i2c_bsp.h" void BSP_I2C_Init(I2C_TypeDef *i2c, I2C_ConfigTypedef *config) { i2c->CR1=I2C_CR1_SWRST; i2c->CR1&=~I2C_CR1_SWRST; i2c->CR2|= config->PeripheralFrequency; i2c->TRISE=config->RiseTime; i2c->CCR|=(config->MasterMode<<I2C_CCR_FS_Pos); i2c->CCR|=(config->DutyMode<<I2C_CCR_DUTY_Pos); if((config->Clock)==0) { float period =1.0/(float)(config->PeripheralFrequency); if((config->MasterMode)==standardSpeed) { uint16_t tmp = 5/period; i2c->CCR|=(tmp<<I2C_CCR_CCR_Pos); } else { if(config->DutyMode==Duty_2) { uint16_t tmp=5/period; i2c->CCR|=(tmp<<I2C_CCR_CCR_Pos); } else { uint16_t tmp=13/period; i2c->CCR|=(tmp<<I2C_CCR_CCR_Pos); } } } else { i2c->CCR|=(config->Clock<<I2C_CCR_CCR_Pos); } i2c->CR1|=I2C_CR1_PE; } void BSP_I2C_Bus_Scan(I2C_TypeDef *i2c) { char data[100]; uint8_t a=0; for (uint8_t i=0;i<128;i++) { i2c->CR1 |= I2C_CR1_START; while(!(i2c->SR1 & I2C_SR1_SB)); i2c->DR=(i<<1|0); while(!(i2c->SR1)|!(I2C1->SR2)){}; i2c->CR1 |= I2C_CR1_STOP; BSP_Delay(1); a=(i2c->SR1&I2C_SR1_ADDR); if (a==2) { sprintf(data,"Found I2C device at address 0x%X (hexadecimal), or %d (decimal)\n\r",i,i); log_info(data); } } } I2C_StatusTypedef BSP_I2C_Write(I2C_TypeDef *i2c, uint8_t address, uint8_t *data,uint16_t length, uint32_t timeout) { uint32_t start_timer=BSP_Get_Ticks(); while (i2c->SR2 & I2C_SR2_BUSY) //wait until bus not busy { if (BSP_Get_Ticks()- start_timer>timeout) { return i2c_timeOut; } } i2c->CR1 |= I2C_CR1_START; //generate start while (!(i2c->SR1 & I2C_SR1_SB)) //wait until start is generated { if (BSP_Get_Ticks()- start_timer>timeout) { return i2c_timeOut; } } i2c->DR = address<< 1; // Send slave address while (!(i2c->SR1 & I2C_SR1_ADDR)) //wait until address flag is set { if (BSP_Get_Ticks()- start_timer>timeout) { return i2c_timeOut; } } (void) i2c->SR2; //Clear SR2 while (!(i2c->SR1 & I2C_SR1_TXE)) //Wait until Data register empty { if (BSP_Get_Ticks()- start_timer>timeout) { return i2c_timeOut; } } for (uint16_t i=0;i<length;i++) { i2c->DR=data[i]; //filling buffer with command or data while (!(i2c->SR1 & I2C_SR1_BTF)) { if (BSP_Get_Ticks()- start_timer>timeout) { return i2c_timeOut; } } } i2c->CR1 |= I2C_CR1_STOP; return i2c_success; } I2C_StatusTypedef BSP_I2C_Read_Memory(I2C_TypeDef *i2c, uint8_t address,uint8_t MemAddr, uint8_t *data,uint16_t length, uint32_t timeout) { uint32_t start_timer=BSP_Get_Ticks(); while (i2c->SR2 & I2C_SR2_BUSY) { if (BSP_Get_Ticks()- start_timer>timeout) { return i2c_timeOut; } } i2c->CR1|=I2C_CR1_START; while(!(i2c->SR1 & I2C_SR1_SB)) { if (BSP_Get_Ticks()- start_timer>timeout) { return i2c_timeOut; } } i2c->DR=address<<1; while(!(i2c->SR1 & I2C_SR1_ADDR)) { if (BSP_Get_Ticks()- start_timer>timeout) { return i2c_timeOut; } } (void)i2c->SR2; while(!(i2c->SR1&I2C_SR1_TXE)) { if (BSP_Get_Ticks()- start_timer>timeout) { return i2c_timeOut; } } i2c->DR = MemAddr; while(!(i2c->SR1&I2C_SR1_TXE)) { if (BSP_Get_Ticks()- start_timer>timeout) { return i2c_timeOut; } } i2c->CR1|=I2C_CR1_START; while(!(i2c->SR1 & I2C_SR1_SB)) { if (BSP_Get_Ticks()- start_timer>timeout) { return i2c_timeOut; } } i2c->DR=address<<1|1; while(!(i2c->SR1 & I2C_SR1_ADDR)) { if (BSP_Get_Ticks()- start_timer>timeout) { return i2c_timeOut; } } (void)i2c->SR2; i2c->CR1|=I2C_CR1_ACK; while(length>0U) { if(length==1U) { i2c->CR1&=~I2C_CR1_ACK; i2c->CR1|=I2C_CR1_STOP; while(!(i2c->SR1&I2C_SR1_RXNE)) { if (BSP_Get_Ticks()- start_timer>timeout) { return i2c_timeOut; } } *data++=i2c->DR; break; } else { while(!(i2c->SR1&I2C_SR1_RXNE)) { if (BSP_Get_Ticks()- start_timer>timeout) { return i2c_timeOut; } } (*data++)=i2c->DR; length--; } } return i2c_success; } I2C_StatusTypedef BSP_I2C_Read(I2C_TypeDef *i2c, uint8_t address, uint8_t *data, uint16_t length, uint32_t timeout) { uint32_t start_timer=BSP_Get_Ticks(); while (i2c->SR2 & I2C_SR2_BUSY) { if (BSP_Get_Ticks()- start_timer>timeout) { return i2c_timeOut; } } i2c->CR1|=I2C_CR1_START; while(!(i2c->SR1 & I2C_SR1_SB)) { if (BSP_Get_Ticks()- start_timer>timeout) { return i2c_timeOut; } } i2c->DR=address<<1|1; while(!(i2c->SR1 & I2C_SR1_ADDR)) { if (BSP_Get_Ticks()- start_timer>timeout) { return i2c_timeOut; } } (void)i2c->SR2; i2c->CR1|=I2C_CR1_ACK; while(length>0U) { if(length==1U) { i2c->CR1&=~I2C_CR1_ACK; i2c->CR1|=I2C_CR1_STOP; while(!(i2c->SR1&I2C_SR1_RXNE)) { if (BSP_Get_Ticks()- start_timer>timeout) { return i2c_timeOut; } } *data++=i2c->DR; break; } else { while(!(i2c->SR1&I2C_SR1_RXNE)) { if (BSP_Get_Ticks()- start_timer>timeout) { return i2c_timeOut; } } (*data++)=i2c->DR; length--; } } return i2c_success; }
3. Main code.
In main.c file:
Include the following:
#include "bsp.h" #include "uart_bsp.h" #include "exti_bsp.h" #include "bsp_debug.h" #include "spi_bsp.h" #include "dma_bsp.h" #include "i2c_bsp.h" #include "stdlib.h"
Declare i2c configuration data structure:
I2C_ConfigTypedef i2c1Config;
Declare an array of 6 bytes to hold the acceleration data:
uint8_t MPU9250_ACC_Data[6];
In main function:
#if FPU_EN SCB->CPACR |= ((3UL << 10*2)|(3UL << 11*2)); #endif clock_config(); BSP_Ticks_Init(100000000); GPIO_Configure_Typedef I2C_PB8, I2C_PB9; GPIOB_CLOCK_ENABLE(); I2C_PB8.PinNumber=8; I2C_PB8.OutputType=Open_Drain; I2C_PB8.Mode=Alternate_function; I2C_PB8.PullUp_PullDown=PullUp; I2C_PB8.AlternateType=AF4; I2C_PB9.PinNumber=9; I2C_PB9.OutputType=Open_Drain; I2C_PB9.Mode=Alternate_function; I2C_PB8.PullUp_PullDown=PullUp; I2C_PB9.AlternateType=AF4; GPIO_Initialization(GPIOB,&I2C_PB8); GPIO_Initialization(GPIOB,&I2C_PB9); __I2C1_CLOCK_ENABLE(); i2c1Config.MasterMode=standardSpeed; i2c1Config.PeripheralFrequency=50; i2c1Config.RiseTime=9; BSP_I2C_Init(I2C1, &i2c1Config);
In while(1) loop:
while(1) { BSP_I2C_Read_Memory(I2C1, 0x68, 0x3B, MPU9250_ACC_Data, 6, 200); }
Hence, the main code as following:
#include "bsp.h" #include "uart_bsp.h" #include "exti_bsp.h" #include "bsp_debug.h" #include "spi_bsp.h" #include "dma_bsp.h" #include "i2c_bsp.h" #include "stdlib.h" void clock_config(void); I2C_ConfigTypedef i2c1Config; uint8_t MPU9250_ACC_Data[6]; int main() { #if FPU_EN SCB->CPACR |= ((3UL << 10*2)|(3UL << 11*2)); #endif clock_config(); BSP_Ticks_Init(100000000); GPIO_Configure_Typedef I2C_PB8, I2C_PB9; GPIOB_CLOCK_ENABLE(); I2C_PB8.PinNumber=8; I2C_PB8.OutputType=Open_Drain; I2C_PB8.Mode=Alternate_function; I2C_PB8.PullUp_PullDown=PullUp; I2C_PB8.AlternateType=AF4; I2C_PB9.PinNumber=9; I2C_PB9.OutputType=Open_Drain; I2C_PB9.Mode=Alternate_function; I2C_PB8.PullUp_PullDown=PullUp; I2C_PB9.AlternateType=AF4; GPIO_Initialization(GPIOB,&I2C_PB8); GPIO_Initialization(GPIOB,&I2C_PB9); __I2C1_CLOCK_ENABLE(); i2c1Config.MasterMode=standardSpeed; i2c1Config.PeripheralFrequency=50; i2c1Config.RiseTime=9; BSP_I2C_Init(I2C1, &i2c1Config); while(1) { BSP_I2C_Read_Memory(I2C1, 0x68, 0x3B, MPU9250_ACC_Data, 6, 200); } } void clock_config(void) { Clock_Config_Typedef clockConfig; clockConfig.PLL_M= 4; clockConfig.PLL_N= 200; clockConfig.PLL_P= 4; clockConfig.AHB1Prescaler=AHB1_Prescaler1; clockConfig.APB1Prescaler=APB1_Prescaler2; clockConfig.APB2Prescaler=APB2_Prescaler1; clockConfig.clockSourc=External_Oscillator; clockConfig.flash_latency= Three_wait_state; Clock_Configuration(&clockConfig); }
4. Results:
Upload the code to your STM32 and connect MPU9250 and you should get the following:
Happy coding 🙂
4 Comments
Dear Sir,
Good Morning,
in UART2 Serial Prinitng, we Use, function
int __io_putchar(int ch) { uart2_write(ch); return ch; }
where as in SWO, we use the Same function as..
int __io_putchar(int ch) { ITM_SendChar(ch); return ch; }
if we need both SWO output for debugging, and Serial Display using Printf(),
simultaneously in the same program how to address, them. Please Respond,
thanks with regards,
HSR-Rao.
Hi,
just put ITM_SendChar(ch); after the uart and you can get both.
Thank you sir,
Dear Sir,
Good morning, Suggestion Worked successfully,
thanks, with regards,
HSR-Rao.
Add Comment