реклама на сайте
подробности

 
 
3 страниц V  < 1 2 3 >  
Reply to this topicStart new topic
> Вопрос по I2C
jcxz
сообщение Dec 17 2016, 11:42
Сообщение #16


Гуру
******

Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713



Цитата(Pridnya @ Dec 16 2016, 12:35) *
Но вот совсем не пойму, а какой смысл использовать на медленной шине I2C прием и передачу по прерываниям, и еще DMA для I2C использовать? Поясните в двух словах, если не сложно! rolleyes.gif

Бывают и I2C мегабитные. Не ногодрыгательные канеш.

Цитата(Pridnya @ Dec 16 2016, 15:05) *
В случае SPI для нескольких микросхем потребуется дешифратор 3-8 для CS и три лини SI, SO, SCK.

Расширяйте свой кругозор:
Для SPI кроме схемы соединения "звезда" (когда каждому слэйву назначается свой CS), бывают ещё слэйвы, поддерживающие соединение "в цепочку" (каждый слэйв имеет MOSI-вход и MOSI-выход, с MISO - аналогично).
А ещё бывают слэйвы, которым можно задать задержку (в тактах от начала CS) начала данных и просто подать все сигналы MOSI/MISO/SCLK/CS на все слэйвы параллельно - все сигналы общие для всех слэйвов. В последнем случае уже получается похоже на I2C - задержку эту можно считать адресом отдельного слэйва.
Go to the top of the page
 
+Quote Post
zltigo
сообщение Dec 17 2016, 11:49
Сообщение #17


Гуру
******

Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244



Цитата(jcxz @ Dec 17 2016, 13:42) *
Бывают и I2C мегабитные. Не ногодрыгательные канеш.

Да, Массово использую I2C FRAM с мегабитным интерфейсом.


--------------------
Feci, quod potui, faciant meliora potentes
Go to the top of the page
 
+Quote Post
KnightIgor
сообщение Dec 17 2016, 16:47
Сообщение #18


Знающий
****

Группа: Участник
Сообщений: 643
Регистрация: 29-05-09
Из: Германия
Пользователь №: 49 725



Цитата(Сергей Борщ @ Dec 16 2016, 08:48) *
Присоединяюсь к вопросу. Я сразу начал и с прерываниями и с ПДП и под ОС. Все работет. Что я сделал неправильно?

Вы, в итоге, наверняка сделали все правильно. Речь о том, что именно у F1xx I2C очень кривой. Об этом было много тем здесь, еще до появления других Fxxx, просто многие подзабыли. Достаточно напомнить, что при работе с I2C по прерываниям необходимо заботится о том, чтобы это прерывание не было прервано (самый высокий приоритет для I2C, либо вообще запреты прерываний на определенных этапах обработки I2C). Более того, на малых скоростях тактирования ядра (например, с целью энергосбережения) наблюдались комбинации флагов прерывания, которые никак не упоминались в документации, и для которых не было даже определений в STL. Это вводило в ступор обработчик. Поскольку большинство заводит камни сразу на максимуме, на такой косяк натыкались не многие, похоже.
Мне понадобилась пара недель, с последующими доработками при работе с различной I2C периферией, чтобы запустить F103 стабильно. Когда появились F0xx, где I2C переработан, мне хватило и пары часов, чтобы запустить I2C так, что работает до сих пор.

Сообщение отредактировал KnightIgor - Dec 17 2016, 16:50
Go to the top of the page
 
+Quote Post
alexf
сообщение Dec 17 2016, 20:48
Сообщение #19


Местный
***

Группа: Свой
Сообщений: 420
Регистрация: 22-12-04
Пользователь №: 1 608



Бывают ситуации когда CPU нечего делать пока идет обмен по I2C и можно без прерываний. У меня в текущем проекте на шине несколько устройств, в то числе разветвитель, которому надо всего один байт в единственный регистр. Все работает, но я довольно криво написал отдельные функции для обмена 1 и 2 байта с адресом и без.
Есть где-нибуть пример универсальной функции с параметрами?
Go to the top of the page
 
+Quote Post
zltigo
сообщение Dec 18 2016, 08:09
Сообщение #20


Гуру
******

Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244



Цитата(alexf @ Dec 17 2016, 22:48) *
Бывают ситуации когда CPU нечего делать пока идет обмен по I2C и можно без прерываний.

Если нечего делать, то пусть спит и не тратит энергию. Проснется по прерыванию sm.gif


--------------------
Feci, quod potui, faciant meliora potentes
Go to the top of the page
 
