jcxz 184 9 апреля, 2018 Опубликовано 9 апреля, 2018 · Жалоба Дык, вы и меня поймите: раз без ногодрыга I2C гарантированно работать не может, то в моем случае я вообще отказался от аппаратного I2C и сделал все ногодрыгом. Почему не может? Во-первых: это не штатная работа, а процесс инициализации из произвольного состояния (сброса без снятия питания). Во-вторых: это только на данном МК так (STM32F4xx), возможно там можно сделать такой сброс и через возможности штатного контроллера I2C, но оно особо не нужно разбираться - это однократная короткая операция при старте, по большому счёту без разницы как она работает. А вот штатный обмен да ещё со множеством устройств да ещё когда среди этих устройств есть FRAM-память с пересылками в несколько десятков КБ и есть устройства выдающие периодически пачки в десятки-сотни байт (тачскрин) - делать это не то что без DMA, а ещё и ногодрыгом - ну это просто какая-то уже совершенно абдуринщина в запущенной стадии. :laughing: PS: У меня в текущем проекте на XMC4500, контроллер I2C гораздо мощнее STM-ного. Здесь думаю сделать процедуру сброса при старте (несколько СТОП-условий) силами самого I2C-контроллера. Потому что на XMC4500 это сделать даже проще чем ногодрыгом. У него вообще можно всю транзакцию (СТАРТ+адрес+W, запись адреса регистра, РЕСТАРТ+адрес+R, N-чтений с ACK, 1 чтение NACK, СТОП) - можно записать одним блоком сразу в FIFO I2C и запустить на выполнение на машине состояний I2C-контроллера. А в конце транзакции получить ОДНО прерывание о завершении и вычитать из FIFO результат. Каждое слово (11 бит) в блоке: младшие 8 бит - слэйв-адрес или байт данных, старшие 3 бита - команда-состояние I2C (СТАРТ,РЕСТАРТ,СТОП,передача,...). И ISR очень простой и всего одно прерывание в конце - просто красота по сравнению с STM. Не говоря уже о ногодрыге... При желании можно подключить и DMA для наполнения FIFO I2C. Все нештатные ситуации - NACK, lost arbitration и т.п. - отслеживаются самим I2C-контроллером, выдаётся нештатное СТОП-условие на шину (или завершение приёма байта, NACK и СТОП если идёт приём) и прерывание с флагами ошибки в регистре статуса. :rolleyes: А я прекрасно понимаю :laughing: потому что на разных МК модули I2C настолько разные, и частенько, настолько кривые, что применять их просто не хочется. Так может нужно выбирать МК с хорошей периферией? :rolleyes: Оцените как выглядит и насколько простая реализация обмена по I2C на XMC4500: extern "C" void concat(isrUSIC, USIC_UNIT(nUSIC_i2c), _, SRUSIC_SR(nUSIC_SR_i2c_CTRL))() { u32 i = io->PSR; if (i & (B0 | B1 | B5 | B6 | B8 | B11 | B16)) trap(TRAP_I2C_ERROR, i); io->PSCR = i; if (!(i & B4)) return; io->TCSR_b[1] = B0; IsrEnter(); MboxPost(mbox); IsrExit(); } //Запись в регистры MPU-6050. //ra - начальный адрес регистра MPU-6050 для записи; //data/len - указатель/длина блока записываемых данных. //return: !=0 - всё ок. int GyroWr(uint ra, void const *data, uint len) { assert(len <= FIFO_SIZE - 3, TRAPR_GYRO); SemPend(sem); io->IN[0] = TDF_START | GYRO_ADDR << 1; io->IN[0] = TDF_TX | ra; for (u8 const *s = (u8 const *)data; (int)--len >= 0; ) io->IN[0] = TDF_TX | *s++; io->IN[0] = TDF_STOP; io->TCSR_b[1] = B0 | 1 << 2; MboxPend(mbox); SemPost(sem); return 1; } //Чтение из регистров MPU-6050. //ra - начальный адрес регистра MPU-6050 для чтения; //data/len - указатель/длина блока записываемых данных. //return: кол-во прочитанных байт; ==0 - произошла ошибка. int GyroRd(uint ra, void *data, uint len) { assert(data && len - 1 <= FIFO_SIZE - 5, TRAPR_GYRO); SemPend(sem); io->IN[0] = TDF_START | GYRO_ADDR << 1; io->IN[0] = TDF_TX | ra; io->IN[0] = TDF_RSTART | GYRO_ADDR << 1 | B0; for (ra = len; --ra; ) io->IN[0] = TDF_RX_A; io->IN[0] = TDF_RX_NA; io->IN[0] = TDF_STOP; io->TCSR_b[1] = B0 | 1 << 2; MboxPend(mbox); if ((ra = io->TRBSR_b[2]) - 1 >= len) trap(TRAP_I2C_RXOVER, ra); u8 *s = (u8 *)data; len = ra; do *s++ = io->OUTR; while (--ra); SemPost(sem); return len; } Первая функция - ISR. Пока нет обработки ошибочных ситуаций (не получен ACK на slave addr, lost arbitration и т.п.), позже добавлю - это мелочи. например еще не подано питание на slave или обращение к нему произошло до того, как завершился его startup. Нормальный I2C должен дать ошибку и возможность привести автомат в нормальное состояние, а не впадать в клиническую смерть. Нормальный драйвер I2C не должен допускать таких ситуаций, ибо то о чём Вы пишете - баги в реализации алгоритма драйвера. Наделать багов в алгоритме, а потом пытаться фиксить их костылями типа таймаутов - это плохое решение. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
let's see 0 9 апреля, 2018 Опубликовано 9 апреля, 2018 · Жалоба По поводу I2C. До 2010 года активно использовал AVR8 для safety-critical проектов. Машина состояний там имеет аппаратную ошибку, подтвержденную тогда еще Atmel'ом. Сут= ее в том, что помехи на шине приводили к потере арбитража в Multi-master mode и шина зависала. Для решения, одновременно с циклом обмена, запускался таймер в режиме watchdog. Если цикл приема-передачи не завершался вовремя, таймер выключал и тут же включал периферию. После перехода проекта на Cortex-M проверял устойчивость I2C на FPGA(NIOS-II), NXP, Atmel, STM32F2xx/4xx(F1xx сильно отличается). Итого: к NXP нет никаких претензий, Atmel не давал никакой возможности stretch cycle, STM худо-бедно позволяла работать НО без всяких кубов/SPL. При этом, подчеркну, что создавал помехи, подключая на шину GPIO с открытым коллектором, управляемым хаотично(0/1) в короткие промежутки времени(единицы us) и проверял целостность и времена трансферов. The product safety tests were completed succesfully. Данная информация доведена до вашего сведения, а не для дальнейших дискуссий. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться