PIC I2C using Colour sensor

Find out how to setup your programmer's software and how to solve many common problems.

Moderator: phalanx

Post Reply
mreiter
Posts: 11
Joined: Thu Feb 09, 2017 11:05 pm

PIC I2C using Colour sensor

Post by mreiter » Tue Feb 14, 2017 3:13 pm

Hello!

I have a colour sensor that I need to communicate with using I2C. I've written the following I2C code based off of this Arduino example (https://github.com/adafruit/Adafruit_TC ... S34725.cpp) but I am not having much luck getting data. If you code give my code a look over, that would be greatly appreciated. The color sensor that I am using is the model TCS34725 (https://cdn-shop.adafruit.com/datasheets/TCS34725.pdf)

Here is my I2C code:

Code: Select all

READ_COLOUR_I2C
    i2c_common_start

    movlw 0x29 ;TCS34725 address | WRITE bit (+0)
    i2c_common_write ;
    i2c_common_check_ack RD_ERR1

    ;Write data to I2C bus (Register Address in TCS34725)
    movlw regaddress
    iorlw 0x80
    i2c_common_write ;
    i2c_common_check_ack RD_ERR2

    ;Re-Select the TCS34725 on the bus, in READ mode
    i2c_common_repeatedstart
    movlw 0x2A ;TCS34725 address | READ bit (+1)
    i2c_common_write
    i2c_common_check_ack RD_ERR3

    ;Read data from I2C bus (Contents of Register in TCS34725)
    i2c_common_read
    movwf datachar
    i2c_common_nack ;Send acknowledgement of data reception

    goto RD_END

    RD_ERR1
 nop
 movlw b'00000011'
 movwf LATA
 goto RD_END
    RD_ERR2
 nop
 movlw b'00000101'
 movwf LATA
 goto RD_END
    RD_ERR3
 nop
 movlw b'00000111'
 movwf LATA
 goto RD_END
    RD_END
 i2c_common_stop
return

WRITE_COLOUR_I2C
    i2c_common_start

    movlw 0x29 ;TCS34725 address | WRITE bit
    i2c_common_write
    i2c_common_check_ack WR_ERR1

    ;Write data to I2C bus (Register Address in TCS34725)
    movlw regaddress
    iorlw 0x80 
    i2c_common_write ;
    i2c_common_check_ack WR_ERR2

    ;Write data to I2C bus (Data to be placed in TCS34725 register)
    movlw databyte
    iorlw 0x80 
    i2c_common_write
    i2c_common_check_ack WR_ERR3

    goto WR_END

    WR_ERR1
 nop
 movlw b'00001101'
 movwf LATA 
 goto WR_END
    
    WR_ERR2
 nop
 movlw b'00001111'
 movwf LATA
 bsf LATE,0
 goto WR_END
 
    WR_ERR3
 nop
 movlw b'00001001'
 movwf LATA
 goto WR_END
    WR_END
 i2c_common_stop ;Release the I2C bus
 
return
Thanks a bunch

Matthew

User avatar
phalanx
Non-SFE Guru
Posts: 1980
Joined: Sun Nov 30, 2003 8:57 am
Location: Candia, NH

Re: PIC I2C using Colour sensor

Post by phalanx » Thu Feb 16, 2017 8:48 pm

Your slave address is 0x29 (0b00101001) which occupies the 7 most significant bits of your first transmitted byte while your read/write bit is the least significant bit. This means you have to left shift 0x29 which gives you 0b01010010 or 0x52. Since the LSB is zero for a write, the byte you write to the I2C bus to address your sensor for a write is 0x52. Add one to this for a read operation and your byte to be written to address the sensor is 0x53.

Also keep in mind that you have to tell the sensor to do something before you can read anything useful back from it.

-Bill

mreiter
Posts: 11
Joined: Thu Feb 09, 2017 11:05 pm

Re: PIC I2C using Colour sensor

Post by mreiter » Sat Feb 18, 2017 1:35 pm

Hello Bill,

Sorry for the delay in getting back to you, times have been crazy at school.

Thanks for the correction, I believe that Ive sorted out the addressing. I have having some issues however with reading the data from this sensor - when I look to get data from my colour sensors, I notice that my SDA/SCL pins both ride low, and my PIC hangs as a result. I am not sure what's causing this, nor have I been able to identify where the exact issue is. Mind if I get you to take a look at my updated I2C code, as well as the previous initializations?

Edit: just to confirm, all I need to do to connect the colour sensor to my PIC is connect the SDA/SCL pins on the sensor to RC4/RC3 respectively? I've not seen any prior literature telling me I need some special configuration, especially when using multiplier I2C devices, which in case as you know, includes a DS1307.

Updated I2C:

Code: Select all

READ_COLOUR_I2C    
    i2c_common_start
    
    movlw   0x52		;TCS34725 address 0x29 << 1, WRITE bit (+0)
    i2c_common_write
    i2c_common_check_ack RD_ERR1_RTC
    
    ;Write command to I2C bus (Register Address in TCS34725)
    movlw   regaddress
    iorlw   0x80		;command bit
    i2c_common_write
    i2c_common_check_ack RD_ERR2
    
    ;Re-Select the TCS34725 on the bus, in READ mode
    i2c_common_repeatedstart
    movlw   0x53		;TCS34725 address 0x29 << 1, READ bit (+1)
    i2c_common_write
    i2c_common_check_ack RD_ERR3
    
    ;Read data from I2C bus (Contents of Register in TCS34725)
    i2c_common_read
    movwf data_colourL
    i2c_common_nack		;Send acknowledgement of data reception

    i2c_common_read
    movwf data_colourH
    i2c_common_nack		;Send acknowledgement of data reception

    goto RD_END

    RD_ERR1
	nop
	movlw	b'00000011'
	movwf	LATA
	goto	RD_END
    RD_ERR2
	nop
	movlw	b'00000101'
	movwf	LATA
	goto	RD_END
    RD_ERR3
	nop
	movlw	b'00000111'
	movwf	LATA
	goto	RD_END
    RD_END
	i2c_common_stop
return

WRITE_COLOUR_I2C
    i2c_common_start

    movlw   0x52 ;TCS34725 address | WRITE bit
    i2c_common_write
    i2c_common_check_ack WR_ERR1

    ;Write data to I2C bus (Register Address in TCS34725)
    movlw   regaddress
    iorlw   0x80
    i2c_common_write
    i2c_common_check_ack WR_ERR2

    ;Write data to I2C bus (Data to be placed in TCS34725 register)
    movlw   databyte 
    i2c_common_write
    i2c_common_check_ack WR_ERR3

    goto    WR_END

    WR_ERR1
	nop
	movlw	b'00001101'
	movwf	LATA	
	goto	WR_END
    
    WR_ERR2
	nop
	movlw   b'00001111'
	movwf   LATA
	bsf	LATE,0
	goto    WR_END
	
    WR_ERR3
	nop
	movlw	b'00001001'
	movwf	LATA
	goto	WR_END
    WR_END
	i2c_common_stop ;Release the I2C bus
	
return
and here is the code I use to initialize/call the read commands for the colour sensor:

Code: Select all

    extern	i2c_common_setup, regaddress, databyte, datachar, READ_COLOUR_I2C, WRITE_COLOUR_I2C, d200us_C, d50ms_C, data_colourL, data_colourH

