Forum Menu




 


Log in Problems?
New User? Sign Up!
AVR Freaks Forum Index

Post new topic   Reply to topic
View previous topic Printable version Log in to check your private messages View next topic
Author Message
ontosas
PostPosted: Nov 09, 2009 - 12:38 PM
Newbie


Joined: Nov 03, 2009
Posts: 6


Hello.
I'm working with Atmega16. My aim is to read temperature data from LM75. Source which I use to interface i2c and lm75 is standart free downloaded from internet. Code is here:
http://www.vabolis.lt/stuff/20070919.zip
(http://www.vabolis.lt/2007/09/19/atmega-usb-005/)
Bellow is main code:
It works only when sensors_init() function is disabled. LCD shows results. So that i2c interface is not initialized.
Atmega16 use PC0 and PC1 for i2c interface. So, I have changed pull-up'ing ports in i2c.c
from PORTC |= (1<<5)|(1<<4); to PORTC |= (1<<1)|(1<<0); But it's dont matter because pull-up is external with 10K resistors. Clock is internal 1MHz.
Do you have idea whats wrong? Why I cannot read data?
Best Regards,
Vytautas
Code:
/*************************************************************************
Title:    I2C FM75 irenginys ir LCD
Author:   Savel
File:     
Software: AVR-GCC 3.3
Hardware: ATMEGA16 testine plokste
**************************************************************************/
#define F_CPU 12000000UL
#define LM75_ADDR       (LM75_ADDR_BASE + 0) //pasitikrinti

#include <stdlib.h>
#include <avr/io.h>
#include <avr/pgmspace.h>
#include "lcd.h"
#include <util\delay.h>

#include "i2c.c"
#include "lm75.c"

int sensors_init(void)
{
   i2c_init();
   return lm75_configure(LM75_ADDR, 0x60); //cia komanda FM75, daugiau tikslumo. Skaityti FM75/LM75 datasheeta.
}

int main(void)
{
    char buffer[16];
    unsigned char dst[2];
   int x=0;

   sensors_init();
    /* initialize display, cursor off */
    lcd_init(LCD_DISP_ON);
    /* turn off cursor */
    lcd_command(LCD_DISP_ON);
   lcd_clrscr();
   lcd_puts("FM75 sensorius");
    for (;;) { /* loop forever */
      dst[0]=0; dst[1]=0;
      // temperaturos nuskaitymas is FM75 cipo
         lcd_gotoxy(0,1);
         x = lm75_readRegister(LM75_ADDR, LM75_REG_TEMP, &dst[0], 2);
         if (x==0){
         x=dst[0];
         itoa( x, buffer, 10);
         lcd_puts("temp:         ");
         lcd_gotoxy(5,1);
         lcd_puts(buffer);
         lcd_puts(".");
         x=dst[1]; // Cia skaiciuojam po kablelio. 1/16 laipsnio.
         if (x<1) {lcd_puts("0");}
         if (x<17) {lcd_puts("0");}
         x=dst[1]*4;
         itoa( x, buffer, 10);
         lcd_puts(buffer);
         } else {lcd_puts("Sensor error "); }
         for (x=0;x<10;x++) { _delay_ms(20); }
      }
}
 
 View user's profile Send private message  
Reply with quote Back to top
atomicdog
PostPosted: Nov 10, 2009 - 03:57 AM
Posting Freak


Joined: Jan 14, 2008
Posts: 1147
Location: San Diego

What value does sensors_init() return?

_________________
~~John
TWI C source code
 
 View user's profile Send private message  
Reply with quote Back to top
js
PostPosted: Nov 10, 2009 - 04:16 AM
10k+ Postman


Joined: Mar 28, 2001
Posts: 20339
Location: Sydney, Australia (Gum trees, Koalas and Kangaroos, No Edelweiss)

Quote:
Clock is internal 1MHz.
Code:
#define F_CPU 12000000UL
Which is it?

_________________
John Samperi
Ampertronics Pty. Ltd.
www.ampertronics.com.au
* Electronic Design * Custom Products * Contract Assembly
 
 View user's profile Send private message Visit poster's website 
Reply with quote Back to top
ontosas
PostPosted: Nov 10, 2009 - 08:00 AM
Newbie


Joined: Nov 03, 2009
Posts: 6


I have changed to this:
#define F_CPU 1000000UL
Maybe TWI clock is too slow now? 1MHz/(4+2*255)~2KHz
 
 View user's profile Send private message  
Reply with quote Back to top
ontosas
PostPosted: Nov 10, 2009 - 08:04 AM
Newbie


Joined: Nov 03, 2009
Posts: 6


sensors_init() function refers to another functions:
Code:
int sensors_init(void)
{
   i2c_init();
   return lm75_configure(LM75_ADDR, 0x60); //cia komanda FM75, daugiau tikslumo. Skaityti FM75/LM75 datasheeta.
}

lm75.c file

Code:
#include <string.h>
#include "i2c.h"
#include "lm75.h"

int lm75_writeRegister(char i2c_addr, char reg_addr, unsigned char *dat, char len)
{
   unsigned char tmp[len+1];
   tmp[0] = reg_addr & 0x03;
   memcpy(&tmp[1], dat, len);
   return i2c_transaction(i2c_addr, len + 1, tmp, 0, NULL);
}

int lm75_readRegister(char i2c_addr, char reg_addr, unsigned char *dst, char len)
{
   unsigned char tmp;
   tmp = reg_addr & 0x03;
   return i2c_transaction(i2c_addr, 1, &tmp, len, dst);
}

int lm75_configure(char i2c_addr, unsigned char cfg)
{
   return lm75_writeRegister(i2c_addr, LM75_REG_CFG, &cfg, 1);
}


and these functions refers to i2c.c files functions:

Code:
#include <avr/io.h>
#include <util/twi.h>

#include "i2c.h"

void i2c_init(void)
{
   /* Use internal pullups */
   PORTC |= (1<<5)|(1<<4);

   /* This gives roughly 30 khz with a 16mhz xtal */
   TWBR = 255;
   TWSR &= ~((1<<TWPS1)|(1<<TWPS0));
}

int i2c_transaction(unsigned char addr, int wr_len, unsigned char *wr_data,
                        int rd_len, unsigned char *rd_data)
{
   int ret =0;

   if (wr_len==0 && rd_len==0)
      return -1;

   if (wr_len != 0)
   {
      // Send a start condition
      TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN);

      while (!(TWCR & (1<<TWINT)))
         { /* do nothing */ }
      if ((TWSR & 0xF8) != TW_START)
         return 1;   /* Failed */

      TWDR = (addr<<1) | 0;   /* Address + write(0) */
      TWCR = (1<<TWINT)|(1<<TWEN);
      
      while (!(TWCR & (1<<TWINT)))
         { /* do nothing */ }

      /* TWSR can be:
       * TW_MT_SLA_ACK, TW_MT_SLA_NACK or TW_MR_ARB_LOST */
      if ((TWSR & 0xF8) != TW_MT_SLA_ACK) {
         ret = 2;
         goto err;
      }
      
      while (wr_len--)
      {
         TWDR = *wr_data;
         TWCR = (1<<TWINT)|(1<<TWEN);

         while (!(TWCR & (1<<TWINT)))
            { /* do nothing */ }

         wr_data++;
      }
   } // if (wr_len != 0)

   if (rd_len != 0)
   {
      /* Do a repeated start condition */
      TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN);
      while (!(TWCR & (1<<TWINT)))
         { /* do nothing */ }
      if (TWSR != TW_REP_START) {
         ret = 3;
         goto err;
      }

      TWDR = (addr<<1) | 1;   /* Address + read(1) */
      TWCR = (1<<TWINT)|(1<<TWEN);
      
      while (!(TWCR & (1<<TWINT)))
         { /* do nothing */ }

      /* TWSR can be:
       * TW_MR_SLA_ACK, TW_MR_SLA_NACK or TW_MR_ARB_LOST */
      if (TWSR != TW_MR_SLA_ACK) {
         ret = 4;
         goto err;
      }

      while (rd_len--)
      {

         if (rd_len)
            TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWEA);      
         else
            TWCR = (1<<TWINT)|(1<<TWEN);      
         
         while (!(TWCR & (1<<TWINT)))
               { /* do nothing */ }

         *rd_data = TWDR;
         rd_data++;
      }
   } // if (rd_len != 0)


   TWCR = (1<<TWINT)|(1<<TWSTO)|(1<<TWEN);

   return 0;

err:

   TWCR = (1<<TWINT)|(1<<TWSTO)|(1<<TWEN);

   return ret;
}
 
 View user's profile Send private message  
Reply with quote Back to top
atomicdog
PostPosted: Nov 10, 2009 - 08:15 AM
Posting Freak


Joined: Jan 14, 2008
Posts: 1147
Location: San Diego

Quote:
sensors_init() function refers to another functions:

Yes exactly, and that function should return a value which will give you a good idea of what the problem is.

_________________
~~John
TWI C source code
 
 View user's profile Send private message  
Reply with quote Back to top
david.prentice
PostPosted: Nov 10, 2009 - 08:32 AM
10k+ Postman


Joined: Feb 12, 2005
Posts: 16280
Location: Wormshill, England

From memory, the LM75 returns the degrees in dst[0] and the 0.5 degree in dst[1]. So you only need:
Code:
atoi(dst[0], buf, 10);
lcd_puts(buf);
if (dst[1] != 0) lcd_puts(".5");

I also note that you have TWBR = 255, which will produce a massively slow bus speed. With 1MHz clock, you need TWBR = 1 or possibly up to 10.

Your 10k pull-ups should be fine unless you have a very large capacitance on the bus, You could reduce to 4k7 or 2k2 if necessary.

You should always initialise the TWI. So try wth a sensible TWBR.

David.
 
 View user's profile Send private message Send e-mail  
Reply with quote Back to top
js
PostPosted: Nov 10, 2009 - 09:07 AM
10k+ Postman


Joined: Mar 28, 2001
Posts: 20339
Location: Sydney, Australia (Gum trees, Koalas and Kangaroos, No Edelweiss)