+Quote Post
dimon_rub
сообщение Dec 20 2016, 06:52
Сообщение #21


Участник
*

Группа: Участник
Сообщений: 40
Регистрация: 10-09-16
Пользователь №: 93 282



Цитата(KnightIgor @ Dec 17 2016, 16:47) *
Вы, в итоге, наверняка сделали все правильно. Речь о том, что именно у F1xx I2C очень кривой. Об этом было много тем здесь, еще до появления других Fxxx, просто многие подзабыли. Достаточно напомнить, что при работе с I2C по прерываниям необходимо заботится о том, чтобы это прерывание не было прервано (самый высокий приоритет для I2C, либо вообще запреты прерываний на определенных этапах обработки I2C). Более того, на малых скоростях тактирования ядра (например, с целью энергосбережения) наблюдались комбинации флагов прерывания, которые никак не упоминались в документации, и для которых не было даже определений в STL. Это вводило в ступор обработчик. Поскольку большинство заводит камни сразу на максимуме, на такой косяк натыкались не многие, похоже.
Мне понадобилась пара недель, с последующими доработками при работе с различной I2C периферией, чтобы запустить F103 стабильно. Когда появились F0xx, где I2C переработан, мне хватило и пары часов, чтобы запустить I2C так, что работает до сих пор.


А можно кусок кода или пример по обработке (что б не пройти по тем же граблям).
ОГРОМНОЕ СПАСИБО
Go to the top of the page
 
+Quote Post
KnightIgor
сообщение Dec 20 2016, 20:52
Сообщение #22


Знающий
****

Группа: Участник
Сообщений: 643
Регистрация: 29-05-09
Из: Германия
Пользователь №: 49 725



Цитата(dimon_rub @ Dec 20 2016, 08:52) *
А можно кусок кода или пример по обработке (что б не пройти по тем же граблям).
ОГРОМНОЕ СПАСИБО