;    #define TCS34725_ADDRESS          (0x29)
;
;    #define TCS34725_COMMAND_BIT      (0x80)
;
;    #define TCS34725_ENABLE           (0x00)
;    #define TCS34725_ENABLE_AIEN      (0x10)    /* RGBC Interrupt Enable */
;    #define TCS34725_ENABLE_WEN       (0x08)    /* Wait enable - Writing 1 activates the wait timer */
;    #define TCS34725_ENABLE_AEN       (0x02)    /* RGBC Enable - Writing 1 actives the ADC, 0 disables it */
;    #define TCS34725_ENABLE_PON       (0x01)    /* Power on - Writing 1 activates the internal oscillator, 0 disables it */
;    #define TCS34725_ATIME            (0x01)    /* Integration time */
;    #define TCS34725_WTIME            (0x03)    /* Wait time (if TCS34725_ENABLE_WEN is asserted) */
;    #define TCS34725_WTIME_2_4MS      (0xFF)    /* WLONG0 = 2.4ms   WLONG1 = 0.029s */
;    #define TCS34725_WTIME_204MS      (0xAB)    /* WLONG0 = 204ms   WLONG1 = 2.45s  */
;    #define TCS34725_WTIME_614MS      (0x00)    /* WLONG0 = 614ms   WLONG1 = 7.4s   */
;    #define TCS34725_AILTL            (0x04)    /* Clear channel lower interrupt threshold */
;    #define TCS34725_AILTH            (0x05)
;    #define TCS34725_AIHTL            (0x06)    /* Clear channel upper interrupt threshold */
;    #define TCS34725_AIHTH            (0x07)
;    #define TCS34725_PERS             (0x0C)    /* Persistence register - basic SW filtering mechanism for interrupts */
;    #define TCS34725_PERS_NONE        (0b0000)  /* Every RGBC cycle generates an interrupt                                */
;    #define TCS34725_PERS_1_CYCLE     (0b0001)  /* 1 clean channel value outside threshold range generates an interrupt   */
;    #define TCS34725_PERS_2_CYCLE     (0b0010)  /* 2 clean channel values outside threshold range generates an interrupt  */
;    #define TCS34725_PERS_3_CYCLE     (0b0011)  /* 3 clean channel values outside threshold range generates an interrupt  */
;    #define TCS34725_PERS_5_CYCLE     (0b0100)  /* 5 clean channel values outside threshold range generates an interrupt  */
;    #define TCS34725_PERS_10_CYCLE    (0b0101)  /* 10 clean channel values outside threshold range generates an interrupt */
;    #define TCS34725_PERS_15_CYCLE    (0b0110)  /* 15 clean channel values outside threshold range generates an interrupt */
;    #define TCS34725_PERS_20_CYCLE    (0b0111)  /* 20 clean channel values outside threshold range generates an interrupt */
;    #define TCS34725_PERS_25_CYCLE    (0b1000)  /* 25 clean channel values outside threshold range generates an interrupt */
;    #define TCS34725_PERS_30_CYCLE    (0b1001)  /* 30 clean channel values outside threshold range generates an interrupt */
;    #define TCS34725_PERS_35_CYCLE    (0b1010)  /* 35 clean channel values outside threshold range generates an interrupt */
;    #define TCS34725_PERS_40_CYCLE    (0b1011)  /* 40 clean channel values outside threshold range generates an interrupt */
;    #define TCS34725_PERS_45_CYCLE    (0b1100)  /* 45 clean channel values outside threshold range generates an interrupt */
;    #define TCS34725_PERS_50_CYCLE    (0b1101)  /* 50 clean channel values outside threshold range generates an interrupt */
;    #define TCS34725_PERS_55_CYCLE    (0b1110)  /* 55 clean channel values outside threshold range generates an interrupt */
;    #define TCS34725_PERS_60_CYCLE    (0b1111)  /* 60 clean channel values outside threshold range generates an interrupt */
;    #define TCS34725_CONFIG           (0x0D)
;    #define TCS34725_CONFIG_WLONG     (0x02)    /* Choose between short and long (12x) wait times via TCS34725_WTIME */
;    #define TCS34725_CONTROL          (0x0F)    /* Set the gain level for the sensor */
;    #define TCS34725_ID               (0x12)    /* 0x44 = TCS34721/TCS34725, 0x4D = TCS34723/TCS34727 */
;    #define TCS34725_STATUS           (0x13)
;    #define TCS34725_STATUS_AINT      (0x10)    /* RGBC Clean channel interrupt */
;    #define TCS34725_STATUS_AVALID    (0x01)    /* Indicates that the RGBC channels have completed an integration cycle */
;    #define TCS34725_CDATAL           (0x14)    /* Clear channel data */
;    #define TCS34725_CDATAH           (0x15)
;    #define TCS34725_RDATAL           (0x16)    /* Red channel data */
;    #define TCS34725_RDATAH           (0x17)
;    #define TCS34725_GDATAL           (0x18)    /* Green channel data */
;    #define TCS34725_GDATAH           (0x19)
;    #define TCS34725_BDATAL           (0x1A)    /* Blue channel data */
;    #define TCS34725_BDATAH           (0x1B)


    COLOUR_INIT macro
	COLOUR_WRITE	0x00, 0x01 ; Enable Register (0x00), Power ON (0x01)
	COLOUR_WRITE	0x00, 0x02 ; Enable Register (0x00), RGBC enable (0x02)
	COLOUR_WRITE	0x01, 0xf6 ; Timing Register (0x01), 24ms rgbc cycle
	COLOUR_WRITE	0x0f, 0x03 ; Control Register (0x0f), 60x gain (0x03)
    endm
    
    COLOUR_READ	 macro	address
	movlw	address
	movwf	regaddress
	call	READ_COLOUR_I2C
    endm
    
    COLOUR_WRITE macro address, datliteral
	movlw	address
	movwf	regaddress
	movlw	datliteral
	movwf	databyte
	call	WRITE_COLOUR_I2C
    endm
    
    COLOUR_GET_DATA macro clear, red, green, blue, temp_col
	COLOUR_READ 0x14    ; read clear colour address low, command bits set later
	DATA_TO_COLOUR	data_colourH, data_colourL, temp_col, clear
	
	COLOUR_READ 0x16    ; read red colour address low, command bits set later
	DATA_TO_COLOUR	data_colourH, data_colourL, temp_col, red
	
	COLOUR_READ 0x18    ; read green colour address low, command bits set later
	DATA_TO_COLOUR	data_colourH, data_colourL, temp_col, green
	
	COLOUR_READ 0x1A    ; read clear colour address low, command bits set later
	DATA_TO_COLOUR	data_colourH, data_colourL, temp_col, blue
    endm
    
    DATA_TO_COLOUR macro addrH, addrL, count, final
	movlw	0x08
	movwf	count
	movlw	addrH
	ROTATEL	count
	iorwf	addrL
	movwf	final
    endm
    
    ROTATEL  macro count
	rlncf	WREG
	decfsz	count
	bra	ROTATEL
    endm
    
