STM32: ведомый I2C без включенной функции растяжения часов - PullRequest
2 голосов
/ 21 мая 2019

Мне нужно реализовать на STM32L053 ведомое устройство I2C для чтения / записи некоторых произвольных байтов памяти на ведомом устройстве uC, и необходимо, чтобы оно также работало для мастеров I2C, которые не поддерживают растягивание тактовой частоты (NOSTRETCH=1).

Я нашел хороший пример по адресу:

А вот реализация этой статьи:

Эта реализация работает для меня без проблем для операции чтения при скорости передачи данных 100 кГц, но операции записи с мастера просто работают правильно примерно на 50%.Иногда записанные байты являются правильными, а иногда нет ...

Разница между этим примером и моей средой заключается в том, что, несмотря на то, что ОК немного отличаются, но все же отклонения STM32L0, я должен использовать более низкий системный такт из-заНа самом деле, я также должен выполнить другое требование для низкого энергопотребления.Мой uC работает на частоте 4 МГц, а тот, что в примере, работает на частоте 32 МГц.Поэтому я боюсь, что из-за того, что мой медленный системный блок не может прочитать входящие данные записи с мастера достаточно быстро в пределах ISR, до получения следующих входящих данных ...

Может кто-нибудь датьПодсказка, можно ли вообще реализовать такой No-Clock-Stretching-I2C-Slave с моей средой 4 МГц, и если да, что я могу сделать, чтобы операции записи также работали надежно?

Вот описание справочного руководства для настройки NOSTRETCH=1:

enter image description here

enter image description here

enter image description here

Вот реализация функций чтения / записи и ISR I2C:


volatile unsigned char i2c_mem[256];     /* contains data, which read or written */
volatile unsigned char i2c_idx;          /* the current index into i2c_mem */
volatile unsigned char i2c_is_write_idx; /* write state */

volatile uint16_t i2c_total_irq_cnt;
volatile uint16_t i2c_TXIS_cnt;
volatile uint16_t i2c_RXNE_cnt;


void i2c_mem_reset_write(void)
{
  i2c_is_write_idx = 1;  
}

void i2c_mem_init(void)
{
  i2c_idx = 0;
  i2c_mem_reset_write();
}

void i2c_mem_set_index(unsigned char value)
{
  i2c_idx = value;
  i2c_is_write_idx = 0;
}

void i2c_mem_write_via_index(unsigned char value)
{
  i2c_mem[i2c_idx++] = value;
}

unsigned char i2c_mem_read(void)
{
  i2c_mem_reset_write();
  i2c_idx++;
  return i2c_mem[i2c_idx];
}

void i2c_mem_write(unsigned char value)
{
  if ( i2c_is_write_idx != 0 )
  {
    i2c_mem_set_index(value);
  }
  else
  {
    i2c_is_write_idx = 0;
    i2c_mem_write_via_index(value);
  }
}

void __attribute__ ((interrupt, used)) I2C1_IRQHandler(void)
{
  unsigned long isr = I2C1->ISR;

  i2c_total_irq_cnt ++;

  if ( isr & I2C_ISR_TXIS )
  {
    i2c_TXIS_cnt++;
    I2C1->TXDR = i2c_mem_read();
  }
  else if ( isr & I2C_ISR_RXNE )
  {
    i2c_RXNE_cnt++;
    i2c_mem_write(I2C1->RXDR);
    I2C1->ISR |= I2C_ISR_TXE;           // allow overwriting the TCDR with new data
    I2C1->TXDR = i2c_mem[i2c_idx];
  }
  else if ( isr & I2C_ISR_STOPF )
  {
    I2C1->ICR = I2C_ICR_STOPCF;
    I2C1->ISR |= I2C_ISR_TXE;           // allow overwriting the TCDR with new data
    I2C1->TXDR = i2c_mem[i2c_idx];
    i2c_mem_reset_write();
  }
  else if ( isr & I2C_ISR_NACKF )
  {
    I2C1->ICR = I2C_ICR_NACKCF;
    I2C1->ISR |= I2C_ISR_TXE;           // allow overwriting the TCDR with new data
    I2C1->TXDR = i2c_mem[i2c_idx];
    i2c_mem_reset_write();
  }
  else if ( isr & I2C_ISR_ADDR )
  {
    /* not required, the addr match interrupt is not enabled */
    I2C1->ICR = I2C_ICR_ADDRCF;
    I2C1->ISR |= I2C_ISR_TXE;           // allow overwriting the TCDR with new data
    I2C1->TXDR = i2c_mem[i2c_idx];
    i2c_mem_reset_write();
  }

  /* if at any time the addr match is set, clear the flag */
  /* not sure, whether this is required */
  if ( isr & I2C_ISR_ADDR )
  {
    I2C1->ICR = I2C_ICR_ADDRCF;
  }

}
...