Mark16 0 6 марта, 2023 Опубликовано 6 марта, 2023 · Жалоба Здравствуйте, вопрос, как сделать раздельные функции начала передачи данных, самой передачи и завершения передачи в i2c? Зачем это нужно? Не всегда есть возможность передать большой массив одним пакетом через стандартные функции типа HAL_I2C_Master_Transmit, т.к. предварительно их придётся поместить в ОЗУ. Код функции старт: Спойлер while (__HAL_I2C_GET_FLAG(&hi2c1, I2C_FLAG_BUSY) == SET) { } I2C_TransferConf(&hi2c1, (60 << 1), 0, I2C_RELOAD_MODE, I2C_GENERATE_START_WRITE); Для функции стоп: Спойлер while (__HAL_I2C_GET_FLAG(&hi2c1, I2C_FLAG_TCR) == RESET) { } I2C_TransferConf(&hi2c1, 0, 0, I2C_SOFTEND_MODE, I2C_GENERATE_STOP); while (__HAL_I2C_GET_FLAG(&hi2c1, I2C_FLAG_STOPF) == RESET) { } __HAL_I2C_CLEAR_FLAG(&hi2c1, I2C_FLAG_STOPF); А вот как передавать между ними что-то, я так и не понял for (int i = 0; i <300;i++) { //ПЕРЕДАЧА данных } Прикрепляю исходник, весь код в функции main, там я пытаюсь отправить 300 байт test_l052c8t6.rar Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Obam 38 6 марта, 2023 Опубликовано 6 марта, 2023 · Жалоба А вот как передавать между ними что-то, я так и не понял А вот на каждый ACK от ведомого и отправлять... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Mark16 0 6 марта, 2023 Опубликовано 6 марта, 2023 · Жалоба 19 минут назад, Obam сказал: А вот как передавать между ними что-то, я так и не понял А вот на каждый ACK от ведомого и отправлять... было бы славно, да вот ACK бита там не наблюдаю Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Obam 38 6 марта, 2023 Опубликовано 6 марта, 2023 · Жалоба "Там" это где? В регистре состояния (SR) I2C нет флага, обозначающего 9-й бит в байтовой транзакции?!! (((-8Ж Серьёзно? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Mark16 0 6 марта, 2023 Опубликовано 6 марта, 2023 · Жалоба 17 минут назад, Obam сказал: "Там" это где? В регистре состояния (SR) I2C нет флага, обозначающего 9-й бит в байтовой транзакции?!! (((-8Ж Серьёзно? Спойлер Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Obam 38 6 марта, 2023 Опубликовано 6 марта, 2023 · Жалоба А ISR (прерываний и состояния регистр) что ж не зацитировали? (((-8Ж А если чуть серьёзнее: вы же HAL хотите применять? Вот и комбинируйте флаги пустого регистра данных (передаваемых) и NACKF. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Mark16 0 7 марта, 2023 Опубликовано 7 марта, 2023 · Жалоба 15 часов назад, Obam сказал: А ISR Спойлер 15 часов назад, Obam сказал: Вот и комбинируйте флаги пустого регистра данных (передаваемых) и NACKF. TXE, я так понимаю? Но ведь нужно и в NBYTES записывать 1 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Obam 38 7 марта, 2023 Опубликовано 7 марта, 2023 · Жалоба Ну да - единожды, автомат I2C будет, если не забудете бит RELOAD установить, требовать новый и новый байт по подтверждении от ведомого, но сами и будете считать сколько отправили: максимально "железяку" разгружаете ;-) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Mark16 0 7 марта, 2023 Опубликовано 7 марта, 2023 · Жалоба 31 минуту назад, Obam сказал: Ну да - единожды, автомат I2C будет, если не забудете бит RELOAD установить, требовать новый и новый байт по подтверждении от ведомого, но сами и будете считать сколько отправили: максимально "железяку" разгружаете 😉 Не совсем понял, в какой последовательности это делать, а старт и стоп я правильно генерирую? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Obam 38 7 марта, 2023 Опубликовано 7 марта, 2023 · Жалоба NBYTES и RELOAD в одном регисте находятся, какая там последовательность может быть ? (Четырьмя машинными командами задаются) а старт и стоп я правильно генерирую? А это ведомый покажет (без него никак) и логический анализатор\осциллограф. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
engel65536 12 7 марта, 2023 Опубликовано 7 марта, 2023 · Жалоба Старт - одновременная запись адреса ведомого (I2C_CR2_SADD), количества байт (I2C_CR2_NBYTES) и I2C_CR2_START в CR2 (возможно, путаю, и запись I2C_CR2_START нужно делать отдельно, через |=). Передачу байт делаем записью в TXDR при получении I2C_ISR_TXIS в ISR, этот самый TXIS у вас возникнет ровно столько раз, сколько байт вы задали в CR2. При получении I2C_ISR_TC генерируете стоп записью I2C_CR2_STOP в CR2. Если я ничего не упустил, этого минимума должно быть достаточно, чтобы оно завелось. Если у вас массив больше, чем 255/256/сколько-там байт (ограничение поля NBYTES в CR2) - сначала запустите на небольших объёмах, а потом читайте reference manual, там должно быть описано, что и как надо делать для этого случая. Но имейте в виду, что так получится очень нехороший драйвер I2C. Для того, чтобы сделать его хорошим, нужно сделать корректную обработку всех получаемых событий, а не только TXIS/TC. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AlanDrakes 1 8 марта, 2023 Опубликовано 8 марта, 2023 · Жалоба Кто как, а у меня на L051 работает вот такой запуск I2C: I2C1->CR2 = (I2C_CR2_AUTOEND | DevAddr << 1 | I2C_CR2_RD_WRN | (DataToRead<<16) | I2C_CR2_START); Сразу пишем в регистр и адрес ведомого и автостоп (после нужного количества байт) и всё прекрасно срабатывает. Ещё раз убеждаюсь, что в L05x перенесли блок I2C от F030, а не из F407, где всё делалось через тыканье битов на каждое действие: Отправили старт? Шлём адрес. Отправили? Отлично. Ошибка?! Ах ты ж... ну ладно. Или Закончили отправлять байт? Отлично, продолжаем. Ошибка линии? Ну вот опять 😞 А тут? Стартуем на адрес XXXX, отправлять будем YYYY байт! После отправки - стоп. И всё! Знай только байты подкладывай. И иногда следи за флагами состояний. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
VladislavS 39 8 марта, 2023 Опубликовано 8 марта, 2023 · Жалоба Только ограничение YYYY на 255 немного портит малину. Если данных мало, то всё просто Спойлер bool MasterWrite(const uint8_t hw_adr, uint8_t *data, uint8_t len) { base()->CR2 = _VAL2FLD(I2C_CR2_NBYTES,len) | hw_adr | I2C_CR2_AUTOEND | I2C_CR2_START; while(len--) { if(!waitISRBitSet<I2C_ISR_TXIS>()) return false; base()->TXDR = *data++; } return true; } // Ожидание статусных бит с обработкой ошибок и антизацикливанием static inline bool waitISRBitSet() { uint32_t sr; uint32_t timeout_counter=1'000'000; do { sr=base()->ISR; if(sr&( I2C_ISR_NACKF | I2C_ISR_ARLO | I2C_ISR_BERR)) { base()->ICR = I2C_ICR_NACKCF | I2C_ICR_BERRCF | I2C_ICR_ARLOCF; return false; } if(--timeout_counter == 0) return false; } while( !(sr&Bit) ); return true; } Тут base() понимать как I2C1, I2C2 и т.д. Эта функция член класса позволяет "протащить" указатель на периферию в constexpr контекст. Без плюсов можно просто указателем на I2C_TypeDef обойтись. template<uint32_t PI2C> class TI2C { static inline auto base() { return (I2C_TypeDef *)PI2C; } } Если надо передавать много, то чуть сложнее Спойлер bool MasterWrite(const uint8_t hw_adr, uint8_t *data, uint32_t len) { bool first_part = true; while(len) { if(len<256) { base()->CR2 = _VAL2FLD(I2C_CR2_NBYTES,len) | hw_adr | I2C_CR2_AUTOEND | (first_part?I2C_CR2_START:0); while(len) { if(!waitISRBitSet<I2C_ISR_TXIS>()) return false; base()->TXDR = *data++; len--; } } else { base()->CR2 = _VAL2FLD(I2C_CR2_NBYTES,255) | hw_adr | I2C_CR2_RELOAD | (first_part?I2C_CR2_START:0); first_part=false; for(uint32_t i=255; i--;) { if(!waitISRBitSet<I2C_ISR_TXIS>()) return false; base()->TXDR = *data++; } if(!waitISRBitSet<I2C_ISR_TCR>()) return false; len-=255; } } return true; } Оба случая можно под шаблон объединить Спойлер template<typename TLen> static inline bool MasterWrite(const uint8_t hw_adr, uint8_t *data, TLen len) { if constexpr(sizeof(TLen)==1) { base()->CR2 = _VAL2FLD(I2C_CR2_NBYTES,len) | hw_adr | I2C_CR2_AUTOEND | I2C_CR2_START; while(len--) { if(!waitISRBitSet<I2C_ISR_TXIS>()) return false; base()->TXDR = *data++; } } else { bool first_part = true; while(len) { if(len<256) { base()->CR2 = _VAL2FLD(I2C_CR2_NBYTES,len) | hw_adr | I2C_CR2_AUTOEND | (first_part?I2C_CR2_START:0); while(len) { if(!waitISRBitSet<I2C_ISR_TXIS>()) return false; base()->TXDR = *data++; len--; } } else { base()->CR2 = _VAL2FLD(I2C_CR2_NBYTES,255) | hw_adr | I2C_CR2_RELOAD | (first_part?I2C_CR2_START:0); first_part=false; for(uint32_t i=255; i--;) { if(!waitISRBitSet<I2C_ISR_TXIS>()) return false; base()->TXDR = *data++; } if(!waitISRBitSet<I2C_ISR_TCR>()) return false; len-=255; } } } return true; } Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Mark16 0 8 марта, 2023 Опубликовано 8 марта, 2023 (изменено) · Жалоба В 08.03.2023 в 08:44, AlanDrakes сказал: автостоп ну мне без автостопа как-то надо. В 07.03.2023 в 20:54, Obam сказал: А это ведомый покажет (без него никак) и логический анализатор\осциллограф. Смотрел, старт стоп работают. Но после передачи нескольких пакетов байт затыкается (так в моём исходнике) Изменено 9 марта, 2023 пользователем Mark16 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Obam 38 8 марта, 2023 Опубликовано 8 марта, 2023 · Жалоба Каких (что значит) пакетов? Ведомый 300 байт (то, что вы привели в первом посте) за один заход в состоянии получать? Но после передачи нескольких пакетов затыкается Ну в отладчике смотрите в чём причина. Всё определяется ведущим - побайтово можно смотреть, больше того - код можно не писать, с остановленным ядром вручную можно байты в TDR класть и смотреть как работает Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться