Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: stm32f0xx + i2c
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
Посторонним В...
срочно нужна помощь...

веду разработку на cortex-m0 stm32f051... отладка stm32f0discovery

пытаюсь адекватно начать работать с I2C ... много гуглил но ни чего не нагуглил...

примеры от других процессоров не помогают stm32

люди жалуются на кривую периферию у stm32...

кто имел опыт с этим камнем отзовитесь... нужна ваша помошь!!!

примеры для работы с термодатчиком и памятью у меня не работают...
kosyak©
Если Вам нужно быстро и I2C "не сильно нагружена" делайте программный ...
_Артём_
Цитата(kosyak© @ Sep 2 2012, 21:33) *
Если Вам нужно быстро и I2C "не сильно нагружена" делайте программный ...

Странно как-то это смотрится - при наличии аппаратного i2с, реализовывать программный...
Там драйвера от ST кривые или сама реализация в камне не того?
И такая ситууация не только с cortex-M0, но и с CM3/4?
kosyak©
Тут главное слово быстро - я на CM3 проплюхался неделю. С примерами от СТ. И вроде запустишь, и вроде работает - а потом вылазит какаянить фигня. Как там в М0 я не знаю.
spectral1989
скачайте последнюю либу на сайте http://st.com для своего проца, она должна называться как-то так: "stm32f0xx standard peripherals library". там есть папка с примерами, они 105% рабочие. проверено неоднократно.
kan35
У F0 новый I2C, говорят учли все недочеты прошлых версий.
Danis
Цитата(_Артём_ @ Sep 2 2012, 22:31) *
Странно как-то это смотрится - при наличии аппаратного i2с, реализовывать программный...


Во всяком случае Errata sheet следует посмотреть, по I2С там не мало приведено ошибок.
Посторонним В...
примеры были от stm320518-eval ...

перекомпилил с помощью gcc - не работает... ни термометр ни eeprom

тишина на выводах sda и scl

а когда брал и пытался под себя переделать функции то передавался один ноль... адрес слейва и остальное не видать....

в отличии от cortex-m3 там все по другому переделали...

у кого программный i2c есть для stm32 ??? киньте примерчик....

эратта есть но там че та про режим 10битного адреса только говорилось
kosyak©
Могу дать в качестве примера. Без переделки мой вариант у вас врядли получится использовать.
Посторонним В...
Цитата(kosyak© @ Sep 3 2012, 09:01) *
Могу дать в качестве примера. Без переделки мой вариант у вас врядли получится использовать.



буду рад любой помощи...

особенно интересует быстрое переключение пинов на "вход" и на "выход"
kosyak©
Ну вот собственно сам код. Не смотрите на несколько странное именование переменных и функций - переименуете на свой вкус.
Вам необходимо определить несколько макросов для работы с пинами SCL и SDA (установка/сброс/чтение).

Пины должны быть настроены как "Выход с открытым коллектором". Как это сделать смотрите даташит на свой процессор.

CODE


//Пины SCL и SDA должны быть настроены как GPIO_Mode_Out_OD
//
#define I2CSWM_DELAY 32

#define I2CSWM_SETSCL()
#define I2CSWM_CLEARSCL()
#define I2CSWM_GETSCL()


#define I2CSWM_SETSDA()
#define I2CSWM_CLEARSDA()
#define I2CSWM_GETSDA()



/*
*/
inline static void __i2cswm___delay( int n )
{
do
{
__no_operation();
}while( --n > 0 );
}

/*
*/
inline static void __i2cswm___start()
{
I2CSWM_SETSDA();
I2CSWM_SETSCL();

I2CSWM_CLEARSDA();
__i2cswm___delay(I2CSWM_DELAY);
I2CSWM_CLEARSCL();
}


/*
*/
inline static void __i2cswm___stop()
{
I2CSWM_CLEARSDA();
I2CSWM_SETSCL();
__i2cswm___delay(I2CSWM_DELAY);

I2CSWM_SETSDA();
}

/*
*/
inline static uint_fast8_t __i2cswm___clock()
{
uint_fast8_t l;
I2CSWM_SETSCL();
__i2cswm___delay(I2CSWM_DELAY);

l = I2CSWM_GETSDA() == Bit_SET ? 1 : 0;

I2CSWM_CLEARSCL();
__i2cswm___delay(I2CSWM_DELAY);
return l;
}

/*
*/
inline static uint_fast8_t __i2cswm___sendb(uint8_t b)
{
uint_fast8_t db = 0x80;
for(uint_fast8_t i = 0; i < 8; i++)
{
if( b & db )
{
I2CSWM_SETSDA();
}else
{
I2CSWM_CLEARSDA();
}
__i2cswm___clock();
db >>= 1;
}

/* Получим ACK */
I2CSWM_SETSDA(); /* отпускаем линию SDA */
return __i2cswm___clock();
}


/*
*/
inline static uint_fast8_t __i2cswm___recvb( uint_fast8_t ack )
{
uint_fast8_t rb = 0;
uint_fast8_t db = 0x80;
for(uint_fast8_t i = 0; i < 8; i++)
{
if( __i2cswm___clock() )
rb |= db;
db >>= 1;
}

if( ack == I2CSWM_ACK )
{
/* шлем ацк */
I2CSWM_CLEARSDA();
__i2cswm___clock();
I2CSWM_SETSDA();
}else
{
/* шлем нацк */
I2CSWM_SETSDA();

__i2cswm___clock();
}
return rb;
}



/*
*/
void __i2cswm___reset()
{
I2CSWM_SETSDA();
for(int i = 0; i < 15; i++)
{
I2CSWM_SETSCL();
__i2cswm___delay(I2CSWM_DELAY);
I2CSWM_CLEARSCL();
__i2cswm___delay(I2CSWM_DELAY);
}
I2CSWM_SETSDA();
I2CSWM_SETSCL();
}



/*
*/
int __i2cswm___recvex(const uint16_t saddr, uint8_t* lpdata1, uint32_t size1, uint8_t* lpdata2, uint32_t size2)
{
__i2cswm___start();
if( lpdata1 != NULL )
{
if( __i2cswm___sendb( saddr | I2CSWM_DIRECTION_TX) == I2CSWM_NACK )
{
__i2cswm___stop();
return FALSE;
}

for(int i = 0; i < size1; i++)
{
if( __i2cswm___sendb(*lpdata1++) == I2CSWM_NACK )
{
__i2cswm___stop();
return FALSE;
}
}
__i2cswm___start();
}

if( lpdata2 != NULL )
{
if( __i2cswm___sendb( saddr | I2CSWM_DIRECTION_RX) == I2CSWM_NACK )
{
__i2cswm___stop();
return FALSE;
}
I2CSWM_SETSCL();
for(int i = 1; i < size2; i++)
{
*lpdata2 = __i2cswm___recvb( I2CSWM_ACK );
lpdata2++;
}
*lpdata2 = __i2cswm___recvb( I2CSWM_NACK );
lpdata2++;
}
__i2cswm___stop();
return TRUE;
}



/*
*/
int __i2cswm___sendex(const uint16_t saddr, uint8_t* lpdata1, uint32_t size1, uint8_t* lpdata2, uint32_t size2)
{
__i2cswm___start();
if( lpdata1 != NULL )
{
if( __i2cswm___sendb( saddr | I2CSWM_DIRECTION_TX) == I2CSWM_NACK )
{
__i2cswm___stop();
return FALSE;
}

for(int i = 0; i < size1; i++)
{
if( __i2cswm___sendb(*lpdata1++) == I2CSWM_NACK )
{
__i2cswm___stop();
return FALSE;
}
}
}

if( lpdata2 != NULL )
{
for(int i = 0; i < size2; i++)
{
if( __i2cswm___sendb(*lpdata2++) == I2CSWM_NACK )
{
__i2cswm___stop();
return FALSE;
}
}
}
__i2cswm___stop();
return TRUE;
}




//использвоание на примере FRAM

static const uint8_t EEPROM_SADDR = 0xA0;

/*******************************************************************************
*
*******************************************************************************/
uint_fast8_t eeprom_read(uint16_t addr, uint8_t* buf, size_t size)
{
addr = SWP(addr);

uint_fast8_t rep_cnt = 3;
uint_fast8_t rc = FALSE;
while( --rep_cnt > 0 && rc == FALSE )
{
rc = i2c_recvex(EEPROM_SADDR, (uint8_t*)&addr, sizeof(addr), buf, size);
}
return rc;
}
/******************************************************************************/



/*******************************************************************************
*
*******************************************************************************/
uint_fast8_t eeprom_write(uint16_t addr, uint8_t* buf, size_t size)
{
addr = SWP(addr);
uint_fast8_t rep_cnt = 3;
uint_fast8_t rc = FALSE;
while( --rep_cnt > 0 && rc == FALSE )
{
rc = i2c_sendex(EEPROM_SADDR, (uint8_t*)&addr, sizeof(addr), buf, size);
}
return rc;
}
/******************************************************************************/



