View previous topic :: View next topic |
Author |
Message |
alique89
Joined: 21 Apr 2012 Posts: 7
|
16F877A i2c to 16F690 |
Posted: Sat Apr 21, 2012 4:46 pm |
|
|
Hello i have been at this for a bit and have not found what might be my problem. I had searched up what others had done and turn out empty there too. i'm using v. 4.120 of the ccs c and real world app.
List of questions that might solve the problem.
1. I'm using the sample code to make my 16f690 a slave and its running at 8 mhz. The master is 16F877A and its on a crystal of 20mhz. would this be a cause that my all results to be 0xff? what would one do to correct this.
2. Is a buffer array necessarily need?
my code.
Master
Code: |
#include <16F877A.h>
#device adc=8
#FUSES NOWDT //No Watch Dog Timer
#FUSES HS //High speed Osc (> 4mhz)
#FUSES NOPUT //No Power Up Timer
#FUSES NOPROTECT //Code not protected from reading
#FUSES NODEBUG //No Debug mode for ICD
#FUSES NOBROWNOUT //No brownout reset
#FUSES NOLVP //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NOCPD //No EE protection
#FUSES NOWRT //Program memory not write protected
#use delay(clock=20000000)
#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8)
#use i2c(Master,fast,sda=PIN_C4,scl=PIN_C3,force_hw)
#include "C:\Users\Alique\Documents\Dropbox\SCHOOL\data ack\lcd_4bit.c"
#include "C:\Users\Alique\Documents\Dropbox\SCHOOL\data ack\I2C_COM.c"
#byte TRISA = 0x85
#byte PORTA = 0x05
int adc_0, copy1;
void adc(void);
void read()
{
int data;
i2c_start();
i2c_write(0xa0);
i2c_write(0x00);
i2c_write("a");
i2c_stop();
delay_ms(1000);
i2c_start();
i2c_write(0xa0);
i2c_write(0x00);
i2c_start();
i2c_write(0xa1);
data = i2c_read(0);
i2c_stop();
dsp_add(L2B1);
text_1("return:");
dbin(data);
}
void main()
{
setup_adc_ports(AN0_AN1_AN3);
setup_adc(ADC_CLOCK_DIV_2);
TRISA = 0xfb;
ini(2);
dsp_add(L1B1);
text_1("ADC_0:");
dsp_add(L2B1);
while(1)
{
adc();
if(copy1 != adc_0)
{
dsp_add(L1B8);
dbin(adc_0);
read();
}
}
}
void adc(void)
{
copy1=adc_0;
SET_ADC_CHANNEL(0);
delay_ms(5);
adc_0=READ_ADC();
}
|
slave
Code: |
#include <16F690.h>
#device adc=8
#FUSES NOWDT //No Watch Dog Timer
#FUSES INTRC_IO //Internal RC Osc, no CLKOUT
#FUSES NOPROTECT //Code not protected from reading
#FUSES BROWNOUT //Reset when brownout detected
#FUSES MCLR //Master Clear pin enabled
#FUSES NOCPD //No EE protection
#FUSES NOPUT //No Power Up Timer
#FUSES IESO //Internal External Switch Over mode enabled
#FUSES FCMEN //Fail-safe clock monitor enabled
#use delay(clock=8000000)
#use i2c(Slave,Fast,sda=PIN_C4,scl=PIN_C3,address=0xa0)
#byte TRISB = 0x86
#byte TRISC = 0x87
#byte PORTB = 0x06
#byte PORTC = 0x07
#bit C0 =0x07.0
INT buffer[0x08],address;
#int_SSP
void ssp_interupt ()
{
BYTE incoming, state;
state = i2c_isr_state();
if(state < 0x80) //Master is sending data
{
incoming = i2c_read();
if(state == 1) //First received byte is address
address = incoming;
if(state == 2) //Second received byte is data
buffer[address] = incoming;
}
if(state == 0x80) //Master is requesting data
{
i2c_write(buffer[address]);
}
}
void main()
{
setup_adc_ports(NO_ANALOGS|VSS_VDD);
setup_adc(ADC_OFF);
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
setup_timer_1(T1_DISABLED);
setup_timer_2(T2_DIV_BY_16,255,4);
enable_interrupts(INT_SSP);
enable_interrupts(GLOBAL);
setup_oscillator(OSC_8MHZ);
TRISC = 0XFe;
WHILE(1)
{
C0=1;
delay_us(buffer[0x00]);
C0=0;
delay_us(buffer[0x00]);
}
}
|
if there is any thing missing i will post.
thanks |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sat Apr 21, 2012 5:30 pm |
|
|
Code: | .................... i2c_write("a");
0045: MOVWF 24
0046: CALL 02B
....................
.................... i2c_write('a');
0047: MOVLW 61
0048: MOVWF 24
0049: CALL 02B |
What's the difference between double quotes and single quotes ?
What does each one send to the i2c_write() routine ? |
|
|
alique89
Joined: 21 Apr 2012 Posts: 7
|
|
Posted: Sat Apr 21, 2012 5:41 pm |
|
|
Originally i was using an int in the place of the "a" so that it looked like this
Code: |
int data;
i2c_start();
i2c_write(0xa0);
i2c_write(0x00);
i2c_write(adc_0);
i2c_stop();
delay_ms(1000);
i2c_start();
i2c_write(0xa0);
i2c_write(0x00);
i2c_start();
i2c_write(0xa1);
data = i2c_read(0);
i2c_stop(); |
In asm i do see there is a huge difference between the two so i'm not sure if that is the starting point of my problem? |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sat Apr 21, 2012 5:46 pm |
|
|
Use the single quotes, and slow down the master PIC to 4 MHz. |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9221 Location: Greensville,Ontario
|
|
Posted: Sat Apr 21, 2012 6:42 pm |
|
|
also be sure to use the correct value I2C bus pullup resistors ! |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19497
|
|
Posted: Sun Apr 22, 2012 4:08 am |
|
|
and get rid of the 'Fast' keyword in the slave.
Slave I2C devices do not specify the speed. This is controlled by the master.
Best Wishes |
|
|
jeremiah
Joined: 20 Jul 2010 Posts: 1345
|
|
Posted: Sun Apr 22, 2012 7:25 am |
|
|
Also, take some time to look up i2c_isr_state() in the compiler manual. You are doing your ISR incorrectly in quite a few places. They even give an example of how to do the ISR there (though I think they have a typo: i@c ). |
|
|
alique89
Joined: 21 Apr 2012 Posts: 7
|
|
Posted: Sun Apr 22, 2012 10:55 am |
|
|
Here is what i have done so far.
1. changed the Quotes.
2. checked the resistor values to be between 10 k and 6k
3. i looked over the slave ssp isr and found 3 logic errors.
4. removed fast out of the #USE I2C command.
Still no luck.
@jeremaih asides the logic errors that i have seen you point out in other post, was there anything else? i did look over the manual and was more confused at the end of reading it.
@pcm i can't lower the clock due to it being a dev board with a Crystal and i need it to remain at 20 mhz for other communications. Unless you meant to assign a speed for the i2c to communicate with. I could also bring the slave chip up to the same speed. |
|
|
jeremiah
Joined: 20 Jul 2010 Posts: 1345
|
|
Posted: Sun Apr 22, 2012 12:05 pm |
|
|
I would say go ahead and either update your original post with the corrected code or post it new so we can take a look at the changes.
Also of note: At SOME point in the 4.1xx series, they changed how the slave address is input in the #use i2c(). For a while they used the 7bit notation (0x50), but later on switched back to the 8 bit notation (0xa0). I don't remember when they switched back, so the first thing I would check is if your ISR is firing at all. find a debug line, set it low, and then call output_toggle() on that pin in the ISR each time it fires. Make sure the ISR is even being fired off. Just use something simple in the master. Have the master simply do:
Code: |
while(TRUE){
i2c_start();
i2c_write(YOUR_SLAVES_ADDRESS_HERE_8BIT_FORMAT);
i2c_stop();
delay_ms(1000);
}
|
Theoretically that should fire off the ISR every second on the slave side.
The first step is to verify some kind of communication happens. After that, we'll look at verifying the actual data coming across. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19497
|
|
Posted: Sun Apr 22, 2012 12:39 pm |
|
|
Two comments:
Your resistor value is _high_ depends on the wire length (capacitance of bus), but typical values for a 5v 'fast' bus are 2.2K to 4.7K.
PCM programmer has posted a little utility program here, that scans an I2C bus and reports every slave device it finds. Run this instead of your master for testing.
Best Wishes |
|
|
alique89
Joined: 21 Apr 2012 Posts: 7
|
|
Posted: Sun Apr 22, 2012 3:16 pm |
|
|
we have progress!!
OK so i'm now pretty sure its the slave side that i'm going to need to fine tune. I know for sure that there is communication and that a values is sent.
the code is all new. i restarted form scratch. so there will be some new errors for sure.
master i2c
Code: |
#include <16F877A.h>
#device adc=8
#FUSES NOWDT //No Watch Dog Timer
#FUSES HS //High speed Osc (> 4mhz)
#FUSES NOPUT //No Power Up Timer
#FUSES NOPROTECT //Code not protected from reading
#FUSES NODEBUG //No Debug mode for ICD
#FUSES NOBROWNOUT //No brownout reset
#FUSES NOLVP //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NOCPD //No EE protection
#FUSES NOWRT //Program memory not write protected
#use delay(clock=20000000)
#use rs232(baud=26000,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8)
#use i2c(Master,Fast,sda=PIN_C4,scl=PIN_C3)
#include "C:\Users\Alique\Documents\Dropbox\SCHOOL\data ack\lcd_4bit.c"
#include "C:\Users\Alique\Documents\Dropbox\SCHOOL\data ack\I2C_COM.c"
#byte TRISA = 0x85
#byte PORTA = 0x05
int adc_0, copy1,data ;
void adc(void);
void write()
{
i2c_start();
i2c_write(0xa0);
i2c_write(0x00);
i2c_write(adc_0);
i2c_stop();
}
void main()
{
setup_adc_ports(AN0_AN1_AN3);
setup_adc(ADC_CLOCK_DIV_2);
TRISA = 0xfb;
ini(2);
dsp_add(L1B1);
text_1("ADC_0:");
dsp_add(L2B1);
while(1)
{
adc();
if(copy1 != adc_0)
{
dsp_add(L1B8);
dbin(adc_0);
write();
}
}
}
void adc(void)
{
copy1=adc_0;
SET_ADC_CHANNEL(0);
delay_ms(5);
adc_0=READ_ADC();
}
|
Slave code
Code: |
#include <16F690.h>
#device adc=8
#FUSES NOWDT //No Watch Dog Timer
#FUSES INTRC_IO //Internal RC Osc, no CLKOUT
#FUSES NOPROTECT //Code not protected from reading
#FUSES BROWNOUT //Reset when brownout detected
#FUSES MCLR //Master Clear pin enabled
#FUSES NOCPD //No EE protection
#FUSES NOPUT //No Power Up Timer
#FUSES IESO //Internal External Switch Over mode enabled
#FUSES FCMEN //Fail-safe clock monitor enabled
#use delay(clock=8000000)
#use i2c(Slave,sda=PIN_B4,scl=PIN_B6,force_hw,address=0xa0)
#byte TRISB = 0x86
#byte TRISC = 0x87
#byte PORTB = 0x06
#byte PORTC = 0x07
#bit C0 =0x07.0
#bit C1 =0x07.1
INT buffer[0x02],address;
#int_SSP
void SSP_isr(void)
{
BYTE incoming, state;
state = i2c_isr_state();
C1=!C1;
if(state <= 0x80) //Master is sending data
{
incoming = i2c_read();
if(state == 1) //First received byte is address
address = incoming;
if(state == 2) //Second received byte is data
buffer[address] = incoming;
}
if(state >= 0x80) //Master is requesting data
{
i2c_write(buffer[address]);
}
}
void main()
{
setup_adc_ports(NO_ANALOGS|VSS_VDD);
setup_adc(ADC_OFF);
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
setup_timer_1(T1_DISABLED);
setup_timer_2(T2_DIV_BY_16,255,1);
setup_comparator(NC_NC_NC_NC);// This device COMP currently not supported by the PICWizard
enable_interrupts(INT_SSP);
enable_interrupts(GLOBAL);
setup_oscillator(OSC_8MHZ);
TRISC = 0XFC;
WHILE(1)
{
C0=!C0;
delay_ms(buffer[0x00]);
}
}
|
so far i'm not seeing and results or dimming of the led i'm using. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19497
|
|
Posted: Mon Apr 23, 2012 1:51 am |
|
|
Before worrying about the slave, get the master reading the ADC.
The clock rate you have selected for the ADC, is about 16* faster than it can handle. I doubt if it'll be returning anything even remotely useable. Data sheet Table 11-1. "Tad vs. Maximum device operating frequencies". 2Tosc (ADC_CLOCK_DIV_2) is allowed up to a maximum CPU clock of 1.25MHz.....
Best Wishes |
|
|
alique89
Joined: 21 Apr 2012 Posts: 7
|
|
Posted: Mon Apr 23, 2012 4:41 am |
|
|
The ADC is outputting fine. i check by changing it to a optimal speed recommended by the data sheet and gave me the same results.
I'll be at the shop today so i know i'll have better test equipment then the analog scope i was using. i may also try to get two of the same chips to master/ slave and see if its speed related or code. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19497
|
|
Posted: Mon Apr 23, 2012 7:32 am |
|
|
Seriously, it _won't_ be 'outputting just fine'. Clocking this type of ADC too fast will mean you probably have something like 3-4bits of real resolution, if that. Part of the lesson here, is _read the data sheet, and follow what it says_, don't assume things are 'OK', because it looks vaguely alright.
Best Wishes |
|
|
alique89
Joined: 21 Apr 2012 Posts: 7
|
|
Posted: Wed Apr 25, 2012 7:25 pm |
|
|
Sorry Ttelmah there was a misunderstanding. You were right, it was indeed one of three problems needing to be solved. With the right equipment I found I have reversed the wiring of the scl and sda, and that I had a nack problem in my code.
I will be posting the final product when i have more time. |
|
|
|