;Delay200us macro
;	local loop200us
;	movlw	0xA4
;	movwf	d200us_C
;
;loop200us
;	decfsz	d200us
;	goto	loop200us
;	nop
;	endm
;	
;
;Delay50ms macro
;	local loop50ms
;	movlw	0xF9
;	movwf	d50ms_C
;
;loop50ms
;	Delay200us
;	decfsz	d50ms_C
;	endm
;;    
Thank you very much

Matthew

avianate
Posts: 1
Joined: Sun Feb 11, 2018 10:19 pm

Re: PIC I2C using Colour sensor

Post by avianate » Sun Feb 11, 2018 10:22 pm

Did you ever get this working? I'm new to i2c on pic and having a similar issue where SDA & SCL both go low and the pic hangs. I'm curious what you've learned.

User avatar
phalanx
Non-SFE Guru
Posts: 1980
Joined: Sun Nov 30, 2003 8:57 am
Location: Candia, NH

Re: PIC I2C using Colour sensor

Post by phalanx » Mon Feb 12, 2018 12:54 pm

I apparently forgot to look at this post again after replying the first time.

Avianate, there are lots of reasons why your SDA and SCL lines could be stuck low. We will need more information on your setup and initialization code for your PIC before we can be of any more help.

-Bill

Post Reply