//и где то в программе

.....

TAPPPARAMS_C d_params_c;
if( eeprom_read(0, (uint8_t*)&d_params_c, sizeof(TAPPPARAMS_C)) )
{
}else
{
//error
}

.....


Посторонним В...
Цитата(kosyak© @ Sep 3 2012, 10:21) *
Ну вот собственно сам код. Не смотрите на несколько странное именование переменных и функций - переименуете на свой вкус.
Вам необходимо определить несколько макросов для работы с пинами SCL и SDA (установка/сброс/чтение).

Пины должны быть настроены как "Выход с открытым коллектором". Как это сделать смотрите даташит на свой процессор.



серьезный код ))) я видел намного попроще для атмелов...

спасибо за помощь...

а каким образом пин прердергиваете на прием-передачу у линии SDA???


а функции действительно странно наименованы ... читабельность уменьшается ...))
kosyak©
Пины настроены как выход с открытым коллектором - Высокий уровень на них формируется с помощью внешнего подтягивающего резистора, а Низкий уровень одним из устройств на шине.
Т.е. если пишете 1 а читаете 0 - значит какое-то устройство на шине передает 0. Это называют Квазидвунаправленный порт.

Коду вообщем то все равно на каком процессоре работать - главное определить макросы для работы с пинами.

А функции.. дело в том что по этому модулю потом проходится скрипт, который меняет имена функций и переменных.

Посторонним В...
Цитата(kosyak© @ Sep 3 2012, 11:29) *
Пины настроены как выход с открытым коллектором - Высокий уровень на них формируется с помощью внешнего подтягивающего резистора, а Низкий уровень одним из устройств на шине.
Т.е. если пишете 1 а читаете 0 - значит какое-то устройство на шине передает 0. Это называют Квазидвунаправленный порт.

Коду вообщем то все равно на каком процессоре работать - главное определить макросы для работы с пинами.

А функции.. дело в том что по этому модулю потом проходится скрипт, который меняет имена функций и переменных.



кстати я правилно понал ??

#define I2CSWM_DIRECTION_TX 0x00
#define I2CSWM_DIRECTION_RX 0x01

#define I2CSWM_NACK 0x01
#define I2CSWM_ACK 0x00


если смотреть спецификацию и2с???

kosyak©
Копировал и забыл про эти константы. Вот

static const uint_fast8_t I2CSWM_DIRECTION_TX = 0;
static const uint_fast8_t I2CSWM_DIRECTION_RX = 1;

static const uint_fast8_t I2CSWM_NACK = 1;
static const uint_fast8_t I2CSWM_ACK = 0;

Можете использовать define, это не принципиально.
Посторонним В...

#define I2C_SCL_PIN GPIO_Pin_0
#define I2C_SDA_PIN GPIO_Pin_1
#define I2C_SCL_PIN_SOURCE GPIO_PinSource0
#define I2C_SDA_PIN_SOURCE GPIO_PinSource1
#define I2C_PORT GPIOB


#define I2CSWM_SET_SCL() (I2C_PORT->ODR |= I2C_SCL_PIN)
#define I2CSWM_RES_SCL() (I2C_PORT->ODR &= ~I2C_SCL_PIN)
#define I2CSWM_GET_SCL() (I2C_PORT->IDR & I2C_SCL_PIN)


#define I2CSWM_SET_SDA() (I2C_PORT->ODR |= I2C_SDA_PIN)
#define I2CSWM_RES_SDA() (I2C_PORT->ODR &= ~I2C_SDA_PIN)
#define I2CSWM_GET_SDA() (I2C_PORT->IDR & I2C_SDA_PIN)

у меня что та типа такого получилось....

код не пробовал.... )))

большие сомнения в I2CSWM_GET_SDA() и I2CSWM_GET_SLC()

Цитата(kan35 @ Sep 3 2012, 05:08) *
У F0 новый I2C, говорят учли все недочеты прошлых версий.


и добавили новых косяков.... )))
kosyak©
Думаю что у вас будет как то так

#define I2C_SCL_PIN 0 /*Номер пина*/
#define I2C_SDA_PIN 1

#define I2C_PORT GPIOB


