|
|
View previous topic :: View next topic |
Author |
Message |
webgiorgio
Joined: 02 Oct 2009 Posts: 123 Location: Denmark
|
pic i2c slave is "not found" |
Posted: Sat Nov 06, 2021 1:02 pm |
|
|
Hi,
I have a PIC16F1789 (slave) connected with i2c to a ESP32.
Both running at 3.3V.
2.2k pull-ups on i2c.
Compiler 5.034.
On the ESP32 I have a i2c scanner code, which works (if I add a i2c device to the bus like a PCF8574 it is detected).
The PIC does not want to work, even though the code is very similar to the CCS example.
Code: |
#include <16F1789.h>
#fuses INTRC_IO, NOLVP, PUT, NOPROTECT //INTRC_IO to be able to use A7 and A6 as GPIO
#use delay(clock=8M) //8M or 8000000
#bit INTF_BIT = 0x0B.1 //corrects something that makes int I/O to work
//pin definitions
#use rs232(baud=19200, xmit=PIN_C6, rcv=PIN_C7)
//#use i2c(Slave,Fast,sda=PIN_C4,scl=PIN_C3,address=0xA0)
//#use i2c(Slave,sda=PIN_C4,scl=PIN_C3,address=0xA0)
#use i2c(SLAVE, I2C1, address=0xA0)
unsigned int8 address, buffer[16];
#INT_SSP
void ssp_interrupt(){
unsigned int8 incoming, state;
state = i2c_isr_state();
if(state <= 0x80) //Master is sending data
{
if(state == 0x80)
incoming = i2c_read(2); //Passing 2 as parameter, causes the function to read the SSPBUF without releasing the clock
else
incoming = i2c_read();
if(state == 1) //First received byte is address
address = incoming;
else if(state >= 2 && state != 0x80) //Received byte is data
buffer[address++] = incoming;
}
if(state >= 0x80) //Master is requesting data
{
i2c_write(buffer[address++]);
}
}
void main(){
enable_interrupts(GLOBAL);
enable_interrupts(INT_SSP);
while(TRUE){
}
}
|
|
|
|
webgiorgio
Joined: 02 Oct 2009 Posts: 123 Location: Denmark
|
|
|
webgiorgio
Joined: 02 Oct 2009 Posts: 123 Location: Denmark
|
|
Posted: Sat Nov 06, 2021 3:40 pm |
|
|
I tested the PIC as a master with a slave i2c display. It works. So my hardware is ok, even though I tested it at 5V, while my slave application need to work at 3.3V.
I read that working at 3.3V could be a problem for i2c, but the option #use i2c(....SMBUS) should fix that.
I run the same setup at 3.3V (simply moving the jumper inside the ICD U64), and it works (I had to adjust the contrast on the display, where I can barely see the text).
Still as a slave, I can't figure what's wrong. A compiler bug? I've an old version 5.034 |
|
|
jeremiah
Joined: 20 Jul 2010 Posts: 1358
|
|
Posted: Sat Nov 06, 2021 4:58 pm |
|
|
I don't recall off the top of my head if the #use spi() uses an 8bit or 7bit address. You might try adjusting the address for the other format. So for example, if the 8bit address representation is 0xA0 then try 0x50 on the PIC side as the 7bit representation. Also I seem to remember some I2C addresses are reserved by the I2C standard (I *think*), but I don't recall which. You might check into that as the internal PIC slave hardware may not allow some addresses (and that wouldn't show up if tested as a master as it's just sent as data and not part of the hardware like the slave is). |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sun Nov 07, 2021 12:07 am |
|
|
webgiorgio wrote: |
I lowered the address to 0x33 (i2c scanner goes to 127 max).
|
What does this mean ? Did you put 0x33 in the PIC's #use i2c()
statement as the slave address ? That's not allowed. The PIC's
slave address must be even.
I suspect your ESP32 device uses 7-bit i2c addresses.
CCS uses 8-bit addresses. So if the ESP32 is setup to talk to a slave
at address 0x50, the PIC should be configured for address=0xA0.
Also, what is the speed of the ESP32 in MIPS ? I suspect it's high.
Your PIC is only running at 2 MIPS. It's better if the PIC slave runs
faster than the master. Try running your PIC at 32 MHz. This will
give 8 MIPS. It still might not be fast enough, depending on the
speed of the ESP32.
Edit: Fixed a typo. I meant "if the ESP32 is setup to talk".
I have fixed that typo above.
Last edited by PCM programmer on Sun Nov 07, 2021 8:03 am; edited 1 time in total |
|
|
webgiorgio
Joined: 02 Oct 2009 Posts: 123 Location: Denmark
|
|
Posted: Sun Nov 07, 2021 4:25 am |
|
|
To my understanding the R/W bit is the LSB.
So if A0 is the read address, A1 is the write address.
The i2c scanner program on the ESP32 is using a "for" loop where the address is incremented from 1 to 127 decimal. So that is the "7 bit address", and is able to go trough all possible read addresses (LSB=0).
Anyway, I have set the PIC address to 0xA0.
Code: | #use i2c(SLAVE, sda=PIN_C4, scl=PIN_C3, address=0xA0, SMBUS, FAST=100000)
|
I've set the PIC to run at 32 MHz.
ESP32 is going at 240 MHz. I've tested also 20 MHz and 10 MHz. I still get no response from the PIC.
ESP32 has something like 400 MIPS. I've set in both slave and master to use a bus speed of 100 kbit/s. Can the CPU speed be an issue? at the end the bus is going at 100 kbit/s speed. |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9246 Location: Greensville,Ontario
|
|
Posted: Sun Nov 07, 2021 6:04 am |
|
|
random thoughts..
1) Since the ESP32(Master) sees the PCF8574(Slave), reprogram the PIC with the same address as the PCF8574. The ESP32 scanner program should now see the PIC. If it doesn't, post the ESP32 scanner program, maybe there's something 'weird' going on,that isn't obvious.
2) The PIC clock should be very fast compared to the I2C bus speed. This allows it to 'do stuff as needed' between I2C bus activity. It's not that the ESP32 clock speed vs PIC that matters, well shouldn't be. There is 'overhead' in any ISR,not just the handler code, and the PIC needs time for that. The faster the clock, the quicker it gets done...
My 'gut' says it's something silly, like the adrs being left shifted one extra position...
Going to be nice to see 'solved' and WHAT the problem was, hopefully before you've gone bald.... |
|
|
webgiorgio
Joined: 02 Oct 2009 Posts: 123 Location: Denmark
|
|
Posted: Sun Nov 07, 2021 2:03 pm |
|
|
I did more testing. I removed the ESP32 to take a variable out of the question.
I wired up two PIC16F1789, 5V, one as a slave, and one as i2c scanner.
The scanner works, as I can detect a i2c display if hooked to the bus at 7E.
The slave PIC however is not found.
I even tried to give the slave the address 7E, but is not found anyway.
So the problem is in the slave program.
It does not enter the interrupt. Shall I try with i2c_poll() ?
Code: | /*
i2c slave
*/
#include <16F1789.h>
#fuses INTRC_IO, NOLVP, PUT, NOPROTECT //INTRC_IO to be able to use A7 and A6 as GPIO
#use delay(clock=32M) //8M or 8000000
//#bit INTF_BIT = 0x0B.1 //corregge qualcosa del compilatore per far funzionare int I/O
//pin definitions
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)
//#use i2c(Slave,Fast,sda=PIN_C4,scl=PIN_C3,address=0xA0)
#use i2c(Slave,sda=PIN_C4,scl=PIN_C3,address=0x10)
//#use i2c(SLAVE, sda=PIN_C4,scl=PIN_C3, address=0xA0, SMBUS, FAST=100000)
unsigned int8 address, buffer[16];
#INT_SSP
void ssp_interrupt(){
output_toggle(PIN_C2);
unsigned int8 incoming, state;
state = i2c_isr_state();
if(state <= 0x80) //Master is sending data
{
if(state == 0x80)
incoming = i2c_read(2); //Passing 2 as parameter, causes the function to read the SSPBUF without releasing the clock
else
incoming = i2c_read();
if(state == 1) //First received byte is address
address = incoming;
else if(state >= 2 && state != 0x80) //Received byte is data
buffer[address++] = incoming;
}
if(state >= 0x80) //Master is requesting data
{
i2c_write(buffer[address++]);
}
}
void main(){
enable_interrupts(INT_SSP);
enable_interrupts(GLOBAL);
printf(" Boot i2c slave \n");
while(TRUE){
delay_ms(1);
}
}
|
Code: | /*
i2c scanner
*/
#include <16F1789.h>
#fuses INTRC_IO,NOWDT,NOPROTECT,PUT,NOLVP,NOBROWNOUT
#use delay(clock=32M)
#use i2c(Master, sda=PIN_C4, scl=PIN_C3)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, ERRORS)
// This function writes the slave address to the i2c bus.
// If a slave chip is at that address, it should respond to
// this with an "ACK". This function returns TRUE if an
// ACK was found. Otherwise it returns FALSE.
int8 get_ack_status(int8 address){
int8 status;
i2c_start();
status = i2c_write(address); // Status = 0 if got an ACK
i2c_stop();
if(status == 0)
return(TRUE);
else
return(FALSE);
}
//=================================
void main(){
unsigned int8 i;
unsigned int8 status;
printf("\n\rStart i2c scanner:\n\r");
while(1){
// Try all slave addresses from 0x10 to 0xEF.
// See if we get a response from any slaves
// that may be on the i2c bus.
for(i=0x10; i < 0xF0; i+=2)
{
status = get_ack_status(i);
if(status == TRUE)
{
printf("ACK addr: %X\n\r", i);
delay_ms(2000);
}
}
if(count == 0)
printf("\n\rNothing Found");
output_toggle(PIN_C2);
delay_ms(2000);
}
} |
|
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sun Nov 07, 2021 11:37 pm |
|
|
There are some differences in the .LST file code between vs. 5.034
and vs. 5.104.
vs. 5.034: Code in #int_ssp
Code: |
....... incoming = i2c_read();
0062: MOVLB 04
0063: BCF SSP1CON1.SSPOV
0064: MOVLB 00
0065: BTFSS PIR1.SSP1IF
0066: GOTO 065
0067: MOVLB 04
0068: MOVF SSP1BUF,W
0069: BSF SSP1CON1.CKP
006A: MOVLB 00
006B: MOVWF incoming
|
vs. 5.104: Code in #int_ssp
Code: |
....... incoming = i2c_read();
0062: MOVLB 04
0063: BCF SSP1CON1.SSPOV
0064: BTFSS SSP1STAT.BF // Tests BF instead of SSP1IF
0065: GOTO 064
0066: MOVF SSP1BUF,W
0067: BSF SSP1CON1.CKP
0068: MOVLB 00
0069: MOVWF incoming
|
vs. 5.034: Init code in main()
Code: |
0131: MOVLW 36
0132: MOVWF SSP1CON1
0133: BSF SSP1CON2.SEN
|
vs. 5.104: Init code in main()
Code: |
012F: MOVLW 36
0130: MOVWF SSP1CON1
0131: BSF SSP1CON2.SEN
0132: BSF SSP1CON2.GCEN // Sets GCEN bit
|
vs. 5.034:
Code: |
...... i2c_write(buffer[address++]);
0087: MOVF address,W
0088: INCF address,F
0089: ADDLW buffer+-32
008A: MOVWF FSR0L
008B: MOVLW buffer+-9
008C: MOVWF FSR0H
008D: BTFSC STATUS.C
008E: INCF FSR0H,F
008F: MOVF INDF0,W
0090: MOVWF @@42
0091: MOVF @@42,W
0092: MOVWF i2c_wrt_data
0093: MOVLB 04
0094: MOVF SSP1BUF,W
0095: MOVLB 00
0096: MOVF i2c_wrt_data,W
0097: MOVLB 04
0098: MOVWF SSP1BUF
0099: BSF SSP1CON1.CKP
009A: MOVLB 00
009B: BCF PIR1.SSP1IF
009C: MOVLB 04
009D: BTFSC SSP1STAT.BF
009E: GOTO 09D
009F: CLRF @78
00A0: BTFSC SSP1CON1.CKP
00A1: INCF @78,F
00A2: MOVLB 00
|
vs. 5.104:
Code: |
...... i2c_write(buffer[address++]);
0085: MOVF address,W
0086: INCF address,F
0087: ADDLW buffer+-32
0088: MOVWF FSR0L
0089: MOVLW 20 // Instead of buffer-9 it uses 0x20
008A: MOVWF FSR0H
008B: BTFSC STATUS.C
008C: INCF FSR0H,F
008D: MOVF INDF0,W
008E: MOVWF @@42
008F: MOVF @@42,W
0090: MOVWF i2c_wrt_data
0091: MOVLB 04
0092: MOVF SSP1BUF,W
0093: MOVLB 00
0094: MOVF i2c_wrt_data,W
0095: MOVLB 04
0096: MOVWF SSP1BUF
0097: BSF SSP1CON1.CKP
0098: MOVLB 00
0099: BCF PIR1.SSP1IF
009A: MOVLB 04
009B: BTFSC SSP1STAT.BF
009C: GOTO 09B
009D: CLRF @78
009E: BTFSS SSP1CON2.ACKSTAT // It tests ACKSTAT vs. CKP
009F: INCF @78,F
00A0: MOVLB 00
|
|
|
|
webgiorgio
Joined: 02 Oct 2009 Posts: 123 Location: Denmark
|
|
Posted: Mon Nov 08, 2021 3:43 am |
|
|
Hi,
thanks for investigating.
Are those differences something that I can fix in my source code? How?
Could you send the .hex file of the slave, to test?
Last edited by webgiorgio on Tue Nov 09, 2021 3:45 am; edited 1 time in total |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Mon Nov 08, 2021 10:25 am |
|
|
Here is the i2c slave hex file for CCS vs. 5.104:
Code: |
:060000008031142900000C
:0800080083018031200077081C
:10001000A0007808A1007908A2007A08A3002300B4
:1000200011082000A400230012082000A5002300CE
:1000300013082000A600230014082000A700850153
:1000400091308400801D262891193F282008F70050
:100050002108F8002208F9002308FA0024082300E8
:10006000910020002508230092002000260823008C
:10007000930020002708230094000900200080310D
:10008000412821000E11043022008E062400941A0B
:1000900051282000B9012400141D51282000B9174F
:1000A000240020003908B90AC1004108803C031C23
:1000B00081284108803C031D62282400110820008B
:1000C000C0006A2824001513141C64281108151692
:1000D0002000C000410B6F284008A800812841087B
:1000E000013C031881284108803C03198128280815
:1000F000A80A093E8400203085000318850A4008BC
:10010000800041087F3C0318A1282808A80A093E5E
:100110008400203085000318850A0008C2004208C8
:10012000C300240011082000430824009100151684
:1001300020009111240014189B28F801161FF80ABA
:1001400020009111803126282021EF377410691981
:1001500063107336613B65100A000B088B13230094
:100160009517151400000000891B8B1713087F39A1
:100170000319FB282000BD00230011082000BE0049
:10018000230012082000BF003D08111EC5282300CF
:100190009A0020003E082300910020003F08230021
:1001A00092000B088B139517151400000000891B93
:1001B0008B17130D140D7F390319FB282000BD0088
:1001C000230011082000BE00230012082000BF00F9
:1001D0003D08111EE92823009A0020003E08230054
:1001E000910020003F0823009200910A0319920A0F
:1001F0002000AD282300803120004C2920308500CC
:100200001C3084000008031912290A30F800F70195
:10021000F70B0829F80B07295F30F700F70B0E29B9
:10022000800B052980314F29F030210099002300EF
:100230009F1540309B0003309C00A6309E009030FC
:100240009D0022001D129D1121008E150E16240006
:1002500017109710971110309200FF30930036302E
:1002600095001614961703302000B900BB01BA019F
:1002700023008C018D018E018F01900122009201DB
:10028000910121009115C0308B04A430230091000E
:10029000003092002000AD280130BC00FE284C291F
:0202A0006300F9
:020000040001F9
:04000E00C43FFF1ECE
:00000001FF
;PIC16F1789
;CRC=023D CREATED="08-Nov-21 08:11"
|
|
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19552
|
|
Posted: Mon Nov 08, 2021 11:52 am |
|
|
The i2c_read code changes don't matter (the older compiler is
wasting one instruction by selecting the bank twice).
The initialisation may, so probably worth manually setting the GCEN
bit,
For the write, try coding as:
Code: |
int temp;
temp=buffer[address++];
i2c_write(temp);
|
It looks as if the .034 compiler is not correctly addressing the array
read inside the function call. |
|
|
webgiorgio
Joined: 02 Oct 2009 Posts: 123 Location: Denmark
|
|
Posted: Tue Nov 09, 2021 4:07 am |
|
|
It works with the file compiled by PCM programmer!
With my compiler version it does not enter the ssp_interrupt() (no Led toggle), so the code inside does not matter.
I think I will download the demo of the latest copiler version.
How do I set the GCEN bit? |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19552
|
|
Posted: Tue Nov 09, 2021 4:25 am |
|
|
Code: |
#bit GCEN=getenv("BIT:GCEN")
//then
GCEN=1; //sets the bit
|
I wouldn't worry about this though, try with the temporary variable for
the array access first. All this bit affects is whether the chip will respond
to a 'general call' (address 0). |
|
|
webgiorgio
Joined: 02 Oct 2009 Posts: 123 Location: Denmark
|
|
Posted: Tue Nov 09, 2021 9:21 am |
|
|
Here is the code I modified according to the suggestions,
It doesn't work.
Code: | /*
i2c slave
*/
#include <16F1789.h>
#fuses INTRC_IO, NOLVP, PUT, NOPROTECT //INTRC_IO to be able to use A7 and A6 as GPIO
#use delay(clock=32M) //8M or 8000000
#bit GCEN=getenv("BIT:GCEN")
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)
#use I2C(slave,sda=PIN_C4,scl=PIN_C3,address=0x10)
unsigned int8 address, buffer[16];
int temp;
//---------------------------------------
#INT_SSP
void ssp_interrupt(){
output_toggle(PIN_C2);
unsigned int8 incoming, state;
state = i2c_isr_state();
if(state <= 0x80) //Master is sending data
{
if(state == 0x80)
incoming = i2c_read(2); //Passing 2 as parameter, causes the function to read the SSPBUF without releasing the clock
else
incoming = i2c_read();
if(state == 1) //First received byte is address
address = incoming;
else if(state >= 2 && state != 0x80) //Received byte is data
buffer[address++] = incoming;
}
if(state >= 0x80) //Master is requesting data
{
//i2c_write(buffer[address++]);
int temp;
temp=buffer[address++];
i2c_write(temp);
}
}
//------------------------------
void main(){
enable_interrupts(INT_SSP);
enable_interrupts(GLOBAL);
printf(" Boot i2c slave \n");
//i2c_init(TRUE);
//setup_spi(TRUE);
GCEN=1; //sets the bit
output_high(PIN_C2);
delay_ms(1000);
output_low(PIN_C2);
while(TRUE){
//delay_ms(1);
}
}
|
|
|
|
|
|
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
|