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

 
 
> Вопрос по I2C
dimon_rub
сообщение Dec 15 2016, 12:21
Сообщение #1


Участник
*

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



Здравствуйте. Вопрос наверно стар но конкретного ответа так я и не нашел. КАКОЙ метод (прерывание или DMA)нужно использовать при работе с STM32F103 по шине I2C с несколькими устройствами. Примеры попадающиеся на просторах в основном проверка в цикле с тайм-аутом (как по мне не очень красиво). Устройства всегда слейв. При этом: одно память чтение/запись не постоянная, второе датчик опрос постоянный. Кроме этого используется АЦП(где тоже соответственно опрос постоянный, сдесь DMA), USART(DMA) и SPI Ethernet(планируется DMA).

СПАСИБО ЗА СОВЕТ!!!
Go to the top of the page
 
+Quote Post
 
Start new topic
Ответов
arhiv6
сообщение Dec 16 2016, 06:07
Сообщение #2


Знающий
****

Группа: Свой
Сообщений: 633
Регистрация: 21-05-10
Из: Томск
Пользователь №: 57 423



KnightIgor, а почему катастрофа?


--------------------
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Dec 16 2016, 06:48
Сообщение #3


Гуру
******

Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095



QUOTE (arhiv6 @ Dec 16 2016, 08:07) *
KnightIgor, а почему катастрофа?
Присоединяюсь к вопросу. Я сразу начал и с прерываниями и с ПДП и под ОС. Все работет. Что я сделал неправильно?


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
KnightIgor
сообщение Dec 17 2016, 16:47
Сообщение #4


Знающий
****

Группа: Участник
Сообщений: 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
dimon_rub
сообщение Dec 20 2016, 06:52
Сообщение #5


Участник
*

Группа: Участник
Сообщений: 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
Сообщение #6


Знающий
****

Группа: Участник
Сообщений: 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

Сообщений в этой теме
- dimon_rub   Вопрос по I2C   Dec 15 2016, 12:21
- - haker_fox   QUOTE (dimon_rub @ Dec 15 2016, 20:21) Зд...   Dec 15 2016, 13:01
- - Obam   По бубну   Dec 15 2016, 13:11
- - pitt   Цитата(dimon_rub @ Dec 15 2016, 07:21) Зд...   Dec 15 2016, 13:25
- - dimon_rub   Спасибо. Хотелось услышать людей непосредственно р...   Dec 15 2016, 14:04
|- - KnightIgor   Цитата(dimon_rub @ Dec 15 2016, 16:04) Сп...   Dec 15 2016, 20:11
|- - dimon_rub   Цитата(KnightIgor @ Dec 15 2016, 20:11) М...   Dec 16 2016, 07:36
|- - Pridnya   Цитата(KnightIgor @ Dec 15 2016, 23:11) М...   Dec 16 2016, 09:35
|- - Сергей Борщ   QUOTE (Pridnya @ Dec 16 2016, 11:35) А во...   Dec 16 2016, 11:15
||- - Kabdim   Цитата(Сергей Борщ @ Dec 16 2016, 14:15) ...   Dec 16 2016, 12:05
||- - Сергей Борщ   QUOTE (Kabdim @ Dec 16 2016, 14:05) Если ...   Dec 16 2016, 12:11
|- - zltigo   Цитата(Pridnya @ Dec 16 2016, 11:35) Но в...   Dec 16 2016, 11:18
||- - Pridnya   Цитата(Сергей Борщ @ Dec 16 2016, 14:15) ...   Dec 16 2016, 12:05
|- - jcxz   Цитата(Pridnya @ Dec 16 2016, 12:35) Но в...   Dec 17 2016, 11:42
|- - zltigo   Цитата(jcxz @ Dec 17 2016, 13:42) Бывают ...   Dec 17 2016, 11:49
|- - alexf   Бывают ситуации когда CPU нечего делать пока идет ...   Dec 17 2016, 20:48
||- - zltigo   Цитата(alexf @ Dec 17 2016, 22:48) Бывают...   Dec 18 2016, 08:09
|- - dimon_rub   Цитата(KnightIgor @ Dec 20 2016, 20:52) Я...   Dec 21 2016, 08:26
- - Aleksandr Baranov   Я бы еще вспомнил процедуру "I2C bus recovery...   Dec 20 2016, 22:22
|- - alexf   Если я раз в секунду читаю пару датчиков за 1 мсек...   Dec 21 2016, 00:37
|- - KnightIgor   Цитата(Aleksandr Baranov @ Dec 21 2016, 00...   Dec 22 2016, 12:14
|- - jcxz   Просто "безудержное дёргание" и не должн...   Dec 22 2016, 12:53
||- - KnightIgor   Цитата(jcxz @ Dec 22 2016, 14:53) Просто ...   Dec 22 2016, 12:59
||- - jcxz   Цитата(KnightIgor @ Dec 22 2016, 15:59) Э...   Dec 22 2016, 13:05
|- - zltigo   Цитата(KnightIgor @ Dec 22 2016, 14:14) О...   Dec 22 2016, 14:51
- - Aleksandr Baranov   В "AN10216-01 I2C Manual" не сказано: ...   Dec 22 2016, 15:37
|- - KnightIgor   Цитата(Aleksandr Baranov @ Dec 22 2016, 17...   Dec 22 2016, 16:32
|- - zltigo   Цитата(KnightIgor @ Dec 22 2016, 18:32) Е...   Dec 22 2016, 17:22
|- - jcxz   Цитата(zltigo @ Dec 22 2016, 20:22) Такое...   Dec 22 2016, 22:44
|- - zltigo   Цитата(jcxz @ Dec 23 2016, 00:44) Да, дол...   Dec 23 2016, 06:35
|- - jcxz   Цитата(zltigo @ Dec 23 2016, 09:35) Я пис...   Dec 23 2016, 16:20
|- - zltigo   Цитата(jcxz @ Dec 23 2016, 18:20) Это у В...   Dec 24 2016, 07:09
- - AVR   Мои 5: когда я работал с I2C на AVR то на коротком...   Dec 23 2016, 07:07


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

 


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


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