#define I2CSWM_SETSCL() (I2C_PORT->BSRR |= 1<<I2C_SCL_PIN)
#define I2CSWM_CLEARSCL() (I2C_PORT->BSRR |= 1<<16<<I2C_SCL_PIN)
#define I2CSWM_GETSCL() ( (I2C_PORT->IDR & (1<<I2C_SCL_PIN)) == 0 ? 0 : 1 )


#define I2CSWM_SETSDA() (I2C_PORT->BSRR |= 1<<I2C_SDA_PIN)
#define I2CSWM_CLEARSDA() (I2C_PORT->BSRR |= 1<<16<<I2C_SDA_PIN)
#define I2CSWM_GETSDA() ( (I2C_PORT->IDR & (1<<I2C_SDA_PIN)) == 0 ? 0 : 1 )

Уделите внимание правильной настройке порта.
Посторонним В...
УРРРРРРРРРРРРРРРРРРААААААААААААААААААААААААААА!!!!!!!!!!!!!!!!!!!!


ВСЕ ЗАРАБОТАЛО!!!!


ДРУЗЬЯ СПАСИБА!!!!


kosyak©
Хм..эт чего мой код заработал? Или удалось запустить аппаратный?
Посторонним В...
Цитата(kosyak© @ Sep 3 2012, 14:22) *
Хм..эт чего мой код заработал? Или удалось запустить аппаратный?



ваш код....


макросы только поправил....


спасибо огромное...


нескромный вопрос :
а "one wire" программного у вас подобного куска кода не завалялось...???
буду признателен вдвойне!!!! )))


хрен с этим аппаратным... программный понятнее )))
kosyak©
Код то у меня есть...только он писан давно и для дургих процессоров.
Он мне не всем нравится..точнее совсем не нравится, имеет неприятные ограничения в использовании.
Приводит такое я не очень хочу ). Поищите в интернете - наверняка найдется более грамотное решение.

А аппаратный I2C все таки хорошо. Правда, если они действительно его поправили ...
Посторонним В...
Цитата(kosyak© @ Sep 3 2012, 15:47) *
Код то у меня есть...только он писан давно и для дургих процессоров.
Он мне не всем нравится..точнее совсем не нравится, имеет неприятные ограничения в использовании.
Приводит такое я не очень хочу ). Поищите в интернете - наверняка найдется более грамотное решение.

А аппаратный I2C все таки хорошо. Правда, если они действительно его поправили ...


ну аппаратный конечно лучше )))

видите ли я новичек в контроллерах...

любую логику реализовать могу запрасто а вот аппаратная часть и периферия мне пока тяжело дается...

уарт вот единственный из интерфейсов освоил... (((

конечно же стараюсь ... набиваю руку...

а ваш пример великолепен... просто - грамотно - четко... "высший пилотаж" )))

и все ошибки по схеме обрабатываются ... у меня был пример более корявый.... здесь можно реализовать контроль статуса связи с контроллером )))

кстати в m0 сейчас поставить вывод в "единицу" через регистр BSRR а сброс в "ноль " через BRR

получилось типа


#define I2CSWM_SETSCL() (I2C_PORT->BSRR |= (1<<I2C_SCL_PIN))
#define I2CSWM_CLEARSCL() (I2C_PORT->BRR |= (1<<I2C_SCL_PIN))
#define I2CSWM_GETSCL() ( (I2C_PORT->IDR & (1<<I2C_SCL_PIN)) == 0 ? 0 : 1 )


#define I2CSWM_SETSDA() (I2C_PORT->BSRR |= (1<<I2C_SDA_PIN))
#define I2CSWM_CLEARSDA() (I2C_PORT->BRR |= (1<<I2C_SDA_PIN))
#define I2CSWM_GETSDA() ( (I2C_PORT->IDR & (1<<I2C_SDA_PIN)) == 0 ? 0 : 1 )


а в stm32f0xx.h есть вообще определения типа

#define GPIO_Pin_0 (uint32_t)(0x00000001)
#define GPIO_Pin_1 (uint32_t)(0x00000002)
#define GPIO_Pin_2 (uint32_t)(0x00000004)
#define GPIO_Pin_3 (uint32_t)(0x00000008)


#define GPIO_Source0 (uint32_t)(0x00)
#define GPIO_Source1 (uint32_t)(0x01)
#define GPIO_Source2 (uint32_t)(0x02)
#define GPIO_Source3 (uint32_t)(0x03)


итд...


получилось проще



#define I2C_SCL_PIN GPIO_Pin_0
#define I2C_SDA_PIN GPIO_Pin_1
#define I2C_SCL_PIN_SOURCE GPIO_Source0
#define I2C_SDA_PIN_SOURCE GPIO_Source1

