i2c программный, STM32

ШЕЛ ЧЕТВЕРТЫЙ ЧАС БОРЬБЫ, А I2C ПРОДОЛЖАЛ РАБОТАТЬ ЧЕРЕЗ ИЗВЕСТНОЕ МЕСТО...

Было принято решение сколхозить написать собственный программный.
Задача достаточно типовая — хранить несколько ценных байт в EEPROM. Выбор пал на M24C02
Результат
Записываем

Считываем


Настройка выводов через макрос, изготовленный товарищем — Mihail, его топик http://we.easyelectronics.ru/STM32/udobnaya-nastroyka-gpio-portov.html
void I2C_Init(void)
{
  GPIO_INIT_PIN(I2C_SDA_PORT, I2C_SDA_PIN, GPIO_MODE_OUTPUT50_OPEN_DRAIN_UP);
  GPIO_INIT_PIN(I2C_SCL_PORT, I2C_SCL_PIN, GPIO_MODE_OUTPUT50_OPEN_DRAIN_UP);
}

Выдаем — Старт, Стоп
void I2C_Start(void)
{
	I2C_SDA_PORT->BSRR = (1<<I2C_SDA_PIN);
	_delay_us(TimeX);
	I2C_SCL_PORT->BSRR = (1<<I2C_SCL_PIN);
	_delay_us(TimeX);
	while(!(I2C_SDA_PORT->IDR & (1<<I2C_SDA_PIN)))
	{
	I2C_SCL_PORT->BRR  = (1<<I2C_SCL_PIN);
	_delay_us(TimeX);
	I2C_SCL_PORT->BSRR = (1<<I2C_SCL_PIN);
	_delay_us(TimeX);
        }
	I2C_SDA_PORT->BRR = (1<<I2C_SDA_PIN);
	_delay_us(TimeX);
	I2C_SCL_PORT->BRR = (1<<I2C_SCL_PIN);
	_delay_us(TimeX);
}
void I2C_Stop(void)
{
	I2C_SDA_PORT->BRR = (1<<I2C_SDA_PIN);
	_delay_us(TimeX);
	I2C_SCL_PORT->BSRR = (1<<I2C_SCL_PIN);
	_delay_us(TimeX);
	I2C_SDA_PORT->BSRR = (1<<I2C_SDA_PIN);
	_delay_us(TimeX);
}

Запись Байта, запись Блока

uint8_t I2C_Write_Byte(uint8_t data)
{
       uint8_t i;
       uint8_t ACK;
       for(i=0;i<8;i++)
       {
       if(data & 0x80)
       {
       I2C_SDA_PORT->BSRR = (1<<I2C_SDA_PIN);
       }
       else
       {
       I2C_SDA_PORT->BRR = (1<<I2C_SDA_PIN);
       }
       _delay_us(TimeX);
       I2C_SCL_PORT->BSRR = (1<<I2C_SCL_PIN);
       _delay_us(TimeX);	
       I2C_SCL_PORT->BRR = (1<<I2C_SCL_PIN);
       data=data<<1;	
       }
       _delay_us(TimeX);	
       I2C_SCL_PORT->BSRR = (1<<I2C_SCL_PIN);
       _delay_us(TimeX);	
       ACK = !(I2C_SDA_PORT->IDR & (1<<I2C_SDA_PIN));
       I2C_SCL_PORT->BRR = (1<<I2C_SCL_PIN);
       I2C_SDA_PORT->BRR = (1<<I2C_SDA_PIN);
       return ACK;
}
void I2C_Write_Block(uint8_t address, uint8_t length)
{
	uint8_t i ;
	
	I2C_Start();
	I2C_Write_Byte(0xA0);
	I2C_Write_Byte(address);
	
	for(i=0;i<length;i++)
	{
        I2C_Write_Byte(I2C_Buffer[i]);      
        }
	I2C_Stop();
}

Чтение Байта, чтение Блока

uint8_t I2C_Read_Byte(uint8_t ACK)
{
	uint8_t i;
	uint8_t data;
	
	I2C_SDA_PORT->BSRR = (1<<I2C_SDA_PIN);
      for(i=0;i<8;i++)
	{
        _delay_us(TimeX);
	I2C_SCL_PORT->BSRR = (1<<I2C_SCL_PIN);
	_delay_us(TimeX);	
	data<<=1;
      if(I2C_SDA_PORT->IDR & (1<<I2C_SDA_PIN))
	data++;	
	I2C_SCL_PORT->BRR = (1<<I2C_SCL_PIN);
        }
      if (ACK)
	I2C_SDA_PORT->BRR = (1<<I2C_SDA_PIN);
	_delay_us(TimeX);	
	I2C_SCL_PORT->BSRR = (1<<I2C_SCL_PIN);
	_delay_us(TimeX);	
	I2C_SCL_PORT->BRR = (1<<I2C_SCL_PIN);
	I2C_SDA_PORT->BSRR = (1<<I2C_SDA_PIN);
	return data;
}
void I2C_Read_Block(uint8_t address, uint8_t length)
{
        uint8_t i ;
	
	I2C_Start();
	I2C_Write_Byte(0xA0);
	I2C_Write_Byte(address);
	I2C_Start();
	I2C_Write_Byte(0xA1);
	for(i=0;i<length;i++)
	{
        I2C_Buffer[i]  = I2C_Read_Byte(i!=(length-1));      
        }
	I2C_Stop();
}

