|
|
View previous topic :: View next topic |
Author |
Message |
Linuxbuilders
Joined: 20 Mar 2010 Posts: 193 Location: Auckland NZ
|
i2c master receiving from slave |
Posted: Tue Feb 28, 2012 4:08 am |
|
|
Hi, I need to do such thing:
Master sends command to slave (both 18F4620) then based on the command slave sends back data to master.
So far I have going:
sending data from master - easy
receiving data by slave - easy
getting and writing time to ds1307 - easy so my i2c is OK
But what I cannot get going is master side being able to get message back from slave pic.
This is master side:
Code: |
i2c_start();
i2c_write(0xA0); //select address of device to communicate with
i2c_write(0x01); //send actual command
i2cread[0] = i2c_read(); //read back from slave
i2c_stop(); |
Whatever I do I get 255 as a result, any suggestions. I cannot find any useful information how master side should look. I have followed code for ds1307 and it looks easy but whatever I do my 255 is always there.
This is slave side:
Code: |
void ssp_interupt(void) {
state = i2c_isr_state();
if(state < 0x80) { //master is sending data
if (state == 0) {
c = i2c_read();
buffer[0] = c;
}
if (state == 1) { //command
c = i2c_read();
buffer[1] = c;
}
if (buffer[1] == 0x01) { //command 0x01 -> send back 0x05
i2c_write(0x05);
}
}
|
What wrong am I doing here?
Thnx _________________ Help "d" others and then you shell receive some help from "d" others. |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9229 Location: Greensville,Ontario
|
|
Posted: Tue Feb 28, 2012 6:40 am |
|
|
comments
0) is this real hardware or a simulation?
1) Rename your variable that gets the data ( i2cread[]) to say 'slave_data[]', 'data_from_first_slave'[]. ANYTHING other than what you have which is confusing and hard to read.
2. What value are your I2C bus pullup resistors?
3. Is the slave address actually 0xA0 ?
4. Post the slave's program,perhaps there's a typo? |
|
|
jeremiah
Joined: 20 Jul 2010 Posts: 1349
|
|
Posted: Tue Feb 28, 2012 8:26 am |
|
|
You also need to NACK the last byte you read in the master. See the description for i2c_read() in the manual or in the IDE (Help->Index I think ). |
|
|
Linuxbuilders
Joined: 20 Mar 2010 Posts: 193 Location: Auckland NZ
|
|
Posted: Tue Feb 28, 2012 4:16 pm |
|
|
Quote: | comments
0) is this real hardware or a simulation? |
YES IT IS - WORKING BOARDS, GOT I2C TALKING TO DS1307 IN REAL TIME - NO PROBLEMS THERE, SO IT IS MY ROUTINE ON MASTER SIDE WRONG FOR READING DATA BACK FROM SLAVE
Quote: |
1) Rename your variable that gets the data ( i2cread[]) to say 'slave_data[]', 'data_from_first_slave'[]. ANYTHING other than what you have which is confusing and hard to read. |
WILL DO
Quote: | 2. What value are your I2C bus pullup resistors? |
1k8 - WORKING WITH SERIAL EEPROMS AND DS1307 - ALL GOOD ON HARDWARE SIDE
Quote: | 3. Is the slave address actually 0xA0 ? |
YES IT IS
4. Post the slave's program,perhaps there's a typo?
Quote: | void ssp_interupt(void) {
state = i2c_isr_state();
if(state < 0x80) { //master is sending data
if (state == 0) {
c = i2c_read();
buffer[0] = c;
}
if (state == 1) { //command
c = i2c_read();
buffer[1] = c;
}
if (buffer[1] == 0x01) { //command 0x01 -> send back 0x05
i2c_write(0x05);
}
} |
_________________ Help "d" others and then you shell receive some help from "d" others. |
|
|
Linuxbuilders
Joined: 20 Mar 2010 Posts: 193 Location: Auckland NZ
|
|
Posted: Tue Feb 28, 2012 4:17 pm |
|
|
Quote: | You also need to NACK the last byte you read in the master. See the description for i2c_read() in the manual or in the IDE (Help->Index I think ). |
WILL DO TODAY, ANY EXAMPLES IN MEAN TIME? thnx _________________ Help "d" others and then you shell receive some help from "d" others. |
|
|
jeremiah
Joined: 20 Jul 2010 Posts: 1349
|
|
Posted: Tue Feb 28, 2012 4:36 pm |
|
|
He wants you to post a complete, short, compilable program, not just a function (please continue to use the CODE tags rather than the QUOTE tags so it is readable). That way he can toss it into his compiler and see what happens to help out.
As for an example. If you go to your compiler directory there is an examples folders. Look for a file called ex_slave.c, make a copy of it in your project directory, change the PIC settings to match your particular PIC, and see if that fixes anything.
I can't post the CCS example code because it is against the rules to do so, but it comes with the compiler when you install it. |
|
|
Linuxbuilders
Joined: 20 Mar 2010 Posts: 193 Location: Auckland NZ
|
|
Posted: Tue Feb 28, 2012 10:42 pm |
|
|
This is slave code, I am testing hardware and writing simple code which is going to check all parts of the circuit. Below I'll put master too in a moment.
Code: | #include <18F4620.h>
#device ADC=10
#include <ctype.h>
#include <stddef.h>
#include <string.h>
//=========DEFINE====================
#define RX PIN_C7 // serial data receive pin
#define TX PIN_C6 // serial data transmit pin
#define TX_ON PIN_C5 // serial TX on
#define STATUS PIN_B2 // status led
#define GOUT1 PIN_D7
#define GOUT2 PIN_D6
#define GOUT3 PIN_D5
#define GOUT4 PIN_D4
#define GOUT5 PIN_D3
#define GOUT6 PIN_D2
#define GOUT7 PIN_D1
#define GOUT8 PIN_D0
#define BUZZ PIN_A4
#define POWER PIN_E1
#define BATTERY PIN_E2
#define MAINS_TEST PIN_AN3
#define POWER_TEST PIN_AN4
#define BATTERY_TEST PIN_AN5
#define INTMP PIN_AN0
#define TMP1 PIN_AN1
#define TMP2 PIN_AN2
#define SLOT0 PIN_B1
#define SLOT1 PIN_B0
#define SLOT2 PIN_B3
#define SLOT3 PIN_B4
#define SLOT4 PIN_B5
#define SLOT5 PIN_B6
#define SLOT6 PIN_B7
#define SLOT7 PIN_C0
#define SLOT8 PIN_C1
#define SLOT9 PIN_C2
#define I2CSCL PIN_C3
#define I2CSDA PIN_C4
//===================================
#FUSES H4
#FUSES MCLR
#FUSES BROWNOUT
#FUSES NODEBUG
#FUSES NOPROTECT
#FUSES WDT32768
#FUSES PUT
#FUSES NOCPD
#FUSES NOXINST
#use delay (clock=40M, oscillator=10M)
#use rs232(baud=19200,xmit=TX,rcv=RX,parity=n,bits=8,stop=1,RESTART_WDT,ERRORS,TIMEOUT=15)
#use i2c(slave, sda=I2CSDA, scl=I2CSCL, address=0xA0)
#use fixed_io(D_outputs=GOUT1,GOUT2,GOUT3,GOUT4,GOUT5,GOUT6,GOUT7,GOUT8)
#use fixed_io(A_outputs=BUZZ)
#use fixed_io(B_outputs=STATUS)
#use fixed_io(C_outputs=TX_ON,TX)
#use fixed_io(E_outputs=POWER,BATTERY)
int a, state, c, buffer[10];
int timer = 0;
int timerstep = 0;
int timerstep2 = 0;
int timerstep3 = 0;
short print = 0;
int adc_read = 0;
short readadc = 0;
int capture[8];
short captureready = 0
#int_RTCC
void timer0_isr(void) {
clear_interrupt(int_RTCC);
timer++;
if (timer == 0) {
output_high(STATUS);
}
if (timer == 0xFF) {
timerstep++;
}
if (timerstep == 128) {
output_low(STATUS);
}
if (timerstep == 0xFF) {
timerstep2++;
}
if (timerstep2 == 0xFF) {
timerstep3++;
readadc = 1;
}
if (timerstep3 == 0x05) {
}
}
#int_RDA
void comms_rda(void) {
int cap;
for (a=0;a<8;a++) {
cap = getc();
capture[a] = cap;
}
captureready = 1;
clear_interrupt(int_RDA);
}
#INT_SSP
//==========================
void ssp_interupt(void) {
state = i2c_isr_state();
if(state < 0x80) { //master is sending data
if (state == 0) { //address
c = i2c_read();
buffer[0] = c;
if (c == 0xA0) {
print = 1;
}
}
if (state == 1) { //command
c = i2c_read();
buffer[1] = c;
}
if (state == 2) { //data1
c = i2c_read();
buffer[2] = c;
}
if (state == 3) { //data2
c = i2c_read();
buffer[3] = c;
}
if (state == 4) { //data3
c = i2c_read();
buffer[4] = c;
}
if (state == 5) { //data4
c = i2c_read();
buffer[5] = c;
}
if (state == 6) { //data5
c = i2c_read();
buffer[6] = c;
}
if (state == 7) { //data6
c = i2c_read();
buffer[7] = c;
}
if (state == 8) { //data7
c = i2c_read();
buffer[8] = c;
}
if (state == 9) { //data8
c = i2c_read();
buffer[9] = c;
}
if (buffer[1] == 0x01) { //command 0x00 -> send value of second timer
i2c_write(timerstep2);
}
if (state > 9) { //data
clear_interrupt(int_SSP);
}
}
if(state == 0x80) { //master is requesting data
//i2c_write (0xFF); //send requested data
}
}
//==========================
//===================================
//========CONTROL RX485 TX===========
void comms_TX_high(void) {
output_high(TX_ON);
delay_ms(10);
} //void
void comms_TX_low(void) {
delay_ms(10);
output_low(TX_ON);
} //void
//===================================
void read_i2c(void) {
if (buffer[0] == 0xA0) { //message for us
if (buffer[1] == 0x00) { //command 0x00 -> input status
if (buffer[2] == 0x01) { //input 1
output_high(GOUT1);
}
else {
output_low(GOUT1);
}
if (buffer[3] == 0x01) { //input 2
output_high(GOUT2);
}
else {
output_low(GOUT2);
}
if (buffer[4] == 0x01) { //input 3
output_high(GOUT3);
}
else {
output_low(GOUT3);
}
if (buffer[5] == 0x01) { //input 4
output_high(GOUT4);
}
else {
output_low(GOUT4);
}
if (buffer[6] == 0x01) { //input 5
output_high(GOUT5);
}
else {
output_low(GOUT5);
}
if (buffer[7] == 0x01) { //input 6
output_high(GOUT6);
}
else {
output_low(GOUT6);
}
if (buffer[8] == 0x01) { //input 7
output_high(GOUT7);
}
else {
output_low(GOUT7);
}
if (buffer[9] == 0x01) { //input 8
output_high(GOUT8);
}
else {
output_low(GOUT8);
}
}
}
}
//===================================
void read_analogue_input(unsigned char adcParameter) { //capture analogue from temperature
set_adc_channel(adcParameter);
adc_read = read_adc();
} //void
//=========MAIN PROGRAM==============
void main() { // main program
setup_wdt(WDT_ON); //set watch dog timer
disable_interrupts(GLOBAL);
output_float(I2CSCL);
output_float(I2CSDA);
set_timer0(0);
set_rtcc(0);
setup_timer_0(RTCC_INTERNAL | RTCC_8_BIT | T0_DIV_1); //set timer 0 parameters
setup_adc_ports(AN0_TO_AN5 | VSS_VDD); //set AD ports
setup_adc(ADC_CLOCK_DIV_16 | ADC_TAD_MUL_16); //ADC_CLOCK_INTERNAL |
setup_comparator(NC_NC_NC_NC); //turn off comparators
enable_interrupts(GLOBAL);
enable_interrupts(int_ssp); //enable serial i2c
enable_interrupts(int_rda); //enable serial port
enable_interrupts(INT_RTCC); //enable TIMERs
//=========BOOT UP===================
output_low(STATUS);
output_low(TX_ON);
output_low(GOUT1);
output_low(GOUT2);
output_low(GOUT3);
output_low(GOUT4);
output_low(GOUT5);
output_low(GOUT6);
output_low(GOUT7);
output_low(GOUT8);
output_low(BUZZ);
output_low(POWER);
output_low(BATTERY);
output_high(BUZZ);
delay_ms(150);
output_low(BUZZ);
delay_ms(150);
output_high(BUZZ);
delay_ms(150);
output_low(BUZZ);
delay_ms(150);
output_high(BUZZ);
delay_ms(150);
output_low(BUZZ);
output_high(STATUS);
output_high(GOUT1);
output_high(GOUT2);
output_high(GOUT3);
output_high(GOUT4);
output_high(GOUT5);
output_high(GOUT6);
output_high(GOUT7);
output_high(GOUT8);
output_high(POWER);
output_high(BATTERY);
buffer[0]=0xFF;
buffer[1]=0xFF;
buffer[2]=0xFF;
buffer[3]=0xFF;
buffer[4]=0xFF;
buffer[5]=0xFF;
buffer[6]=0xFF;
buffer[7]=0xFF;
buffer[8]=0xFF;
buffer[9]=0xFF;
while(true) { //loop program
restart_wdt();
if (captureready == 1) {
comms_TX_high();
printf("%u:%u:%u:%u:%u:%u:%u:%u%c",capture[0],capture[1],capture[2],capture[3],capture[4],capture[5],capture[6],capture[7],0x0D);
comms_TX_low();
captureready = 0;
}
if (print == 1) {
comms_TX_high();
printf("%u:%u:%u:%u:%u:%u:%u:%u:%u:%u%c",buffer[0],buffer[1],buffer[2],buffer[3],buffer[4],buffer[5],buffer[6],buffer[7],buffer[8],buffer[9],0x0D);
comms_TX_low();
print = 0;
}
read_i2c();
int mains;
if (readadc == 1) {
read_analogue_input(0);
long int ar1 = adc_read;
read_analogue_input(1);
long int ar2 = adc_read;
read_analogue_input(2);
long int ar3 = adc_read;
read_analogue_input(3);
long int ar4 = adc_read;
read_analogue_input(4);
if (ar4 > 10) {
mains = 1;
}
long int ar5 = adc_read;
read_analogue_input(5);
long int ar6 = adc_read;
float ar1f = ar1;
float ar2f = ar2;
float ar3f = ar3;
float ar4f = ar4;
float ar5f = ar5;
float ar6f = ar6;
comms_TX_high();
// printf("1. %lu TMP0: %lu TMP1: %lu TMP2: %lu MAINS: %lu POWER: %lu BATTERY %c",ar1,ar2,ar3,ar4,ar5,ar6,0x0D);
printf("2. %f TMP0: %f TMP1: %f TMP2: %f MAINS: %f POWER: %f BATTERY %c",ar1f/4.16,ar2f/4.68,ar3f/4.68,ar4f,ar5f/13.31,ar6f/13.31,0x0D);
comms_TX_low();
readadc = 0;
}
} //while
} //void |
_________________ Help "d" others and then you shell receive some help from "d" others. |
|
|
Linuxbuilders
Joined: 20 Mar 2010 Posts: 193 Location: Auckland NZ
|
|
Posted: Tue Feb 28, 2012 10:48 pm |
|
|
master code:
Code: | #include <18F4620.h>
#include <ctype.h>
#include <stddef.h>
#include <string.h>
//=========DEFINE====================
#define RX PIN_C7
#define TX PIN_C6
#define TX_ON PIN_C5
#define STATUS PIN_D5
#define GIN1 PIN_B1
#define GIN2 PIN_B2
#define GIN3 PIN_A4
#define GIN4 PIN_B0
#define GIN5 PIN_A3
#define GIN6 PIN_A2
#define GIN7 PIN_A1
#define GIN8 PIN_A0
/*
#define LCD_E PIN_A5
#define LCD_RS PIN_B3
#define LCD_RW PIN_B4
#define LCD_DB4 PIN_D3
#define LCD_DB5 PIN_D2
#define LCD_DB6 PIN_D1
#define LCD_DB7 PIN_D0
*/
#define BCK_LIGHT PIN_D4
#define LK2 PIN_E2
#define LK1 PIN_E1
#define SLOT10 PIN_D6
#define SLOT11 PIN_D7
#define SLOT12 PIN_E0
#define SLOT13 PIN_B5
#define SLOT14 PIN_B6
#define SLOT15 PIN_B7
#define SLOT16 PIN_C0
#define SLOT17 PIN_C1
#define SLOT18 PIN_C2
#define I2CSCL PIN_C3
#define I2CSDA PIN_C4
//===================================
#FUSES H4
#FUSES MCLR
#FUSES BROWNOUT
#FUSES NODEBUG
#FUSES NOPROTECT
#FUSES WDT32768
#FUSES NOWDT
#FUSES PUT
#FUSES NOCPD
#FUSES NOXINST
//===================================
#use delay (clock=40M, oscillator=10M)
#use rs232(baud=19200,xmit=TX,rcv=RX,parity=n,bits=8,stop=1,RESTART_WDT,ERRORS,TIMEOUT=15)
#use i2c(master, sda=I2CSDA, scl=I2CSCL)
#include "flex_lcd.c"
#use fixed_io(D_outputs=LCD_DB4,LCD_DB5,LCD_DB6,LCD_DB7,BCK_LIGHT,STATUS) //LCD_DB4,LCD_DB5,LCD_DB6,LCD_DB7,BCK_LIGHT,STATUS
#use fixed_io(A_outputs=LCD_E) //LCD_E
#use fixed_io(B_outputs=LCD_RS,LCD_RW) //LCD_RS,LCD_RW
#use fixed_io(C_outputs=TX_ON, TX)
//===================================
//===================================
BYTE bin2bcd(BYTE binary_value); //clock data
BYTE bcd2bin(BYTE bcd_value); //clock data
int a, day, mth, year, dow, hr, min, sec; //dow - day of the week
int timer = 0;
int timerstep = 0;
int timerstep2 = 0;
int timerstep3 = 0;
int instate[8];
int in[8];
short testinputs = 0;
short print = 0;
short print1 = 0;
short link1,link2;
int capture[8];
int i2cread[9];
short settime = 0;
short chktime = 0;
short ticked = 0;
short requesti2c = 0;
short printrda = 0;
//========CONTROL RX485 TX===========
void comms_TX_high() {
output_high(TX_ON);
delay_ms(10);
} //void
void comms_TX_low() {
delay_ms(10);
output_low(TX_ON);
} //void
//===================================
#int_RTCC
void timer0_isr(void) {
clear_interrupt(int_RTCC);
timer++;
if (timer == 0) {
output_high(STATUS);
}
if (timer == 0xFF) {
timerstep++;
}
if (timerstep == 128) {
output_low(STATUS);
}
if (timerstep == 0xFF) {
timerstep2++;
chktime = 1;
}
if (timerstep2 == 0xFF) {
timerstep3++;
}
if (timerstep3 == 1) {
print = 1;
timerstep3++;
}
if (timerstep3 == 3) {
print1 = 1;
timerstep3 = 0;
}
}
#int_RDA
void comms_rda(void) {
int c;
for (a=0;a<8;a++) {
c = getc();
capture[a] = c;
}
printrda = 1;
if (capture[0] == 0x00) { // set time
settime = 1;
}
if (capture[0] == 0x01) { // request data back from i2c
requesti2c = 1;
}
clear_interrupt(int_RDA);
}
#int_SSP
void comms_ssp(void) {
clear_interrupt(int_SSP);
}
void clrsrcn() {
lcd_putc("\f\n");
}
//===================================
// note - DS1307 ADDRESSING D0 - WRITE, D1 - READ
// note -
//=========I2C=======================
void send_to_i2c(BYTE destinationi2c, BYTE command, BYTE data1, BYTE data2, BYTE data3, BYTE data4, BYTE data5, BYTE data6, BYTE data7, BYTE data8) {
i2c_start(); //begin transmission
i2c_write(destinationi2c); //select address of device to communicate with
i2c_write(command); //send actual command
i2c_write(data1); //send actual data
i2c_write(data2); //send actual data
i2c_write(data3); //send actual data
i2c_write(data4); //send actual data
i2c_write(data5); //send actual data
i2c_write(data6); //send actual data
i2c_write(data7); //send actual data
i2c_write(data8); //send actual data
i2c_stop(); //terminate communication
}
//===================================
//=========CLOCK=====================
/// ds1307_init() - Enable oscillator without clearing the seconds register -///
/// used when PIC loses power and DS1307 run from 3V BAT ///
/// - Disable squarewave output ///
/// ///
/// ds1307_set_date_time(day,mth,year,dow,hr,min,sec) Set the date/time ///
/// ///
/// ds1307_get_date(day,mth,year,dow) Get the date ///
/// ///
/// ds1307_get_time(hr,min,sec) Get the time ///
BYTE bin2bcd(BYTE binary_value)
{
BYTE temp;
BYTE retval;
temp = binary_value;
retval = 0;
while(1)
{
// Get the tens digit by doing multiple subtraction
// of 10 from the binary value.
if(temp >= 10)
{
temp -= 10;
retval += 0x10;
}
else // Get the ones digit by adding the remainder.
{
retval += temp;
break;
}
}
return(retval);
}
// Input range - 00 to 99.
BYTE bcd2bin(BYTE bcd_value)
{
BYTE temp;
temp = bcd_value;
// Shifting upper digit right by 1 is same as multiplying by 8.
temp >>= 1;
// Isolate the bits for the upper digit.
temp &= 0x78;
// Now return: (Tens * 8) + (Tens * 2) + Ones
return(temp + (temp >> 2) + (bcd_value & 0x0f));
}
void ds1307_init(void)
{
BYTE seconds = 0;
i2c_start();
i2c_write(0xD0); // WR to RTC
i2c_write(0x00); // REG 0
i2c_start();
i2c_write(0xD1); // RD from RTC
seconds = bcd2bin(i2c_read(0)); // Read current "seconds" in DS1307
i2c_stop();
seconds &= 0x7F;
delay_us(3);
i2c_start();
i2c_write(0xD0); // WR to RTC
i2c_write(0x00); // REG 0
i2c_write(bin2bcd(seconds)); // Start oscillator with current "seconds value
i2c_start();
i2c_write(0xD0); // WR to RTC
i2c_write(0x07); // Control Register
i2c_write(0x80); // Disable squarewave output pin
i2c_stop();
}
void ds1307_set_date_time(BYTE day, BYTE mth, BYTE year, BYTE dow, BYTE hr, BYTE min, BYTE sec)
{
sec &= 0x7F;
hr &= 0x3F;
i2c_start();
i2c_write(0xD0); // I2C write address
i2c_write(0x00); // Start at REG 0 - Seconds
i2c_write(bin2bcd(sec)); // REG 0
i2c_write(bin2bcd(min)); // REG 1
i2c_write(bin2bcd(hr)); // REG 2
i2c_write(bin2bcd(dow)); // REG 3
i2c_write(bin2bcd(day)); // REG 4
i2c_write(bin2bcd(mth)); // REG 5
i2c_write(bin2bcd(year)); // REG 6
i2c_write(0x80); // REG 7 - Disable squarewave output pin
i2c_stop();
}
void ds1307_get_date(BYTE &day, BYTE &mth, BYTE &year, BYTE &dow)
{
i2c_start();
i2c_write(0xD0);
i2c_write(0x03); // Start at REG 3 - Day of week
i2c_start();
i2c_write(0xD1);
dow = bcd2bin(i2c_read() & 0x7f); // REG 3
day = bcd2bin(i2c_read() & 0x3f); // REG 4
mth = bcd2bin(i2c_read() & 0x1f); // REG 5
year = bcd2bin(i2c_read(0)); // REG 6
i2c_stop();
}
void ds1307_get_time(BYTE &hr, BYTE &min, BYTE &sec)
{
i2c_start();
i2c_write(0xD0);
i2c_write(0x00); // Start at REG 0 - Seconds
i2c_start();
i2c_write(0xD1);
sec = bcd2bin(i2c_read() & 0x7f);
min = bcd2bin(i2c_read() & 0x7f);
hr = bcd2bin(i2c_read(0) & 0x3f);
i2c_stop();
}
//=========CLOCK I2C ENDS============
void set_time (void) {
if (settime == 1) {
printf(lcd_putc,"\f%02d-%02d-%02d %02d:%02d",day,mth,year,hr,min);
printf(lcd_putc,"\n%u,%u,%u,%u,%u,%u,%u,%u",capture[0],capture[1],capture[2],capture[3],capture[4],capture[5],capture[6],capture[7]);
ds1307_set_date_time(capture[1],capture[2],capture[3],capture[4],capture[5],capture[6],capture[7]);
settime = 0;
}
}
void inputs(void) {
in[0]=input(GIN1);
in[1]=input(GIN2);
in[2]=input(GIN3);
in[3]=input(GIN4);
in[4]=input(GIN5);
in[5]=input(GIN6);
in[6]=input(GIN7);
in[7]=input(GIN8);
delay_ms(10); //debouncing delay
if ((instate[0] != in[0]) || (instate[1] != in[1]) || (instate[2] != in[2]) || (instate[3] != in[3]) || (instate[4] != in[4]) || (instate[5] != in[5]) || (instate[6] != in[6]) || (instate[7] != in[7])) { //change detected
send_to_i2c(0xA0, 0x00, in[0], in[1], in[2], in[3], in[4], in[5], in[6], in[7]);
}
instate[0] = in[0]; // copy state to buffer
instate[1] = in[1]; // copy state to buffer
instate[2] = in[2]; // copy state to buffer
instate[3] = in[3]; // copy state to buffer
instate[4] = in[4]; // copy state to buffer
instate[5] = in[5]; // copy state to buffer
instate[6] = in[6]; // copy state to buffer
instate[7] = in[7]; // copy state to buffer
int link1=input(LK1);
int link2=input(LK2);
}
void time(void) {
ds1307_get_date(day,mth,year,dow);
ds1307_get_time(hr,min,sec);
chktime = 0;
}
//=========MAIN PROGRAM==============
void main() { // main program
setup_wdt(WDT_ON);
output_float(I2CSCL);
output_float(I2CSDA);
disable_interrupts(GLOBAL);
set_timer0(0);
set_rtcc(0);
setup_timer_0(RTCC_INTERNAL | RTCC_8_BIT | T0_DIV_1); //set timer 0 parameters
setup_adc(ADC_OFF);
setup_comparator(NC_NC_NC_NC); //turn off comparators
enable_interrupts(GLOBAL);
enable_interrupts(int_ssp); //enable serial i2c
enable_interrupts(int_rda); //enable serial port
enable_interrupts(INT_RTCC); //enable TIMERs
//=========BOOT UP===================
lcd_init();
output_low(BCK_LIGHT);
lcd_putc("\BOOTING...\n");
delay_us(1);
for (a=0;a<8;a++) {
instate[0] =0;
}
output_Low(TX_ON);
output_Low(STATUS);
delay_ms(2000);
output_high(STATUS);
output_high(BCK_LIGHT);
ds1307_init();
in[0]=input(GIN1);
in[1]=input(GIN2);
in[2]=input(GIN3);
in[3]=input(GIN4);
in[4]=input(GIN5);
in[5]=input(GIN6);
in[6]=input(GIN7);
in[7]=input(GIN8);
send_to_i2c(0xA0, 0x00, in[0], in[1], in[2], in[3], in[4], in[5], in[6], in[7]);
clrsrcn();
output_high(BCK_LIGHT);
while(true) { //loop program
restart_wdt();
set_time();
if (chktime == 1) {
time();
chktime = 0;
}
if (print == 1) {
print = 0;
printf(lcd_putc,"\f%02d-%02d-%02d %02d:%02d",day,mth,year,hr,min);
printf(lcd_putc,"\nDoW %u; HBIT: ",dow);
}
if (print1 == 1) {
print1 = 0;
printf(lcd_putc,"\f%02d-%02d-%02d %02d:%02d",day,mth,year,hr,min);
printf(lcd_putc,"\nDoW %u; HBIT: *",dow);
}
if (requesti2c == 1) {
printf(lcd_putc,"\f%02d-%02d-%02d %02d:%02d",day,mth,year,hr,min);
printf(lcd_putc,"\nRS232->%u",capture[0]);
delay_ms(500);
i2c_start();
i2c_write(0xA0); //select address of device to communicate with
i2c_write(0x01); //send actual command
i2c_write(0x02); //send actual data
i2c_write(0x03); //send actual data
i2c_write(0x04); //send actual data
i2c_write(0x05); //send actual data
i2c_write(0x06); //send actual data
i2c_write(0x07); //send actual data
i2c_write(0x08); //send actual data
i2c_write(0x09); //send actual data
i2cread[0] = i2c_read(); // read data back from slave
i2c_stop();
printf(lcd_putc,"\f%02d-%02d-%02d %02d:%02d",day,mth,year,hr,min);
printf(lcd_putc,"\nI2C->%u",i2cread[0]);
delay_ms(500);
requesti2c = 0;
}
if (printrda == 1) {
//printf(lcd_putc,"\f%u,%u,%u,%u,%u,%u,%u,%u",capture[0],capture[1],capture[2],capture[3],capture[4],capture[5],capture[6],capture[7]);
printrda = 0;
}
inputs();
} //while
} //void |
_________________ Help "d" others and then you shell receive some help from "d" others. |
|
|
Linuxbuilders
Joined: 20 Mar 2010 Posts: 193 Location: Auckland NZ
|
|
Posted: Wed Feb 29, 2012 2:02 am |
|
|
...this is poorly a coding issue, 2 years ago I had it going , I cannot find my code then... if I find it sure I will post it. I scratch my head over this. I think I remember that need to emulate eeprom on slave pic. I remember it was tricky but was working well. Going over all files from 2009 - I may find it Thnx for any hints, will speed up work.
---
found something gives a hint:
Code: | #if defined(__PCM__)
#include <16F628A.h>
#include <ctype.h>
#include <stddef.h>
#include <string.h>
#use delay (clock=20000000) // oscillator frequency for delay_ms()
// Config: ext reset, no code protect, no watchdog, 20MHz int clock
#fuses MCLR,NOPROTECT,NOWDT,HS
#use rs232(baud=9600,parity=n,xmit=pin_B2,rcv=pin_B1,bits=8,stream=PC)
#use I2C(MASTER, scl=PIN_A0, sda=PIN_A1, stream=I2CM)
#use i2c(SLAVE, sda=PIN_B4, scl=PIN_B5, address=0xA0, force_hw, stream=I2CS)
#endif
//=========COMMS I2C============
//NOTE: Must declare MASTER before SLAVE, i2c_isr_state() returns 0
// when MASTER is the most recent #use i2c
int rcv_buf[0x10];
int wrt_buf[0x10];
int cmd=0xFF;
#int_spp // interrupt on i2c activity
void i2c_isr(void)
{
int state, incoming;
state = i2c_isr_state();
if(state < 0x80)
{
incoming = i2c_read(I2CS);
if (state == 1)
{
cmd = incoming;
}
else if (state > 1)
{
rcv_buf[state-2]=incoming;
}
}
else
{
i2c_write(I2CS,wrt_buf[state-0x80]);
}
}
//=========COMMS ENDS============ |
_________________ Help "d" others and then you shell receive some help from "d" others. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed Feb 29, 2012 11:35 pm |
|
|
Comments on Master code:
Quote: |
#use fixed_io(D_outputs=LCD_DB4,LCD_DB5,LCD_DB6,LCD_DB7,BCK_LIGHT,STATUS)
#use fixed_io(B_outputs=LCD_RS,LCD_RW)
|
You are using the lcd's r/w pin. This means the flex driver will read the
busy bit, which requires reading the LCD's data bus. This means you
should not set the LCD_DBx pins as "output only".
Quote: |
#int_RDA
void comms_rda(void) {
int c;
for (a=0;a<8;a++) {
c = getc();
capture[a] = c;
}
.
.
.
}
|
The getc() loop is a mistake. You should only get one character per
interrupt. What if your program receives less than 8 bytes ? It would
lock up the program, while waiting for an 8th byte that might never
arrive. Or, what if your program receives a 9th byte ? It would re-enter
the #int_rda interrupt routine and wait there, locking up your program.
Look at the CCS Ex_sisr.c example file for a better method.
Quote: |
#int_rda
void comms_rda(void) {
.
.
.
clear_interrupt(int_RDA);
}
|
The call to clear_interrupt() at the end is not necessary. The compiler
automatically inserts code to clear the RDA interrupt flag at the end of
the isr. Look at the .LST file (in Symbolic format) to see this.
Quote: |
#int_SSP
void comms_ssp(void) {
clear_interrupt(int_SSP);
}
|
Same thing here.
Also, you don't need SSP interrupts for an i2c master. Remove this
routine and also remove the enable_interrupts(INT_SSP) line.
Quote: |
void inputs(void) {
.
.
.
.
int link1=input(LK1);
int link2=input(LK2);
}
|
CCS doesn't support declaring variables at any place within a routine.
You should declare them only at the start of a routine.
Quote: |
i2c_start();
i2c_write(0xA0); //select address of device to communicate with
i2c_write(0x01); //send actual command
i2c_write(0x02); //send actual data
i2c_write(0x03); //send actual data
i2c_write(0x04); //send actual data
i2c_write(0x05); //send actual data
i2c_write(0x06); //send actual data
i2c_write(0x07); //send actual data
i2c_write(0x08); //send actual data
i2c_write(0x09); //send actual data
i2cread[0] = i2c_read(); // read data back from slave
i2c_stop();
|
0xA0 is an i2c slave address used by EEPROM chips. I wouldn't use it
for a PIC slave. What if you decide to add an external EEPROM later ?
Choose some other address for your PIC slave.
Your protocol shown above is not normal for an i2c Master that writes
to the slave and then reads from it. Look at any of the CCS driver
files for i2c eeproms, such as the 24256.c file. They do a re-start
to begin a read operation. They send the i2c read address. You're not
doing any of that. They also do a NACK on the last i2c read.
You're not doing that either.
I didn't look at your code completely. There could be other problems.
Your slave code has similar problems. |
|
|
jeremiah
Joined: 20 Jul 2010 Posts: 1349
|
|
Posted: Thu Mar 01, 2012 2:39 pm |
|
|
Some things I noticed about the slave code:
Code: |
void ssp_interupt(void) {
state = i2c_isr_state();
if(state < 0x80) { //master is sending data
/* I cut this part out for readability*/
if (buffer[1] == 0x01) { //command 0x00 -> send value of second timer
i2c_write(timerstep2);
}
if (state > 9) { //data
clear_interrupt(int_SSP);
}
}
if(state == 0x80) { //master is requesting data
//i2c_write (0xFF); //send requested data
}
}
|
1. Inside of the comparison state < 0x80 IF statement, you do an i2c_write(), which you should not be doing. You should only do a i2c_write() if your state is 0x80-0xFF
2. Inside of the comparison state == 0x80 IF statement, you do not do an i2c_read() which you should. The state 0x80 indicates that the address byte was sent with the "read/write" bit set to 0. You still have to read that before writing any data back.
Take a look at the example in the manual entry for i2c_isr_state(). It lists all the rules.
Also note that there is a bug (or maybe just an undocumented feature) with using i2c_isr_state(). If you use a data stream that is 128 bytes or longer, then on some compiler versions, you will get a 0x80 and higher for those bytes because the state counter keeps incrementing past 0x7f. If your data streams are always shorter than that, then you will never run into this. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Thu Mar 01, 2012 2:57 pm |
|
|
Quote: | found something gives a hint:
#include <16F628A.h>
#use rs232(baud=9600,parity=n,xmit=pin_B2,rcv=pin_B1,bits=8,stream=PC)
#use I2C(MASTER, scl=PIN_A0, sda=PIN_A1, stream=I2CM)
#use i2c(SLAVE, sda=PIN_B4, scl=PIN_B5, address=0xA0, force_hw, stream=I2CS)
|
Also, this code which you claim gives a hint, won't work at all for an i2c
slave. The 16F628A doesn't have an SSP or MSSP module. That means
there is no hardware i2c capability. That means it can't do an i2c slave
with the CCS #use i2c() library. |
|
|
Linuxbuilders
Joined: 20 Mar 2010 Posts: 193 Location: Auckland NZ
|
|
Posted: Thu Mar 01, 2012 10:58 pm |
|
|
Quote: | This means you
should not set the LCD_DBx pins as "output only". |
will do thnx
Quote: | The getc() loop is a mistake. |
this is test program to check if all circuit parts are working, main software will be different and much more sofisticated, I know that this bit is wrong, thnx
Quote: | The call to clear_interrupt() at the end is not necessary. |
good to know, thnx
Quote: | Also, you don't need SSP interrupts for an i2c master. Remove this
routine and also remove the enable_interrupts(INT_SSP) line. |
this is inherrited from trying to get it working, thnx for confirmation
Quote: | CCS doesn't support declaring variables at any place within a routine.
You should declare them only at the start of a routine. |
dirty code, thnx
Quote: | 0xA0 is an i2c slave address used by EEPROM chips. I wouldn't use it
for a PIC slave. What if you decide to add an external EEPROM later ?
Choose some other address for your PIC slave. |
good idea, thnx
Quote: | Your protocol shown above is not normal for an i2c Master that writes
to the slave and then reads from it. Look at any of the CCS driver
files for i2c eeproms, such as the 24256.c file. They do a re-start
to begin a read operation. They send the i2c read address. You're not
doing any of that. They also do a NACK on the last i2c read.
You're not doing that either. |
this I need to research, thnx _________________ Help "d" others and then you shell receive some help from "d" others. |
|
|
Linuxbuilders
Joined: 20 Mar 2010 Posts: 193 Location: Auckland NZ
|
|
Posted: Thu Mar 01, 2012 11:03 pm |
|
|
Quote: | 1. Inside of the comparison state < 0x80 IF statement, you do an i2c_write(), which you should not be doing. You should only do a i2c_write() if your state is 0x80-0xFF |
this comes for trying to get it working, how do I define the state itself? what in Master is actually telling slave that it is <80 or >80?
Quote: | 2. Inside of the comparison state == 0x80 IF statement, you do not do an i2c_read() which you should. The state 0x80 indicates that the address byte was sent with the "read/write" bit set to 0. You still have to read that before writing any data back. |
any example here? I am not entirely understand this bit.
Quote: | Take a look at the example in the manual entry for i2c_isr_state(). It lists all the rules. |
will do in a sec
Quote: | Also note that there is a bug (or maybe just an undocumented feature) with using i2c_isr_state(). If you use a data stream that is 128 bytes or longer, then on some compiler versions, you will get a 0x80 and higher for those bytes because the state counter keeps incrementing past 0x7f. If your data streams are always shorter than that, then you will never run into this. |
good to know, thnx _________________ Help "d" others and then you shell receive some help from "d" others. |
|
|
Linuxbuilders
Joined: 20 Mar 2010 Posts: 193 Location: Auckland NZ
|
|
Posted: Thu Mar 01, 2012 11:06 pm |
|
|
Quote: | Also, this code which you claim gives a hint, won't work at all for an i2c
slave. The 16F628A doesn't have an SSP or MSSP module. That means
there is no hardware i2c capability. That means it can't do an i2c slave
with the CCS #use i2c() library. |
this is some old code I have found in my archives, I am not surprised but the hint is that there is use of master and slave within the code.
Quote: | #use I2C(MASTER, scl=PIN_A0, sda=PIN_A1, stream=I2CM)
#use i2c(SLAVE, sda=PIN_B4, scl=PIN_B5, address=0xA0, force_hw, stream=I2CS) |
I have been reading about that before. I am not sure how much it is correct to use but people indicate that it works.
thnx _________________ Help "d" others and then you shell receive some help from "d" others. |
|
|
|
|
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
|