#define I2C_PORT GPIOB



#define I2CSWM_SETSCL() (I2C_PORT->BSRR |= I2C_SCL_PIN )
#define I2CSWM_CLEARSCL() (I2C_PORT->BRR |= I2C_SCL_PIN )
#define I2CSWM_GETSCL() ( ( I2C_PORT->IDR & I2C_SCL_PIN ) == 0 ? 0 : 1 )


#define I2CSWM_SETSDA() (I2C_PORT->BSRR |= I2C_SDA_PIN)
#define I2CSWM_CLEARSDA() (I2C_PORT->BRR |= I2C_SDA_PIN)
#define I2CSWM_GETSDA() ( ( I2C_PORT->IDR & I2C_SDA_PIN ) == 0 ? 0 : 1 )



и сразу пошел обмен с контроллером ))))))))
Мур
Народ, бодаюсь с отладкой I2C для Кортекса М4 (EFM32WG990F256). Есть в Кейле возможность просмотра окна периферии I2C. Красота!..
Только в толк не пойму, почему выполняя последовательность команд

i2c->TXDATA = tmp; /* Data not transmitted until START sent */
i2c->CMD = I2C_CMD_START;

в строчках Property CMD
TXDATA не вижу новых кодов (только нули), хотя должны быть коды 0x01 0xe2

Без этого не могу стартануть последовательность от моего мастера... Что это может быть?
KnightIgor
Цитата(Мур @ Aug 30 2014, 15:20) *
Народ, бодаюсь с отладкой I2C для Кортекса М4 (EFM32WG990F256). Есть в Кейле возможность просмотра окна периферии I2C. Красота!..
Только в толк не пойму, почему выполняя последовательность команд

i2c->TXDATA = tmp; /* Data not transmitted until START sent */
i2c->CMD = I2C_CMD_START;

в строчках Property CMD
TXDATA не вижу новых кодов (только нули), хотя должны быть коды 0x01 0xe2

Без этого не могу стартануть последовательность от моего мастера... Что это может быть?

Не углубляясь в дебри доков на указаный процессор (Ваша задача), но рассуждая по аналогии с EFM32G210, сообщу, что:
- первая команда есть загрузка адреса ведомого на шине I2C, а вторая команда вырабатывает START и немедленную последующую передачу этого адреса.
- регистр TXDATA есть только для чтения и НЕ отображает записаное в него значение.
Мур
Цитата(KnightIgor @ Aug 30 2014, 21:05) *
Не углубляясь в дебри доков на указаный процессор (Ваша задача), но рассуждая по аналогии с EFM32G210, сообщу, что:
- первая команда есть загрузка адреса ведомого на шине I2C, а вторая команда вырабатывает START и немедленную последующую передачу этого адреса.
- регистр TXDATA есть только для чтения и НЕ отображает записаное в него значение.

Спасибо!...
Я догадывался.... Ну а START ?... Его я и осцилом на ножке не вижу.... Окошко периферии для регистра CMD бит тоже не взводится...
KnightIgor
Цитата(Мур @ Aug 31 2014, 09:37) *
Спасибо!...
Я догадывался.... Ну а START ?... Его я и осцилом на ножке не вижу.... Окошко периферии для регистра CMD бит тоже не взводится...

Предполагаю, что периферия не инициализирована. Во-первых, необходимо включить такт периферии I2C. Во-вторых, правильно проинициализировать линии портов. В-третьих, не забыть "соединить" I2C с линиями портов, правильно взведя соответствующие биты в I2C->ROUTE. Я настоятельно рекомендую использовать периферийную библиотеку для процессора. Для EFM32 она написана очень умно и эффективно. Помощь прилагается.
Мур
Цитата(KnightIgor @ Aug 31 2014, 13:34) *
Предполагаю, что периферия не инициализирована. Во-первых, необходимо включить такт периферии I2C. Во-вторых, правильно проинициализировать линии портов. В-третьих, не забыть "соединить" I2C с линиями портов, правильно взведя соответствующие биты в I2C->ROUTE. Я настоятельно рекомендую использовать периферийную библиотеку для процессора. Для EFM32 она написана очень умно и эффективно. Помощь прилагается.


Отлично! Пригодится...
Самое интересное, что за основу взят фирменный проект для изучения, где именно средствами этой библиотеки инициализируется тактирование... Буду ковырять... Спасибо еще раз!
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.