Мне нужно реализовать на STM32L053 ведомое устройство I2C для чтения / записи некоторых произвольных байтов памяти на ведомом устройстве uC, и необходимо, чтобы оно также работало для мастеров I2C, которые не поддерживают растягивание тактовой частоты (NOSTRETCH=1
).
Я нашел хороший пример по адресу:
А вот реализация этой статьи:
Эта реализация работает для меня без проблем для операции чтения при скорости передачи данных 100 кГц, но операции записи с мастера просто работают правильно примерно на 50%.Иногда записанные байты являются правильными, а иногда нет ...
Разница между этим примером и моей средой заключается в том, что, несмотря на то, что ОК немного отличаются, но все же отклонения STM32L0, я должен использовать более низкий системный такт из-заНа самом деле, я также должен выполнить другое требование для низкого энергопотребления.Мой uC работает на частоте 4 МГц, а тот, что в примере, работает на частоте 32 МГц.Поэтому я боюсь, что из-за того, что мой медленный системный блок не может прочитать входящие данные записи с мастера достаточно быстро в пределах ISR, до получения следующих входящих данных ...
Может кто-нибудь датьПодсказка, можно ли вообще реализовать такой No-Clock-Stretching-I2C-Slave с моей средой 4 МГц, и если да, что я могу сделать, чтобы операции записи также работали надежно?
Вот описание справочного руководства для настройки NOSTRETCH=1
:
Вот реализация функций чтения / записи и 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;
}
}