cancel
Showing results for 
Search instead for 
Did you mean: 

Issues with FM24CLXX_WriteData function in STM32 project

VThuong99
Associate

I have the following function to write data to the FM24CL64 memory:

 

void FM24CLXX_WriteData(uint16_t memAddr, uint8_t *data, uint16_t size) {
    uint8_t memAddrData[2] = { (uint8_t)(memAddr >> 8), (uint8_t)(memAddr & 0xFF) };
    HAL_StatusTypeDef status = HAL_I2C_Mem_Write(&hi2c1, FM24CLXX_I2C_ADDR, memAddrData[0], I2C_MEMADD_SIZE_8BIT, data, size, 100);

    if (status != HAL_OK) {
        Error_Handler();
    }
}

 

 

Symptoms:

  • The write operation fails, but the HAL_StatusTypeDef status returns a code that doesn't indicate exactly where the issue is.
  • I have verified that the I2C address FM24CLXX_I2C_ADDR = 0xA0 is correct.
  • The Error_Handler() function is being triggered, but I don't know exactly why.

Possible Causes:

  • There could be an issue with how the I2C command is sent.
  • Maybe the address or size format isn't compatible with the memory or STM32 I2C configuration.

Request:

  • Anyone with experience in using STM32 with I2C and FM24CLXX memory, could you please help me identify what could be wrong?
  • Suggestions for debugging or best practices when working with I2C memory like the FM24CL64 would be appreciated.

Full code:

This is my full code, I using stm32f405 OpenX05R-C board.

 

#include "main.h"
#include "cmsis_os.h"

#include <stdio.h>
#include "backup_sram.h"
#include "fm24clxx.h"

#define Avg_slope (2.5F)
#define V_25  (0.76F)

osThreadId_t Task1Handle;
osThreadId_t Task2Handle;
osThreadId_t Task3Handle;

osMutexId_t sharedMutex;

ADC_HandleTypeDef hadc1;
DMA_HandleTypeDef hdma_adc1;

I2C_HandleTypeDef hi2c1;

UART_HandleTypeDef huart2;

// Printf with USART
int _write(int file, char *data, int len) {
    HAL_UART_Transmit(&huart2, (uint8_t*)data, len, HAL_MAX_DELAY);
    return len;
}

uint32_t temperature_value;
volatile uint8_t button_pressed = 0;

#define DEBOUNCE_DELAY 50
#define STABLE_THRESHOLD 4

int is_button_pressed() {
    uint8_t counter = 0;
    uint8_t i;
    uint8_t button_input;

    button_input = HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_1);
    if (button_input != GPIO_PIN_RESET) {
        return 0;
    }

    for (i = 0; i < 10; i++) {
        osDelay(5);
        button_input = HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_1);
        if (button_input == GPIO_PIN_SET) {
            counter = 0;
        } else {
            counter++;
        }
        if (counter >= STABLE_THRESHOLD) {
            return 1;
        }
    }

    return 0;
}
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc) {
    if (hadc->Instance == ADC1) {
//        float value = HAL_ADC_GetValue(&hadc1);
    	float value = temperature_value;
        float V_sense = (value * 3.0f) / 4095.0f;
        temperature_value = (uint32_t)((V_sense  - V_25) / Avg_slope + 25.0f);
        printf("ADC value: %d, Temperature: %lu\r\n", (int)V_sense, temperature_value);

        BKPSRAM_Write(0x00, temperature_value);
        HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_1);

    }
}

void Task1_Blink_LED(void *argument) {
    while (1) {
        HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_0);
        osDelay(1000);
    }
}
void Task2_Read_Temperature(void *argument) {
    while(1){
        HAL_ADC_Start_DMA(&hadc1, &temperature_value, 1);
    	osDelay(5000);
        uint32_t temp_from_sram = BKPSRAM_Read(0x00);
        printf("Temp from Backup SRAM: %lu\r\n", temp_from_sram);
//        HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_1);
    }
//    while (1) {
//        HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_1);
//        osDelay(1000);
//    }
}

