Перейти к содержанию
    

STM32F1 и i2c зависает шина

Добрый день. 

Есть утройство у которого на шине i2c висит 3 слейва, все в приделах одной платы. Часы, ээпром и дисплей. Так вот, основная часть логики завязана с роботой еепром. Программа довольно много обращается к еепром и иногда бывают сбои. Пишу код под Coide и готового решения AN2824 для него я не нашел.

Собственно проблема в том, что если читаю 1 или 2 байта читается какой-то мусор, а если больше 3 то и вовсе виснет еепром и шина всегда занята, даже если перезагружаю i2c на контроллере. С записью проблем нет. DMA не использую так как приходится много читать для поиска пустого блока, проверку делаю "на лету" без выгрузки всего муссора с eeprom в озу. Второй день уже не могу понять в чем проблема, может чего уже не замечаю, вот код.

unsigned char I2C_Read_git(I2C_TypeDef* I2Cx, unsigned char SlaveAddress, unsigned char *buf, unsigned int nbyte){
	//I2C2->CR2 |= I2C_IT_ERR;  //interrupts for errors
	// Wait for idle I2C interface
	if(wait_for(FLAG, I2C_FLAG_BUSY) == 0) return I2CERR; //go out with timeout error
	// Enable Acknowledgement, clear POS flag
	I2C_AcknowledgeConfig(I2Cx, ENABLE);
	I2C_NACKPositionConfig(I2Cx, I2C_NACKPosition_Current);

	// Intiate Start Sequence (wait for EV5
	I2C_GenerateSTART(I2Cx, ENABLE);
	if(wait_for(EVENT, I2C_EVENT_MASTER_MODE_SELECT) == 0) return I2CERR; //go out with timeout error

	// Send Address
	I2C_Send7bitAddress(I2Cx, SlaveAddress, I2C_Direction_Receiver);

	// EV6
	if(wait_for(FLAG, I2C_FLAG_ADDR) == 0) return I2CERR; //go out with timeout error
	if(nbyte == 1){
		// Clear Ack bit
		I2C_AcknowledgeConfig(I2Cx, DISABLE);

		// EV6_1 -- must be atomic -- Clear ADDR, generate STOP
		__disable_irq();
		(void) I2Cx->SR2;
		I2C_GenerateSTOP(I2Cx,ENABLE);
		__enable_irq();

		// Receive data   EV7
		if(wait_for(FLAG, I2C_FLAG_RXNE) == 0) return I2CERR; //go out with timeout error
		*buf++ = I2C_ReceiveData(I2Cx);

    }else if(nbyte == 2){
    	// Set POS flag
    	I2C_NACKPositionConfig(I2Cx, I2C_NACKPosition_Next);

    	// EV6_1 -- must be atomic and in this order
    	__disable_irq();
    	(void) I2Cx->SR2;                           // Clear ADDR flag
    	I2C_AcknowledgeConfig(I2Cx, DISABLE);       // Clear Ack bit
    	__enable_irq();

    	// EV7_3  -- Wait for BTF, program stop, read data twice
    	if(wait_for(FLAG, I2C_FLAG_BTF) == 0) return I2CERR; //go out with timeout error

    	__disable_irq();
    	I2C_GenerateSTOP(I2Cx,ENABLE);
    	*buf++ = I2C_ReceiveData(I2Cx);
    	__enable_irq();
    	*buf++ = I2C_ReceiveData(I2Cx);

    	I2C_NACKPositionConfig(I2Cx, I2C_NACKPosition_Current);
    }else{
    	(void) I2Cx->SR2;                           // Clear ADDR flag
    	while (nbyte-- != 3){
    		// EV7 -- cannot guarantee 1 transfer completion time, wait for BTF
    		//        instead of RXNE
        	if(wait_for(FLAG, I2C_FLAG_BTF) == 0) return I2CERR; //go out with timeout error
    		*buf++ = I2C_ReceiveData(I2Cx);
    	}

    	if(wait_for(FLAG, I2C_FLAG_BTF) == 0) return I2CERR; //go out with timeout error

    	// EV7_2 -- Figure 1 has an error, doesn't read N-2 !
    	I2C_AcknowledgeConfig(I2Cx, DISABLE);           // clear ack bit

    	__disable_irq();
    	I2C_GenerateSTOP(I2Cx,ENABLE);              // program stop
		*buf++ = I2C_ReceiveData(I2Cx);             // receive byte N-2
    	__enable_irq();

    	// wait for byte N
    	if(wait_for(EVENT, I2C_EVENT_MASTER_BYTE_RECEIVED) == 0) return I2CERR; //go out with timeout error
    	*buf++ = I2C_ReceiveData(I2Cx);             // receive byte N-1
    	nbyte = 0;
    }

	// Wait for stop
	if(wait_for(FLAG, I2C_FLAG_STOPF) == 0) return I2CERR; //go out with timeout error
	I2C_AcknowledgeConfig(I2Cx, ENABLE);

	return I2COK;
}
unsigned char EEPROM_Read(unsigned int addr, unsigned char *data, unsigned char len){
	unsigned char y=0;
	// While the bus is busy
	 if(wait_for(FLAG, I2C_FLAG_BUSY) == 0) return I2CERR; //go out with timeout error
	 I2C_AcknowledgeConfig(I2C2, ENABLE);
	 // Generate the Start Condition
	 I2C_GenerateSTART(I2C2, ENABLE);
	 if(wait_for(EVENT, I2C_EVENT_MASTER_MODE_SELECT) == 0) return I2CERR; //go out with timeout error

	 I2C_Send7bitAddress(I2C2, 0xA0, I2C_Direction_Transmitter);     //send adress chip
	 if(wait_for(EVENT, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED) == 0) return I2CERR; //go out with timeout error

	 I2C_SendData(I2C2, addr>>8); 	//send upper bit
	 if(wait_for(EVENT, I2C_EVENT_MASTER_BYTE_TRANSMITTED) == 0) return I2CERR; //go out with timeout error

	 I2C_SendData(I2C2, addr & 0xFF);		//send lower bit
	 if(wait_for(EVENT, I2C_EVENT_MASTER_BYTE_TRANSMITTED) == 0) return I2CERR; //go out with timeout error

	 I2C_GenerateSTOP(I2C2, ENABLE);
	 if(wait_for(FLAG, I2C_FLAG_BUSY) == 0) return I2CERR; //go out with timeout error

	 y=I2C_Read_git(I2C2, 0xA0, data, len);
	 return y;
}

