addi 0 28 сентября, 2008 Опубликовано 28 сентября, 2008 · Жалоба Злравствуйте, прошу поделиться отработанным кодом программной реализации I2C на Си для микроконтроллера, т.к свой вариант работает в некоторых случаях неправильно, пока не нашел причину. Заранее благодарен. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 140 28 сентября, 2008 Опубликовано 28 сентября, 2008 · Жалоба т.к свой вариант работает в некоторых случаях неправильно, пока не нашел причину.Ну так показали бы - вместе и нашли бы. #ifndef I2C_SOFT_H__ #define I2C_SOFT_H__ #include <stdint.h> #include "../common/Hardware.h" template <uint8_t address> class i2c_t { public: static void on() {} static void off() {} static uint8_t read(bool ack); static bool write(uint8_t byte); private: static void start(); static void stop(); static INLINE inline void SDA_low() { DRIVER(SDA, OUTPUT); } static INLINE inline void SDA_high() { DRIVER(SDA, INPUT); } static INLINE inline bool SDA_get() { return ACTIVE(SDA); } static INLINE inline void SCL_low() { DRIVER(SCL, OUTPUT); } static INLINE inline void SCL_high() { DRIVER(SCL, INPUT); } }; template <uint8_t address> void i2c_t<address>::start() { SDA_high(); SCL_high(); nop(); //nop(); nop(); nop(); // ~0.6us TSU:SUA SDA_low(); nop(); //nop(); nop(); nop(); // ~0.6us THD:STA SCL_low(); } template <uint8_t address> void i2c_t<address>::stop() { SDA_low(); nop(); //nop(); nop(); nop(); // ~0.6us TSU:SUA SCL_high(); nop(); //nop(); nop(); nop(); // ~0.6us TSU:STO SDA_high(); nop(); //nop(); nop(); nop(); // ~1.3us TBUF - TSU:SUA delay by wrapping commands } template <uint8_t address> bool i2c_t<address>::write(uint8_t value) { uint8_t Counter = 8; do { if(value & (1 << 7)) { SDA_high(); } else { SDA_low(); } SCL_high(); value <<= 1; SCL_low(); } while(--Counter); SDA_high(); SCL_high(); nop(); nop(); if(SDA_get()) { stop(); return false; } SCL_low(); return true; } template <uint8_t address> uint8_t i2c_t<address>::read(bool ack) { uint8_t Counter = 8; uint8_t Result = 0; do { SDA_high(); SCL_high(); Result <<= 1; if(SDA_get()) Result |= 1; SCL_low(); } while (--Counter); if(ack) SDA_low(); else SDA_high(); SCL_high(); nop(); nop(); SCL_low(); return Result; } #endif // I2C_SOFT_H__ Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
vik0 0 28 сентября, 2008 Опубликовано 28 сентября, 2008 · Жалоба Можете объяснить, зачем шаблон? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 140 28 сентября, 2008 Опубликовано 28 сентября, 2008 · Жалоба Можете объяснить, зачем шаблон?Устройство на шине одно, храниь его адрес в переменной неэффективно по времени и коду. А встраивать его жестко в код некрасиво. Элегантнее его указывать при создании объекта. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
vik0 0 28 сентября, 2008 Опубликовано 28 сентября, 2008 · Жалоба Устройство на шине одно Спасибо. Это все поясняет. :) Просто подумалось, что для нескольких устройств получается немного нерационально по объему коду. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
addi 0 29 сентября, 2008 Опубликовано 29 сентября, 2008 (изменено) · Жалоба Здравствуйте, спасибо большое за поддержку. Вот мой код: #include "io78f9222.h" #include <intrinsics.h> #define SCL P2_bit.no1 #define SDA P2_bit.no2 #define SCL_IN PM2_bit.no1 #define SDA_IN PM2_bit.no2 #define _1600_ns 0x04 // 300k #define _3300_ns 0x08 // 300k extern void _delay(unsigned int tt); void ini() { SDA = 1; SCL = 1; SCL_IN = 0; SDA_IN = 0; } void i2c_dly(void) { _delay(_3300_ns); } void i2c_start(void) { SDA_IN = 0; SCL_IN = 0; SDA = 1; i2c_dly(); SCL = 1; i2c_dly(); SDA = 0; i2c_dly(); SCL = 0; i2c_dly(); } void i2c_stop(void) { SDA_IN = 0; SCL_IN = 0; SDA = 0; i2c_dly(); SCL = 1; i2c_dly(); SDA = 1; i2c_dly(); } unsigned char i2c_rx(char ack) { unsigned char x, d=0; SDA_IN = 1; SCL_IN = 0; for(x=0; x<8; x++) { d <<= 1; SCL = 1; SCL_IN = 1; while(SCL==0); i2c_dly(); SCL_IN = 0; if(SDA) { d |= 1; } SCL = 0; i2c_dly(); } SDA_IN = 0; if(ack) { SDA = 0; } else { SDA = 1; } SCL = 1; i2c_dly(); SCL = 0; SDA = 1; i2c_dly(); return d; } unsigned char i2c_tx(unsigned char d) { unsigned char x; unsigned char b; SDA_IN = 0; SCL_IN = 0; SCL = 0; for(x=0; x<8; x++) { if(d&0x80) { SDA = 1; } else { SDA = 0; } i2c_dly(); SCL = 1; d <<= 1; i2c_dly(); SCL = 0; } SDA = 1; i2c_dly(); SCL = 1; i2c_dly(); SDA_IN =1; b = SDA; SDA_IN = 0; SCL = 0; i2c_dly(); return b; } Функции чтения записи работают, но не всегда. Общаюсь с миркосхемой, и после преобразования, читаю все FF, думаю что-то напутал с клоками или с подтверждением. Изменено 29 сентября, 2008 пользователем addi Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 140 1 октября, 2008 Опубликовано 1 октября, 2008 · Жалоба #include "io78f9222.h" #define SCL P2_bit.no1 #define SDA P2_bit.no2 #define SCL_IN PM2_bit.no1 #define SDA_IN PM2_bit.no2 Не знаком со схемотехникой портов NECовских контроллеров, но гляньте вот это обсуждение - не ваш ли случай? P.S. Да, почитал User Guide на uPD78F922X - вот такое делать на I2C никак нельзя: SDA_IN = 0; SCL_IN = 0; SDA = 1; i2c_dly(); SCL = 1; Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
NullPointer 0 2 октября, 2008 Опубликовано 2 октября, 2008 · Жалоба ...читаю все FF... У вас тут что-то не вижу детектирования ситуации, когда slave удерживает на SCL низкий уровень (slave занят и ставит обмен на паузу по спецификации I2C).. Может в этом дело.. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
addi 0 5 октября, 2008 Опубликовано 5 октября, 2008 · Жалоба Здравствуйте, еще раз благодарю за поддержку. Проблема почти исчерпана, теперь вся память, кроме регистров с значением преобразования, читается правильно. С регистрами , котрые хранят значения преобразования, после преобразования читаются FF-ми. Думаю что ето не в микросхеме, т.к провел над ней серию тестов. Думаю, что что-то с удержанием шины. Вот исправленный код: #include "io78f9222.h" #include <intrinsics.h> #define SCL P2_bit.no1 #define SDA P2_bit.no2 #define SCL_IN PM2_bit.no1 #define SDA_IN PM2_bit.no2 #define _1600_ns 0x04 #define _3300_ns 0x08 extern void _delay(unsigned int tt); void ini() { SCL_IN = 1; SDA_IN = 1; } void i2c_dly(void) { _delay(_3300_ns); _delay(_3300_ns); _delay(_3300_ns); } void i2c_start(void) { SDA_IN = 1; SCL_IN = 1; i2c_dly(); SDA_IN = 0; SDA = 0; i2c_dly(); SCL_IN = 0; SCL = 0; i2c_dly(); } void icc_reset(void) { i2c_start(); i2c_start(); } void i2c_stop(void) { SDA_IN = 0; SDA = 0; i2c_dly(); SCL_IN = 1; i2c_dly(); SDA_IN = 1; i2c_dly(); } unsigned char i2c_rx(char ack) { unsigned char x, d=0; SDA_IN = 1; for(x=0; x<8; x++) { d <<= 1; do { SCL_IN = 1; __no_operation(); __no_operation(); __no_operation(); } while(SCL==0); i2c_dly(); if(SDA) { d |= 1; } SCL_IN = 0; SCL = 0; i2c_dly(); } if(ack) { SDA_IN = 0; SDA = 0; } else { SDA_IN = 1; } do { SCL_IN = 1; __no_operation(); __no_operation(); __no_operation(); } while(SCL==0); //SCL_IN = 1; i2c_dly(); SCL_IN = 0; SCL = 0; i2c_dly(); SDA_IN = 1; return d; } unsigned char i2c_tx(unsigned char d) { unsigned char x; unsigned char b; for(x=0; x<8; x++) { if(d&0x80) { SDA_IN = 1; } else { SDA_IN = 0; SDA = 0; } do { SCL_IN = 1; __no_operation(); __no_operation(); __no_operation(); } while(SCL==0); //SCL_IN = 1; d <<= 1; i2c_dly(); SCL_IN = 0; SCL = 0; i2c_dly(); } SDA_IN = 1; do { SCL_IN = 1; __no_operation(); __no_operation(); __no_operation(); } while(SCL==0); //SCL_IN = 1; i2c_dly(); b = SDA; SCL_IN = 0; SCL = 0; i2c_dly(); return b; } Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
umup 0 5 октября, 2008 Опубликовано 5 октября, 2008 · Жалоба вотъ ul_i2c.zip Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться