cancel
Showing results for 
Search instead for 
Did you mean: 

Problem with HAL_I2C_Mem_Write_DMA when using page write to EEPROM M24256

Gaurav_rajput
Associate II

I am using Stm32L431Rbt6 for page writing on EEPROM M2456.

When using HAL_I2C_Mem_Write_DMA , I am getting interrupt HAL_MemTxCpltCallback , but data is not written on EEPROM when I do page read on EEPROM.

I am using I2C1, dma channel 6. I have enabled I2c event and error interrupt. I2C clock freq = 100 Khz., EEPROM page size is 64 bytes.

I am setting the I2C_CR2_STOP bit in HAL_MemTxCpltCallback  for generating stop condition.

 

Please guide if I am doing anything wrong or provide any reference code using HAL_I2C_Mem_Write_DMA .

4 REPLIES 4
Bob S
Principal

You shouldn't have to set the STOP bit int he callback - the HAL interrupt handler should do that.

Are you waiting for the "write" operation to finish before trying to read back from the EEPROM? [EDIT: Not just for the HAL write call to finish, but the EEPROM itself to store the new data]

Show our relevant code - code that calls HAL_I2C_Mem_Write_DMA(), code that reads back, and your callback functions.  Please paste you code here in the chat using the "code" formatting button (click on "..." then "</>").



I have checked using breakpoints HAL_I2C_MemTxCpltCallback is called and HAL_I2C_EV_IRQHandler is called.

Page write and page read done seperately by commenting write and read enable macros.

After doing page write , then page read data is not correct in the page.

HAL_I2C_MemTxCpltCallback => i2c_dma_tf_cplt is set , / This flag tells us DMA has completed transmission of data to i2c_tx data register

 

In HAL_I2C_EV_IRQHandler

I2C_TransferConfig(hi2c, 0xA0, 1, I2C_AUTOEND_MODE, I2C_GENERATE_STOP);    // stop condition sent
tmr_EEPROM_wr = 0; // starting timer counts for waiting 5ms EEPROM internal write
i2c_pg_wr_done = 1; // flag for page write done to eeprom

 

 

 

"code"


@Bob S wrote:

You shouldn't have to set the STOP bit int he callback - the HAL interrupt handler should do that.

Are you waiting for the "write" operation to finish before trying to read back from the EEPROM? [EDIT: Not just for the HAL write call to finish, but the EEPROM itself to store the new data]

Show our relevant code - code that calls HAL_I2C_Mem_Write_DMA(), code that reads back, and your callback functions.  Please paste you code here in the chat using the "code" formatting button (click on "..." then "</>").


 

volatile uint32_t  tmr_EEPROM_wr = 0;  // timer variable for EEPROM internal page write delay
DMA_HandleTypeDef hdma_i2c1_tx;
uint8_t EEPROM_data_buff[64];
uint8_t EEPROM_read_data_buff[64];

#define EEPROM_page_write_enabled   // Read and write done seperately . First doing page write by commenting EEPROM_page_read_enabled

//#define EEPROM_page_read_enabled

main()
{
	
	static void MX_GPIO_Init(void);
	static void MX_DMA_Init(void);
	static void MX_I2C1_Init(void);
	HAL_delay(100);
	Feed_dummy_Data_EEPROM();

	HAL_GPIO_WritePin(GPIOC, GPIO_PIN_12, GPIO_PIN_SET);   //enabling the WR pin of EEPROM
	HAL_I2C_Mem_Write_DMA(&hi2c1, 0xA0, 0x140,2, EEPROM_data_buff, 64);

	while(1)
	{
	  #ifdef EEPROM_page_write_enabled	
		if((i2c_pg_wr_done == 1) && (tmr_EEPROM_wr >= 5))
		{
			HAL_GPIO_WritePin(GPIOC, GPIO_PIN_12, GPIO_PIN_RESET);   //disabling the WR pin of EEPROM
			i2c_pg_wr_done = 0;
		}	
	 #endif
	
	#ifdef EEPROM_page_read_enabled
	M24256_Read(6, EEPROM_read_data_buff);
	#endif


	// other code		

	}
	
}

void Feed_dummy_Data_EEPROM(void)
{
	int16_t temp_var_signed;
	uint16_t temp_var_2;
	uint32_t temp_var_4;

	
	for(i= 0 ; i<64; i++)
	{
		EEPROM_data_buff[i]= 12;
	}

}


static void MX_I2C1_Init(void)
{

	

	hi2c1.Instance = I2C1;
	hi2c1.Init.Timing = 0x007075B1;
	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();
	}
	/** Configure Analogue filter
	 */
	if (HAL_I2CEx_ConfigAnalogFilter(&hi2c1, I2C_ANALOGFILTER_DISABLE) != HAL_OK)
	{
		Error_Handler();
	}
	/** Configure Digital filter
	 */
	if (HAL_I2CEx_ConfigDigitalFilter(&hi2c1, 0) != HAL_OK)
	{
		Error_Handler();
	}
	/* USER CODE BEGIN I2C1_Init 2 */

	(I2C1->CR1)|= (I2C_CR1_TXDMAEN);
	/* USER CODE END I2C1_Init 2 */

}




static void MX_DMA_Init(void)
{
	__HAL_RCC_DMA1_CLK_ENABLE();
	HAL_NVIC_SetPriority(DMA1_Channel6_IRQn, 0, 0);
	HAL_NVIC_EnableIRQ(DMA1_Channel6_IRQn);

}




void HAL_I2C_MspInit(I2C_HandleTypeDef* hi2c)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};
  RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
  if(hi2c->Instance==I2C1)
  {
  /* USER CODE BEGIN I2C1_MspInit 0 */

  /* USER CODE END I2C1_MspInit 0 */

    __HAL_RCC_GPIOB_CLK_ENABLE();
    /**I2C1 GPIO Configuration
    PB6     ------> I2C1_SCL
    PB7     ------> I2C1_SDA
    */
    GPIO_InitStruct.Pin = GPIO_PIN_6|GPIO_PIN_7;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF4_I2C1;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

    /* Peripheral clock enable */
    __HAL_RCC_I2C1_CLK_ENABLE();
  /* USER CODE BEGIN I2C1_MspInit 1 */
    /* I2C1 DMA Init */
        /* I2C1_TX Init */
	hdma_i2c1_tx.Instance = DMA1_Channel6;
	hdma_i2c1_tx.Init.Request = DMA_REQUEST_3;
	hdma_i2c1_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
	hdma_i2c1_tx.Init.PeriphInc = DMA_PINC_DISABLE;
	hdma_i2c1_tx.Init.MemInc = DMA_MINC_ENABLE;
	hdma_i2c1_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
	hdma_i2c1_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
	hdma_i2c1_tx.Init.Mode = DMA_NORMAL;
	hdma_i2c1_tx.Init.Priority = DMA_PRIORITY_LOW;
	if (HAL_DMA_Init(&hdma_i2c1_tx) != HAL_OK)
	{
	  Error_Handler();
	}

    __HAL_LINKDMA(hi2c,hdmatx,hdma_i2c1_tx);


    /* I2C1 interrupt Init */
	HAL_NVIC_SetPriority(I2C1_EV_IRQn, 0, 0);
	HAL_NVIC_EnableIRQ(I2C1_EV_IRQn);
	HAL_NVIC_SetPriority(I2C1_ER_IRQn, 0, 0);
	HAL_NVIC_EnableIRQ(I2C1_ER_IRQn);



  /* USER CODE END I2C1_MspInit 1 */
  }


void HAL_I2C_MemTxCpltCallback(I2C_HandleTypeDef *hi2c)
{
   UNUSED(hi2c);
  i2c_dma_tf_cplt = 1;           // This flag tells us DMA has completed transmission of data to i2c_tx data register
  
}




void HAL_I2C_EV_IRQHandler(I2C_HandleTypeDef *hi2c)
{
  /* Get current IT Flags and IT sources value */
  uint32_t itflags   = READ_REG(hi2c->Instance->ISR);
  uint32_t itsources = READ_REG(hi2c->Instance->CR1);


  /* I2C events treatment -------------------------------------*/
  if (hi2c->XferISR != NULL)
  {
    hi2c->XferISR(hi2c, itflags, itsources);
  }

  if((itsources)&(I2C_ISR_TC))
  {
	  if(i2c_dma_tf_cplt)
	  {
		  I2C_TransferConfig(hi2c, 0xA0, 1, I2C_AUTOEND_MODE, I2C_GENERATE_STOP);  
		  tmr_EEPROM_wr = 0;    // starting timer counts for waiting 5ms EEPROM internal write 
		  i2c_pg_wr_done = 1;   // flag for page write done to eeprom
	  }

  }
}


void SysTick_Handler(void)
{
  HAL_IncTick();
  tmr_EEPROM_wr++;

}


// Doing page read in seperate code
void M24256_Read(uint16_t page, uint8_t *data)
{
  uint16_t MemAddr = page << 8;
  HAL_I2C_Mem_Read(&hi2c1, 0xA0, MemAddr, 2, &data[position], remainingbytes, 100);
	
}

 

 

The read function at the end uses variables unrelated to parameters passed in.

Does the part work as expected in polled mode, ie without IT and DMA usage?

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..

@Tesla DeLorean 

yes, it's working fine with polling method