Я приведу кусок - обработчик прерывания. Сразу скажу, что он работает в моей, назовем это так, - экосистеме. Это макросы, различные процедуры, не приведенные здесь. Обработчик - один для нескольких I2C периферий. Поэтому используются управляющие структуры данных. Смотрите не столько на инструкции, сколько на комментарии.
CODE
// -----------------------------------------------------------------------------
// EVENT INTERRUPT HANDLER
// -----------------------------------------------------------------------------
static void I2Cx_EV_IRQHandler(uint8_t port)
{
I2C_Control_Type *ctrl = &control[port];
I2C_TypeDef *i2c = ctrl->i2c;

switch (ctrl->evnt = I2C_Event(i2c, ctrl->readsr2)) {

// - - I2C Started - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

case I2C_EVENT_MASTER_MODE_SELECT_NO_SB: // MASTER, START sent: BUSY, MSL but SB are set

break; // ignore, wait for SB set

case I2C_EVENT_MASTER_MODE_SELECT: // MASTER, (RE)START sent: BUSY, MSL and SB are set

if (ctrl->wcnt > 0) { // PREPARE WRITING: send the slave Address
// with R/W bit ==0
I2C_SEND_ADDR(i2c, ctrl->ptr[0] & ~I2C_Direction_Receiver);

} else { // PREPARE READING:

// For N == 2 set POS bit to move
// NACK to the second byte.

if (ctrl->icnt == 2)
{
I2C_POS(i2c); // ACK is already set

} else {
#if (USE_I2C_RX_DMA1)

// if RX DMA enabled, allow below only for N == 1...

if (ctrl->icnt < 2)
#endif
// For pure interrupt mode RX and
// cases (N != 2) enable RxNE interrupt:
I2C_BUFIE_SET(i2c);
}
// Prevent reading of SR2 to avoid resetting of ADDR bit,
// if two or less bytes to read (cases N == 1 or N == 2).
// See RM0008.PDF, Doc ID 13902 Rev 14, Page 735.

if (ctrl->icnt <= 2)
ctrl->readsr2 = 0;

// Send I2C ID (slave Address to receive).
// Writing DR here preceeded by SR1 reading above clears SB
// with R/W bit ==1
I2C_SEND_ADDR(i2c, ctrl->ptr[0] | I2C_Direction_Receiver);
}
break;

// - - I2C Transmitting - - - - - - - - - - - - - - - - - - - - - - - - - - -

case I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED: // ADDR sent with /W bit

#if (USE_I2C_TX_DMA1)

// Transmit bytes via DMA

I2C_START_DMA_TX(ctrl);
#else
// WRITE the FIRST data byte:

I2C_WRITE_NEXT(ctrl, ctrl->ptr[ctrl->indx++]); // .icnt-- and .wnt-- inside...
#endif

break;
//
// ATTENTION! - since 03.11.11. does not work without the simple
// case I2C_EVENT_MASTER_BYTE_TRANSMITTING below as if
// I2C_EVENT_MASTER_BYTE_TRANSMITTING occures sometimes
// before I2C_EVENT_MASTER_BYTE_TRANSMITTED.
// Possible reasons (due to the following changes):
// 1). Interrupt priority of I2C has been changed to the highest one;
// 2). The I2C speed has been reduced down to 100kHz from 400kHz,
// the driver was tested before.
//
case I2C_EVENT_MASTER_BYTE_TRANSMITTING: // Data being SENT; TRA, BSY, MSL and
{ // TxE but BTF are set.
uint8_t ex = 0;
uint32_t tp = i2c_SBTimeoutInit(port, 10 * BITS_ONE_BYTE); // Time of two I2C bytes to wait

while (!I2C_BTF(i2c) &&
!(ex = i2c_SBTimeoutExpired(&tp))); // Wait for BTF! It MUST arrive else
// it were a severe hardware error...
if (ex) // BTF still off: expired!
{
I2C_ERROR_HANDLER(port, ctrl->code = ctrl->evnt);
break;
} // else CONTINUE:
}
case I2C_EVENT_MASTER_BYTE_TRANSMITTED: // Data byte's been SENT; TRA, BSY, MSL and
// both TxE and BTF are set.
if (ctrl->icnt)
{
if (ctrl->wcnt == 0)

// RESTART after the last byte from [WRITE] transaction.
// See RM0008.PDF, Doc ID 13902 Rev 12, Page 733,
// Note to START and Page 734 to "Closing the
// communication"

I2C_START(i2c);

else
// just write the next byte
I2C_WRITE_NEXT(ctrl, ctrl->ptr[ctrl->indx++]); // .icnt-- and .wnt-- inside...

} else {
// The last byte is completely pushed out, ACK from slave got.
// Bus is stretched (BTF is set), issue STOP.
I2C_ISSUE_STOP(i2c);
I2C_SUCCESS_HANDLER(ctrl);
}
break;

// TRAP: where is TRA bit?!
case I2C_EVENT_MASTER_BYTE_TRANSMITTED_BUT_TRA:

I2C_ERROR_HANDLER(port, ctrl->code = ctrl->evnt);
break;

// - - I2C Receiving - - - - - - - - - - - - - - - - - - - - - - - - - - - -

// +++ case N == 1 (single byte) and N == 2 begin +++


// .icnt is == 1 here if READ ONLY operation started,
// or == 1 + wcnt if RESTART-AFTER-WRITE preceeded.

// +++ case N == 1 (single byte) and N == 2; I2C_readSR2 == 0
// See RM0008.PDF, Doc ID 13902 Rev 14, Page 735.

case I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED_SR1: // ADDR sent, bit still set (I2C_readSR2 == 0)
{
I2C_PREPARE_CRITICAL_SECTION(sv);

// To avoid multiply data receiption...
I2C_BEGIN_CRITICAL_SECTION(sv);

// Clear ADDR bit by reading SR2 out (SR1's been read at "switch").
// This starts the receiption immediately.
ctrl->evnt |= I2C_GET_SR2(i2c) << 16;

// Prepare NACK (clear ACK); if POS is set it goes to the second (==last) byte.
// Don't worry about too late NACK setting: all IRQs are disabled!
I2C_NACK_IT(i2c);

if (ctrl->icnt == 1)
// Prepare/issue STOP after the SINGLE byte
I2C_ISSUE_STOP(i2c);

I2C_END_CRITICAL_SECTION(sv);

// Allow SR2 readout at "switch" again to get into RxNE interrupt.
// CONTINUE...
}
// This fucking case is neccessary for reading two bytes @48MHz CPU
// while I2C_readSR2 == 0 after the address has been sent.
// Occured when trying to read MCP4661 (2x Reostat) out.
//
// It seems that the interrupt is generated by ADDR = 1 while the bit
// has not appeared in SR1 yet! At the same time the SB bit is still
// seen in SR1. Madness!
//
case I2C_EVENT_MASTER_MODE_SELECT_SR1:

ctrl->readsr2 = 1; // Allow SR2 readout at "switch" again
break;

// --- case N == 1 (single byte) and N == 2 end ---

// +++ case N > 2:

case I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED: // ADDR sent, bit cleared

// 1. ADDR has already been cleared at "switch", thus
// 2. the receiption of the first byte must be in
// progress now;
#if (USE_I2C_RX_DMA1)

// Receive bytes via DMA
I2C_START_DMA_RX(ctrl);
#else
// 3. RxNE buffer interrupt is enabled.
// So do nothing here.
#endif

break;

// BTF is set:

case I2C_EVENT_MASTER_BYTE_RECEIVED_BTF:

switch (ctrl->icnt) {

case 2: // N == 2 (two bytes only)

// Here both DR and SHIFT are full with expected
// two bytes because RxNE interrupt has not been
// enabled yet. NACK has been issued to the last
// byte because NACK along with POS were prepared
// before.
// I2C bus is stretched (BTF set). Issue STOP.
// Read data TWICE (both from DR and SHIFT)!
// See Errata about disable IRQ for
// [STOP-read DATA(N-1)-read DATA(N)]

I2C_STOPN_2(ctrl); // surrounded by disabled IRQs...
ctrl->icnt = 0; // All data got.

I2C_SUCCESS_HANDLER(ctrl);
break;

case 3: // N == 3 bytes left to receive

// Here Data(N-2) in DR and Data(N-1) in SHIFT;
// The bus is stretched/pending (BTF is set).

// Prepare NACK for Data(N) and...
I2C_NACK_IT(i2c);

// ...read Data(N-2) out:
// this starts the receiption of the last byte
// with NACK at its end.
I2C_STORE(ctrl, ctrl->ptr[ctrl->indx++]);

// Prepare STOP and read Data(N-1) out:
// See Errata about disable IRQ for [STOP-read DATA(N-1)]
I2C_STOPN_1(ctrl); // surrounded by disabled IRQs
ctrl->icnt = 1;

// One byte left to read as soon as RxNE set
// Enable RxNE interrupt again to read it out.
I2C_BUFIE_SET(i2c);
break;

default:
// RxNE _AND_ BTF are set: store and check if complete.
// This occures also at enabled RxNE interrupt if
// there were no possibility to process RxNE below
// because of too long interrupts of higher priority.
// Store, check if complete:
I2C_STORE_NEXT(ctrl, ctrl->ptr[ctrl->indx++]);
}
break;

case I2C_EVENT_MASTER_BYTE_RECEIVED: // RxNE is set

if (ctrl->icnt == 3) // 3 bytes left to receive:

// Here Data(N-2) in DR and the receiption of Data(N-1)
// must/can be in progress.

// See RM0008.PDF, Doc ID 13902 Rev 12, Page 737:
// DON'T READ the data byte, just disable RxNE interrupt and
// let be interrupted by BTF above (both DR and SHIFT are full)

I2C_BUFIE_CLEAR(i2c);

else // Store, check if complete:
I2C_STORE_NEXT(ctrl, ctrl->ptr[ctrl->indx++]);

break;
// --- case N > 2 end ---

default:
//
// 19.03.2014: At 24MHz an interrupt can occure while no status bits set yet!
// This case is not to consider as an error: exit the interrupt
// and let it shoot again with all bits set.
// It seems to occure when prepared to read only 2 bytes (when
// ctrl->readsr2 is 0).
//
if (ctrl->readsr2 && ctrl->evnt)
I2C_ERROR_HANDLER(port, ctrl->code = ctrl->evnt);
}
ctrl->guard = 1;
}


