I2C No ack error

ChibiOS public support forum for topics related to the STMicroelectronics STM32 family of micro-controllers.

Moderator: RoccoMarco

user99
Posts: 4
Joined: Tue Jul 16, 2013 10:54 pm

I2C No ack error

Post by user99 »

I'm trying to write to a 24lc256 with all the address pins at ground, it should have an address of 0x50. When I call i2cMasterTransmitTimeout I see the correct start bit and address and I think that the ACK is there but only the first byte is sent over the bus and i2cGetErrors responds with a value of 4.

The EEPROM works fine when I bit bang the i2c.

static const I2CConfig i2cconfig =
{
OPMODE_I2C, 100000, STD_DUTY_CYCLE
};

unsigned char rxBuf[16];
unsigned char txBuf[16];

int main(void)
{
halInit();
chSysInit();

i2cStart(&I2CD1, &i2cconfig);

palSetPadMode(GPIOB, 8, PAL_MODE_ALTERNATE(4) | PAL_STM32_OTYPE_OPENDRAIN ); /* SCL */
palSetPadMode(GPIOB, 7, PAL_MODE_ALTERNATE(4) | PAL_STM32_OTYPE_OPENDRAIN ); /* SDA */

txBuf[0] = 0 ;
txBuf[1] = 0 ;

i2cStart(&I2CD1, &i2cconfig);
i2cAcquireBus(&I2CD1);

i2cMasterTransmitTimeout(&I2CD1, 0x50 , txBuf, 2, rxBuf, 8, TIME_INFINITE );
i2cErrors = i2cGetErrors(&I2CD1);

i2cReleaseBus(&I2CD1);
i2cStop(&I2CD1);

and here are scope traces that show the complete trace and the rise/fall time
Attachments
NewFile1.png
NewFile1.png (6.58 KiB) Viewed 8981 times
NewFile0.png
NewFile0.png (6.89 KiB) Viewed 8981 times
User avatar
Giovanni
Site Admin
Posts: 14893
Joined: Wed May 27, 2009 8:48 am
Has thanked: 1202 times
Been thanked: 997 times

Re: I2C No ack error

Post by Giovanni »

Hi.

Do you have external pull-up resistors? is the address the correct one?

Please also look at the following guide: http://www.chibios.org/dokuwiki/doku.ph ... e_shooting

Giovanni
user99
Posts: 4
Joined: Tue Jul 16, 2013 10:54 pm

Re: I2C No ack error

Post by user99 »

4.7K pullups on both lines.

The first scope screenshot shows the rise and fall time of the signals. From what I've read within spec for 100KHz timing.
It's a stm32f4discovery board and the pins I'm using are marked as free in the user manual.

Anything unusual in the code?
user99
Posts: 4
Joined: Tue Jul 16, 2013 10:54 pm

Re: I2C No ack error

Post by user99 »

I think I figured out I'm reading the trace incorrectly. Only the 9th rising edge of sda should be at gnd level for the ack.
From and i2c tutorial I found "If the receiving device sends back a low ACK bit, then it has received the data and is ready to accept another byte"

Shouldn't the ack have a bar over it to indicate it's asserted low or is that notation no longer common?
User avatar
barthess
Posts: 861
Joined: Wed Dec 08, 2010 7:55 pm
Been thanked: 7 times

Re: I2C No ack error

Post by barthess »

hi user99
I successfully use 24LC via I2C and have some clues for your case:
1)

Code: Select all

i2cStart(&I2CD1, &i2cconfig);
palSetPadMode(GPIOB, 8, PAL_MODE_ALTERNATE(4) | PAL_STM32_OTYPE_OPENDRAIN ); /* SCL */
palSetPadMode(GPIOB, 7, PAL_MODE_ALTERNATE(4) | PAL_STM32_OTYPE_OPENDRAIN ); /* SDA */

Fist you must set pal mode than start I2C. The best place for tuning pins is board.h file. For example take a look at my one at boards/NONSTANDARD_STM32F4_BARTHESS1
2) Are you able to power cycle your 24LC via your firmware? This IC has no watchdog in it. It means IC must be power cycled if previous transaction interrupted by something (mostly by JTAG reset). Otherwise it will no ack. Workaround: insert sleep about 1s before first transaction.

