CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to support@ccsinfo.com

Question about light sensor ISL29004 and PIC18F2480

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
Keith1130
Guest







Question about light sensor ISL29004 and PIC18F2480
PostPosted: Sat Oct 24, 2009 5:59 pm     Reply with quote

I want to transfer the data from the ISL29004 (one digital serial output) to the PIC18F2480. Does anyone know the driver code for ISL29004? Thank you very much.
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Sun Oct 25, 2009 12:59 pm     Reply with quote

Here is a method to make a driver for the isl29004.

Download the ISL29004 data sheet:
http://www.intersil.com/data/fn/FN6221.pdf
Look on page 5. It gives the i2c timing diagrams for reading and writing
a register. You can turn these timing diagrams into functions:
Code:

#define ISL29004_WRITE_ADDR  0x44
#define ISL29004_READ_ADDR  0x45

void write_isl29004(int8 register, int8 value)
{

}


int8 read_isl29004(int8 register)
{
int8 retval;

return(retval);
}

These are the shells for the basic low level functions for interfacing
to the isl29004. To finish the driver, you need to fill in the code for
each function. You can use the built-in CCS i2c functions to do this.

CCS has these built-in functions for an i2c master (a PIC) to communicate
with an i2c slave (the ISL29004):
Code:

i2c_start()
i2c_write([byte value])
retval = i2c_read()  [use i2c_read(0) to do a NAK]
i2c_stop()

Look at the top lines of each timing diagram on page 5 of the isl29004
data sheet. It lists the i2c operations that must be done. Turn each
operation into a line of code that uses a CCS i2c function, as given above.
Keith1130
Guest







PostPosted: Mon Oct 26, 2009 4:27 pm     Reply with quote

Hi, PCM programmer. I am trying to write the code as your mentioned above, but I am still getting confused about how to convert the operations into codes.

1. Through the timing diagram, the master will drive one byte before pulling SDA low. My assumption is when I use "i2c_start()", the master will automatically assert a starting condition. Then I can use "i2c_write([byte value]) " to write the device address INCLUDING the read/write bit to the SDA. For example, if I use device address as x44, I have to write "10001000" to the SDA instead of just "01000100" because the device address bit writen to the SDA actually contains only 7 bits. Am I right?

2. Since the master should pull SDA low after each byte transition, can I use "output_low(PIN#); delay_us( 1 clock cycle );" to do that? I have one more idea that I can use a divided clock signal. For example, I can use "output_low(PIN#)" each 9 clock cycles. However, I don't know how to do it in coding. Because the "i2c_write([byte value]) " and "i2c_read()" actually write or read one byte, i am not quite sure how to transmit only one bit to the SDA. Can you tell me some ideas how to do it?

Sorry for asking simple questions like above. Because I am just a beginner in PIC programming, I am not quite familiar with the functions that can be used in PIC programming. Thank you very much.
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Mon Oct 26, 2009 4:58 pm     Reply with quote

Quote:

For example, if I use device address as x44, I have to write "10001000"
to the SDA instead of just "01000100" because the device address bit
written to the SDA actually contains only 7 bits. Am I right?

The value written should include the R/W bit in it. The 0x44 is in 7-bit
format, so it should be pre-shifted to become 0x88. Then combine it with
the R/W bit. So the Write address is 0x88 and the Read address is 0x89.
Those are the bytes that you will send to the chip with i2c_write().
(Depending on whether you are doing a Write or a Read operation).
Here are the #define statements for the slave addresses:
Code:

#define ISL29004_WRITE_ADDRESS 0x88
#define ISL29004_READ_ADDRESS  0x89


Quote:

Since the master should pull SDA low after each byte transition, can I
use "output_low(PIN#); delay_us( 1 clock cycle );" to do that

The CCS functions will handle this. You don't have to worry about
handling things at that level. Don't do output_low() in a series of
i2c operations. Just call the CCS i2c functions.
Keith1130



Joined: 31 Oct 2009
Posts: 6

View user's profile Send private message

PostPosted: Sun Nov 29, 2009 1:37 am     Reply with quote