void Task3_Button_Check(void *argument) {
    static uint8_t button_stable = 0;

    while(1){
    	printf("t3\r\n");
        if (is_button_pressed()) {
        	printf("0.\r\n");
            if (!button_stable) {
                button_stable = 1;

                if (!button_pressed) {
                    button_pressed = 1;

                    uint32_t temperature;
                    printf("1.\r\n");
		    temperature = BKPSRAM_Read(0x00);
		    printf("2.%lu\r\n", temperature);

		    FM24CLXX_WriteData(0x0000, (uint8_t*)&temperature, sizeof(temperature));

		    printf("Button Pressed, Data written to FM24CLXX: %lu\r\n", temperature);

		    uint32_t read_temp;
		    FM24CLXX_ReadData(0x0000, (uint8_t*)&read_temp, sizeof(read_temp));

		    printf("Data read from FM24CLXX: %lu\r\n", read_temp);

		    HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_2);
				}
			}
		} else {
			if (button_stable) {
				button_stable = 0;
				button_pressed = 0;
			}
		}

		osDelay(10);
	}
}


void RTOS_Tasks_Init() {
    osThreadAttr_t task1_attr = {.name = "Task1", .priority = osPriorityNormal, .stack_size = 128 * 4};
    osThreadAttr_t task2_attr = {.name = "Task2", .priority = osPriorityNormal, .stack_size = 128 * 4};
    osThreadAttr_t task3_attr = {.name = "Task3", .priority = osPriorityHigh, .stack_size = 128 * 4};

    Task1Handle = osThreadNew(Task1_Blink_LED, NULL, &task1_attr);
    Task2Handle = osThreadNew(Task2_Read_Temperature, NULL, &task2_attr);
    Task3Handle = osThreadNew(Task3_Button_Check, NULL, &task3_attr);
}
/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_DMA_Init(void);
static void MX_ADC1_Init(void);
static void MX_I2C1_Init(void);
static void MX_USART2_UART_Init(void);
int main(void)
{
  HAL_Init();

  SystemClock_Config();

  MX_GPIO_Init();
  MX_DMA_Init();
  MX_ADC1_Init();
  MX_I2C1_Init();
  MX_USART2_UART_Init();
  BKPSRAM_Init();

  sharedMutex = osMutexNew(NULL);

  osKernelInitialize();
  RTOS_Tasks_Init();
  osKernelStart();



  while (1){
  }

}
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Configure the main internal regulator output voltage
  */
  __HAL_RCC_PWR_CLK_ENABLE();
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);

  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }

  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK)
  {
    Error_Handler();
  }
}

static void MX_ADC1_Init(void)
{

  /* USER CODE BEGIN ADC1_Init 0 */

  /* USER CODE END ADC1_Init 0 */

  ADC_ChannelConfTypeDef sConfig = {0};

  /* USER CODE BEGIN ADC1_Init 1 */

  /* USER CODE END ADC1_Init 1 */

  /** Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion)
  */
  hadc1.Instance = ADC1;
  hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV2;
  hadc1.Init.Resolution = ADC_RESOLUTION_12B;
  hadc1.Init.ScanConvMode = ENABLE;
  hadc1.Init.ContinuousConvMode = DISABLE;
  hadc1.Init.DiscontinuousConvMode = DISABLE;
  hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
  hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
  hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
  hadc1.Init.NbrOfConversion = 2;
  hadc1.Init.DMAContinuousRequests = DISABLE;
  hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
  if (HAL_ADC_Init(&hadc1) != HAL_OK)
  {
    Error_Handler();
  }

  /** Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.
  */
  sConfig.Channel = ADC_CHANNEL_TEMPSENSOR;
  sConfig.Rank = 1;
  sConfig.SamplingTime = ADC_SAMPLETIME_144CYCLES;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }

  /** Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.
  */
  sConfig.Rank = 2;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN ADC1_Init 2 */

  /* USER CODE END ADC1_Init 2 */

}

static void MX_I2C1_Init(void)
{

  /* USER CODE BEGIN I2C1_Init 0 */

  /* USER CODE END I2C1_Init 0 */

  /* USER CODE BEGIN I2C1_Init 1 */

  /* USER CODE END I2C1_Init 1 */
  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();
  }
  /* USER CODE BEGIN I2C1_Init 2 */

  /* USER CODE END I2C1_Init 2 */

}

/**
  * @brief USART2 Initialization Function
  * @PAram None
  * @retval None
  */
