STM32 I2C EEPROM 24СXX

Пошел дальше в освоении периферии на STM32 решил eeprom присобачить- благо вроде и примеры есть и все такое…
НО вдруг возник совершенно непонятный тупняк… что то по невнимательности что то видимо из своеобразной работы I2C на STM32
На моей отладочной плате стояла 24C02 -мелкий епром и по забывчивости я начал его длинными адресами 16бит вместо 8 писать, потом правда исправил на 8 битный — чето читалось, чето писалось, но все как то криво, думаю дай запаяю 24с64wp — вроде она от 3.3в работает. Но тут началась какаято дикость… Если читать только что запаянную микросхему, то вроде чето читается, НО! если что нибудь попытаться записать в нее (вроде как операция проходит) и после ресета считать контроллер начинает висеть в i2c функциях в цикле ожидания -якобы шина занята. Потом уже смотрел на другой плате и микросхеме SDA висело на низком уровне после неудачного завершения операции и как показалось и eeprom ее вешало и проц иногда ( тобишь зависания в цикле проверки какого нибудь условия в i2c) и надо было сбрасывать питание.

/* While the bus is busy */
    while(I2C_GetFlagStatus(I2C_EE, I2C_FLAG_BUSY));//висит в этом цикле если SDA low


В общем как оказалось проблема не у меня одного- то работает то не работает I2C можно еще на electronix.ru поискать в топике по ARM. Ну как говориться и лыжи не ехали и я молодец был…
Сейчас вроде все разрешилась (лыжи натер :) ) читается и пишется попробовано со следующими eeprom:

ST 24C64WP
MC 24LC64

все они поддерживают 3.3V

Но если сразу попытаться считать после записи — все виснет… и само не отвисает обязательно нужна задержка между записью и чтением у меня получилось не менее 4ms — на всякий случай поставил 5ms. Прилагаю код для простого чтения и записи проверил на STM32F100RBT6 и STM32F103VCT6

Ну и напоследок — не забываем повесить резисторы 4к7 подтяжки к питанию на SCL (6я-нога) и SDA (5я-нога) и проконтролировать адрес eeprom — если ноги 1,2,3 на земле то он 0xA0 (0xA0 адрес по умолчанию когда b1,b2,b3 =0 иначе смотрим в датащит как он считается) и 7 ногу WC — тоже на землю иначе только чтение. Ну и питание 4-общий, 8-+питание


//***************************************************************************//**
//EEPROM LIB v 1.0
//******************************************************************************/
#include "stm32f10x_gpio.h"
#include "stm32f10x_i2c.h"
#include "stm32f10x_rcc.h"

//#define I2C_FLASH_PAGESIZE     32 //not used yet
#define EEPROM_HW_ADDRESS      0xA0   /* E0 = E1 = E2 = 0 */
#define I2C_EE             I2C1//interface number

void Delay_ms(uint32_t ms);

/***************************************************************************//**
 *  @brief  I2C Configuration
 ******************************************************************************/
void I2C_Configuration(void)
{

   	   I2C_InitTypeDef  I2C_InitStructure;
	   GPIO_InitTypeDef  GPIO_InitStructure;

	   RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1,ENABLE);

	   RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB| RCC_APB2Periph_AFIO , ENABLE);//

	   /* Configure I2C1 pins: PB6->SCL and PB7->SDA */
	   GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_6 | GPIO_Pin_7;
	   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
	   GPIO_Init(GPIOB, &GPIO_InitStructure);

	   I2C_DeInit(I2C_EE);
	   I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
	   I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_16_9;
	   I2C_InitStructure.I2C_OwnAddress1 = 1;
	   I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
	   I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
	   I2C_InitStructure.I2C_ClockSpeed = 100000;  /* 100kHz */

	   I2C_Cmd(I2C_EE, ENABLE);
	   I2C_Init(I2C_EE, &I2C_InitStructure);
	   I2C_AcknowledgeConfig(I2C_EE, ENABLE);

}

//*******************************************************************8
//***************************************************************

