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 CCS Technical Support

Help with this code for APDS-9930 proximity sensor
Goto page 1, 2  Next
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
juca85



Joined: 28 Jun 2020
Posts: 8
Location: Colombia

View user's profile Send private message ICQ Number

Help with this code for APDS-9930 proximity sensor
PostPosted: Sun Jun 28, 2020 12:58 am     Reply with quote

Hello i need help with this code.
This code appears on the sensor data sheet APDS-9930:
Code:
WriteRegData(uint8 reg, uint8 data)
{
m_I2CBus.WriteI2C(0x39, 0x80 | reg, 1, &data);
}


0x39 is the sensor address and 0x80 is a command register for repeated byte or increment byte protocol, the register doesn't have an address.

In Arduino library appears this code. I don't know how translate that:
Code:
bool APDS9930::wireWriteDataByte(uint8_t reg, uint8_t val)
{
    Wire.beginTransmission(0x39);
    Wire.write(reg | 0x80);
    Wire.write(val);
    if( Wire.endTransmission() != 0 ) {
        return false;
    }

    return true;
}


This is how the code should be but it doesn't work. I don't know where to put 0x80 instruction:
Code:
 void write_reg(int reg,int val)
{
   i2c_Start();                           
   i2c_write(0x39);                       
   i2c_write(reg);       
   i2c_write(val);                       
   i2c_stop();
   delay_ms(70);
   return;
}


Please help with this code!!!

Datasheet:
https://docs.broadcom.com/doc/AV02-3190EN
Library Arduino:
https://github.com/Depau/APDS9930
Ttelmah



Joined: 11 Mar 2010
Posts: 19537

View user's profile Send private message

PostPosted: Sun Jun 28, 2020 1:38 am     Reply with quote

First key thing is this:

0x39

Wrong....

The PIC uses an 8bit address. Means that translating from any device using
the 7bit address format, you have to multiply the number by 2.....

Then the register does have an address. It just happens to be zero.

Code:

//You need to include <stdint.h> to give definitions for uint8_t etc..
//before this.
#define APDADDR (0x39*2)

BOOLEAN APDS9930wireWriteDataByte(uint8_t reg, uint8_t val)
{
    int1 ack;
    I2C_start();
    I2C_write(APDADDR);
    I2C_write(reg | 0x80);
    ack=I2C_write(val);
    I2C_stop();
    if( ack==0)
        return false;
    return true;
}   


Why the delay?. Not wanted or needed.

The reason your code didn't work was the device address....
juca85



Joined: 28 Jun 2020
Posts: 8
Location: Colombia

View user's profile Send private message ICQ Number

PostPosted: Sun Jun 28, 2020 5:48 pm     Reply with quote

Ttelmah wrote:
First key thing is this:

0x39

Wrong....

The PIC uses an 8bit address. Means that translating from any device using
the 7bit address format, you have to multiply the number by 2.....

Then the register does have an address. It just happens to be zero.


//You need to include <stdint.h> to give definitions for uint8_t etc..
//before this.
#define APDADDR (0x39*2)

BOOLEAN APDS9930wireWriteDataByte(uint8_t reg, uint8_t val)
{
int1 ack;
I2C_start();
I2C_write(APDADDR);
I2C_write(reg | 0x80);
ack=I2C_write(val);
I2C_stop();
if( ack==0)
return false;
return true;
}


Why the delay?. Not wanted or needed.

The reason your code didn't work was the device address....


No, that is not the problem, check all my code. Write address is 0x72, is ok.

Code:
#include <18F4550.h>
#fuses NOMCLR, INTRC_IO, NOWDT, NOPROTECT, NOLVP
#use DELAY(CLOCK=8M)
#use standard_io(b)
#use I2C(master, sda=PIN_B0, scl=PIN_B1)

/* Command register modes */
#define REPEATED_BYTE           0x80
#define AUTO_INCREMENT          0xA0

/* Interrupt clear values */       
#define CLEAR_PROX_INT          0xE5
#define CLEAR_ALS_INT           0xE6
#define CLEAR_ALL_INT           0xE7

/* Default values */
#define DEFAULT_ATIME           0xFF
#define DEFAULT_WTIME           0xFF
#define DEFAULT_PTIME           0xFF
#define DEFAULT_PPULSE          0x08
#define DEFAULT_POFFSET         0         // 0 offset
#define DEFAULT_CONFIG          0
#define DEFAULT_CONTROL         0X20      //PDRIVE=0;PDIODE=2;PGAIN=0;PGAIN=0         
#define DEFAULT_PERS            0x22      // 2 consecutive prox or ALS for int.

/* Acceptable parameters for Enable */
#define POWER_ALL          0x7F                 
#define POWER_OFF          0x00           
#define POWER_PROXIMITY    0x2D
#define POWER_ALS          0x5B


#define ID_W           0x72
#define ID_R           0X73

/* APDS-9930 Direcciones de registro */
#define ENABLE         0x00
#define ATIME          0x01
#define PTIME          0x02
#define WTIME          0x03
#define AILTL          0x04
#define AILTH          0x05
#define AIHTL          0x06
#define AIHTH          0x07
#define PILTL          0x08
#define PILTH          0x09
#define PIHTL          0x0A
#define PIHTH          0x0B
#define PERS           0x0C
#define CONFIG         0x0D
#define PPULSE         0x0E
#define CONTROL        0x0F
#define ID             0x12
#define STATUS         0x13
#define CH0DATAL       0x14
#define CH0DATAH       0x15
#define CH1DATAL       0x16
#define CH1DATAH       0x17
#define PDATAL         0x18
#define PDATAH         0x19
#define POFFSET        0x1E

#define LED PIN_B4 //

float proximity_data = 0;
int   isr_flag = 0;

int read_reg(int reg)
{
   i2c_start();
   i2c_write(ID_W);
   i2c_write(reg | REPEATED_BYTE);
   i2c_start();
   i2c_write(ID_R);
   int8 val=i2c_read(0);
   i2c_stop();
   return(val);
}

void write_reg(int reg,int val)
{
   i2c_Start();                             
   i2c_write(ID_W);                         
   i2c_write(reg | REPEATED_BYTE);       
   i2c_write(val);                         
   i2c_stop();
   delay_ms(70);
   return;
}

void cmd(int val)
{
   i2c_Start();               
   i2c_write(ID_W);           
   i2c_write(val);           
   i2c_stop();
   delay_ms(70);
   return;
}

int16 get_value(int reg_h,int reg_l)
{
   int8 data_h=read_reg(reg_h);
   int8 data_l=read_reg(reg_l);
   int16 datahl=make16(data_h,data_l);
   return(datahl);
}

void blink_led (int8 valor)
{
   int8 x=0;
   for (x=1;x<=valor;x++)
   {
      output_high(LED);
      delay_ms(500);
      output_low(LED);
      delay_ms(500);
   }
   return;
}

void test(void)
{
   int8 i=0;
   i=read_reg(ID);
   if (i==0x39 || i==0x12)
      blink_led(5);
   else
      blink_led(4);
   return;
}

void begin(void)
{
   delay_ms(1000);
   write_reg(ENABLE,POWER_OFF);       
   write_reg(ATIME,DEFAULT_ATIME);
   write_reg(PTIME,DEFAULT_PTIME);
   write_reg(WTIME,DEFAULT_WTIME);
   write_reg(PPULSE,DEFAULT_PPULSE);
   write_reg(POFFSET,DEFAULT_POFFSET);
   write_reg(CONFIG,DEFAULT_CONFIG);
   write_reg(CONTROL,DEFAULT_CONTROL); 
   write_reg(AILTL,0xFF);   
   write_reg(AILTH,0xFF);
   write_reg(AIHTL,0x00);   
   write_reg(AIHTH,0x00);
   write_reg(PILTL,0x00);
   write_reg(PILTH,0x00);
   write_reg(PIHTL,0x32);
   write_reg(PIHTH,0x00);
   write_reg(PERS,DEFAULT_PERS);
   blink_led(3);
   delay_ms(1000);
   return;
}

#int_EXT2
void ext_isr()
{
   isr_flag = 1;
}

void main(void)
{
   setup_oscillator(OSC_8MHZ);
   set_tris_b(0x0F);
   enable_interrupts(GLOBAL);                      //Habilita interrupciones
   enable_interrupts(INT_EXT2_L2H);                //Habilita interrupcion RB
   delay_ms(1000);
 
   test();                                //check id reg
   begin();                               //config start
   write_reg(CONTROL,0x24);               //define Pgain 2x
   write_reg(ENABLE,POWER_ALL);
   write_reg(PILTL,0x00);
   write_reg(PILTH,0x00);
   write_reg(PIHTL,0x58);
   write_reg(PIHTH,0x02);                 //Proximity interrupt high threshold 600
   blink_led(2);
   delay_ms(1000);

   while(true)
   {
      if (isr_flag)
      {
         output_high(LED);
         delay_ms(3000);
         output_low(LED);
         cmd(CLEAR_PROX_INT);
         isr_flag = 0;
      }
   }
}


i think is the problem is cmd register or i don't know, need help, the register 0x00 is Enable, cmd doen't have address, see yourself:



Ttelmah



Joined: 11 Mar 2010
Posts: 19537

View user's profile Send private message

PostPosted: Sun Jun 28, 2020 10:21 pm     Reply with quote

Your original code showed:

i2c_write(0x39);


The command register is always selected, when you start a write
transaction.
So sequence is:

start
Write device address
Write to command register
......

Quote:

During a write operation, the first byte written is a command byte followed by data. In a combined protocol, the first byte written is the command byte followed by reading a series.
juca85



Joined: 28 Jun 2020
Posts: 8
Location: Colombia

View user's profile Send private message ICQ Number

PostPosted: Sun Jun 28, 2020 10:45 pm     Reply with quote

Ttelmah wrote:
Your original code showed:

i2c_write(0x39);


The command register is always selected, when you start a write
transaction.
So sequence is:

start
Write devive address
Write to command register
......

Quote:

During a write operation, the first byte written is a command byte followed by data. In a combined protocol, the first byte written is the command byte followed by reading a series.


OK my bad in the first code, i get it, that part is ready, thanks. Now please help with the configuration of ports in the code. The sensor has six pins 1-VL, 2-GND, 3-VCC, 4-SCL, 5-SDA, 6-INT.

I connected SDA to RB0, SCL to RB1 with pull-up resistor 4.7k.
The INT interrupt pin sensor is connected to RB2 with pull-up resistor 10k, and the port is set interrupt ext2, and last RB4 is an LED for show the interrupt for proximity,
The question is how to configure the port B of the PIC to work fine?
Ttelmah



Joined: 11 Mar 2010
Posts: 19537

View user's profile Send private message

PostPosted: Mon Jun 29, 2020 12:49 am     Reply with quote

There is a glaring problem.

You have a 5v PIC. This is a 3.3v device.
If you have connected your PIC Vcc to this, you have probably destroyed
the chip. It is rated for 3.8v _max_.

The I2C inputs are rated to go up to it's Vcc maximum.

Potentially you can use it on your PIC, with a separate 3.3v supply, pull-
ups to 3.3v, and specifying the PIC I2C using the 'SMBUS' option, which
turns 'down' the voltage the PIC will expect on the I2C bus (the Arduino
inputs run at this lower voltage by default). Make your pull-ups lower
(1K2R), 4K7, even at 5v, is not adequate for 400K, and at 3.3v, is even
worse.

Get your hardware right first.

With your hardware sorted, your register read and writes, look OK.

Change your I2C setup, to:

#use I2C(master, FAST=400000, I2C1, SMBUS)

Then use PCM Programmer's I2C bus scan program, and verify that with
this setting, the chip is being seen on addresses 0x72 and 0x73.
This should always be treated as the 'first thing to do' with I2C. Very Happy
It's in the code library.
Personally, I would add a 'read_word' function as:
Code:

int16 read_word(int reg)
{
   int8 low;
   int16 whole;
   i2c_start();
   i2c_write(ID_W);
   i2c_write(reg | AUTO_INCREMENT);
   i2c_start();
   i2c_write(ID_R);
   low=i2c_read();
   whole=make16(i2c_read(0),low);
   i2c_stop();
   return(whole);
}


Then the pseudo code on page 15, can be used as a starting point for
the setup, with this replacing the 'read_word' function used in this.
temtronic



Joined: 01 Jul 2010
Posts: 9241
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Mon Jun 29, 2020 7:36 am     Reply with quote

sigh.. this post is WHY we need to see a small, complete, compilable program in the FIRST posting.
As Mr. T correctly points out 5 volt PIC and 3 volt peripherals don't 'play well together' !!
While there are 'tricks' like SMB....it's often easier to just use an 'L' version PIC or one with 3-5v ability. Using 'logic level converters' is anothe roption but 'messy'. More parts, more wires, more to go wrong.....

Jay
juca85



Joined: 28 Jun 2020
Posts: 8
Location: Colombia

View user's profile Send private message ICQ Number

PostPosted: Mon Jun 29, 2020 11:05 am     Reply with quote

Ttelmah wrote:
There is a glaring problem.

You have a 5v PIC. This is a 3.3v device.
If you have connected your PIC Vcc to this, you have probably destroyed
the chip. It is rated for 3.8v _max_.

The I2C inputs are rated to go up to it's Vcc maximum.

Potentially you can use it on your PIC, with a separate 3.3v supply, pull-
ups to 3.3v, and specifying the PIC I2C using the 'SMBUS' option, which
turns 'down' the voltage the PIC will expect on the I2C bus (the Arduino
inputs run at this lower voltage by default). Make your pull-ups lower
(1K2R), 4K7, even at 5v, is not adequate for 400K, and at 3.3v, is even
worse.

Get your hardware right first.

With your hardware sorted, your register read and writes, look OK.

Change your I2C setup, to:

#use I2C(master, FAST=400000, I2C1, SMBUS)

Then use PCM Programmer's I2C bus scan program, and verify that with
this setting, the chip is being seen on addresses 0x72 and 0x73.
This should always be treated as the 'first thing to do' with I2C. Very Happy
It's in the code library.
Personally, I would add a 'read_word' function as:
Code:

int16 read_word(int reg)
{
   int8 low;
   int16 whole;
   i2c_start();
   i2c_write(ID_W);
   i2c_write(reg | AUTO_INCREMENT);
   i2c_start();
   i2c_write(ID_R);
   low=i2c_read();
   whole=make16(i2c_read(0),low);
   i2c_stop();
   return(whole);
}


Then the pseudo code on page 15, can be used as a starting point for
the setup, with this replacing the 'read_word' function used in this.


Thanks for the code is necessary to read all the data. I change the resistors for 1,2k in the i2c ports. I use LM1117T-3.3. I use 3.3volts in both PIC and sensor, still not work. Help me with the proper configuration of the ports in and outs. Maybe that's the problem.
Ttelmah



Joined: 11 Mar 2010
Posts: 19537

View user's profile Send private message

PostPosted: Mon Jun 29, 2020 11:50 am     Reply with quote

Your PIC is not rated to run at 3.3v.
Hence the comments about this.
The 18F4550, is rated for 4.2v _minimum_.
To run below this you need the LF version (PIC18LF4550).
juca85



Joined: 28 Jun 2020
Posts: 8
Location: Colombia

View user's profile Send private message ICQ Number

PostPosted: Mon Jun 29, 2020 11:19 pm     Reply with quote

Ttelmah wrote:
Your PIC is not rated to run at 3.3v.
Hence the comments about this.
The 18F4550, is rated for 4.2v _minimum_.
To run below this you need the LF version (PIC18LF4550).

Yes you right!, but the same doesn't work, how to configure port B ?
With trisb the interrupt is in, sda? scl? led is out. I use standard i/o, but i am not sure how!
Ttelmah



Joined: 11 Mar 2010
Posts: 19537

View user's profile Send private message

PostPosted: Tue Jun 30, 2020 12:18 am     Reply with quote

If you configure the I2C as I show, the PortB configuration is all done.
juca85



Joined: 28 Jun 2020
Posts: 8
Location: Colombia

View user's profile Send private message ICQ Number

PostPosted: Tue Jun 30, 2020 12:38 am     Reply with quote

Ttelmah wrote:
If you configure the I2C as I show, the PortB configuration is all done.

The interrupt pin is necesary set as input?
Ttelmah



Joined: 11 Mar 2010
Posts: 19537

View user's profile Send private message

PostPosted: Tue Jun 30, 2020 1:14 am     Reply with quote

Pins always wake set as inputs. Unless you switch them, or automatic
switching is done (as will happen when you setup the I2C), these settings
remain.
juca85



Joined: 28 Jun 2020
Posts: 8
Location: Colombia

View user's profile Send private message ICQ Number

PostPosted: Tue Jun 30, 2020 2:20 pm     Reply with quote

Ttelmah wrote:
Pins always wake set as inputs. Unless you switch them, or automatic
switching is done (as will happen when you setup the I2C), these settings
remain.


ok i connect a LCD 20x2 for see the write and read reg and is all good, works perfect, maybe i made something wrong with the configuration, the interrupt of the sensor doesn't trigger when reach the high threshold.
Ttelmah



Joined: 11 Mar 2010
Posts: 19537

View user's profile Send private message

PostPosted: Wed Jul 01, 2020 12:29 am     Reply with quote

There are a huge number of things that affect how/when the interrupt
will trigger.
You have first of all, the PIEN, and AIEN fields to determine if the
interrupt is enabled. Then the upper and lower limit fields. Then the
persistence fields determine how long the trigger must exist before the
interrupt will fire. At this point it will optionally put the chip to sleep
as well.
AIL, AIH, PIL, PIH, PERS all need to be set correctly. Also you should
clear the interrupt in case is has been set on boot.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Goto page 1, 2  Next
Page 1 of 2

 
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