Сообщение отредактировал KnightIgor - Dec 20 2016, 21:17
Go to the top of the page
 
+Quote Post
Aleksandr Barano...
сообщение Dec 20 2016, 22:22
Сообщение #23


Частый гость
**

Группа: Участник
Сообщений: 169
Регистрация: 31-08-05
Из: New York
Пользователь №: 8 118



Я бы еще вспомнил процедуру "I2C bus recovery", описанную, например, здесь:
http://www.cs.unc.edu/~stc/FAQs/Interfaces/I2C-AN10216_1.pdf
на странице 17.
Мне приходилось прибегать.


--------------------
ASB
Go to the top of the page
 
+Quote Post
alexf
сообщение Dec 21 2016, 00:37
Сообщение #24


Местный
***

Группа: Свой
Сообщений: 420
Регистрация: 22-12-04
Пользователь №: 1 608



Если я раз в секунду читаю пару датчиков за 1 мсек, много энергии не с'экономить. Тем более питание от USB.

Но неожиданно оказалось что в HAL, который я не особо жаловал, есть именно то что надо: общая форма чтения/записи Н байт по адресу М.

HAL_I2C_Mem_Read(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size, uint32_t Timeout)

HAL_I2C_Mem_Write(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size, uint32_t Timeout)


Даже можно задать размер адреса: иногда 1 байт, иногда 2.
Go to the top of the page
 