void I2C_EE_ByteWrite(uint8_t val, uint16_t WriteAddr)
{


    /* Send START condition */
    I2C_GenerateSTART(I2C_EE, ENABLE);

    /* Test on EV5 and clear it */
    while(!I2C_CheckEvent(I2C_EE, I2C_EVENT_MASTER_MODE_SELECT));

    /* Send EEPROM address for write */
    I2C_Send7bitAddress(I2C_EE, EEPROM_HW_ADDRESS, I2C_Direction_Transmitter);

    /* Test on EV6 and clear it */
    while(!I2C_CheckEvent(I2C_EE, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));


    /* Send the EEPROM's internal address to write to : MSB of the address first */
    I2C_SendData(I2C_EE, (uint8_t)((WriteAddr & 0xFF00) >> 8));

    /* Test on EV8 and clear it */
    while(!I2C_CheckEvent(I2C_EE, I2C_EVENT_MASTER_BYTE_TRANSMITTED));



    /* Send the EEPROM's internal address to write to : LSB of the address */
    I2C_SendData(I2C_EE, (uint8_t)(WriteAddr & 0x00FF));

    /* Test on EV8 and clear it */
    while(! I2C_CheckEvent(I2C_EE, I2C_EVENT_MASTER_BYTE_TRANSMITTED));


     I2C_SendData(I2C_EE, val);

        /* Test on EV8 and clear it */
    while (!I2C_CheckEvent(I2C_EE, I2C_EVENT_MASTER_BYTE_TRANSMITTED));

    /* Send STOP condition */
    I2C_GenerateSTOP(I2C_EE, ENABLE);

    //delay between write and read...not less 4ms
    Delay_ms(5);
}
//*********************************************************************************
uint8_t I2C_EE_ByteRead( uint16_t ReadAddr)
{
    uint8_t tmp;

	/* While the bus is busy */
    while(I2C_GetFlagStatus(I2C_EE, I2C_FLAG_BUSY));

    /* Send START condition */
    I2C_GenerateSTART(I2C_EE, ENABLE);

    /* Test on EV5 and clear it */
    while(!I2C_CheckEvent(I2C_EE, I2C_EVENT_MASTER_MODE_SELECT));

    /* Send EEPROM address for write */
    I2C_Send7bitAddress(I2C_EE, EEPROM_HW_ADDRESS, I2C_Direction_Transmitter);

    /* Test on EV6 and clear it */
    while(!I2C_CheckEvent(I2C_EE, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));


    /* Send the EEPROM's internal address to read from: MSB of the address first */
    I2C_SendData(I2C_EE, (uint8_t)((ReadAddr & 0xFF00) >> 8));

    /* Test on EV8 and clear it */
    while(!I2C_CheckEvent(I2C_EE, I2C_EVENT_MASTER_BYTE_TRANSMITTED));

    /* Send the EEPROM's internal address to read from: LSB of the address */
    I2C_SendData(I2C_EE, (uint8_t)(ReadAddr & 0x00FF));

    /* Test on EV8 and clear it */
    while(!I2C_CheckEvent(I2C_EE, I2C_EVENT_MASTER_BYTE_TRANSMITTED));


    /* Send STRAT condition a second time */
    I2C_GenerateSTART(I2C_EE, ENABLE);

    /* Test on EV5 and clear it */
    while(!I2C_CheckEvent(I2C_EE, I2C_EVENT_MASTER_MODE_SELECT));

    /* Send EEPROM address for read */
    I2C_Send7bitAddress(I2C_EE, EEPROM_HW_ADDRESS, I2C_Direction_Receiver);

    /* Test on EV6 and clear it */
    while(!I2C_CheckEvent(I2C_EE,I2C_EVENT_MASTER_BYTE_RECEIVED));//I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));

    tmp=I2C_ReceiveData(I2C_EE);


    I2C_AcknowledgeConfig(I2C_EE, DISABLE);

    /* Send STOP Condition */
    I2C_GenerateSTOP(I2C_EE, ENABLE);

    return tmp;
    }
