Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

Slave I2C, 16F88

Status
Not open for further replies.

Fred.Amoson

New Member
Hello,

I am trying to use my PIC16F88 as a slave i2c device. I am using BoostC with the SourceBoost compiler, but I'm not using any proprietary functions, so you should be able to understand it.

When The i2c slave (the PIC) is addressed , it should interrupt. BoostC uses the interrupt function for this. When the interrupt happens my testing LED should change from on to off. When I connect the PIC to the master I2C, the led never turns off. I'm sure the master is working correctly and the address is correct.

I have tested the interrupt/LED by setting up an external interrupt. Using that the LED does what it should when the external interrupt pin is brought high, so the interrupt function works properly.

Any ideas?

My code is as follows:

Code:
#include <system.h>

#pragma CLOCK_FREQ 8000000
#pragma DATA 0x2007, 0b0001111100010000

volatile bit led1    @ PORTB.3;

void init_i2c_slave();
void interrupt();

void main()
{
    //*********************//
    // configure I/O ports //
    //*********************//
    portb   = 00000000b;
    trisb   = 11110111b; //0 = Output, 1 = Input
    porta   = 00000000b;    
    trisa   = 11111111b; //0 = Output, 1 = Input
    osccon  = 01110000b; //internal oscillator @ 8MHz
    cmcon   = 00000111b; //comparators off
    ansel   = 00000001b; //AN0 on (RA0)
    
    init_i2c_slave();
    
    led1 = 1;
    
    while(1);
}

void interrupt()
{
    led1 = 0;
}

void init_i2c_slave()
{
    //SSPSTAT
    sspstat.7 = 0;  // this bit must be maintained clear
    sspstat.6 = 0;// this bit must be maintained clear
    //SCL and SDA as input
    trisb.1 = 1; //SDA
    trisb.4 = 1; //SCL
    //SSPCON
    sspcon = 0x36;
    sspadd=0x86;
    //SSP IE
    pie1.3 = 1;
    pir1.3 = 0;
    //Interrupt Control
    intcon.7=1;     //enable global interrupt
    intcon.6=1;     //enable global interrupt
}
 
at first glance, I think you need to enable the 'global' periphal interrupt flag as well as your ssp flag. "PEIE"

i've implemented interrupt driven i2c slave code on a 16f767, which periphally is similar to your f88, I'll review a few more things and see what else i can find.

edit: just glanced at the datasheet for the f88, you're already there with your intcon.6=1 ... guess it wasn't that easy, i'll keep looking
 
Last edited:
your init of the ssp module looks the same as mine.

the only exception is in Basic, I need to tell the compiler where the interrupt handler is, and whether I want soft interrupts (polled) or hard interrupts... a command like this

On Interrupt GOTO IntHndlr ' install soft interrupt handler

does your C compiler automatically default to an interrupt handler of interrupt() ?
 
Sourceboost automatically polls the void interrupt(void) function. Then to detect what interrupt happened you use if statements.

If the software seems okay, I wonder if it is because I am using a PIC16F88 at 3 volts. It has never caused problems in the past, but technically I should be using a 16LF88.

Thank you for the help, DIY
 
My master only likes 3V, so I will probably order a 16LF88 and wait to test it with that.

If anyone has any more ideas I can try in the mean time, I would love to try them! :)
 
i2c is open drain, so all the slave (or master) does is pull the lines low when they're talking.

what is the master, another pic or something more fragile? could throw some 1k resistors in series with sda and scl, and pull them up to 5v on the slave side instead of 3v on the master side. the series resistors should protect the master from any ill-effects of the 5v, assuming it has internal protection diodes to clamp the voltage.
 
I went ahead and hooked the PIC up to 5V and used series resistors back to the master. Still no luck.

Am I correct in thinking that this will (should) interrupt the instant it's address is polled?

Does the speed of the i2c matter? Should I increase my clock speed or something?
 
do you have a scope? i2c is pretty easy to read with just about any scope, this way we can verify the transactions are taking place. the speed is not really important, I use 100khz for most of my projects, you can push a lot of data at 100khz.

yes, the interrupt should fire the instant the pic 'hears' its address on the bus. do you have other i2c devices on the bus already, are they working, can the master talk to anything else?

oh, in basic, with polled interrupts, the code needs to have at least one non-branch/jump/goto instruction in a loop in order to do polling. not sure if your lang is the same way. example:

Code:
while 1=1   ' infinite loop for polled interrupts, this one works
   NOP
wend

while 1=1 ' infinite loop for polled interrupts, this one doesn't work
wend

when I look at the assembly that produces, there is no instruction 'inside' the loop to return from polling the interrupts, so they don't get checked. putting the simple NOP inside the loop gives the program something to jump back to after polling interrupts, and then it is happy.
 
Thanks for the input. The while/nop idea is very interesting, although I suspect that is not the case with sourceboost, since I have done an external interrupt with a simple while(1); statement, and it did interrupt. I will definitely give it a shot when I get home and let you know though.

The master is calling the slave. It is also talking to an eeprom i2c with no problems, so the issue has to lie in my PIC slave.

Thanks!
 
This is ridiculous :(

I've done everything I can think of, and this thing still won't interrupt. Increased my clock freq to 20 MHZ, nop in while, etc. I have attached both my C code and ASM code, maybe the compiler is making an error.

For what it's worth, the External Interrupt enabled in this code works great. The led goes off when I bring that pin high. (RB0)

My i2c is fast i2c, could that be the problem?

C Code
Code:
#include <system.h>

#pragma CLOCK_FREQ 20000000
#pragma DATA 0x2007, 0b0001111100000010
//					 0b00* * = 0 for code protect

volatile bit led1    @ PORTB.3;

void init_i2c_slave();
void interrupt();

void main()
{
    //*********************//
    // configure I/O ports //
    //*********************//
    portb   = 00000000b;
    trisb   = 11110111b; //0 = Output, 1 = Input
    porta   = 00000000b;    
    trisa   = 11111111b; //0 = Output, 1 = Input
    osccon  = 01110000b; //internal oscillator @ 8MHz
    cmcon   = 00000111b; //comparators off
    ansel   = 00000001b; //AN0 on (RA0)
    
    init_i2c_slave();
    
    led1 = 1;
    
    while(1) nop();
}

void interrupt()
{
    led1 = 0;
}

void init_i2c_slave()
{
    //SSPSTAT
    sspstat.7 = 0;  // this bit must be maintained clear
    sspstat.6 = 0;// this bit must be maintained clear
    sspstat.0 = 0; //clear buffer full bit
    
    //SCL and SDA as input
    trisb.1 = 1; //SDA
    trisb.4 = 1; //SCL

    sspadd = 0x86;

    pie1.3 = 1;
    pir1.3 = 0;
    //Interrupt Control
    intcon.7=1;     //enable global interrupt
    intcon.6=1;     //enable peripheral interrupt
    intcon.4=1;
    sspcon.7 = 0;// WCOL Write Collision Detect bit
    sspcon.6 = 0;// SSPOV Receive Overflow Indicator bit
    sspcon.4 = 0;// CKP
    sspcon.3 = 0;//0110: I2C slave mode: 7 bits address
    sspcon.2 = 1;
    sspcon.1 = 1;
    sspcon.0 = 0;
    sspcon.5 = 1;// Synchronous Serial Port Enable
}

Assembly
Code:
;/////////////////////////////////////////////////////////////////////////////////
;// Code Generator: BoostC Compiler - http://www.sourceboost.com
;// Version       : 6.60
;// License Type  : Pro License
;// Limitations   : PIC12,PIC16 max code size:Unlimited, max RAM banks:Unlimited
;/////////////////////////////////////////////////////////////////////////////////

	include "P16F88.inc"
; Heap block 0, size:111 (0x00000110 - 0x0000017E)
__HEAP_BLOCK0_BANK               EQU	0x00000002
__HEAP_BLOCK0_START_OFFSET       EQU	0x00000010
__HEAP_BLOCK0_END_OFFSET         EQU	0x0000007E
; Heap block 1, size:96 (0x00000190 - 0x000001EF)
__HEAP_BLOCK1_BANK               EQU	0x00000003
__HEAP_BLOCK1_START_OFFSET       EQU	0x00000010
__HEAP_BLOCK1_END_OFFSET         EQU	0x0000006F
; Heap block 2, size:80 (0x000000A0 - 0x000000EF)
__HEAP_BLOCK2_BANK               EQU	0x00000001
__HEAP_BLOCK2_START_OFFSET       EQU	0x00000020
__HEAP_BLOCK2_END_OFFSET         EQU	0x0000006F
; Heap block 3, size:76 (0x00000024 - 0x0000006F)
__HEAP_BLOCK3_BANK               EQU	0x00000000
__HEAP_BLOCK3_START_OFFSET       EQU	0x00000024
__HEAP_BLOCK3_END_OFFSET         EQU	0x0000006F
CompGblVar12                     EQU	0x00000023 ; bit:0
CompGblVar13                     EQU	0x00000023 ; bit:1
gbl_status                       EQU	0x00000003 ; bytes:1
gbl_indf                         EQU	0x00000000 ; bytes:1
gbl_tmr0                         EQU	0x00000001 ; bytes:1
gbl_pcl                          EQU	0x00000002 ; bytes:1
gbl_fsr                          EQU	0x00000004 ; bytes:1
gbl_porta                        EQU	0x00000005 ; bytes:1
gbl_portb                        EQU	0x00000006 ; bytes:1
gbl_pclath                       EQU	0x0000000A ; bytes:1
gbl_intcon                       EQU	0x0000000B ; bytes:1
gbl_pir1                         EQU	0x0000000C ; bytes:1
gbl_pir2                         EQU	0x0000000D ; bytes:1
gbl_tmr1l                        EQU	0x0000000E ; bytes:1
gbl_tmr1h                        EQU	0x0000000F ; bytes:1
gbl_t1con                        EQU	0x00000010 ; bytes:1
gbl_tmr2                         EQU	0x00000011 ; bytes:1
gbl_t2con                        EQU	0x00000012 ; bytes:1
gbl_sspbuf                       EQU	0x00000013 ; bytes:1
gbl_sspcon                       EQU	0x00000014 ; bytes:1
gbl_ccpr1l                       EQU	0x00000015 ; bytes:1
gbl_ccpr1h                       EQU	0x00000016 ; bytes:1
gbl_ccp1con                      EQU	0x00000017 ; bytes:1
gbl_rcsta                        EQU	0x00000018 ; bytes:1
gbl_txreg                        EQU	0x00000019 ; bytes:1
gbl_rcreg                        EQU	0x0000001A ; bytes:1
gbl_adresh                       EQU	0x0000001E ; bytes:1
gbl_adcon0                       EQU	0x0000001F ; bytes:1
gbl_option_reg                   EQU	0x00000081 ; bytes:1
gbl_trisa                        EQU	0x00000085 ; bytes:1
gbl_trisb                        EQU	0x00000086 ; bytes:1
gbl_pie1                         EQU	0x0000008C ; bytes:1
gbl_pie2                         EQU	0x0000008D ; bytes:1
gbl_pcon                         EQU	0x0000008E ; bytes:1
gbl_osccon                       EQU	0x0000008F ; bytes:1
gbl_osctune                      EQU	0x00000090 ; bytes:1
gbl_pr2                          EQU	0x00000092 ; bytes:1
gbl_sspadd                       EQU	0x00000093 ; bytes:1
gbl_sspstat                      EQU	0x00000094 ; bytes:1
gbl_txsta                        EQU	0x00000098 ; bytes:1
gbl_spbrg                        EQU	0x00000099 ; bytes:1
gbl_ansel                        EQU	0x0000009B ; bytes:1
gbl_cmcon                        EQU	0x0000009C ; bytes:1
gbl_cvrcon                       EQU	0x0000009D ; bytes:1
gbl_adresl                       EQU	0x0000009E ; bytes:1
gbl_adcon1                       EQU	0x0000009F ; bytes:1
gbl_wdtcon                       EQU	0x00000105 ; bytes:1
gbl_eedata                       EQU	0x0000010C ; bytes:1
gbl_eeadr                        EQU	0x0000010D ; bytes:1
gbl_eedath                       EQU	0x0000010E ; bytes:1
gbl_eeadrh                       EQU	0x0000010F ; bytes:1
gbl_eecon1                       EQU	0x0000018C ; bytes:1
gbl_eecon2                       EQU	0x0000018D ; bytes:1
gbl_led1                         EQU	0x00000006 ; bit:3
Int1Context                      EQU	0x0000007F ; bytes:1
Int1BContext                     EQU	0x00000020 ; bytes:3
	ORG 0x00000000
	GOTO	_startup
	ORG 0x00000004
	MOVWF Int1Context
	SWAPF STATUS, W
	BCF STATUS, RP0
	BCF STATUS, RP1
	MOVWF Int1BContext
	SWAPF PCLATH, W
	MOVWF Int1BContext+D'1'
	SWAPF FSR, W
	MOVWF Int1BContext+D'2'
	BCF PCLATH,3
	BCF PCLATH,4
	GOTO	interrupt
	ORG 0x00000010
init_i2c_s_00013
; { init_i2c_slave ; function begin
	BSF STATUS, RP0
	BCF STATUS, RP1
	BCF gbl_sspstat,7
	BCF gbl_sspstat,6
	BCF gbl_sspstat,0
	BSF gbl_trisb,1
	BSF gbl_trisb,4
	MOVLW 0x86
	MOVWF gbl_sspadd
	BSF gbl_pie1,3
	BCF STATUS, RP0
	BCF gbl_pir1,3
	BSF gbl_intcon,7
	BSF gbl_intcon,6
	BSF gbl_intcon,4
	BCF gbl_sspcon,7
	BCF gbl_sspcon,6
	BCF gbl_sspcon,4
	BCF gbl_sspcon,3
	BSF gbl_sspcon,2
	BSF gbl_sspcon,1
	BCF gbl_sspcon,0
	BSF gbl_sspcon,5
	RETURN
; } init_i2c_slave function end

	ORG 0x00000028
main
; { main ; function begin
	BCF STATUS, RP0
	BCF STATUS, RP1
	CLRF gbl_portb
	MOVLW 0xF7
	BSF STATUS, RP0
	MOVWF gbl_trisb
	BCF STATUS, RP0
	CLRF gbl_porta
	MOVLW 0xFF
	BSF STATUS, RP0
	MOVWF gbl_trisa
	MOVLW 0x70
	MOVWF gbl_osccon
	MOVLW 0x07
	MOVWF gbl_cmcon
	MOVLW 0x01
	MOVWF gbl_ansel
	CALL init_i2c_s_00013
	BSF gbl_led1,3
label268438774
	NOP
	GOTO	label268438774
; } main function end

	ORG 0x0000003D
_startup
	BCF STATUS, RP0
	BCF STATUS, RP1
	BCF CompGblVar12,0
	BCF CompGblVar13,1
	BCF PCLATH,3
	BCF PCLATH,4
	GOTO	main
	ORG 0x00000044
interrupt
; { interrupt ; function begin
	BCF STATUS, RP0
	BCF STATUS, RP1
	BCF gbl_led1,3
	SWAPF Int1BContext+D'2', W
	MOVWF FSR
	SWAPF Int1BContext+D'1', W
	MOVWF PCLATH
	SWAPF Int1BContext, W
	MOVWF STATUS
	SWAPF Int1Context, F
	SWAPF Int1Context, W
	RETFIE
; } interrupt function end

	ORG 0x00002007
	DW 0x1F02
	END

Thanks!
 
Last edited:
i don't remember the naming convention for i2c bus speeds ... how fast is fast?

I know Philips recently introduced a new bus speed, over 1mhz for i2c, but I also seem to recall there were special considerations for using it.

Fastest I've tried with my slave code was 400kHz.

Just grasping at straws here, but the pic expects a 7 bit address right? 0x86 is an eight bit number ... obviously bit 0 is the read/write bit but maybe that doesn't matter. try loading SSPADD with an address of 0x7F or less, so you get a 7 bit number ... then add that eight bit to it on the master side?
 
The "fast i2c" is 400KHz

You are absolutely right on the 0x86. I changed the address to 0x50 on both the slave and master, still no luck though.

Did you do your i2c on a 16F88? If so, would you be willing to share any of your code?
 
I can share my code; other than stuff I've added to respond to the different i2c states it is the same as what you've got. I think you'll have an easier time following this, It is the code I based mine on, I added a bunch of stuff to turn a PIC16F767 into a i2c ADC

here's the link:
http://www.astrosurf.com/soubie/fichiers/i2cInt.pbp

I'm at a loss as to why your code doesn't work. I'm surprised no one else has offered any ideas, I sometimes think is electro-tech is pretty much an assembler only board.
 
Status
Not open for further replies.

Latest threads

Back
Top