Обратите внимание, _delay_us собственная! Время другое
void _delay_us (int long delay)
{
        int long i;
      for (i=0;i<delay;i++)
      {
       i++;
       i--;
      }
}
  • +3
  • 01 августа 2013, 12:04
  • khomin

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

RSS свернуть / развернуть
Вот как-то так )
0
А как боролись поначалу? CPAL не устроил?
0
я уже вроде публиковал свои мытарства с i2c на stm32 в принципе все работает и поточную запись чтение щас прикрутил
пришлось некоторые вещи конечно научным тыком отладчика но вроде все ничего
0
Аппаратный не работал вообще, или на самом деле работал через зад?
Вообще, я сталкивался с некоторыми странностями в работе I2C, но в итоге все решилось наилучшим образом. Всего одна бессонная ночь. =)
0
Аппаратный работал ужасно.
Выкачивал автоматом, минимум по 2 байта.
И периодически создавал нехорошие ситуации, когда слейф оставался в подвешенном состоянии (SDA в 0).
Errat-а на 1,5 страницы тоже поспособствовала :)
0
Если внимательно почитать даташит, то для отправки приема только 1-го байта необходимо сгенерить старт, стоп и записать байт… Как то не очень очевидно и понятно, на на стм32 все катит...=)
0
Вопрос к знатокам: насколько совпадают баги(или фичи;) в I2C STM8 — STM32?
После плясок с бубном на восьмерке I2c завелся. Теперь я занялся STM32, все придется сначала запиливать (то есть, I2C)?
0
Думаю, картинка в рамочке — это лишнее.
+1
Убрал. Согласен
0
кхм, а о чём собственно топик?
и ещё, интересно, почему не оптимизируется ф-ция _delay_us(long int);
0
в следующий раз буду рекламировать «Миландр» :))

На компиляторе Keil-а не оптимизируется (g3 включен).
CoIDE подобную функцию пролетает.
0
миландр то тут причём? с чем знаком — о том и говорю.

в кокосе обычный gcc — там всё ясно. а вот с кейлом интересно — это баг или фича?.. подозреваю что фича.
0
слово волшебное есть volatile шоб не пролетало
ps Я смотрю вы милейший вообще интернетов не читаете :)
+2
Странная у вас реализация _delay_us(), если уж хотите сделать задержку через цикл — объявите итератор цикла как volatile. Но такая (программная) реализация задержки далеко не самый лучший вариант — в любом случае длительность задержки зависит от частоты МК и многих других факторов. ИМХО, в данном случае лучше сделать задержку на таймере.
0
Интересует 2 момента:
1. Перед выдачей условия СТАРТ Вы освобождаете линии опрашиваете свободу SDA и подаёте импульсы на SCL. Я как-то обходился без этого, но подивился Вашей прозорливости насчет возможного залипания ACK со стороны Slave)) Понимаю, что подача импульсов даёт возможность прочухаться Slave (правда, вечный цикл как-то не нравится, сделал бы счетчик). Вопрос: то есть кошерно так делать? Это общая практика и только я отстал?
2.Кажется, в функции I2C_Write_Byte Вы после выдачи 8 битов можете остаться в 0 на SDA если последний выдаваемый бит данных=0. Почему Вы перед опросом ACK не освобождаете SDA? (Или я в этих макросах запутался?)
0
случались моменты, при дебаге, что процесс выполнения программы останавливался посередине (кстати, имеет право быть просто зависон проца во время работы. так вот, проц такой чистый и веселый не знает, что совсем недавно он попросил девайс что то передать ему и тот смиренно ждет следующих клоков, честно удерживая линию SDA, чтобы завершить передачу байта. И вот здесь сразу проблемаЖ если не прогнать тики — то старт не инициализируется, работа не стоит
)
0
если не прогнать тики — то старт не инициализируется, работа не стоит
Процедура называется Bus Clear.
0
Да, полезная штука. «If the data line (SDA) is stuck LOW, the master
should send nine clock pulses. The device that held the bus LOW should release it sometime within those nine clocks. If not, then use the HW reset or cycle power to clear the bus».
0
под вторым пунктом здесь явный косяк. Исправим
0
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.