//*******************************************************************************
void Delay_ms(uint32_t ms)
{
        volatile uint32_t nCount;
        RCC_ClocksTypeDef RCC_Clocks;
    RCC_GetClocksFreq (&RCC_Clocks);

        nCount=(RCC_Clocks.HCLK_Frequency/10000)*ms;
        for (; nCount!=0; nCount--);
}
//*****************************************************************************

  • 0
  • 21 августа 2011, 17:21
  • GYUR22
  • 1
Файлы в топике: i2c_lib.zip

Комментарии (51)

RSS свернуть / развернуть
При чтении последнего байта всегда нужно посылать NACK:
I2C_AcknowledgeConfig(I2C_EE, DISABLE);
tmp = I2C_ReceiveData(I2C_EE);
I2C_GenerateSTOP(I2C_EE, ENABLE);
Ну и после сброса при инициализации не помешает STOP в шину загнать (мало ли когда сброс произошел).
0
  • avatar
  • Resp
  • 21 августа 2011, 19:22
проблема в том что
while(I2C_GetFlagStatus(I2C_EE, I2C_FLAG_BUSY));//висит в этом цикле
висит — на ничего еще не делавшей шине…
чем она занята?
0
проблема в том что
while(I2C_GetFlagStatus(I2C_EE, I2C_FLAG_BUSY));//висит в этом цикле
висит — на ничего еще не делавшей шине…
чем она занята?
причем если перепаять епромину то вроде заводится но если что то попытаться записать то виснет и до перепайки — пуллапы на месте.
0
А можно код самих функций?
0
  • avatar
  • Zov
  • 21 августа 2011, 22:45
каких?
0
"I2C_GetFlagStatus(I2C_EE, I2C_FLAG_BUSY)"
"I2C_GenerateSTART(I2C_EE, ENABLE)"
0
дык это cmsis вроде…
I2C_GetFlagStatus(I2C_EE, I2C_FLAG_BUSY) — помыл 100раз прошла эту функцию
но теперь после старта не видит видимо ack…
/* Send START condition */
I2C_GenerateSTART(I2C_EE, ENABLE);//видно даже дерганье короткое но потом глухо
/* Test on EV5 and clear it */
while(!I2C_CheckEvent(I2C_EE, I2C_EVENT_MASTER_MODE_SELECT));- dbcbn pltcm
0
и нифига проходил проходил этот флаг
попробовал записать ченито рестарт и опять стоим в I2C_FLAG_BUSY
0
А может банально плату промыть. Я тут буквально в четверг с такой траблой боролся на CoLinkEx. На ней не было штыревых разъемов. Запаял и пипец — I2C то работает, то не работает.(LM75 иногда срабатывает, флэшка — нет) Все перепробовал, а потом глянул осциллографом — на шине тактов сигнал 1.5в… Помыл спиртом — и все заработало.
ЗЫ. А вот на запуск SPI я два дня убил… из-за дятлов которые на CoLinkEx маркировку делали -пины поперепутали сцуки… а я доверчивый — написанному верил. :-)
0
  • avatar
  • Telek
  • 21 августа 2011, 22:47
Люди отзовитесь!
Кто удачно пользуется i2c на STM32
0
УФФ…
Вроде заработало…
0
Так в чем было дело?
У меня почему-то не заводится I2C на stm32f105 для внешней EEPROM. — такая же фигня — виснет контроллер.
0
попробуйте приложенную библиотечку с ней работает — просто запишите и считайте байт.
проверьте вашу еепромину поддерживает ли 3.3в
И каждый раз выключаййте при зависании и смотрите при отладке когда входите в функции чтения записи что с ногой SDA если она на низком уровне то чето гдето висит — сброс питания и подождать пока все разрядится.
0
на SDA 0, еепром 2,5 — 5 В. Не проходит даже чтение, зависает на

/* Test on EV5 and clear it */
while(!I2C_CheckEvent(I2C_EE, I2C_EVENT_MASTER_MODE_SELECT));
0
/* While the bus is busy */
while(I2C_GetFlagStatus(I2C_EE, I2C_FLAG_BUSY));

/* Send START condition */
I2C_GenerateSTART(I2C_EE, ENABLE);

/* Test on EV5 and clear it */
while(!I2C_CheckEvent(I2C_EE, I2C_EVENT_MASTER_MODE_SELECT));

здесь?
до этого запись производиться? -если да то есть ли задержка между операциями?
0
/* While the bus is busy */
while(I2C_GetFlagStatus(I2C_EE, I2C_FLAG_BUSY));

/* Send START condition */
I2C_GenerateSTART(I2C_EE, ENABLE);

/* Test on EV5 and clear it */
while(!I2C_CheckEvent(I2C_EE, I2C_EVENT_MASTER_MODE_SELECT));

здесь?
до этого запись производиться? -если да то есть ли задержка между операциями?

проверьте еще епромину не висит ли она и не держит ли low — у меня похоже так было
0
на обоих ногах 0 — микросхема AT24C02BN — пробовал чтение — не проходит, запись -5 мс -чтение
0
мне чтобы разобраться пришлось делать — отдельную платку и тока там я увидел что епромина висит. Уберите пока запись. попробуйте только чтение.
0
да еще у вашей епромины адресация восьмибитная

/* Send the EEPROM's internal address to read from: MSB of the address first */
I2C_SendData(I2C_EE, (uint8_t)((ReadAddr & 0xFF00) >> 8));

/* Test on EV8 and clear it */
while(!I2C_CheckEvent(I2C_EE, I2C_EVENT_MASTER_BYTE_TRANSMITTED));

это закомментируйте
0
Спасибо — все заработало — косяк был в том, что я неправильно выставил адрес EEPROM — Все ноги подключил к 0 — и думал, что адрес 0, а оказалось 0хА0. И не подключил поддягивающие резисторы к ногам I2C.
0
У меня похожая проблема возникла: тоже зависает контроллер, тоже на
/* Test on EV5 and clear it */
while(!I2C_CheckEvent(I2C_EE, I2C_EVENT_MASTER_MODE_SELECT));
Вот только "… косяк был в том, что я неправильно выставил адрес EEPROM — Все ноги подключил к 0 — и думал, что адрес 0, а оказалось 0хА0. И не подключил поддягивающие резисторы к ногам I2C." — это не мой случай: адрес изначально указал правильный, подтягивающие резисторы подключил. Вскрытие показывает, что на линии SCL нет тактового сигнала. Проинициализировать I2C не забыл.
0
Сам наткнулся на стм8, что если отлаживать работу по шагам, то считывание некоторых флагов через отладчик приводит к их сбросу и программа циклится. Если просто запустить, то все работает нормально.
0
  • avatar
  • PRC
  • 25 августа 2011, 17:48