Update: Please use code box for source samples in future.
user99
Posts: 4
Joined: Tue Jul 16, 2013 10:54 pm

Re: I2C No ack error

Post by user99 »

After a lot of headache I finally found that a different i2c config works, at least it doesn't stop after the first byte.
I found this on a post from someone who also had problems running the STM32F4 with STD_DUTY_CYCLE.

Code: Select all

/* this didn't work
static const I2CConfig i2c1cfg =
{
  OPMODE_I2C,
  100000,
  STD_DUTY_CYCLE
};
*/

// this one does
static I2CConfig i2c1cfg =
{
    OPMODE_I2C,
    400000,
    FAST_DUTY_CYCLE_2
};

caheo
Posts: 9
Joined: Mon Jun 12, 2017 2:40 pm
Has thanked: 2 times

Re: I2C No ack error

Post by caheo »

Hi,
I faced a problem in reading EEPROM 24LC512 using I2C STM32F103C8T6. Whenever I tried to use i2cMasterTransmitTimeout() and it hang at ch.dbg.panic_msg = reason when I commented the function and it works fine. I tested EEPROM on Arduino and it works just fine so it's not EEPROM problem. Debug info is showed as following.
Image
Image
Image

Source code (Please let me know if I should skip irrelevant code next time for easier reading)

Code: Select all

#include "ch.h"
#include "hal.h"
#include "chprintf.h"
#include "onewire.h"

static int32_t ftomod(float value);
static uint32_t ftodp(float value);
void setRTCAlarmPeriod(uint32_t seconds);
void powerStandby(void);

#define RTC_ALARM_PERIOD  10
RTCDateTime timespec;
RTCAlarm alarmspec;

#define ADC_GRP1_NUM_CHANNELS   1
#define ADC_GRP1_BUF_DEPTH      8

#define EEPROM_ADD 0x50

static BaseSequentialStream* chp = (BaseSequentialStream*)&SD2;

static adcsample_t samples1[ADC_GRP1_NUM_CHANNELS * ADC_GRP1_BUF_DEPTH];

static float mean;
/*
 * ADC conversion group.
 * Mode:        Linear buffer, 8 samples of 1 channel, SW triggered.
 * Channels:    IN10.
 */
static const ADCConversionGroup adcgrpcfg1 = {
  FALSE,
  ADC_GRP1_NUM_CHANNELS,
  NULL,
  NULL,
  0, 0,                         /* CR1, CR2 */
  0,                            /* SMPR1 */
  ADC_SMPR2_SMP_AN8(ADC_SAMPLE_1P5),                           
  ADC_SQR1_NUM_CH(ADC_GRP1_NUM_CHANNELS),
  0,                            /* SQR2 */
  ADC_SQR3_SQ1_N(ADC_CHANNEL_IN8)
};

/*
 * I2C1 config.
 */
static const I2CConfig i2cfg1 = {
    OPMODE_I2C,
    400000,
    FAST_DUTY_CYCLE_2,
};

i2cflags_t i2cflags = 0;
static uint8_t tx_data[4];
static uint8_t rx_data[4];

static systime_t calc_timeout(size_t bytes, uint32_t clock) {
  const uint32_t bitsinbyte = 10;
  uint32_t tmo_ms;

  tmo_ms = ((bytes + 1) * bitsinbyte * 1000);
  tmo_ms /= clock;
  tmo_ms += 10; /* some additional milliseconds to be safer */
  return MS2ST(tmo_ms);
}

static THD_WORKING_AREA(waEEPROM, 128);
static THD_FUNCTION(Thread_EEPROM, arg) {
  msg_t status = MSG_OK;
  systime_t tmo = calc_timeout(3, 100000);

  (void)arg;
  chRegSetThreadName("EEPROM");

  while(true) {
  chprintf(chp, "EEPROM\r\n");
  i2cAcquireBus(&I2CD1);\
  tx_data[0] = 0x00;
  tx_data[1] = 0x00;
  //status = i2cMasterReceiveTimeout(&I2CD1, EEPROM_ADD, rx_data, 2, tmo);
  status = i2cMasterTransmitTimeout(&I2CD1, EEPROM_ADD, tx_data, 2, rx_data, 2, tmo);
  if (MSG_OK != status)
      i2cflags = i2cGetErrors(&I2CD1);
    //osalDbgCheck(MSG_OK == status);
  i2cReleaseBus(&I2CD1);
  chprintf(chp, "Status: %d, Data: %d, %d\r\n", status, rx_data[0], rx_data[1]);
  chThdSleepSeconds(1);
  }
}
/*
 * Light sensor measurement thread.
 */