Hi, i finished the driver of isl29004 and write a program to communicate 4 light sensors with PIC18F2480. However, when I used MPLAB ICD 2 debugger to debug the program, I cannot read the values of the readings from the light sensors, and the PIN_A0 and PIN_A1 were both outputting low. Is there something wrong with my code?

Code:

#include <18F2480.h>
#device *=16 ADC = 8
// internal osilator used
#FUSES NOWDT,INTRC, NOPUT, NOPROTECT, NOBROWNOUT, NOMCLR, NOLVP, NOCPD//for 16f628
#use delay(clock=20000000)
#USE i2c(Master, SCL = PIN_C3, SDA = PIN_C4)

#define ISL29004_1_WRITE_ADDRESS 0x88
#define ISL29004_1_READ_ADDRESS  0x89
#define ISL29004_2_WRITE_ADDRESS 0x8A
#define ISL29004_2_READ_ADDRESS  0x8B
#define ISL29004_3_WRITE_ADDRESS 0x8C
#define ISL29004_3_READ_ADDRESS  0x8D
#define ISL29004_4_WRITE_ADDRESS 0x8E
#define ISL29004_4_READ_ADDRESS  0x8F

#define register_0 0x00
#define register_1 0x01
#define register_4 0x04
#define register_5 0x05
#define register_6 0x06
#define register_7 0x07

#define sensor_command 0xA2
#define sensor_control 0x00

void write_isl29004_1(int8, int8);
int8 read_isl29004_1(int8);
void write_isl29004_2(int8, int8);
int8 read_isl29004_2(int8);
void write_isl29004_3(int8, int8);
int8 read_isl29004_3(int8);
void write_isl29004_4(int8, int8);
int8 read_isl29004_4(int8);
int16 get_lux_1(void);
int16 get_lux_2(void);
int16 get_lux_3(void);
int16 get_lux_4(void);

void write_isl29004_1(int8 reg, int8 value)
{
   i2c_start();
   i2c_write(ISL29004_1_WRITE_ADDRESS);
   i2c_write(reg);
   i2c_write(value);
   i2c_stop();
}


int8 read_isl29004_1(int8 reg)
{
   int8 retval;
   
   i2c_start();
   i2c_write(ISL29004_1_WRITE_ADDRESS);
   i2c_write(reg);
   i2c_start();
   i2c_write(ISL29004_1_READ_ADDRESS);
   retval = i2c_read(0);
   i2c_stop();

   return(retval);
}

void write_isl29004_2(int8 reg, int8 value)
{
   i2c_start();
   i2c_write(ISL29004_2_WRITE_ADDRESS);
   i2c_write(reg);
   i2c_write(value);
   i2c_stop();
}


int8 read_isl29004_2(int8 reg)
{
   int8 retval;
   
   i2c_start();
   i2c_write(ISL29004_2_WRITE_ADDRESS);
   i2c_write(reg);
   i2c_start();
   i2c_write(ISL29004_2_READ_ADDRESS);
   retval = i2c_read(0);
   i2c_stop();

   return(retval);
}

void write_isl29004_3(int8 reg, int8 value)
{
   i2c_start();
   i2c_write(ISL29004_3_WRITE_ADDRESS);
   i2c_write(reg);
   i2c_write(value);
   i2c_stop();
}


int8 read_isl29004_3(int8 reg)
{
   int8 retval;
   
   i2c_start();
   i2c_write(ISL29004_3_WRITE_ADDRESS);
   i2c_write(reg);
   i2c_start();
   i2c_write(ISL29004_3_READ_ADDRESS);
   retval = i2c_read(0);
   i2c_stop();

   return(retval);
}

void write_isl29004_4(int8 reg, int8 value)
{
   i2c_start();
   i2c_write(ISL29004_4_WRITE_ADDRESS);
   i2c_write(reg);
   i2c_write(value);
   i2c_stop();
}


int8 read_isl29004_4(int8 reg)
{
   int8 retval;
   
   i2c_start();
   i2c_write(ISL29004_4_WRITE_ADDRESS);
   i2c_write(reg);
   i2c_start();
   i2c_write(ISL29004_4_READ_ADDRESS);
   retval = i2c_read(0);
   i2c_stop();

   return(retval);
}