А вот код который работает, но здесь нет всех замечаний которые были написаны в AN2824 о глючном i2c в stm32f1:

unsigned char EEPROM_Read(unsigned int addr, unsigned char *data, unsigned char len){
	 unsigned int i;
	 // While the bus is busy
	 if(wait_for(FLAG, I2C_FLAG_BUSY) == 0) return I2CERR; //go out with timeout error
	 I2C_AcknowledgeConfig(I2C2, ENABLE);
	 // Generate the Start Condition
	 I2C_GenerateSTART(I2C2, ENABLE);
	 if(wait_for(EVENT, I2C_EVENT_MASTER_MODE_SELECT) == 0) return I2CERR; //go out with timeout error

	 I2C_Send7bitAddress(I2C2, 0xA0, I2C_Direction_Transmitter);     //send adress chip
	 if(wait_for(EVENT, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED) == 0) return I2CERR; //go out with timeout error

	 I2C_SendData(I2C2, addr>>8); 	//send upper bit
	 if(wait_for(EVENT, I2C_EVENT_MASTER_BYTE_TRANSMITTED) == 0) return I2CERR; //go out with timeout error

	 I2C_SendData(I2C2, addr & 0xFF);		//send lower bit
	 if(wait_for(EVENT, I2C_EVENT_MASTER_BYTE_TRANSMITTED) == 0) return I2CERR; //go out with timeout error

	 I2C_GenerateSTOP(I2C2, ENABLE);
	 if(wait_for(FLAG, I2C_FLAG_BUSY) == 0) return I2CERR; //go out with timeout error

	 I2C_GenerateSTART(I2C2, ENABLE);   // Generate the Start Condition
	 if(wait_for(EVENT, I2C_EVENT_MASTER_MODE_SELECT) == 0) return I2CERR; //go out with timeout error

	 I2C_Send7bitAddress(I2C2, 0xA0, I2C_Direction_Receiver);		//send adress chip
	 if(wait_for(EVENT, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED) == 0) return I2CERR; //go out with timeout error

	 for(i = 0; i<len; i++){
		 if(i<len-1){
		 	if(wait_for(EVENT, I2C_EVENT_MASTER_BYTE_RECEIVED) == 0) return I2CERR; //go out with timeout error
		 }else{
		 	I2C_AcknowledgeConfig(I2C2, DISABLE);			// Prepare an NACK for the next data received
		 	if(wait_for(EVENT, I2C_EVENT_MASTER_BYTE_RECEIVED) == 0) return I2CERR; //go out with timeout error
		 	I2C_GenerateSTOP(I2C2, ENABLE);
		 }
		 *data = I2C_ReceiveData(I2C2);
		 data++;
	 }
	 if(wait_for(FLAG,I2C_FLAG_STOPF)==0) return I2CERR;
	 I2C_AcknowledgeConfig(I2C2, ENABLE);
	 //Delay_ms(5);
	 return I2COK;
}

За ранние спасибо.

