ขอความช่วยเหลือเกี่ยวกับ I2C Bit-bang หน่อยครับ

Started by win268727, February 28, 2013, 11:07:31 PM

Previous topic - Next topic

win268727


คือต้องการใช้ ATmega32a ติดต่อกับ DS1307 แบบ I2C Bit-Bang เป็นฐานนาฬิกาอ่ะครับ
แต่มีปัญหาคือมันอ่านค่าออกมาเป็นลอจิก 1 ตลอดเลยอ่ะครับอยากให้ช่วยดูโค๊ดให้หน่อยอ่ะครับ
ว่าผมเขียนผิดตรงไหน หรือขอโค๊ดของ AVR เป็นตัวอย่างก็ได้ครับ เอาของตระกูลอื่นมาแก้แล้วมัน
ไม่ออกเป็นอาการเดียวๆกันหมดเลยครับ ขอบคุณมากครับ  ???

#include <avr/io.h>
#include <compat/deprecated.h>

#define F_CPU 12000000UL
#include <util/delay.h>

unsigned int sec, min, hr;

#define DDR_I2C DDRA
#define DDSDA DDA6
#define DDSCL DDA7
#define PORT_OUT_I2C                 PORTA
#define SDA PA6
#define SCL PA7
#define PORT_IN_I2C PINA
#define PINSDA PINA6
#define PINSCL PINA7

#define DS1307_CODE_WRITE 0xD0
#define DS1307_CODE_READ 0xD1

void delay_ms(unsigned int ms)
{
for(;ms>0;ms--)
{
_delay_ms(1);
}
}
void delay_us(unsigned int us)
{
for(;us>0;us--)
{
_delay_us(1);
}
}

void I2C_SETUP(void)
{
DDR_I2C |= (1<<DDSDA)|(1<<DDSCL); //SET OUTPUT
sbi(PORT_OUT_I2C, SDA);
sbi(PORT_OUT_I2C, SCL); //SET SDA and SCL to HIGH
}
void I2C_START(void)
{
I2C_SETUP();

cbi(PORT_OUT_I2C, SDA);
delay_us(6);
cbi(PORT_OUT_I2C, SCL);
delay_us(6);
}
void I2C_STOP(void)
{
cbi(PORT_OUT_I2C, SCL);
delay_us(6);
cbi(PORT_OUT_I2C, SDA);
delay_us(6);

sbi(PORT_OUT_I2C, SCL);
delay_us(6);
sbi(PORT_OUT_I2C, SDA);
delay_us(6);
}
void I2C_RESTART(void)
{
cbi(PORT_OUT_I2C, SCL);
delay_us(6);
sbi(PORT_OUT_I2C, SDA);
delay_us(6);
sbi(PORT_OUT_I2C, SCL);
delay_us(6);
cbi(PORT_OUT_I2C, SDA);
delay_us(6);
cbi(PORT_OUT_I2C, SCL);
delay_us(6);
}
void I2C_ACK(void)
{
sbi(PORT_OUT_I2C, SCL);
delay_us(6);
cbi(PORT_OUT_I2C, SCL);
delay_us(6);
}
void I2C_NAK(void)
{
sbi(PORT_OUT_I2C, SDA);
delay_us(6);
sbi(PORT_OUT_I2C, SCL);
delay_us(6);
cbi(PORT_OUT_I2C, SCL);
delay_us(6);
}
void I2C_WRITE(unsigned int DataWrite)
{
for(unsigned char index=0;index < 8;index++)
{
cbi(PORT_OUT_I2C, SCL);
delay_us(6);
if(DataWrite & 0x80) //MSB------------------LSB
{
sbi(PORT_OUT_I2C, SDA);
}
else
{
cbi(PORT_OUT_I2C, SDA);
}

sbi(PORT_OUT_I2C, SCL);
delay_us(6);
DataWrite = DataWrite<<1;
}
cbi(PORT_OUT_I2C, SCL);
delay_us(6);
sbi(PORT_OUT_I2C, SDA);
delay_us(6);
}
unsigned int I2C_READ(void)
{
unsigned char DataRead = 0x00;
DDR_I2C &= (0<<DDA6)|(1<<DDA7); //SET SDA to INPUT
PORT_OUT_I2C |= (1<<SDA); //PULL UP SDA PIN

for(unsigned char index=0;index < 8;index++)
{
DataRead = DataRead<<1;
sbi(PORT_OUT_I2C, SCL);
delay_us(6);
if((~PORT_IN_I2C&(1<<PINSDA))==0x40)
{
DataRead |= 0;
}
else
{
DataRead |= 1;
}
cbi(PORT_OUT_I2C, SCL);
delay_us(6);
}
DDR_I2C = (1<<DDA6)|(1<<DDA7);
cbi(PORT_OUT_I2C, SCL);
delay_us(6);
sbi(PORT_OUT_I2C, SDA);
delay_us(6);
return (DataRead);
}
/////////////////////////////// MAINPROGRAM ///////////////////////////////////////////
void main(void)
{
sec = min = hr = 0;
    while(1)
    {
DP12_input(sec, min, 1);
DP34_input(hr, 0, 1);

I2C_START();
I2C_WRITE(DS1307_CODE_WRITE);
I2C_ACK();
I2C_WRITE(0x00);
I2C_ACK();
I2C_RESTART();
I2C_WRITE(DS1307_CODE_READ);
I2C_ACK();
sec = I2C_READ();
I2C_NAK();
    }
return 0;
}