static THD_WORKING_AREA(waLightSensor, 128);
static THD_FUNCTION(Thread_LightSensor, arg) {
  uint8_t i;

  (void)arg;
  chRegSetThreadName("lightsensor");

  // Convert ADC
  adcConvert(&ADCD1, &adcgrpcfg1, samples1, ADC_GRP1_BUF_DEPTH);
  // Turn off ADC
  adcStop(&ADCD1);

  // Calculate mean value
  mean = 0;
  for (i = 0; i < ADC_GRP1_NUM_CHANNELS * ADC_GRP1_BUF_DEPTH; i++) {
      mean += samples1[i];
  }
  mean = (float)(mean / (ADC_GRP1_NUM_CHANNELS * ADC_GRP1_BUF_DEPTH));
  //last_value = (float)(mean * 3.218 / 4095);
  //sensor_value = (float)(97500 * last_value / (3.218 - last_value));
  chprintf(chp, "Mean: %d.%03d\n\r", ftomod(mean), ftodp(mean));
  //chprintf(chp, "Voltage output: %d.%03dV\n\r", ftomod(last_value), ftodp(last_value));
  //chprintf(chp, "Resistant: %d\n\r", ftomod(sensor_value));

  //chThdSleepSeconds(RTC_ALARM_PERIOD);
  //chprintf(chp, "\033[2J\033[1;1H");
}

/*
 * DS18B20 thread
 */
static THD_WORKING_AREA(waDS18B20, 128);
static THD_FUNCTION(Thread_DS18B20, arg) {
  float temperature = 0.0;

  (void)arg;
  chRegSetThreadName("ds18b20");
  // Read temperature
  temperature = oneWireReadTemperature();

  // Stop gpt
  oneWireStop();

  chprintf(chp, "Temperature: %d.%01d\n\r", ftomod(temperature), ftodp(temperature));
  //chThdSleepSeconds(RTC_ALARM_PERIOD);
}

int main(void) {
  halInit();
  chSysInit();

  // Serial UART2
  sdStart(&SD2, NULL);
  chprintf(chp, "iSensor\r\n");

  // MOSFET drive
  //palSetPadMode(GPIOB, 11, PAL_MODE_OUTPUT_OPENDRAIN);
  //palSetPad(GPIOB, 11);

  //chThdSleepSeconds(1);
  // Onewire for DS18B20
  //oneWireInit();
  // DS18B20 sensor thread
  //chThdCreateStatic(waDS18B20, sizeof(waDS18B20), NORMALPRIO + 2, Thread_DS18B20, NULL);

  // Setting up analog inputs
  //palSetPadMode(GPIOB, 0, PAL_MODE_INPUT_ANALOG);
  // Activates the ADC1 driver and the temperature sensor.
  //adcStart(&ADCD1, NULL);
  // Light sensor thread
  //chThdCreateStatic(waLightSensor, sizeof(waLightSensor), NORMALPRIO + 2, Thread_LightSensor, NULL);

  // I2C
  palSetPadMode(GPIOB, 6, PAL_MODE_STM32_ALTERNATE_OPENDRAIN);   /* SCL */
  palSetPadMode(GPIOB, 7, PAL_MODE_STM32_ALTERNATE_OPENDRAIN);   /* SDA */
  i2cStart(&I2CD1, &i2cfg1);
  chThdCreateStatic(waEEPROM, sizeof(waEEPROM), NORMALPRIO + 1, Thread_EEPROM, NULL);

  setRTCAlarmPeriod(RTC_ALARM_PERIOD);

  while(true) {
  chprintf(chp, "SLEEP...\r\n");
  chThdSleepSeconds(3);
  //powerStandby();
  }
  return 0;
}

