I am interfacing AT24C02 external eeprom using stm32f401 nucleo. I am facing few issues.
Lets consider some address
/* 24c02 Device Address */
#define EEPROM_ADDRESS (uint8_t)0xA0
/*Demo addr*/
#define DEMO_BYTE_ADDR (uint16_t)0x01
#define DEMO_WORD_ADDR (uint16_t)0x02
#define DEMO_FLOAT_ADDR (uint16_t)0x06
#define DEMO_STRING_ADDR (uint16_t)0x0A
1. Writing and reading simultaneously.
I am able to write and read data to and from eeprom simultaneously.
/*Writing Byte*/
uint8_t byte;
eep_write_byte(DEMO_BYTE_ADDR, 50);
eep_read_byte(DEMO_BYTE_ADDR, &byte);
/*Wrinting word*/
uint32_t word;
eep_write_word(DEMO_WORD_ADDR, 123456789);
word = eep_read_word(DEMO_WORD_ADDR);
/*Writing float*/
float fData;
eep_write_float(DEMO_FLOAT_ADDR, 9876.54);
fData = eep_read_float(DEMO_FLOAT_ADDR);
This code works fine. Below is the snapshot of output.
2. Problems with writing string
After the above portion of code i have written some lines to write string and read string. As you can see in output buffer dest contains some value.
uint8_t dest[50] = {0};
eep_write_string(DEMO_STRING_ADDR, (uint8_t*)"Hello World!", strlen("Hello World!"));
eep_read_string(DEMO_STRING_ADDR, dest, strlen("Hello World!"));
3. After writing all these values the reading shows corrupted data
After the above portion of the code if i read back all the addresses i have wrote gives me corrupted data.
eep_read_byte(DEMO_BYTE_ADDR, &byte);
word = eep_read_word(DEMO_WORD_ADDR);
fData = eep_read_float(DEMO_FLOAT_ADDR);
eep_read_string(DEMO_STRING_ADDR, dest, strlen("Hello World!"));
Below is the snapshot of out for this code.
As you can see all the data is now corrupted.
you can find eeprom.c from this link https://pastebin.com/2vYWYhnw or just scroll below.
/*
* eeprom.c
*
* Created on: 04-Jan-2021
* Author: DEVJEET MANDAL
*/
#include "i2c.h"
#include "eeprom.h"
#include "stdio.h"
#include "stdlib.h"
/* Low Level function */
void eep_small_delay(void) {
for (uint32_t i = 0; i < 65535; i++)
__asm__("NOP");
}
void i2c_error(void) {
HAL_I2C_DeInit(&hi2c1); //De-init i2c bus
__asm__("NOP");
HAL_I2C_Init(&hi2c1); //re-init i2c bus
__asm__("NOP");
}
eep_status_t i2c_write(uint16_t u8_reg_addr, uint8_t *u8_data, uint16_t len) {
HAL_StatusTypeDef xStatus = HAL_ERROR;
xStatus = HAL_I2C_Mem_Write(&hi2c1, EEPROM_ADDRESS, u8_reg_addr, I2C_MEMADD_SIZE_16BIT, u8_data, len, 100);
HAL_Delay(5);
if (xStatus != HAL_OK) {i2c_error();}
return xStatus;
}
eep_status_t i2c_read(uint16_t u8_reg_addr, uint8_t *u8_data, uint16_t len) {
HAL_StatusTypeDef xStatus = HAL_ERROR;
xStatus = HAL_I2C_Mem_Read(&hi2c1, EEPROM_ADDRESS, u8_reg_addr, I2C_MEMADD_SIZE_16BIT, u8_data, len, 100);
eep_small_delay();
if (xStatus != HAL_OK) {i2c_error();}
return xStatus;
}
/* High Level Functions */
eep_status_t eep_write_byte(uint16_t u8_reg_addr, uint8_t u8_data) {
return i2c_write(u8_reg_addr, &u8_data, 1);
}
eep_status_t eep_read_byte(uint16_t u8_reg_addr, uint8_t *u8_data) {
return i2c_read(u8_reg_addr, u8_data, 1);
}
eep_status_t eep_is_data_avaiable(void) {
eep_status_t xStatus = EEP_ERROR;
uint8_t data = 0;
eep_read_byte(EEPROM_DATA_AVAILABLE_ADDR, &data);
if (data == 0) {xStatus = EEP_ERROR;}
else if (data == 1) {xStatus = EEP_OK;}
else {xStatus = EEP_ERROR;}
return xStatus;
}
eep_status_t eep_set_data_available(uint8_t val) {
return eep_write_byte(EEPROM_DATA_AVAILABLE_ADDR, val);
}
eep_status_t eep_write_word(uint16_t reg_addr, uint32_t value) {
uint8_t val_byte[4] = {0};
val_byte[0] = (value >> 24) & 0xFF;
val_byte[1] = (value >> 16) & 0xFF;
val_byte[2] = (value >> 8) & 0xFF;
val_byte[3] = (value >> 0) & 0xFF;
return i2c_write(reg_addr, val_byte, 4);
}
eep_status_t eep_write_float(uint16_t reg_addr, float value) {
union FtoHex{
float fval;
uint32_t hval;
}float_to_hex;
float_to_hex.fval = value;
return eep_write_word(reg_addr, float_to_hex.hval);
}
uint32_t eep_read_word(uint16_t reg_addr) {
uint8_t val_buff[4] = {0};
i2c_read(reg_addr, val_buff, 4);
return ((val_buff[0] << 24) | (val_buff[1] << 16) | (val_buff[2] << 8) | (val_buff[3] << 0));
}
float eep_read_float(uint8_t reg_addr) {
union FtoHex{
float fval;
uint32_t hval;
}float_to_hex;
float_to_hex.hval = eep_read_word(reg_addr);
return float_to_hex.fval;
}
void eep_write_string(uint16_t reg_addr, uint8_t *src, uint16_t len) {
i2c_write(reg_addr, src, len);
}
void eep_read_string(uint16_t reg_addr, uint8_t *dest, uint16_t len) {
i2c_read(reg_addr, dest, len);
}
//---------------------------------------------------------------------
Almost forgot to mention i m running I2C #400Khz. Though i have tried 100KHz which results same.
Below is the HAL generated I2C init.
/* I2C1 init function */
void MX_I2C1_Init(void)
{
hi2c1.Instance = I2C1;
hi2c1.Init.ClockSpeed = 400000;
hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2;
hi2c1.Init.OwnAddress1 = 0;
hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
hi2c1.Init.OwnAddress2 = 0;
hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
if (HAL_I2C_Init(&hi2c1) != HAL_OK)
{
Error_Handler();
}
}
Now the question is why this problem. Basically the HAL should take care of all the situation and i will just send data to it. Any help will be appreciated.
Regards.
You missed that AT24C02 is organized in 16 byte (write) pages.
The corruption is caused by rollover/wrap # offset 0x0F when writing the string starting # offset 0x0A.
See the data sheet for details.
Related
I wrote a little program that reads I2C values with interrupts: The Problem is that sometimes it just doesn't work after uploading. I just have to run it so many times until it works (not changing anything in the code). It seems like its just coincidence if it works or not.
Here are the Details:
Sensor: HMC 5983 or MPU-6050 (same problem)
Board: STM32F103RB (Nucleo 64)
Code (without the generated Cubemx stuff):
int main(void) {
/*/////////////////////Setup/////////////////////////*/
buf[0] = 0x00;
buf[1] = 0x78;
buf[2] = 0x80;
buf[3] = 0x00;
HAL_I2C_Master_Transmit(&hi2c1, Kompass_ADDR, buf, 4, 100);
/*//////////////////////Start of IT Routine//////////////////*/
buf[0] = 0x03;
HAL_I2C_Master_Transmit_IT(&hi2c1, Kompass_ADDR, buf, 1);
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1) {
/*/////////////////////printing the value////////////////////////*/
sprintf((char*) Serial_buffer, " X %i \r\n", DataX);
HAL_UART_Transmit(&huart2, (uint8_t*) Serial_buffer, strlen((char*) Serial_buffer), 100);
HAL_Delay(500);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
void HAL_I2C_MasterTxCpltCallback(I2C_HandleTypeDef *hi2c) {
HAL_I2C_Master_Receive_IT(&hi2c1, Kompass_ADDR, buf, 6);
}
void HAL_I2C_MasterRxCpltCallback(I2C_HandleTypeDef *hi2c) {
DataX = ((int16_t) buf[0]) << 8 | buf[1];
buf[0] = 0x03;
HAL_I2C_Master_Transmit_IT(&hi2c1, Kompass_ADDR, buf, 1);
}
////////////////////////////I2C Init Function////////////////////////
static void MX_I2C1_Init(void) {
hi2c1.Instance = I2C1;
hi2c1.Init.ClockSpeed = 100000;
hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2;
hi2c1.Init.OwnAddress1 = 0;
hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
hi2c1.Init.OwnAddress2 = 0;
hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
if (HAL_I2C_Init(&hi2c1) != HAL_OK) {
Error_Handler();
}
}
After some Error searching I found out, that the error occurs when there I2C port is busy during the reading.
Does somebody have Experience with this I2C Problem?
I'm getting FIFO data from MAX30100 using the MCU STM32F4 to measure Heart Rate. In the signal received I can see the Heart Beat but also fails in the samples, as u can see below:
I'm dont have a filter working but the signal without filter was diferent when I did this on the Arduino board. Am I losting samples or it's normal? What I did wrong?
Datasheet MAX30100: https://img.filipeflop.com/files/download/Datasheet_MAX30100.pdf
Following my code:
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "usb_device.h"
/* Private define ------------------------------------------------------------*/
// FIFO registers
#define MAX30100_FIFO_W_POINTER 0x02
#define MAX30100_OVF_COUNTER 0x03
#define MAX30100_FIFO_R_POINTER 0x04
#define MAX30100_FIFO_DATA_REG 0x05
// configuration registers
#define MAX30100_MODE_CONFIG 0x06
#define MAX30100_SPO2_CONFIG 0x07
#define MAX30100_LED_CONFIG 0x09
// PART ID registers
#define MAX30100_PART_ID 0xFF
// MAX30100 I2C addresses
#define MAX30100_WADDRESS 0xAE // 8bit address converted to 7bit + W
#define MAX30100_RADDRESS 0xAF // 8bit address converted to 7bit + R
/* Private variables ---------------------------------------------------------*/
I2C_HandleTypeDef hi2c3;
char buffer[30];
unsigned long ir_buff[16] = {0}, red_buff[16] = {0};
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_I2C3_Init(void);
uint8_t CDC_Transmit_FS(char* Buf, uint16_t Len);
uint8_t MAX30100_getNumSamp(uint16_t* ir_buff, uint16_t* red_buff);
uint8_t MAX30100_getPartID(void);
void MAX30100_reset(void);
void MAX30100_wakeup(void);
void MAX30100_SetHR (void);
void MAX30100_InitFIFO (void);
void MAX30100_setLEDs(uint8_t ledCurrentRed, uint8_t ledCurrentIr);
void MAX30100_setSR(uint8_t sr);
void MAX30100_setPW (uint8_t pw);
uint8_t MAX30100_read (uint8_t device_register);
void MAX30100_write (uint8_t device_register, uint8_t reg_data);
int main(void)
{
uint8_t id;
uint8_t i;
uint8_t samples;
uint16_t ir_average = 0;
uint16_t red_average = 0;
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_I2C3_Init();
MX_USB_DEVICE_Init();
HAL_Delay(10);
MAX30100_reset();
id = MAX30100_getPartID();
if (id == 0x11) //OK
// Set LED current
MAX30100_setLEDs(0x07, 0xFF);
// Set sample rate
MAX30100_setSR(0x00);
// Set pulse width
MAX30100_setPW(0x3);
// Set heart rate mode
MAX30100_SetHR ();
// Set RD and WR pointers to 0x00
MAX30100_InitFIFO();
// Wake up
MAX30100_wakeup();
while (1)
{
// Gets the number of samples in the FIFO and reads then
samples = MAX30100_getNumSamp((uint16_t*)ir_buff, (uint16_t*)red_buff);
if (samples > 0 )
{
// we have data in FIFO
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_14,1); //LED ON
ir_average = 0;
red_average = 0;
for (i = 0; i < samples; i++)
{
ir_average += (uint16_t)ir_buff[i];
red_average += (uint16_t)red_buff[i];
}
ir_average /= samples; // calculate the average value for this reading
red_average /= samples;
memset(buffer,0,sizeof(buffer));
sprintf(buffer, "HR: %d,", (uint16_t)ir_average);
CDC_Transmit_FS((char*)buffer, 20); //print the ir value to CDC
}
else
{
// There's no data in FIFO
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_14,0); //LED OFF
HAL_Delay(1); // Wait for samples to be aquired
}
}
}
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
__HAL_RCC_PWR_CLK_ENABLE();
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE2);
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = 25;
RCC_OscInitStruct.PLL.PLLN = 336;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV4;
RCC_OscInitStruct.PLL.PLLQ = 7;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV2;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1) != HAL_OK)
{
Error_Handler();
}
}
static void MX_I2C3_Init(void)
{
hi2c3.Instance = I2C3;
hi2c3.Init.ClockSpeed = 400000;
hi2c3.Init.DutyCycle = I2C_DUTYCYCLE_2;
hi2c3.Init.OwnAddress1 = 0;
hi2c3.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
hi2c3.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
hi2c3.Init.OwnAddress2 = 0;
hi2c3.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
hi2c3.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
if (HAL_I2C_Init(&hi2c3) != HAL_OK)
{
Error_Handler();
}
}
static void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOH_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_14|GPIO_PIN_15, GPIO_PIN_RESET);
/*Configure GPIO pins : PC14 PC15 */
GPIO_InitStruct.Pin = GPIO_PIN_14|GPIO_PIN_15;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
}
// Reads from register 0xFF
// should return 0x11
uint8_t MAX30100_getPartID(void)
{
uint8_t reg;
reg = MAX30100_read (MAX30100_PART_ID);
return reg;
}
// Resets the MAX30100 IC
void MAX30100_reset(void)
{
uint8_t reg;
reg = MAX30100_read (MAX30100_MODE_CONFIG);
// RESET bit is B6
// 0x40 = 0100 0000
reg = (reg | 0x40); // Set reset bit to 1
MAX30100_write (MAX30100_MODE_CONFIG, reg);
}
// Wakes up the MAX30100
void MAX30100_wakeup(void)
{
uint8_t reg;
reg = MAX30100_read (MAX30100_MODE_CONFIG);
reg = reg & 0x7F; // Set SHDN bit to 0
MAX30100_write (MAX30100_MODE_CONFIG, reg);
}
// Sets Heart rate mode
// This means MODE{2:0} = 0b010 (or 0x02 in hexadecimal)
void MAX30100_SetHR (void)
{
uint8_t reg;
reg = MAX30100_read (MAX30100_MODE_CONFIG);
// RESET bit is B7
// First we clear bits 2:0
reg = reg & 0xF8;
// Then we set bits 2:0 to 0x02
reg = reg | 0x02;
MAX30100_write (MAX30100_MODE_CONFIG, reg);
}
// Initializes FIFO
// Sets RD and WR pointers to 0
// Clears OVF
void MAX30100_InitFIFO (void)
{
MAX30100_write (MAX30100_FIFO_W_POINTER, 0x00);
MAX30100_write (MAX30100_FIFO_R_POINTER, 0x00);
MAX30100_write (MAX30100_OVF_COUNTER, 0x00);
}
// Sets LED currents
void MAX30100_setLEDs(uint8_t ledCurrentRed, uint8_t ledCurrentIr)
{
uint8_t reg;
reg = ( ledCurrentRed << 4 ) | ledCurrentIr;
MAX30100_write (MAX30100_LED_CONFIG, reg);
}
// Sets sample rate
// sample rate is bits 4:2 of register MAX30100_SPO2_CONFIG
// bitmask is 0xE3
void MAX30100_setSR (uint8_t sr)
{
uint8_t reg;
reg = MAX30100_read (MAX30100_SPO2_CONFIG);
reg = reg & 0xE3;
reg = reg | (sr << 2);
MAX30100_write (MAX30100_SPO2_CONFIG, reg);
}
// Sets pulse width
// sample rate is bits 1:0 of register MAX30100_SPO2_CONFIG
void MAX30100_setPW (uint8_t pw)
{
uint8_t reg;
reg = MAX30100_read (MAX30100_SPO2_CONFIG);
reg = reg & 0xFC;
reg = reg | pw;
MAX30100_write (MAX30100_SPO2_CONFIG, reg);
}
// Gets number of samples in FIFO and read then
uint8_t MAX30100_getNumSamp(uint16_t* ir_buff, uint16_t* red_buff)
{
uint8_t wreg;
uint8_t rreg;
uint8_t sampleNum;
uint8_t samples[4];
wreg = MAX30100_read (MAX30100_FIFO_W_POINTER);
rreg = MAX30100_read (MAX30100_FIFO_R_POINTER);
sampleNum = (abs( 16 + wreg - rreg ) % 16);
if(sampleNum > 0)
{
//HAL_I2C_Mem_Read(&hi2c3,MAX30100_RADDRESS,MAX30100_FIFO_DATA_REG,4,(uint8_t*)samples,1,1000);
HAL_I2C_Mem_Read(&hi2c3,MAX30100_RADDRESS,MAX30100_FIFO_DATA_REG,1,&samples[0],1,250);
HAL_I2C_Mem_Read(&hi2c3,MAX30100_RADDRESS,MAX30100_FIFO_DATA_REG,1,&samples[1],1,250);
HAL_I2C_Mem_Read(&hi2c3,MAX30100_RADDRESS,MAX30100_FIFO_DATA_REG,1,&samples[2],1,250);
HAL_I2C_Mem_Read(&hi2c3,MAX30100_RADDRESS,MAX30100_FIFO_DATA_REG,1,&samples[3],1,250);
*(ir_buff) = (uint16_t)samples[1];
*(ir_buff++) |= (uint16_t)samples[0] << 8;
*(red_buff) = (uint16_t)samples[3];
*(red_buff++) |= (uint16_t) samples[2] << 8;
//HAL_Delay(7); // just test
}
return sampleNum;
}
// My I2C read and write functions
uint8_t MAX30100_read (uint8_t device_register )
{
uint8_t read_data;
HAL_I2C_Mem_Read(&hi2c3,MAX30100_RADDRESS,device_register,I2C_MEMADD_SIZE_8BIT,&read_data,1,250);
return read_data;
}
void MAX30100_write (uint8_t device_register, uint8_t reg_data)
{
HAL_I2C_Mem_Write(&hi2c3,MAX30100_WADDRESS,device_register,I2C_MEMADD_SIZE_8BIT,®_data,1,250);
}
I am new I2C communication. I examined some running code. And I used function their used. But I can't get any data. I wonder if I2C have to do initial config? Where is the problem. This is function I wrote:
void GetI2CAccelerometer(uint8_t slaveAddress,uint8_t accelData[6])
{
// slaveAddress=0x68 (default address is written in datasheet)
HAL_I2C_Master_Transmit(&hi2c1,slaveAddress<<1,1,0x3B,1,200);
HAL_I2C_Master_Receive(&hi2c1,slaveAddress<<1,accelData,6,200);
HAL_I2C_Mem_Read(&hi2c1,(slaveAddress<<1)+1,0x3B,1,accelData,1,200);
// i tried this function too but not working
}
I created this project with CubeMX. This is initial I2C config and also GPIO_A clock line is activated in another function which I did not write:
static void MX_I2C1_Init(void)
{
hi2c1.Instance = I2C1;
hi2c1.Init.ClockSpeed = 100000;
hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2;
hi2c1.Init.OwnAddress1 = 208;
hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
hi2c1.Init.OwnAddress2 = 0;
hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
if (HAL_I2C_Init(&hi2c1) != HAL_OK)
{
Error_Handler();
}
}
First of all, better use DMA or IT data exchange. Polling is not good, but ok for testing.
You must put pointers to data, not the data itself. The good practice is something like this:
void GetI2CAccelerometer(I2C_HandleTypeDef * hi2c, uint8_t slaveAddress, uint8_t * accelData, size_t size) {
uint8_t request = 0x3B;
// slaveAddress=0x68 (default address is written in datasheet)
// HAL_I2C_Master_Transmit(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout)
while (HAL_I2C_Master_Transmit(hi2c, slaveAddress << 1, (uint8_t*)request, 1, 200) != HAL_OK) {
// Use FreeRTOS vTaskDelay(1) and/or check errors here
// And check timeout or you will hang over here
}
//HAL_I2C_Master_Receive(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout)
while (HAL_I2C_Master_Receive(hi2c, slaveAddress << 1, accelData, size, 200) != HAL_OK) {
// Use FreeRTOS vTaskDelay(1) and/or check errors here
// And check timeout or you will hang over here
}
while (HAL_I2C_GetState(hi2c) != HAL_I2C_STATE_READY) {
// Use FreeRTOS vTaskDelay(1) and/or check errors here
// And check timeout or you will hang over here
}
}
And then request data by function:
uint8_t accelData[6];
GetI2CAccelerometer(&hi2c1, 0x68, accelData, 6);
Thats ok for testing, but bad for production. Get the data and then rewrite to use I2C DMA or IT. Check errors at I2C bus and make some enum to return errors/states from function.
When i run the I2C scanner on STM32F303, i see both devices connected to the bus. Names a device on address 0x3C (OLED) and address (0x68) MPU6050. Both addresses, specifically agree with what the datasheet says.
However, when i try to read the WHO_AM_I register on address 0x68 using HAL_I2C_IsDeviceReady, i realize that it even times out.
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_I2C1_Init();
MX_SPI1_Init();
MX_TIM6_Init();
MX_USART1_UART_Init();
I2C_Scanner();
SSD1306_Init();
HAL_Delay (2000);
MPU6050_Init();
while (1)
{
}
}
Function (MPU6050_Init) to check if the device is ready
static void MPU6050_Init(void)
{
HAL_Delay(1);
SSD1306_Clear();
SSD1306_GotoXY (0, 0);
char OutputArray[50] = {0};
if(HAL_I2C_IsDeviceReady(&hi2c1, MPU6050_I2C_ADDR, 10, HAL_MAX_DELAY) != HAL_OK)
{
sprintf(OutputArray, "0x%02x : Not ready", MPU6050_I2C_ADDR);
}
else
{
HAL_GPIO_WritePin(LD3_GPIO_Port, LD3_Pin, GPIO_PIN_SET);
uint8_t check;
HAL_I2C_Mem_Read(&hi2c1, MPU6050_I2C_ADDR, WHO_AM_I_REG, 1, &check, 1, HAL_MAX_DELAY);
sprintf(OutputArray,"0x%02x", (uint16_t)check);
}
HAL_Delay(1);
SSD1306_Puts (OutputArray, &Font_7x10, SSD1306_COLOR_WHITE);
SSD1306_UpdateScreen();
}
Function (I2C_Scanner) to scan for I2C bus for available devices
static void I2C_Scanner(void)
{
HAL_StatusTypeDef result;
uint8_t i;
for (i = 1; i < 128; i++)
{
result = HAL_I2C_IsDeviceReady(&hi2c1, (uint16_t)(i << 1), 1, HAL_MAX_DELAY);
char* period = ".";
char OutputArray[5];
if (result != HAL_OK) // HAL_ERROR or HAL_BUSY or HAL_TIMEOUT
{
HAL_UART_Transmit(&huart1, (uint8_t*)period, sizeof(period), HAL_MAX_DELAY);
}
if (result == HAL_OK)
{
sprintf(OutputArray, "0x%02x", i); // Received an ACK at that address
HAL_UART_Transmit(&huart1, (uint8_t*)OutputArray, sizeof(OutputArray), HAL_MAX_DELAY);
}
HAL_Delay(1);
}
}
Function (MC_I2C1_Init) to initialize the I2C
static void MX_I2C1_Init(void)
{
hi2c1.Instance = I2C1;
hi2c1.Init.Timing = 0x0000020B;
hi2c1.Init.OwnAddress1 = 0;
hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
hi2c1.Init.OwnAddress2 = 0;
hi2c1.Init.OwnAddress2Masks = I2C_OA2_NOMASK;
hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
if (HAL_I2C_Init(&hi2c1) != HAL_OK)
{
Error_Handler();
}
if (HAL_I2CEx_ConfigAnalogFilter(&hi2c1, I2C_ANALOGFILTER_ENABLE) != HAL_OK)
{
Error_Handler();
}
if (HAL_I2CEx_ConfigDigitalFilter(&hi2c1, 0) != HAL_OK)
{
Error_Handler();
}
}
The expected results would be to check that the device is available, ready and convey back the contents of the WHO_AM_I register
Found a solution. The problem was that i had defined the MPU6050 address as follows
#define MPU6050_I2C_ADDR 0x68
The correct definition should have been
#define MPU6050_I2C_ADDR 0x68 << 1
Which resulted in 0xD0
I want use camera ov5640 with stm32l4r5 nucleo-144 kit. We use i2c for setting up camera. I am using following code for i2c communication.
#define OV5640_ADDR 0x78
int ov7670_init(I2C_HandleTypeDef *p_hi2c)
{
sp_hi2c = p_hi2c;
HAL_Delay(100);
uint8_t reg;
uint8_t buffer;
reg = ov7670_read(OV5640_CHIPIDH, &buffer);
if (buffer == 0x56)
{
reg = ov7670_read(OV5640_CHIPIDL, &buffer);
if (buffer == 0x40)
{
return 0;
}
else
{
return 1;
}
}
else
{
return 1;
}
}
static int ov5640_write(uint16_t regAddr, uint8_t data)
{
HAL_StatusTypeDef ret;
do {
ret = HAL_I2C_Mem_Write(sp_hi2c, OV5640_ADDR, regAddr, I2C_MEMADD_SIZE_8BIT, &data, 1, 100);
} while (ret != HAL_OK && 0);
return ret;
}
static int ov7670_read(uint16_t regAddr, uint8_t *data)
{
HAL_StatusTypeDef ret;
uint8_t regAddrMSB = regAddr >> 8;
uint8_t regAddrLSB = regAddr & 0x00FF;
do {
ret = HAL_I2C_Master_Transmit(sp_hi2c, OV5640_ADDR, ®AddrMSB, 1, 100);
ret |= HAL_I2C_Master_Transmit(sp_hi2c, OV5640_ADDR, ®AddrLSB, 1, 100);
ret |= HAL_I2C_Master_Receive(sp_hi2c, OV5640_ADDR, data, 1, 100);
} while (ret != HAL_OK && 0);
return ret;
}
I used STM32CUBEMX software for setting up i2c pins and generating related code for initialising i2c pins. The camera has i2c registers address is 16bit. But i2c communication not working. I am not able to read registers.