int16 get_lux_1(void)
{
   int8 light_up_1;
   int8 light_down_1;
   int8 count_up_1;
   int8 count_down_1;
   int16 light_1;
   int16 count_1;
   int16 lux_1;
   
   //setting the function mode to register 0 and 1
   //enable adc-core, normal operation, external clock,
   //convert Diode1, 8 clock cycles, disable interrupt, range1: 0-1000
   write_isl29004_1(register_0,sensor_command);
   write_isl29004_1(register_1,sensor_control); 

   //read measurements from registers
   light_up_1 = read_isl29004_1(register_5);
   light_down_1 = read_isl29004_1(register_4);
   count_up_1 = read_isl29004_1(register_7);
   count_down_1 = read_isl29004_1(register_6);

   // calculate lux
   light_1 = make16(light_up_1, light_down_1);
   count_1 = make16(count_up_1, count_down_1);
   lux_1 = 1000*light_1/count_1;
   delay_ms(100);
   return lux_1;
}

int16 get_lux_2(void)
{
   int8 light_up_2;
   int8 light_down_2;
   int8 count_up_2;
   int8 count_down_2;
   int16 light_2;
   int16 count_2;
   int16 lux_2;

   write_isl29004_2(register_0,sensor_command);
   write_isl29004_2(register_1,sensor_control);

   light_up_2 = read_isl29004_2(register_5);
   light_down_2 = read_isl29004_2(register_4);
   count_up_2 = read_isl29004_2(register_7);
   count_down_2 = read_isl29004_2(register_6);

   light_2 = make16(light_up_2, light_down_2);
   count_2 = make16(count_up_2, count_down_2);
   lux_2 = 1000*light_2/count_2;
   delay_ms(100);
   return lux_2;
}

int16 get_lux_3(void)
{
   int8 light_up_3;
   int8 light_down_3;
   int8 count_up_3;
   int8 count_down_3;
   int16 light_3;
   int16 count_3;
   int16 lux_3;

   write_isl29004_3(register_0,sensor_command);
   write_isl29004_3(register_1,sensor_control);

   light_up_3 = read_isl29004_3(register_5);
   light_down_3 = read_isl29004_3(register_4);
   count_up_3 = read_isl29004_3(register_7);
   count_down_3 = read_isl29004_3(register_6);

   light_3 = make16(light_up_3, light_down_3);
   count_3 = make16(count_up_3, count_down_3);
   lux_3 = 1000*light_3/count_3;
   delay_ms(100);
   return lux_3;
}

int16 get_lux_4(void)
{
   int8 light_up_4;
   int8 light_down_4;
   int8 count_up_4;
   int8 count_down_4;
   int16 light_4;
   int16 count_4;
   int16 lux_4;

   write_isl29004_4(register_0,sensor_command);
   write_isl29004_4(register_1,sensor_control);

   light_up_4 = read_isl29004_4(register_5);
   light_down_4 = read_isl29004_4(register_4);
   count_up_4 = read_isl29004_4(register_7);
   count_down_4 = read_isl29004_4(register_6);

   light_4 = make16(light_up_4, light_down_4);
   count_4 = make16(count_up_4, count_down_4);
   lux_4 = 1000*light_4/count_4;
   delay_ms(100);
   return lux_4;
}

void main()
{
   int16 light_lux_1;
   int16 light_lux_2;
   int16 light_lux_3;
   int16 light_lux_4;

   //setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
   //setup_timer_1(T1_DISABLED);
   //setup_timer_2(T2_DISABLED,0,1);
 
   while(1)
   {
   light_lux_1 = get_lux_1();
   light_lux_2 = get_lux_2();
   light_lux_3 = get_lux_3();
   light_lux_4 = get_lux_4();

   if (light_lux_1 < 500 && light_lux_2 < 500 && light_lux_3 < 500 && light_lux_4 < 500){
     output_high(PIN_A0);
     output_low(PIN_A1);
   }
   else{
     output_low(PIN_A0);
      output_high(PIN_A1);
   }

   delay_ms(100);
   }   
}
   
   
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Sun Nov 29, 2009 2:03 am     Reply with quote

Quote:

#include <18F2480.h>
#device *=16 ADC = 8
// internal osilator used
#FUSES NOWDT,INTRC, NOPUT, NOPROTECT, NOBROWNOUT, NOMCLR, NOLVP, NOCPD//for 16f628
#use delay(clock=20000000)

You can't get 20 MHz from the internal oscillator of the 18F2480.
The speeds that are available are shown in the 18F2480.h file, in the
oscillator section. Because you are using the wrong setting, the program
will probably behave in unexpected ways.
Keith1130



Joined: 31 Oct 2009
Posts: 6

View user's profile Send private message

PostPosted: Sun Nov 29, 2009 3:00 am     Reply with quote

Thanks, PCM programmer. However, after I changed the clock to 16MHz, the PIN_A0 and PIN_A1 were both outputting low. I don't really know what happened because I have double checked the wiring to make sure nothing is wrong with the circuit.
Guest








PostPosted: Sun Nov 29, 2009 7:56 am     Reply with quote

Keith130,

Your post is a typical "it doesn't work, please tell me what's wrong" post, and everytime I read one I want to bang my head against a wall! Doesn't anyone teach, or practice, basic trouble shooting anymore???

You've got to break your program down into managable chunks and see what is/is not working. You don't need to have FOUR light sensors for this, because once the code for one works, they'll all work.....

1. Can you flash an LED in a repeatable and predictable manner? Is your PIC functioning at all??
2. Is there ANY evidence that you are successfully sending data to and from the light sensors? What data is being returned? What do you expect?
3. If the light sensors are working as expected, is your logic correct to deal with the return values?

The project is right in front of you, so you are best equipped to correct any problems, not any of us from a great distance.....

So far, I haven't seen any evidence that you've done ANY comprehensive troubleshooting on your own. Until that happens, I don't think you are going to solve your problem!

Jeff (AKA Mr. 'tough love')
ckielstra



Joined: 18 Mar 2004
Posts: 3680
Location: The Netherlands

View user's profile Send private message

PostPosted: Sun Nov 29, 2009 8:07 am     Reply with quote

In addition to the above:
- Post your compiler version number.

And a design tip:
Your four functions for addressing the sensors are all equal, except for the sensor's address. You can reduce the code size and make it easier to maintain when you create just a single function with the address as an extra function parameter.
Keith1130



Joined: 31 Oct 2009
Posts: 6

View user's profile Send private message

PostPosted: Sun Nov 29, 2009 9:22 pm     Reply with quote

hi, I use the CCS C compiler. I tried to test the circuit with only one light sensor. However, the output is not expected since the output of PIN_A0 and PIN_A2 are outputting high, which means the value of lux_1 is 64000(the maximum value in the range) and counter_1 is 0xFFFF(which is supposed to be 1000 since I set up the i2c frequency as 10000 and the integration time as 100ms from the two i2c_sync() function, and from the datasheet of isl29004, counter_1 = integration time * i2c frequency).

Since I am using the external timing mode, I have to use two i2c sync_iic command to initialize the integration time for analog to digital conversion. From isl29004 datasheet page 10 in the section of "INTEGRATION TIME IN EXTERNAL TIMING MODE", it shows that the integration time is achieved from two consecutive i2c sync_iic command. I wrote the function "void i2c_sync()" to implement the i2c sync_iic timing diagram on page 5 in datasheet, and used it to create the integration time. However, the result is not expected since the counter_1 value I test is not what I expected. I really need your help. Thanks.

Here is the code for one light sensor isl29004 communicate with PIC18F2480 through i2c.
Code:

#include <18F2480.h>
#device *=16 ADC = 10
// internal osilator used
#FUSES NOWDT,INTRC, NOPUT, NOPROTECT, NOBROWNOUT, NOMCLR, NOLVP, NOCPD//for 16f628
#use delay(clock=2000000)
#USE i2c(Master, SCL = PIN_C3, SDA = PIN_C4, Fast = 10000)

#use fast_io(A)
#use fast_io(B)
#use fast_io(C)

#define ISL29004_1_WRITE_ADDRESS 0x88
#define ISL29004_1_READ_ADDRESS  0x89

#define register_0 0x00
#define register_1 0x01
#define register_4 0x04
#define register_5 0x05
#define register_6 0x06
#define register_7 0x07

#define sensor_command 0xA2
#define sensor_control 0x0C
#define syn_function 0x10

void write_isl29004_1(int8, int8);
int8 read_isl29004_1(int8);
float get_lux_1(void);
void i2c_sync(void);
int1 i2c_ready(void);

/*int1 i2c_ready() {
   int1 ack;
   i2c_start();            // If the write command is acknowledged,
   ack = i2c_write(0xa0);  // then the device is ready.
   i2c_stop();
   return !ack;
}*/

void i2c_sync()
{
//    while(!i2c_ready()){
//    }
   i2c_start();
   i2c_write(ISL29004_1_WRITE_ADDRESS);
   i2c_write(syn_function);
   i2c_stop();
}

void write_isl29004_1(int8 reg, int8 value)
{
//   while(!i2c_ready()){
//   }
   i2c_start();
   i2c_write(ISL29004_1_WRITE_ADDRESS);
   i2c_write(reg);
   i2c_write(value);
   i2c_stop();
}


int8 read_isl29004_1(int8 reg)
{
   int8 retval;
//   while(!i2c_ready()){
//   }
   i2c_start();
   i2c_write(ISL29004_1_WRITE_ADDRESS);
   i2c_write(reg);
   i2c_start();
   i2c_write(ISL29004_1_READ_ADDRESS);
   retval = i2c_read(0);
   i2c_stop();

   return(retval);
}

/*float get_lux_1(void)
{
   int8 light_up_1;
   int8 light_down_1;
   int8 count_up_1;
   int8 count_down_1;
   int16 light_1;
   int16 count_1;
   float lux_1;

   //integration
   i2c_sync();
   delay_ms(100);
   i2c_sync();

   //read measurements from registers
   light_up_1 = read_isl29004_1(register_5);
   light_down_1 = read_isl29004_1(register_4);
   count_up_1 = read_isl29004_1(register_7);
   count_down_1 = read_isl29004_1(register_6);

   // calculate lux
   light_1 = make16(light_up_1, light_down_1);
   count_1 = make16(count_up_1, count_down_1);
   lux_1 = 64000*(float)light_1/(float)count_1;
   //delay_ms(100);
   return lux_1;
}*/

void main()
{
   int8 light_up_1;
   int8 light_down_1;
   int8 count_up_1;
   int8 count_down_1;
   int16 light_1;
   int16 count_1;
   float lux_1;

   set_tris_a(0x00);
   set_tris_c(0x10);

   output_low(PIN_A0);
   output_low(PIN_A1);
   output_low(PIN_A2);

   //setting the function mode to register 0 and 1
   //enable adc-core, normal operation, external clock,
   //convert Diode1, 8 clock cycles, disable interrupt, range1: 0-1000
   write_isl29004_1(register_0,sensor_command);
   write_isl29004_1(register_1,sensor_control); 
 
   while(1)
   {
   //integration
   i2c_sync();
   delay_ms(100);
   i2c_sync();

   //read measurements from registers
   light_up_1 = read_isl29004_1(register_5);
   light_down_1 = read_isl29004_1(register_4);
   count_up_1 = read_isl29004_1(register_7);
   count_down_1 = read_isl29004_1(register_6);

   // calculate lux
   light_1 = make16(light_up_1, light_down_1);
   count_1 = make16(count_up_1, count_down_1);
   lux_1 = 64000*(float)light_1/(float)count_1;

   if (lux_1 == 64000){     //debug                         
     output_high(PIN_A0);
     output_low(PIN_A1);
   }
   else{
     output_low(PIN_A0);
      output_high(PIN_A1);
   }

   if (count_1 == 0xFFFF){  //debug
     output_high(PIN_A2);
   }
   else{
      output_low(PIN_A2);
   }

   delay_ms(100);
   }   
}
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group