да я пробовал по разному
0
Делайте выдачу результата события на шине I2C в СОМ — порт. Проверено на LPC24xx,LPC17xx и LPC11C14. Очень помогает.
void I2C0_IRQHandler(void)  
{
  uint8_t StatValue;

  /* this handler deals with master read and master write only */
  StatValue = LPC_I2C0->I2STAT;
	
  switch ( StatValue )
  {
	case 0x08:			/* A Start condition is issued. */
	LPC_I2C0->I2DAT = I2CMasterBuffer[0];
	LPC_I2C0->I2CONCLR = (I2CONCLR_SIC | I2CONCLR_STAC);
	I2CMasterState = I2C_STARTED;
	break;
	
	case 0x10:			/* A repeated started is issued */
	if ( I2CCmd == LM75_TEMP )
	{
	  LPC_I2C0->I2DAT = I2CMasterBuffer[2];
	}
	LPC_I2C0->I2CONCLR = (I2CONCLR_SIC | I2CONCLR_STAC);
	I2CMasterState = I2C_RESTARTED;
	break;
	
	case 0x18:			/* Regardless, it's a ACK */
	if ( I2CMasterState == I2C_STARTED )
	{
	  LPC_I2C0->I2DAT = I2CMasterBuffer[1+WrIndex];
	  WrIndex++;
	  I2CMasterState = DATA_ACK;
	}
	LPC_I2C0->I2CONCLR = I2CONCLR_SIC;
	break;

	case 0x28:	/* Data byte has been transmitted, regardless ACK or NACK */
	case 0x30:
	if ( WrIndex != I2CWriteLength )
	{   
	  LPC_I2C0->I2DAT = I2CMasterBuffer[1+WrIndex]; /* this should be the last one */
	  WrIndex++;
	  if ( WrIndex != I2CWriteLength )
	  {   
		I2CMasterState = DATA_ACK;
	  }
	  else
	  {
		I2CMasterState = DATA_NACK;
		if ( I2CReadLength != 0 )
		{
		  LPC_I2C0->I2CONSET = I2CONSET_STA;	/* Set Repeated-start flag */
		  I2CMasterState = I2C_REPEATED_START;
		}
	  }
	}
	else
	{
	  if ( I2CReadLength != 0 )
	  {
		LPC_I2C0->I2CONSET = I2CONSET_STA;	/* Set Repeated-start flag */
		I2CMasterState = I2C_REPEATED_START;
	  }
	  else
	  {
		I2CMasterState = DATA_NACK;
		LPC_I2C0->I2CONSET = I2CONSET_STO;      /* Set Stop flag */
	  }
	}
	LPC_I2C0->I2CONCLR = I2CONCLR_SIC;
	break;
	
	case 0x40:	/* Master Receive, SLA_R has been sent */
	LPC_I2C0->I2CONSET = I2CONSET_AA;	/* assert ACK after data is received */
	LPC_I2C0->I2CONCLR = I2CONCLR_SIC;
	break;
	
	case 0x50:	/* Data byte has been received, regardless following ACK or NACK */
	case 0x58:
	I2CMasterBuffer[3+RdIndex] = LPC_I2C0->I2DAT;
	RdIndex++;
	if ( RdIndex != I2CReadLength )
	{   
	  I2CMasterState = DATA_ACK;
	}
	else
	{
	  RdIndex = 0;
	  I2CMasterState = DATA_NACK;
	}
	LPC_I2C0->I2CONSET = I2CONSET_AA;	/* assert ACK after data is received */
	LPC_I2C0->I2CONCLR = I2CONCLR_SIC;
	break;
	
	case 0x20:		/* regardless, it's a NACK */

	case 0x48:
	LPC_I2C0->I2CONCLR = I2CONCLR_SIC;
	I2CMasterState = DATA_NACK;
	break;
	
	case 0x38:		/* Arbitration lost, in this example, we don't
					deal with multiple master situation */
	default:
	LPC_I2C0->I2CONCLR = I2CONCLR_SIC;	
	break;
        printf("\n\rI22STAT=%2X %2X", StatValue,LPC_I2C->DAT); // выдача состояния шины
                                                             //  итекущего значения регистра данных
  }
0
А осциллограмм коммуникации нет? Во время чтения и записи.
0
они есть в датащитах — в разделе порядок обмена?
0
из датащита на микрочиповскую 24с08:
Write cycle time 10 ms (Byte or Page mode)
наверно в течение этих 10 мс к еепромке вообще прикасаться не стоит? странно, конечно что контроллер так реагирует.
все еще не победили на 100% глюк?
0
наверно в течение этих 10 мс к еепромке вообще прикасаться не стоит?
Можно прикасаться, она после приема байта адреса должна возвращать NACK если занята.
0
Почитайте, пожалуйста, мое сообщение на казусе
kazus.ru/forums/showthread.php?t=28338&page=86
Я там и логическим анализатором подключался и функции переписал не много. Тоже не могу I2C победить.
0
Может кому поможет. При работе с I2C ножки IO должны быть сконфигурированы GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
0
  • avatar
  • sprut
  • 09 декабря 2011, 16:39
пользуюсь программным I2C, в результате обошел стороной все эти грабли…
0
Ваш косяк. Всё просто нужно поменять местами сторочки кода при чтении
tmp=I2C_ReceiveData(I2C_EE);
I2C_AcknowledgeConfig(I2C_EE, DISABLE);
понятно почему?
0
  • avatar
  • rual
  • 15 марта 2012, 20:07
Вопрос о зависании I2C

Здесь было написано такое:
Qwertty
Зависает не ведущий, а ведомое устройство. Обмен идет байтами. Если в середине байта появляется лишний такт, то ведомое устройство заканчивает его принимать раньше, чем заканчивает передавать ведущее. Соответственно, если помеха «сделала» SCL==1 и возникла при изменении SDA, то «лишние» такты от ведущего ведомым воспринимаются как условие «старт» на шине с последующей передачей нового байта. Устройство начинает принимать этот виртуальный байт (кусок от старого) и, очевидно, не может дождаться его окончания. Ситуация эта кажется надуманной, но в фирме, где я работаю, I2C эксплуатировалась в условиях не сильных, но помех. В результате приборы регулярно «умирали». Хорошо, что все ведомые устройства были реализованы на PICах — это позволило ввести программный сброс при истечении таймаута при обмене. В случае покупных устройств ситуация была бы фатальной.

И я с таким столкнулся. При больших импульсных помехах программа виснет при проверке флага занятости I2C
/* While the bus is busy */
    while(I2C_GetFlagStatus(I2C_EE, I2C_FLAG_BUSY));

И никакие рестарты не помагают — нужно либо сбросить зависшую микросхему I2C (передёрнуть на ней питание), либо программно дать Slave-у недостающие данные для завершения пакета данных. Здесь об этом написано. Как я с этим справился: при старте программы после настройки I2C проверяю, не взведён ли I2C_FLAG_BUSY. Если нет, иду спокойно дальше, если же взведён — рулю ситуацию описанным в pdf-ке способом.

Вот код. Стандартные библиотеки не использовал — экономил ресурсы ядра. Код рабочий


#define _I2C_SR2_BUSY		1

#define PIN6				6
#define PIN7				7
#define CR_PIN6				(PIN6 << 2)
#define CR_PIN7				(PIN7 << 2)

#define CR_MODE6			CR_PIN6
#define CR_MODE7			CR_PIN7

#define CR_CNF6				(CR_PIN6 + 2)
#define CR_CNF7				(CR_PIN7 + 2)

void TestI2CAccess()
{
   if(!(I2C1->SR2 & (1 << _I2C_SR2_BUSY))) // проверяю, занята ли шина I2C (взведён ли флаг BUSY) 
      return; // если нет - выходим
   // а если взведён - рулю ситуацию
   GPIOB->BSRR |= (1 << PIN7) | (1 << PIN6); // выставляю SDA и SCL в 1
   GPIOB->CRL &= ~(0xC << CR_PIN6) & ~(0xF << CR_PIN7); // настраиваю порты: 6 - выход(SCL), 7 - вход(SDA)
   GPIOB->CRL |= (0x3 << CR_MODE6) | (0x2 << CR_CNF7);
    
   while(1) // здесь мы можем быть максимум 9 раз (крайний случай, смотри в pdf)
   {// дёргаю SCL (тактирую Slave)
      GPIOB->BRR |= 1 << PIN6; // SCL = 0
      Wait_ms(1);
      GPIOB->BSRR |= 1 << PIN6; // SCL = 1
      Wait_ms(1);
      if(GPIOB->IDR & (1 << PIN7)) // смотрю, отпустил ли Slave SDA (SDA == 1 ?)
      {// если да - настраиваю выводы на выход и делаю Stop состояние
         GPIOB->BRR |= 1 << PIN6; // SCL = 0
         Wait_ms(1);
         GPIOB->BRR |= 1 << PIN7; // SDA = 0
         Wait_ms(1);
         
         GPIOB->CRL &= ~(0xC << CR_PIN7); // выход
         GPIOB->CRL |= (0x3 << CR_MODE7);
         
         GPIOB->BSRR |= 1 << PIN6; // SCL = 1
         Wait_ms(1);
         GPIOB->BSRR |= 1 << PIN7; // SDA = 1
         break; // выходим из цикла
      }
   }
   // возвращаю настройки порта (аппаратный I2C)
   GPIOB->CRL |=  (0x3 << CR_MODE6) | (0x3 << CR_CNF6) | (0x3 << CR_MODE7) | (0x3 << CR_CNF7);
   // после этого шина I2C свободна и готова к работе
}
0
А у меня похоже виснет не слейв, а сам стмовский i2c. stm32f1 — dma — i2c — pcf8574
Так вот, дма в кольцевом режиме шлет непрерывно один байт из памяти стм. Но при ресете, иногда, 1 раз из 20 примерно, стмовский i2c выдает флаг busy, хотя фактически линия в 1. Вообщем расширил возможности вышеизложенной функции, может комунить пригодится)

void TestI2CAccess()
{
#define I2C_HW          I2C1
#define PIN_SCL         GPIO_Pin_8
#define PIN_SDA         GPIO_Pin_9

    static uint8_t timeout;
    GPIO_InitTypeDef GPIO_InitStructure;

    DelayMillis(5);
    if(!I2C_GetFlagStatus(I2C_HW, I2C_FLAG_BUSY)) // проверяю флаг BUSY, если да, чето подвисло
        return; // если нет - выходим

    DMA_Cmd(DMA1_Channel6, DISABLE); // dma канал подключенный к i2c
    I2C_DeInit(I2C_HW); //вырубаем i2c
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Pin = PIN_SCL; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;      GPIO_Init(GPIOB, &GPIO_InitStructure);
    GPIO_InitStructure.GPIO_Pin = PIN_SDA; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOB, &GPIO_InitStructure);
    timeout = 9;
    if (!(GPIOB->IDR & PIN_SDA)) //если на линии 1, значит висит не слэйв, а мастер
    {
        //похоже что завис слэйв, нужно добить клоки битбангом, пока не освободиться линия
        while(timeout) { // здесь мы можем быть максимум 9 раз
            timeout--;
            // дёргаю SCL (тактирую Slave)
            GPIOB->BRR = PIN_SCL; // SCL = 0
            DelayMillis(1);
            GPIOB->BSRR = PIN_SCL; // SCL = 1
            DelayMillis(1);
            if(GPIOB->IDR & PIN_SDA) // смотрю, отпустил ли Slave SDA (SDA == 1 ?)
                break;
        }
    }
    // настраиваю выводы на аппаратный i2c и делаю Stop состояние ЕСЛИ висел слейв
    GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_8 | GPIO_Pin_9;/* Configure I2C1 pins: PB8->SCL and PB9->SDA */
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
    GPIO_Init(GPIOB, &GPIO_InitStructure);
    I2C_Configuration(); //настройка i2c и дма канала
    if (timeout < 9) I2C_GenerateSTOP(I2C_HW, ENABLE);
}
0
Что-то код весь в циклах ожидания, DMA/прерывания там (stm32) вообще рабоают?
0
Насколько я понимаю, этот код нужен для «приведения в чувство» шины, а не для постоянного использования.
0
У шины I2C есть строгие ограничения по времени между фронтами SCL и другими. Я не стал разбираться, где сколько подождать, а просто налепил между всеми изменениями в линии задержки. Задержки должны быть около 1 мкс (на частоте шины 400кГц) и стоять не везде, где я их поставил. Мне нужно было освободить шину, и задачу я решил. Мой код требует оптимизации, но это второстепенная задача. Если кто-то это сделает, честь ему и хвала! :)