+Quote Post
dimon_rub
сообщение Dec 21 2016, 08:26
Сообщение #25


Участник
*

Группа: Участник
Сообщений: 40
Регистрация: 10-09-16
Пользователь №: 93 282



Цитата(KnightIgor @ Dec 20 2016, 20:52) *
Я приведу кусок - обработчик прерывания. Сразу скажу, что он работает в моей, назовем это так, - экосистеме. Это макросы, различные процедуры, не приведенные здесь. Обработчик - один для нескольких I2C периферий. Поэтому используются управляющие структуры данных. Смотрите не столько на инструкции, сколько на комментарии.


СПАСИБО. БУДУ РАЗБИРАТЬСЯ
Go to the top of the page
 
+Quote Post
KnightIgor
сообщение Dec 22 2016, 12:14
Сообщение #26


Знающий
****

Группа: Участник
Сообщений: 643
Регистрация: 29-05-09
Из: Германия
Пользователь №: 49 725



Цитата(Aleksandr Baranov @ Dec 21 2016, 00:22) *
Я бы еще вспомнил процедуру "I2C bus recovery", описанную, например, здесь:
http://www.cs.unc.edu/~stc/FAQs/Interfaces/I2C-AN10216_1.pdf
на странице 17.
Мне приходилось прибегать.

О, это вообще отдельная тема! EEPROMы cтрадают такой херней, что затыкаются и держат SDA в нуле. Причем так строго, что иногда и безудержное дергание SCL не помогает. В одной ответственной схеме (охранное устройство) пришлось предусмотреть типа watchdog, который снимал питание с EEPROM, если SDA слишком долго висит в нуле (схему рисовать не буду; описательно - цепочка быстро заряжается высоким SDA, медленно разряжается низким, и, долетев до низа, выключает транзистор, который и обесточивает EEPROM).
Go to the top of the page
 
+Quote Post
jcxz
сообщение Dec 22 2016, 12:53
Сообщение #27


Гуру
******

Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713



Просто "безудержное дёргание" и не должно помогать. Ведь есть такая вещь как "clock stretching". SCL надо дёргать с его учётом.
Go to the top of the page
 
+Quote Post
KnightIgor
сообщение Dec 22 2016, 12:59
Сообщение #28


Знающий
****

Группа: Участник
Сообщений: 643
Регистрация: 29-05-09
Из: Германия
Пользователь №: 49 725



Цитата(jcxz @ Dec 22 2016, 14:53) *
Просто "безудержное дёргание" и не должно помогать. Ведь есть такая вещь как "clock stretching". SCL надо дёргать с его учётом.

Это был оборот речи. Если периферийный I2C "застретчил" SCL и на том и застрял, то тут уже горю ничем не поможешь.
Go to the top of the page
 
+Quote Post
jcxz
сообщение Dec 22 2016, 13:05
Сообщение #29


Гуру
******

Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713



Цитата(KnightIgor @ Dec 22 2016, 15:59) *
Это был оборот речи. Если периферийный I2C "застретчил" SCL и на том и застрял, то тут уже горю ничем не поможешь.

Я не о том. Я говорю, что если тупо подёргать ножкой: set "1", пауза, set "0", пауза, ...
То может оказаться, что для чипа памяти прошёл всего один клок, так как он всё это время держал SCL=0 выбирая данные из одной из своих ячеек.
После каждого SCL="1" ждать надо пока напряжение на линии в реале не станет "1".
Go to the top of the page
 
+Quote Post
zltigo
сообщение Dec 22 2016, 14:51
Сообщение #30


Гуру
******

Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244



Цитата(KnightIgor @ Dec 22 2016, 14:14) *
О, это вообще отдельная тема! EEPROMы cтрадают такой херней, что затыкаются и держат SDA в нуле.

Это только для тех, кто не понимает, как работает автомат I2C в этом самом EEPROM и соответственно не понимают, как его вывести в исходное состояние.
А автомат там простой и тупой. Завесить его намертво нереально. Для выведения в исходное, правда, обычно приходится ручками диаграмму отрабатывать. От "безудержного-же дергания",
как и от любого мусора, можно только затыкание получить.




--------------------
Feci, quod potui, faciant meliora potentes
Go to the top of the page
 
+Quote Post

3 страниц V  < 1 2 3 >
Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 18th July 2025 - 20:04
Рейтинг@Mail.ru


Страница сгенерированна за 0.01502 секунд с 7
ELECTRONIX ©2004-2016