static void MX_USART2_UART_Init(void)
{

  /* USER CODE BEGIN USART2_Init 0 */

  /* USER CODE END USART2_Init 0 */

  /* USER CODE BEGIN USART2_Init 1 */

  /* USER CODE END USART2_Init 1 */
  huart2.Instance = USART2;
  huart2.Init.BaudRate = 115200;
  huart2.Init.WordLength = UART_WORDLENGTH_8B;
  huart2.Init.StopBits = UART_STOPBITS_1;
  huart2.Init.Parity = UART_PARITY_NONE;
  huart2.Init.Mode = UART_MODE_TX_RX;
  huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart2.Init.OverSampling = UART_OVERSAMPLING_16;
  if (HAL_UART_Init(&huart2) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN USART2_Init 2 */

  /* USER CODE END USART2_Init 2 */

}

/**
  * Enable DMA controller clock
  */
static void MX_DMA_Init(void)
{

  /* DMA controller clock enable */
  __HAL_RCC_DMA2_CLK_ENABLE();

  /* DMA interrupt init */
  /* DMA2_Stream0_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(DMA2_Stream0_IRQn, 5, 0);
  HAL_NVIC_EnableIRQ(DMA2_Stream0_IRQn);

}

/**
  * @brief GPIO Initialization Function
  * @PAram None
  * @retval None
  */
static void MX_GPIO_Init(void)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};
/* USER CODE BEGIN MX_GPIO_Init_1 */
/* USER CODE END MX_GPIO_Init_1 */

  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOC_CLK_ENABLE();
  __HAL_RCC_GPIOH_CLK_ENABLE();
  __HAL_RCC_GPIOA_CLK_ENABLE();
  __HAL_RCC_GPIOB_CLK_ENABLE();

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(GPIOB, led0_Pin|led1_Pin|led2_Pin|led3_Pin, GPIO_PIN_RESET);

  /*Configure GPIO pin : PA1 */
  GPIO_InitStruct.Pin = GPIO_PIN_1;
  GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  /*Configure GPIO pins : led0_Pin led1_Pin led2_Pin led3_Pin */
  GPIO_InitStruct.Pin = led0_Pin|led1_Pin|led2_Pin|led3_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

  /* EXTI interrupt init*/
  HAL_NVIC_SetPriority(EXTI1_IRQn, 5, 0);
  HAL_NVIC_EnableIRQ(EXTI1_IRQn);

/* USER CODE BEGIN MX_GPIO_Init_2 */
/* USER CODE END MX_GPIO_Init_2 */
}



/* USER CODE END 4 */



/**
  * @brief  Period elapsed callback in non blocking mode
  * @note   This function is called  when TIM6 interrupt took place, inside
  * HAL_TIM_IRQHandler(). It makes a direct call to HAL_IncTick() to increment
  * a global variable "uwTick" used as application time base.
  * @PAram  htim : TIM handle
  * @retval None
  */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
  /* USER CODE BEGIN Callback 0 */

  /* USER CODE END Callback 0 */
  if (htim->Instance == TIM6) {
    HAL_IncTick();
  }
  /* USER CODE BEGIN Callback 1 */

  /* USER CODE END Callback 1 */
}

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */
  __disable_irq();
  while (1)
  {
  }
  /* USER CODE END Error_Handler_Debug */
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @PAram  file: pointer to the source file name
  * @PAram  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

 

1 ACCEPTED SOLUTION

Accepted Solutions
Techn
Senior III

looks like your memaddress is two bytes? So you have to indicate memaddress as 16bit.. and the data is only 8bits? Is it auto incrementing if you write many bytes? but when you read the data, you may have to set the address and then do a repeat start or stop after address write and do a start with read... There is a HAL document for detailed on each API call for your device. UM1725

If you feel a post has answered your question, please click "Accept as Solution".

View solution in original post

2 REPLIES 2
Techn
Senior III

looks like your memaddress is two bytes? So you have to indicate memaddress as 16bit.. and the data is only 8bits? Is it auto incrementing if you write many bytes? but when you read the data, you may have to set the address and then do a repeat start or stop after address write and do a start with read... There is a HAL document for detailed on each API call for your device. UM1725

If you feel a post has answered your question, please click "Accept as Solution".

Thank you so much for your detailed response! As you mentioned, the issue was indeed caused by not configuring the memory address (memaddress) correctly – it needed to be 16-bit. I also realized that reading data requires resetting the address and performing the steps you described (repeat start/stop).

 

Fortunately, after reviewing the UM1725 document, I gained a better understanding of the HAL API and was able to fix the issue. I really appreciate your help!