Изменено пользователем Krik99

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Ну то, что можно порекомендовать без привязки к конкретному микроконтроллеру, так это подключить осциллограф, и посмотреть форму сигналов на шине. А затем, если с ней всё в порядке, можно поглядеть, что с данными.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

5 hours ago, haker_fox said:

Ну то, что можно порекомендовать без привязки к конкретному микроконтроллеру, так это подключить осциллограф, и посмотреть форму сигналов на шине. А затем, если с ней всё в порядке, можно поглядеть, что с данными.

Конкретный контроллер Stm32f103rbt6. Но на сколько я понял с AN2824 i2c у них у всех глючный. Ок, как будет доступ к осциллографу сделаю скрины

Изменено пользователем Krik99

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

11 minutes ago, Krik99 said:

i2c у них у всех глючный

что это значит? Возможно в errata есть какая-то полезная информация. Возможно придётся всё отлаживать по-шагово, проверяя выполнение всех условий на шине (START, STOP, ACK, NACK) и т.п. Ну и снова повторюсь, лучше попробовать написать свой драйвер. Пусть медленно, зато знакомый до каждого угла)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

20 hours ago, Krik99 said:

а если больше 3 то и вовсе виснет еепром и шина всегда занята, даже если перезагружаю i2c на контроллере

В данном случае висит один из слейвов, вероятно eeprom, нужно в ручную(gpio) клочить и ждать пока этот слейв отпустить линию SDA, либо дернуть питание слейвам, если это конечно возможно и позволяет ситуация.
 

В  I2C_Read_git точно должно быть 3?

while (nbyte-- != 3){

Я сейчас не уверен, но мне кажется Вы один байт потеряете, могу ошибаться. Сложно код читается...

Вообще, стремно выглядит этот I2C_Read_git...
 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

8 minutes ago, Integro said:

вероятно eeprom, нужно в ручную(gpio) клочить

В своё время я где-тона просторах сети встречало документ, в котором рекомедовалось при инициализации шины подать клок не менее 30 тактов на SCL. Что должно быть при этом с SDA я не помню. И только после этого можно было начинать работу. Вообще такое мне ни разу не понадобилось. Ассортимент микросхем с которыми я работал на этой шине не очень широк, но всё же: pca9534, ds1682, рахные часы, разные цифрорезисторы. И все они нормально работали сразу. Но вот с tsc2007 (контроллер резистивного тач-скрина) в нескольких приборах была проблема: он просто иногда (редко) при включении прибора не работал. Не отвечал. Логический анализатор показывал, что к микросхеме стучаться правильно. Не выручили и хололстые клоки на SCL. А вот передёргивание питания - выручило. Допускаю, что мы могли накосячить со схемотехникой, хотя где там можно ошибиться, я не знаю. Мы для этого приспособили полевичок на питании микросхемы, и просто при включении прибора включаем микросхему после инициализации шины. Работает надёжно. С первопричиной же пробовали разобраться, так и не вышло. В документации ничего на этот счёт не сказано. На форумах тоже тишина. В другом приборе на линуксе такой проблемы, похоже, нет. Но там драйвер этой микросхемы подробно никто не смотрел.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

17 hours ago, haker_fox said:

Ассортимент микросхем с которыми я работал на этой шине не очень широк

От сюда следствие...

17 hours ago, haker_fox said:

Вообще такое мне ни разу не понадобилось.

Не понимаю для каких целей Вы нам это написали...
 

17 hours ago, haker_fox said:

он просто иногда (редко) при включении прибора не работал.

А вот это не нормально, я бы грешил на ошибку в схемотехнике(проблемы с качесвом питания) или не соблюдение рекомендуемых Power-On\Reset timings

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

10 minutes ago, Integro said:

Не понимаю для каких целей Вы нам это написали...

А что, чтобы делиться своим опытом, я должен разрешение спрашивать?

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

5 minutes ago, haker_fox said:

чтобы делиться своим опытом

17 hours ago, haker_fox said:

Ассортимент микросхем с которыми я работал на этой шине не очень широк,

Так Вы ведь написали что опыта у Вас как такового нет. Простите если задел.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 minute ago, Integro said:

Так Вы ведь написали что опыта у Вас как такового нет.

Я написал, что ассортимент микросхем не очень широк. С опытом это прямо не связано.  Ну да, ещё, конечно же, забыл упомянуть разномастную память, начиная от 24c02, заканчивая какими-то современными от микрочип EEPROM (названия не помню). Но разве это меняет суть? Подход-то одинаковый. И про документ я написал. Я вообще сейчас заметил, что здесь обращался не к автору темы. Перепутал.

4 minutes ago, Integro said:

Простите если задел.

Всё нормально, я искренне удивился. Тема-то для начинающих. Я и подумал. что автору будет полезен мой скромный опыт.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...