|
|
 |
Ответов
(15 - 29)
|
Dec 17 2016, 11:42
|
Гуру
     
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713

|
Цитата(Pridnya @ Dec 16 2016, 12:35)  Но вот совсем не пойму, а какой смысл использовать на медленной шине I2C прием и передачу по прерываниям, и еще DMA для I2C использовать? Поясните в двух словах, если не сложно!  Бывают и 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 - задержку эту можно считать адресом отдельного слэйва.
|
|
|
|
|
Dec 17 2016, 16:47
|
Знающий
   
Группа: Участник
Сообщений: 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
|
|
|
|
|
Dec 20 2016, 06:52
|
Участник

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

|
Цитата(KnightIgor @ Dec 17 2016, 16:47)  Вы, в итоге, наверняка сделали все правильно. Речь о том, что именно у F1xx I2C очень кривой. Об этом было много тем здесь, еще до появления других Fxxx, просто многие подзабыли. Достаточно напомнить, что при работе с I2C по прерываниям необходимо заботится о том, чтобы это прерывание не было прервано (самый высокий приоритет для I2C, либо вообще запреты прерываний на определенных этапах обработки I2C). Более того, на малых скоростях тактирования ядра (например, с целью энергосбережения) наблюдались комбинации флагов прерывания, которые никак не упоминались в документации, и для которых не было даже определений в STL. Это вводило в ступор обработчик. Поскольку большинство заводит камни сразу на максимуме, на такой косяк натыкались не многие, похоже. Мне понадобилась пара недель, с последующими доработками при работе с различной I2C периферией, чтобы запустить F103 стабильно. Когда появились F0xx, где I2C переработан, мне хватило и пары часов, чтобы запустить I2C так, что работает до сих пор. А можно кусок кода или пример по обработке (что б не пройти по тем же граблям). ОГРОМНОЕ СПАСИБО
|
|
|
|
|
Dec 20 2016, 20:52
|
Знающий
   
Группа: Участник
Сообщений: 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
|
|
|
|
|
Dec 20 2016, 22:22
|
Частый гость
 
Группа: Участник
Сообщений: 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
|
|
|
|
|
Dec 21 2016, 00:37
|
Местный
  
Группа: Свой
Сообщений: 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.
|
|
|
|
|
Dec 21 2016, 08:26
|
Участник

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

|
Цитата(KnightIgor @ Dec 20 2016, 20:52)  Я приведу кусок - обработчик прерывания. Сразу скажу, что он работает в моей, назовем это так, - экосистеме. Это макросы, различные процедуры, не приведенные здесь. Обработчик - один для нескольких I2C периферий. Поэтому используются управляющие структуры данных. Смотрите не столько на инструкции, сколько на комментарии. СПАСИБО. БУДУ РАЗБИРАТЬСЯ
|
|
|
|
|
Dec 22 2016, 12:14
|
Знающий
   
Группа: Участник
Сообщений: 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).
|
|
|
|
|
Dec 22 2016, 13:05
|
Гуру
     
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713

|
Цитата(KnightIgor @ Dec 22 2016, 15:59)  Это был оборот речи. Если периферийный I2C "застретчил" SCL и на том и застрял, то тут уже горю ничем не поможешь. Я не о том. Я говорю, что если тупо подёргать ножкой: set "1", пауза, set "0", пауза, ... То может оказаться, что для чипа памяти прошёл всего один клок, так как он всё это время держал SCL=0 выбирая данные из одной из своих ячеек. После каждого SCL="1" ждать надо пока напряжение на линии в реале не станет "1".
|
|
|
|
|
Dec 22 2016, 14:51
|

Гуру
     
Группа: Свой
Сообщений: 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
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|