void setRTCAlarmPeriod(uint32_t seconds) {
  uint32_t tv_sec;

  /* compile ability test */
  rtcGetTime(&RTCD1, &timespec);
  /* set alarm in near future */
  rtcSTM32GetSecMsec(&RTCD1, &tv_sec, NULL);
  alarmspec.tv_sec = tv_sec + seconds;
  rtcSetAlarm(&RTCD1, 0, &alarmspec);
}

void powerStandby(void) {
  //palClearPad(GPIOB, 11);
  // Turn off Serial
  sdStop(&SD2);

  palSetGroupMode(GPIOA, 0xFFFF, 0, PAL_MODE_INPUT_ANALOG);
  palSetGroupMode(GPIOB, 0xFFFF, 0, PAL_MODE_INPUT_ANALOG);
  palSetGroupMode(GPIOC, 0xFFFF, 0, PAL_MODE_INPUT_ANALOG);

  rccDisableAHB(RCC_AHBENR_DMA1EN | RCC_AHBENR_SRAMEN | RCC_AHBENR_FLITFEN | \
                RCC_AHBENR_CRCEN, lp);
  rccDisableAPB2(RCC_APB2ENR_AFIOEN | RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPBEN | \
                 RCC_APB2ENR_IOPCEN | RCC_APB2ENR_ADC1EN | RCC_APB2ENR_ADC2EN | \
                 RCC_APB2ENR_TIM1EN | RCC_APB2ENR_SPI1EN | RCC_APB2ENR_USART1EN, lp);
  rccDisableAPB1(RCC_APB1ENR_TIM2EN | RCC_APB1ENR_TIM3EN | RCC_APB1ENR_WWDGEN | \
                 RCC_APB1ENR_USART2EN | RCC_APB1ENR_I2C1EN | RCC_APB1ENR_CAN1EN | \
                 RCC_APB1ENR_USBEN, lp);

  chSysLock();
  PWR->CR |= PWR_CR_CWUF;
  //PWR->CR |= PWR_CR_PDDS | PWR_CR_LPDS;
  PWR->CR |= PWR_CR_PDDS;
  SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
  __WFI();
}

/*
 * Retrieve the integer part of value
 */
static int32_t ftomod(float value){
  if (value >= 0)
    return (int32_t) value;
  else
    return (int32_t) -1 * value;
}
 
/*
 * Retrieve the decimal part of value
 */
static uint32_t ftodp(float value) {
 
  if (value >= 0)
    return (uint32_t) ((value - ftomod (value)) * 1000);
  else
    return (uint32_t) ((-value - ftomod (value)) * 1000);
}
User avatar
Giovanni
Site Admin
Posts: 14893
Joined: Wed May 27, 2009 8:48 am
Has thanked: 1202 times
Been thanked: 997 times

Re: I2C No ack error

Post by Giovanni »

Hi,

The reason is "not ready" meaning that the driver is not in the ready state, what is the state when the problem occurs?

Giovanni
steved
Posts: 834
Joined: Fri Nov 09, 2012 2:22 pm
Has thanked: 12 times
Been thanked: 138 times

Re: I2C No ack error

Post by steved »

On a quick look, the code looks sensible (and, yes, strip the code down to the minimum which shows the problem).

Two hardware things to check:
1. Do you have pullups on the I2C lines? (Typically in the region of 2K2 to 4K7; higher should work if lines are short and speed is low)
2. Are other pins assigned to the same I2C functions (perhaps in the board file)?

Does the problem arise on the first attempt to communicate with the EEPROM?

You might need to put a scope on the lines to see what's going on.
caheo
Posts: 9
Joined: Mon Jun 12, 2017 2:40 pm
Has thanked: 2 times

Re: I2C No ack error

Post by caheo »

Giovanni wrote:Hi,

The reason is "not ready" meaning that the driver is not in the ready state, what is the state when the problem occurs?

Giovanni

I printed out I2CD1.state and it says state 5. I guess it's I2C_LOCKED = 5 /**> Bus or driver locked. */.
Post Reply