|
|
  |
I2C на Си, Программная реализация |
|
|
|
Sep 28 2008, 17:52
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
Цитата(addi @ Sep 28 2008, 19:28)  т.к свой вариант работает в некоторых случаях неправильно, пока не нашел причину. Ну так показали бы - вместе и нашли бы. CODE #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__
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Sep 28 2008, 18:53
|
Местный
  
Группа: Свой
Сообщений: 381
Регистрация: 27-07-08
Из: теплые края
Пользователь №: 39 233

|
Цитата(Сергей Борщ @ Sep 28 2008, 21:42)  Устройство на шине одно Спасибо. Это все поясняет.  Просто подумалось, что для нескольких устройств получается немного нерационально по объему коду.
|
|
|
|
|
Sep 29 2008, 16:59
|
Знающий
   
Группа: Участник
Сообщений: 679
Регистрация: 9-08-06
Пользователь №: 19 422

|
Здравствуйте, спасибо большое за поддержку. Вот мой код: Код #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, думаю что-то напутал с клоками или с подтверждением.
Сообщение отредактировал addi - Sep 29 2008, 17:02
|
|
|
|
|
Oct 1 2008, 12:55
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
Цитата(addi @ Sep 29 2008, 19:59)  #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;
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Oct 5 2008, 18:19
|
Знающий
   
Группа: Участник
Сообщений: 679
Регистрация: 9-08-06
Пользователь №: 19 422

|
Здравствуйте, еще раз благодарю за поддержку. Проблема почти исчерпана, теперь вся память, кроме регистров с значением преобразования, читается правильно. С регистрами , котрые хранят значения преобразования, после преобразования читаются 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;
}
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|