Насколько я понимаю, этот код нужен для «приведения в чувство» шины, а не для постоянного использования.
Я использую функцию единоразово при старте программы (когда рестартанул по вотчдогу).

Думаю идею выхода из зависания шины вы поняли. А с кодом делайте что хотите, главное чтоб во благо
0
А не проще замитать микруху с ноги МК… и не городить огород??? ))))))
Дёрнул питание… и не думаешь… отвиснет/не отвиснет...)))))))
И софтварный I2C, как уже сказали, позволяет избежать гемора во многих случаях… Нет особого смысла, в данном случае (да и не только), юзать хардварный… кроме как «получить удовольствие от нескончаемого секаса»… ))))))
0
А не проще замитать микруху с ноги МК… и не городить огород??? ))))))
Дёрнул питание… и не думаешь… отвиснет/не отвиснет...)))))))
И софтварный I2C, как уже сказали, позволяет избежать гемора во многих случаях… Нет особого смысла, в данном случае (да и не только), юзать хардварный… кроме как «получить удовольствие от нескончаемого секаса»… ))))))

Можно рестартонуть I2C микросхему передёрнув питание, можно программно, можно юзать хардварный I2C, можно софтварный — кому что нравится. И нет лучше или хуже. Есть различные ситуации и решаться они могут по разному. Благо, есть из чего выбирать
0
а что в коде за такие переменные WriteAddr и ReadAddr?
0
это не переменные, а параметры, передаваемые в функции записи и чтения епром-ки.
указывают 16-битный адрес в самой EEPROM куда мы хотим записать байт или откуда его надо прочитать.
0
А я вот сейчас пытаюсь скрестить STM32 и AT45DB081B, — тоже как-то вяло. Может у кого есть опыт в этом деле?
0
Была подобная фигня при переходе с памяти AT на ST. Вылечилось принудительной задержкой между операциями записи (между пакетами). Там аккурат происходило чтение-запись. И проявилось при переходе с 10мгц на 40мгц контроллера — пакеты не укладывались в безопасный интервал, слишком шустро все работало :D
0
  • avatar
  • hexus
  • 27 августа 2012, 19:58
Проблему зависания контроллера решил для stm32f4 установкой ножек sda и scl как «open drain low», но вот беда I2C_EE_ByteRead отдает одно и тоже значение. например:
USART2_Init();
	init_I2C1();
	printf("Start \r\n");
	for(i=0;i<10;i++)
	{
	    I2C_EE_ByteWrite(2,i);
	}
	for(i=11;i<16;i++)
	{
	    I2C_EE_ByteWrite(7,i);
	}
	for(i=0;i<16;i++)
	{
		printf("Address: %x ",i);
		printf("value : %x \r\n",I2C_EE_ByteRead(i)); 	
	}

отдает в терминал
<0>tart
Address: 0 value: 7
Address: 1 value: 7
Address: 2 value: 7
Address: 3 value: 7
Address: 4 value: 7
Address: 5 value: 7
Address: 6 value: 7
Address: 7 value: 7
Address: 8 value: 7
Address: 9 value: 7
Address: a value: 7
Address: b value: 7
Address: c value: 7
Address: d value: 7
Address: e value: 7
Address: f value: 7
0
Все разобрался. просто пытался читать данные с модуля 2 байтами, а надо было 1 байтом. читайте камменты выше
0
Хочу еще добавить: на HY-mini stm32v i2c1 не запустить. используйте i2c2!
0
Помогите пожалуйста разобраться. У меня IIC читает байт из еепром только один раз, вторичный вызов I2C_EE_ByteRead() с тем же байтом для чтения приводит к зависанию программы на while(I2C_GetFlagStatus(I2C_EE, I2C_FLAG_BUSY)); и так же помогает лишь сброс питания. В чем может быть дело?
0
Проблему решил как подсказал OlejanJa в комментариях выше. Спасибо!
0
здравствуйте!
собрал DS1307 24С32 STM32F0 в кучу написал небольшую программку и нарисовалась проблема. без подключенной к DS1307 батарейки все работает отлично, а при подключение на 3пин батарейки, считывание прекращается. (точнее считывание почему-то происходит в фоне, почему не пойму, питание же не отключаю!)
есть у кого-то какие-то идеи?!?!
0
Спасибо всем, что помогли…
сам нашел косяк. STM32 работает от 3,3В, а 1307 минимум в даташите написано от 4,5В. каким-то чудом без подключенной батарейки микросхеме хватало питания для работы
0
«Если ничего не помогает — прочтите, наконец, документацию»
0
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.