firmware.c

อันดับแรก circuit ถูกต้องแล้วใช่ไหมครับ
IAR Embedded Workbench for ARM
AVR-Studio + AVR-GCC
CodeBlocks + MinGw
CodeBlocks + Gtk+



crywolf

ทำไมไม่ใช้ Hardware I2C ล่ะครับ สะดวกกว่าเยอะเลย
ไม่ต้องมาสนใจเรื่อง Timing

wlasoi

ถ้าชอบ Bit-Bank แนะนำไปใช้  DS1302 หรือ SPI ครับ ... สำหรับ I2C ไม่เหมาะกับวิธีการ Bit-Bank ด้วยประการทั้งปวง เนื่องจากมันมีสัญญาน ACK กลับ ถ้าเป็น device ที่มีความซับซ้อนในการสื่อสารสูง โอกาศที่จะรวนมีมาก

pa_ul

I2C_ACK ดูแปลกๆ นะครับ ไม่เห็นมีการอ่านค่า SDA กลับเข้ามาดูว่าเป็น ACK หรือเป็น NAK ผมไม่ค่อยได้ใช้ AVR แต่เท่าที่ดูเข้าใจว่าขา SDA จะยังคงเป็น output อยู่ในระหว่างการ ACK ซึงหมายความว่า SDA อาจจะกำลังขับ Logic 1 ออกมา ในขณะที่ slave พยายามจะ ACK (คือขับ logic 0) ซึ่งในกรณีนี้ตามมาตรฐานของ I2C จะถือว่าเกิด contention และอุปกรณ์จะต้องหยุด (Abort) การทำงาน และรอการติดต่อรอบใหม่

การ ACK นี้เป็นสิ่งที่สำคัญมากใน I2C มันเป็นการยืนยันว่า slave มีการตอบรับหรือไม่ จึงไม่ควรแค่สร้าง SCL เฉยๆ โดยไม่สนใจ SDA แต่ควรจะอ่านค่า SDA กลับมาจริงๆว่าเป็น 0 'ACK' หรือ 1 'NAK' และในแง่ของการดีบักตัวโปรแกรมในกรณีที่ใช้ bit-bang แล้ว การตรวจสอบ ACK จะเป็นการยึนยันว่าการติดต่อแต่ละไบท์เป็นไปอย่างถูกต้องหรือไม่ ควรทดสอบเบื้องต้นด้วยการส่งแค่ address แล้วดูสถานะ ACK ว่าถูกต้องหรือไม่เสียก่อน ถ้าได้แล้วถึงค่อยไปลงในรายละเอียดของแต่ละคำสั่งอีกที

win268727

ขอบคุณสำหรับข้อมูลมากๆ ครับ ผมจะเอาไปปรับแต่งโค๊ดใหม่แล้วมารายงานผลนะครับ :)

ส่วนของ Hardware ผมปรับเปลี่ยนไม่ได้ครับ เพราะผมได้มาเป็นบอร์ดวงจรเปล่าๆ ไม่มี
โปรแกรมมาด้วย ต้องมาเขียนให้มันทำงานเอง แล้วขาสำหรับใช้กับ I2C มันไปต่อใช้กับ
อย่างอื่นอ่ะครับ เลยต้องเขียนแบบ Bit-Bang

JENG

สามารถติดตาม electoday ได้ที่

Facebook
www.facebook.com/groups/coopmicro

Google+
https://plus.google.com/communities/103482067769375459277

☺☺☺ความรู้ และความฉลาด ไม่ใช่สิ่งเดียวกัน จะมีประโยชน์อะไร ถ้าฉลาดแต่อยู่ในกะลา☺☺☺