2024-12-20 02:21 AM
Hi everyone,
I get stuck with an issue and can't figure what to do.
I implemented on a STM32l071 a I2C slave and using DMA with circular buffer, I am using HAL with CubeMX generated code.
The microcontroller is by default in stop mode, so when something communicates with the microcontroller with I2C, the microcontroller wakes up by I2c address match, then do what it has to do, then return in stop mode.
All that I have implemented seems to work well.
The custom board we are using consume around 22µA when the microcontroller is in stop mode.
The problem is:
When I disconnect only the SDA line before SCL line, the board consume arround 321µA .
(I can then disconnect and reconnect all lines it doesn't change the result).
Then If a send a read or write I2C frame with the master with SCL connected, (SDA connected or not), the board consumption go back to normal at 22µA.
Before entering stop mode, I clear all power flag and I2c flag just in case.
I also activate an output pin in order to see if some I2C callback function are called but it does'nt semm to be the case.
I attach the code and capture of SCL, SDA and output pin
Thanks in advance for your help
Yohann
// ================================================================================================
// ========================================== Includes ============================================
// ================================================================================================
// HAL headers
#include "main.h"
// ================================================================================================
// ======================================= External data ==========================================
// ================================================================================================
// Layer Hal
extern "C" I2C_HandleTypeDef hi2c1;
// ================================================================================================
// ===================================== Private variables ========================================
// ================================================================================================
#define I2C_RX_BUFFER_SIZE 255
#define I2C_TX_BUFFER_SIZE 255
uint8_t _rxBufferI2C[I2C_RX_BUFFER_SIZE] = {0};
uint8_t _txBufferI2C[I2C_TX_BUFFER_SIZE] = {0x10, 0x11, 0x12, 0x13, 0x14, 0x15};
uint8_t countAddrI2C = 0;
uint8_t countRxCpltI2C = 0;
uint8_t countTxCpltI2C = 0;
uint8_t countErrorI2C = 0;
uint8_t countlistenCpltI2C = 0;
volatile uint8_t i2cSlaveTransferDirection = I2C_DIRECTION_TRANSMIT;
volatile bool i2cSlaveCommunicating = false;
volatile bool processReceivedMessage = false;
// ================================================================================================
// ======================================= Implementation =========================================
// ================================================================================================
extern "C" void HAL_I2C_ListenCpltCallback(I2C_HandleTypeDef *hi2c)
{
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_9, GPIO_PIN_SET);
countlistenCpltI2C++;
if (i2cSlaveTransferDirection == I2C_DIRECTION_TRANSMIT)
{
processReceivedMessage = true;
}
// I2C slave has finished to communicate
i2cSlaveCommunicating = false;
// slave is ready again
HAL_I2C_EnableListen_IT(hi2c);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_9, GPIO_PIN_RESET);
}
extern "C" void HAL_I2C_AddrCallback(I2C_HandleTypeDef *hi2c, uint8_t TransferDirection, uint16_t AddrMatchCode)
{
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_9, GPIO_PIN_SET);
countAddrI2C++;
i2cSlaveTransferDirection = TransferDirection;
// I2C slave is communicating
i2cSlaveCommunicating = true;
// Master is transmitting data
if(TransferDirection == I2C_DIRECTION_TRANSMIT)
{
HAL_I2C_Slave_Sequential_Receive_DMA(hi2c, _rxBufferI2C, I2C_RX_BUFFER_SIZE, I2C_FIRST_AND_LAST_FRAME);
}
else
{
HAL_I2C_Slave_Sequential_Transmit_DMA(hi2c, _txBufferI2C, I2C_TX_BUFFER_SIZE, I2C_FIRST_AND_LAST_FRAME);
}
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_9, GPIO_PIN_RESET);
}
extern "C" void HAL_I2C_SlaveRxCpltCallback(I2C_HandleTypeDef *hi2c)
{
// Count how many times we enter this function
countRxCpltI2C++;
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_9, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_9, GPIO_PIN_RESET);
}
extern "C" void HAL_I2C_SlaveTxCpltCallback(I2C_HandleTypeDef *hi2c)
{
// Count how many times we enter this function
countTxCpltI2C++;
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_9, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_9, GPIO_PIN_RESET);
}
extern "C" void HAL_I2C_ErrorCallback(I2C_HandleTypeDef *hi2c)
{
// Count how many times we enter this function
countErrorI2C++;
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_9, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_9, GPIO_PIN_RESET);
}
// ================================================================================================
// ======================================= Implementation =========================================
// ================================================================================================
void enterStopMode()
{
// I2C clear all flags before entering stop mode
__HAL_I2C_CLEAR_FLAG(&hi2c1, I2C_FLAG_TXE); // Transmit data register empty
__HAL_I2C_CLEAR_FLAG(&hi2c1, I2C_FLAG_ADDR); // Address matched (slave mode)
__HAL_I2C_CLEAR_FLAG(&hi2c1, I2C_FLAG_AF); // Acknowledge failure received flag
__HAL_I2C_CLEAR_FLAG(&hi2c1, I2C_FLAG_STOPF); // STOP detection flag
__HAL_I2C_CLEAR_FLAG(&hi2c1, I2C_FLAG_BERR); // Bus error
__HAL_I2C_CLEAR_FLAG(&hi2c1, I2C_FLAG_ARLO); // Arbitration lost
__HAL_I2C_CLEAR_FLAG(&hi2c1, I2C_FLAG_OVR); // Overrun/Underrun
__HAL_I2C_CLEAR_FLAG(&hi2c1, I2C_FLAG_PECERR); // PEC error in reception
__HAL_I2C_CLEAR_FLAG(&hi2c1, I2C_FLAG_TIMEOUT); // Timeout or Tlow detection flag
__HAL_I2C_CLEAR_FLAG(&hi2c1, I2C_FLAG_ALERT); // SMBus alert
// POWER clear all flag before entering stop mode
__HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU);
__HAL_PWR_CLEAR_FLAG(PWR_FLAG_SB);
__HAL_PWR_CLEAR_FLAG(PWR_FLAG_PVDO);
__HAL_PWR_CLEAR_FLAG(PWR_FLAG_VREFINTRDY);
__HAL_PWR_CLEAR_FLAG(PWR_FLAG_VOS);
__HAL_PWR_CLEAR_FLAG(PWR_FLAG_REGLP);
// Enable Power Control clock
__HAL_RCC_PWR_CLK_ENABLE();
// Ensure that MSI is wake-up system clock -> Doesn't work to wakeup from I2C
//__HAL_RCC_WAKEUPSTOP_CLK_CONFIG(RCC_STOP_WAKEUPCLOCK_MSI);
// Need to put HSI as wake-up system clock in order to wakeup from I2C
// (RCC -> Reset and Clock Control)
__HAL_RCC_WAKEUPSTOP_CLK_CONFIG(RCC_STOP_WAKEUPCLOCK_HSI);
// Suspend Tick increment to prevent wakeup by Systick interrupt.
// Otherwise the Systick interrupt will wake up the device within 1ms (HAL time base)
HAL_SuspendTick();
// Enter Stop Mode
HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI);
}
void leaveStopMode()
{
// Set system clock back to ... oscillator because when exiting Stop mode by using an interrupt or a wake up event,
// ... oscillator is selected as system clock
SystemClock_Config ();
//Resume Tick interrupt if disabled prior to Stop mode entry
HAL_ResumeTick();
}
extern "C" void main_app()
{
// ##### I2C #####
HAL_StatusTypeDef status = HAL_OK;
// Enable the Analog I2C Filter
status = HAL_I2CEx_ConfigAnalogFilter(&hi2c1 ,I2C_ANALOGFILTER_ENABLE);
// Enable I2C peripheral in wake up from stop mode
status = HAL_I2CEx_EnableWakeUp(&hi2c1);
status = HAL_I2C_EnableListen_IT(&hi2c1);
HAL_Delay(1000);
bool enableEnterStopMode = true;
while (1)
{
if (processReceivedMessage == true)
{
// Do something
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_9, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_9, GPIO_PIN_RESET);
processReceivedMessage = false;
}
if (enableEnterStopMode == true && processReceivedMessage == false && i2cSlaveCommunicating == false)
{
enterStopMode();
leaveStopMode();
}
}
}
2024-12-20 05:40 AM
When SDA drops with SCL high, that is a start condition and the bus is no longer idle. It makes sense that current consumption would increase as it's now waiting for something to happen.
You should pull up SDA/SCL on the STM32 side of the disconnection. That way they stay high and the chip doesn't even know it's disconnected.
2024-12-26 09:46 AM
I will try that and let you know.
Thanks for your support