Quote:
you need TWBR = 1 or possibly up to 10.
From the data sheet
Quote:
Note: TWBR should be 10 or higher if the TWI operates in Master mode. If TWBR is lower than
10, the Master may produce an incorrect output on SDA and SCL for the reminder of the
byte. The problem occurs when operating the TWI in Master mode, sending Start + SLA
+ R/W to a Slave (a Slave does not need to be connected to the bus for the condition to
happen).

_________________
John Samperi
Ampertronics Pty. Ltd.
www.ampertronics.com.au
* Electronic Design * Custom Products * Contract Assembly
 
 View user's profile Send private message Visit poster's website 
Reply with quote Back to top
david.prentice
PostPosted: Nov 10, 2009 - 09:19 AM
10k+ Postman


Joined: Feb 12, 2005
Posts: 16280
Location: Wormshill, England

Yes, John this is on the Mega16 and Mega32 data sheet.

I have never discovered this behaviour on a real chip. It is is not in other AVR families data sheets.

David.
 
 View user's profile Send private message Send e-mail  
Reply with quote Back to top
Paddy
PostPosted: Nov 10, 2009 - 01:51 PM
Resident


Joined: May 30, 2002
Posts: 652
Location: Landgraaf, The Netherlands

Hi,
I see in your code :
Code:
#define LM75_ADDR       (LM75_ADDR_BASE + 0)

Did you #define LM_ADDR_BASE somewhere ? Its probably 0x90 or 0x92.
 
 View user's profile Send private message Visit poster's website 
Reply with quote Back to top
ontosas
PostPosted: Nov 10, 2009 - 04:45 PM
Newbie


Joined: Nov 03, 2009
Posts: 6


I have done several changes:
my board with Atmega16 has external 16MHz oscilator. So, in lcd_test.c I have changed:
Code:
#define F_CPU 16000000UL
and in lcd.h:
Code:
#define XTAL 16000000UL

Base LM75 address is defined in lm75.h file:
Code:
#define LM75_ADDR_BASE      0x48

The main file takes this constant and use like this:
Code:
#define LM75_ADDR       (LM75_ADDR_BASE + 0x48)

3 address pins of LM75 are connected to GND.
In PonyProg I have deactivated these fuse bits:
CKOPT, BODLEVEL, BODEN, CKSEL0
 
 View user's profile Send private message  
Reply with quote Back to top
david.prentice
PostPosted: Nov 10, 2009 - 05:10 PM
10k+ Postman


Joined: Feb 12, 2005
Posts: 16280
Location: Wormshill, England

I am surprised anything will work at all!

Your
int i2c_transaction(unsigned char addr, int wr_len, unsigned char *wr_data, int rd_len, unsigned char *rd_data);

requires a 7-bit Slave address, which should be 0x48 for your LM75.

Now you are very sensibly using the error-return from your lm75() functions. I would personally name the variable something better than 'x'. And now that you have the error status, why not examine its value?

I have no idea what your PonyProg fuses mean by 'deactivated'. The BODxx "brown-out" fuses will only affect your AVR if you are running on a flat battery.

If your AVR is running at 1MHz, you should not write F_CPU as 16MHz. You should also set TWBR to a sensible value.

David.
 
 View user's profile Send private message Send e-mail  
Reply with quote Back to top
ontosas
PostPosted: Nov 10, 2009 - 05:14 PM
Newbie


Joined: Nov 03, 2009
Posts: 6


I think that this code forever in this line of i2c.c file:
Code:
if (wr_len != 0)
   {
      // Send a start condition
      TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN);

      while (!(TWCR & (1<<TWINT)))
         { DDRD=255;PORTD=255;/* do nothing */ }
         PORTD=0b00000000; //stops!!!!!

hight interupt signal stops any action. (PORTD Leds light forever
 
 View user's profile Send private message  
Reply with quote Back to top
ontosas
PostPosted: Nov 11, 2009 - 10:52 AM
Newbie


Joined: Nov 03, 2009
Posts: 6


I'm using 16Mhz external clock.
I think that problem is related to hardware. So, I'm going to buy new LM75 and create new i2c device.
 
 View user's profile Send private message  
Reply with quote Back to top
david.prentice
PostPosted: Nov 11, 2009 - 06:06 PM
10k+ Postman


Joined: Feb 12, 2005
Posts: 16280
Location: Wormshill, England

I do not have a LM75, but used your program to write to a CONFIG register of a PCF8563 RTC. And then read the time back.

Your code works ok with a correctly addressed Slave device.
If you have a device on the bus but not the correct address, you ge "Sensor error"
If you have nothing on the bus, the program just HANGS.

It does not seem to matter if you have a large TWBR. But it certainly matters if you use wrong Slave address. It should be 0x48 for the LM75.

Chips do not normally die, unless you have deliberately fried them. So I would check your Slave address first and then your wiring.

David.
 
 View user's profile Send private message Send e-mail  
Reply with quote Back to top
Display posts from previous:     
Jump to:  
All times are GMT + 1 Hour
Post new topic   Reply to topic
View previous topic Printable version Log in to check your private messages View next topic
Powered by PNphpBB2 © 2003-2006 The PNphpBB Group
Credits