Отправка данных по ай-ту-си
- Войдите на сайт для отправки комментариев
Чт, 05/10/2017 - 14:11
Решил прикрутить к системе управлениея чем-то там логгер. Но чтобы не сильно расходовать и без того скромные ресурсы, решил отправлять по i2c состояние системы ( 64 байта) на контроллер SD карты, который это дело будет парсить и записывать.
Сначала уткнуся в то, что максимальный буфер в библиотеке Wire - 32 байта. Изменения в библиотеке счастья не принесли, т.к. резко подскочил расход памяти. Пришлось отправлять в два этапа по 32 байта.
Дописал простенькую функцию:
void tx_data_toLogger() { unsigned long time = millis(); Wire.beginTransmission(35); Wire.write(tx_buffer,32); Wire.endTransmission(); Wire.beginTransmission(35); for (byte i = 32; i < 64; i++)Wire.write(tx_buffer[i]); Wire.endTransmission(); Serial.print("Data sent "); Serial.println(millis() - time); }
в процессе выполнения получил:
Data sent 132
Data sent 134
Data sent 132
Data sent 132
Data sent 132
Чему был жестко опечален: 132 мс для меня непозволительная роскошь. Буду благодарен на совет что делать, чтобы минимизировать это время.
Как минимум - можно начать вычислять время выполнения до вызова Serial.print() ;) Пока оно там на 9600 выплюнет в UART...
Потом, наверное, можно еще немножко сэкономить, вызывая не TwoWire::write(uint8_t data) в своем цикле, а сразу TwoWire::write(const uint8_t *data, size_t quantity)...
Или плюнуть на SD и перейти на NVRAM.
Как минимум - можно начать вычислять время выполнения до вызова Serial.print() ;) Пока оно там на 9600 выплюнет в UART...
Да, выкроил 1 мс.
первая половина так и сделана. А ранее стоял тоже цикл - увы, разница видимо менее 1мс, ибо не видна.
Пойду покурю что есть NVRAM. Спс! :)
Еще есть FRAM: https://habrahabr.ru/post/319336/
А вот тут есть кой-какие цифры характеризующие скорости, которых можно достичь на SD https://forum.arduino.cc/index.php?topic=98898.0
Вообще-то SD принято подключать по SPI, а не по I2C.
И причина этого проста: I2C - 100кГц при наличии служебной информации, а SPI - не менее 4 МГц без дополнительной служебной.
Но вообще, 132 мс - это жесть.
Во-первых, Вы неправильно измеряете. В частности, во время измерение включается время передачи Serial.
Если правильно организовать передачу данных по I2C, то 1024 байта можно передать примерно за 45 мс.
Да, об этом уже говорилось. Разница составила 1мс, что , увы, погоды не делает.
В этом и смысл поста. Буду искренне признателен, если Вы подскажете мне как минимизировать время передачи.
Да, об этом уже говорилось. Разница составила 1мс, что , увы, погоды не делает.
Вы явно продолжаете неправильно измеряить время, так как за счет удаления Serial.print выигрыш должен был составить минимум 10мс. Приведите правленный скетч
Вы явно продолжаете неправильно измеряить время, так как за счет удаления Serial.print выигрыш должен был составить минимум 10мс. Приведите правленный скетч
вот, пожалуйста:
Я конечно умею сильно ошибаться, у меня просто талант к этому! :) Неужели и тут умудрился?
можно было и так записать, чтобы не использовать дополнительную переменную : time = millis()-time; но это не делает никакой заметной разницы.
Но, кстати, и 10мс мне погоду не делают.
Вот это зачем:
Если можно:
И кстати - если у вас буфер в 64 символа, то вот здесь
вы пошлёте 31 символ ;)
Вот это зачем:
Если можно:
И кстати - если у вас буфер в 64 символа, то вот здесь
вы пошлёте 31 символ ;)
Вы меня не путайте, я и сам запутаюсь. :)
Во-первых, я на противоположной стороне контролирую данные, там все в порядке: приходит 32+32 байта в правильном порядке. Я дал значения ячейкам массива от 0 до 63.
Во-вторых, предлагаемая Вами строка должна выглядеть так:
Но за подсказку спасибо!
В-третьих, это вообще не решает мою проблему - те же 132мс.
Увы :(
Вот это зачем:
Если можно:
И кстати - если у вас буфер в 64 символа, то вот здесь
вы пошлёте 31 символ ;)
Вы меня не путайте, я и сам запутаюсь. :)
Во-первых, я на противоположной стороне контролирую данные, там все в порядке: приходит 32+32 байта в правильном порядке. Я дал значения ячейкам массива от 0 до 63.
Да, туплю сегодня чего-то видимо :) С индексами всё норм, вместо 31 должно быть 32 в моём примере, жёсткий у мну тупняк, осень, все дела :)
Вообще-то SD принято подключать по SPI, а не по I2C.
И причина этого проста: I2C - 100кГц при наличии служебной информации,
А я че-то думал, что ай2си работает на 400кГц.
в ардуино действительно ограничено 100кгц, причем ограничение в самой библиотеке Wire.
Вот древняя статья по этому вопросу: http://forum.arduino.cc/index.php?topic=16793.0
Вдохновленный я попробовал это воплотить, прописать 400000L в файле twi.h , правда никаких twi.o wire.o я не обнаружил. Но вроде изменения случились. Но, сука, это не то, на что я надеялся. Вместо 132мс я получил 127мс. Печаль!
плз хелп!
Так это... на SPI-то пробовали? Может дело не в бобине...
SPI не пробовал т.к. нет пинов свободных, а i2c уже есть и реализована в том устройстве, куда я хочу еще и логгер прикрутить.
мрак. Длительность чего Вы меряете? Первые 32 байта отправляются блоком а вторые 32 циклом и длительность суммарная. Сделайте блоком обе отправки и померяйте. Подозреваю что потери производительности у вас гдето не на отправке. На 100КГц 32байта передаются за ~3мсек. Если хуже в разы - то чегото не так. А прерывания сильно нагружены?
SPI не пробовал т.к. нет пинов свободных, а i2c уже есть и реализована в том устройстве, куда я хочу еще и логгер прикрутить.
Может чего на i2c висит и занимает её. Переходить на spi - безсмысленная возня.
Может чего на i2c висит и занимает её.
Я пока на макетке меряю, ничего не висит пока.
мрак. Длительность чего Вы меряете? Первые 32 байта отправляются блоком а вторые 32 циклом и длительность суммарная. Сделайте блоком обе отправки и померяйте. Подозреваю что потери производительности у вас гдето не на отправке. На 100КГц 32байта передаются за ~3мсек. Если хуже в разы - то чегото не так. А прерывания сильно нагружены?
Вы просто не дочитали, при отправке блоком обоих пачек время передачи не меняется. Что-то явно не так. Что именно - не пойму. Прерывания не нагружены аапще.
Ну, а скажем, замерять не общее, а поэтапное время - пробовали? Сколь конкретно beginTransmission идет, передача и пр.
Имея ваши 10 строчек кода остается только пальцами в небо тыкать.
Прерывания могут неявно дергаться, как вон, например с SoftSerial-ом.
Имея ваши 10 строчек кода остается только пальцами в небо тыкать.
Прерывания могут неявно дергаться, как вон, например с SoftSerial-ом.
мне просто показалось, что там не на что смотреть.
С этим кодом имеем:
Ну, а скажем, замерять не общее, а поэтапное время - пробовали? Сколь конкретно beginTransmission идет, передача и пр.
Это интересно! перемещаем time = millis() - time; построчно
Перед тем, как пихонуть вторые 32 байта полезно проверить отправлены ли первые и освободился ли буфер. Может из за этого и бошку ссносит. А данные вобще передаются корректно?
Вообще, если позволите субъективный взгляд, у меня есть чувство, что писалка не успевает скидывать данные и шину держит. Я не сильно I2C увлекался, но глянул одним глазом исходник Wire - там endTransmission() вызывает twi_writeTo() с параметром wait = true. Т.е., как я понимаю, пока прием не будет подтвержден, twi_writeTo() будет тупо крутить while(wait && (TWI_MTX == twi_state)) .
P.S. Писалка - это штука с SD-картой.
Перед тем, как пихонуть вторые 32 байта полезно проверить отправлены ли первые и освободился ли буфер. Может из за этого и бошку ссносит. А данные вобще передаются корректно?
Вообще, если позволите субъективный взгляд, у меня есть чувство, что писалка не успевает скидывать данные и шину держит.
Такое имхо, что пока читалка не считает, новая порция не уйдет.
А на стороне логгера что - микросхема, вторая ардуина? Пишет на SD не завершая транзакцию по I2C и не кэширует оперативные данные ?
А на стороне логгера что - микросхема, вторая ардуина? Пишет на SD не завершая транзакцию по I2C и не кэширует оперативные данные ?
На второй стороне ардуина. Пока ничего никуда не пишет, просто принимает.
Если что, то rx_event просто для определения это первые 32 байта или вторые.
Не понимаю в деталях, что у вас там там за логика, но если взять обычный экзэмпл из Arduino IDE -> Wire -> slave_reciever и сериал из него выкинуть, то как со скоростью будет? Мои идеи по простой диагностике исчерпываются. Дальше только аппаратный логический анализатор.
Не понимаю в деталях, что у вас там там за логика,
Да ладно! :)
Заработало! 3-4 мс. Блииииииин ! :)))))))))))
16ю строчку прописал как
и все пошло как надо. Ну я ж говорил, что я мастер спорта по затыкам :))))
надо было просто запретить выводить в сериал после приема первых 32 байт, а только после вторых. Ну ё-маё!
Спасибо всем за участие! Прелесть форума в том, что обговаривая проблему , тебя подталкивают смотреть на эту проблему под разными углами. И таким образом есть шанс выйти из тупика, даже без прямых указаний.
Короче, всем добра! :)
Осталось ощущения и интуитивные действия перевести в научное объяснение.
Приемная сторона тормозит передающую. Это хороше, либка правильная значить.
Осталось ощущения и интуитивные действия перевести в научное объяснение.
все вполне научно - 32 байта в строковом представлении, включая пробелы - это 100 - 150 символов. что при скорости 9600 бод (1200 символов в сек) - как раз и дает порядка 100 -120 мс задержки
Осталось ощущения и интуитивные действия перевести в научное объяснение.
Код передающей части был верным, я не там рылся. На скорость работы то, как организована передача данных, побайтно ли с помощью цикла, или одним паком. не влияет. По крайней мере на таких небольших пачках.
Ну, еще можно сделать последний, самый глобальный и столь же бесполезный вывод: хороший программер сразу напишет правильный код. :)
Всем бобра!