так и задумано, если вдруг стало cond=1 то значит уже начался приём, шина занята, пусть ждёт дальше.
Похоже Вы не поняли: while(cond) видит cond=0 и выходит из цикла, но до момента cond=2 срабатывает прерывание таймера и ставит cond=1, выдавая при этом и старт на шину. Что будет дальше - вопрос тонкий, вдруг успеет обработаться и прерывание i2c и продолжит выдачу запроса чтения, а потом уже cond сменится на два и попытается выдаться новый старт прямо посреди обмена. Чтобы таких тонких вопросов не было - и надо не допускать таких двухсмысленностей.
Вод почему нельзя её вызывать из прерываний, не понимаю, а это может понадобится. Ведь INT0 имеет наивысший приоритет, а остальные прерывания должны выполняться в оставшееся время.
Приоритет влияет только на порядок обработки возникших одновременно прерываний: если активны более одного флага прерываний, то обработается сначала с высшим приоритетом и только потом оставшиеся (по порядку приоритетов).
А почему нельзя вызывать write_i2c в том виде из прерываний я же объяснил: вложенные прерывания аппаратно не реализованы (а про программную реализацию я упорно молчу, это весьма нетривиально), сработало первое, вызвало write_i2c,
и если шина оказалась занята (таймером), то цикл ожидания никогда не завершится, ведь некому сбросить cond в 0 - прерывания i2c выставляются, но не обрабатываются пока не завершится прерывание вызвавшее write_i2c.
т.е. данные копируются в буфер, правда не volatile а просто static, так что все данные из одного и того же пакета,
Для buf[] volatile и не нужно, он же не меняется в другом потоке (в прерываниях). И static ему не нужно (глобальные и так всегда статик, а не глобальный buf в других функциях и не нужен).
А вот что данные правильные - это нет: кто вам гарантировал что в момент копирования buf[]=vals[] не возникнет прерывание по таймеру, не отработаются прерывания i2c и не появятся в vals[] новые данные? Только лично ваша надежда что if(cond) и for() buf[]=vals[] отработаются быстрее и такой накладки не произойдёт. Надежда, не гарантия! Сейчас работает, а потом, нагрузите вычислениями и другими прерываниями - и перестанет работать.
Нужно будет прикинуть время считывания по i2c, рискну предположить, что это не менее 20 байт, при частоте 400 кгц, получится наверное не более 1 мс, запись займёт ещё меньше. Если внешние прерывания будут поступать с частотой не более 100 гц, то всё успеет и отправиться и приняться с большим запасом. Так ведь?
Нет, не так. I2C это не UART и не SPI master, его частота не фиксирована и может падать вплоть до нуля. Да, наверное конкретно GY521 не затягивает обмен, но в будущем могут быть и другие устройства на I2C шине, которые могут и снижать частоту тактирования - а ведь адрес устройств распознаётся (два раза, в команде записи и в команде чтения) всеми устройствами на шине, и сигналы SCL будут затягиваться по самому медленному устройству. Да, такие устройства (с замедлением обмена) редки, но всё же. Потому пока у вас только GY521 или EEPROM (они тоже не затягивают обмен вплоть до мегагерца)- всё работает, а потом, при расширении функционала - может раз и перестать работать. И хрен Вы это увидите без осцила! Ведь замедление тактирования SCL нигде не отображается, это нормальная стандартная ситуация, протокол I2C специально так и разработан чтобы позволять замедляться обмену до нужной каждому девайсу скорости.
Посмотрите пожалуйста Dmitriy40, правильно ли у меня сделана инициализация GY521, или есть смысл как то это изменить?
Э нет, разбираться ещё и с GY521 мне влом.
Что вижу: перед while (err & 2) надо дождаться конца транзакции, delay_ms(100) ненадёжно (да и перебор), лучше while(cond) вместо неё, или любого другого флага что передача завершена.
Что прерывания (тьфу, они же не от таймера, с чего я вообще про него подумал?! они же внешние) разрешаются после инициализации - это хорошо.
Еще 1 вопрос, можно ли подключать ножку МК прямо к затвору IRLML2244TRPBF, или между затвором и vcc поставить резистор? Эо чтобы можно было программно отключать GY521.
Можно, в этом и преимущество полевика, что не нужно ограничение тока затвора (ну если он не амперный как для импульсных бп). Резистор ставят для уменьшения помех (от броска большого тока в ёмкость затвора) и для защиты ножки от пробития полевика. Но тут напруга маленькая, 3В, а сопротивление канала ножки большое (десятки Ом), так что резистор считайте уже и так встроен в ножку. Да и частота переключений мизерная (важно что не сотни кГц). И время в активном состоянии полевика доли мкс, тоже пофиг, тем более на токе 4мА. Защищаться от пробития полевика ... ну, это по желанию (и умению правильно рассчитать номинал резистора), как-то не ожидаю от 3В и 5мА возможности пробития 12В (по затвору) и 4А полевика.
Ещё совет, тоже бесполезный (должны и так знать): не забывайте что под ресетом ножки вовсе не притянуты никуда! Потому если это (потенциал ножек под ресетом) важно, стоит ставить внешнюю подтяжку. Тем более для полевика, это биполяр не откроется от мелкой эфирной наводки (а они есть практически всегда!), ему ток базы подавай, а полевику хватит и наноампер зарядить ёмкость затвора. А МК может и секунды под ресетом сидеть (например при перепрошивке или BOD сработает или задержка для старта кварца на полсотни мс). Об этом вечно забывают. С подтяжкой преимущество полевика от биполяра исчезает - и там и там по одному резистору (хотя я предпочитаю и к биполяру ставить подтяжку, ток базы дело такое, то он есть, то его нет ... а тут хватит и десятка мкА чтобы его приоткрыть на 4мА нагрузки, но это лично моя заморочка). Но напомню что даже и голая ножка вполне может питать GY521, во всяком случае пока питание МК выше 3.15В.