|
|
View previous topic :: View next topic |
Author |
Message |
PICmodule
Joined: 26 Oct 2021 Posts: 32
|
Problem with Silicon Errata on PIC24FJ128GA705 |
Posted: Tue Jun 20, 2023 6:49 am |
|
|
Hi,
I made a PCB based on the PIC24FJ128GA705 using I2C that is working with Raspberry Pi. We manufactured some hundreds of them and working perfectly. New production we done, used the same PIC24FJ128GA705 however seems different MARKING CODE. We realized that the I2C is not working. After a deep search, we decided that the problem is in the Silicon Errata on PIC24FJ128GA705.
https://ww1.microchip.com/downloads/aemDocuments/documents/MCU16/ProductDocuments/Errata/PIC24FJ256GA705-Family-Silicon-Errata-and-Data-Sheet-Clarification-DS80000718H.pdf
In order to avoid any misunderstanding, we de-soldered the microcontroller PIC24FJ128GA705 from the former (working well) boards and solder it to the new one and after that (with old microcontroller) works perfectly. Therefore this confirmed me that the reason is NOT PCB (it is exactly the same), but different LOT of micro controllers.
I'm trying to implement the Silicon Errata, but unsuccessfully because I do not have source of the i2c_isr_state and i2c_read
My Compiler Version is 5.115
I asked CCS info to provide it, but no luck.
Therefore I have 4 solutions:
1. Write from the scratch the new I2C Slave handler (difficult and take time for me).
2. Replace the i2c_isr_state and i2c_read by my (yours) own similar routines (this is what I m asking for).
3. Take the Microchip driver and convert to CCS (but their driver provided is very bad).
4. Use any ready and offered by you slave driver.
Any help would be very appreciated.
Below is simplified my I2C slave routine I'm using.
Code: |
///////////////////////////////////////////////////////////////////////////////
/// DEFAULT: 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F
/// NO_RTC: 0x69, 0x6B
/// ALTERNATE1: 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F
/// ALTERNATE2: 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F
///////////////////////////////////////////////////////////////////////////////
#INT_SI2C LEVEL=7
void normal_SI2C_isr(void)
{
unsigned int8 dummy;
static unsigned int8 incoming, state;
static unsigned int8 MatchAddress;
static unsigned int8 i2c_adr;
run_status.i2c_running++;
state=i2c_isr_state(RPI_I2C);
if(state <= 0x80) //Master is sending data
{
if(state == 0x80)
{
incoming = i2c_read(RPI_I2C); //Passing 2 as parameter, causes the function to read the SSPBUF without releasing the clock
}
else
{
incoming = i2c_read(RPI_I2C,2);
}
if(state == 1) //First received byte is address
i2c_adr = incoming;
if((state == 0) || (state == 0x80))
MatchAddress = incoming;
if(state >= 2 && state != 0x80) //Received byte is data
{
switch(MatchAddress)
{
case 0xd0: //0x68
if(i2c_adr<=sizeof((struct _rtc)-1))
rtc.buffer[i2c_adr++]=incoming;
if(i2c_adr==sizeof((struct _rtc)-1))
{
bcd_rtc_write();
rtc_rw_flag=WRITE;
}
break;
case 0xd2: //0x69
if(i2c_adr<=sizeof(struct _stat)-1)
{
stat.buffer[i2c_adr++] = incoming;
}
else
#asm
NOP;
#endasm
break;
case 0xd4: //0x6A
if(i2c_adr<=sizeof(struct _rtc)-1)
rtc.buffer[i2c_adr++] = incoming;
else
#asm
NOP;
#endasm
break;
case 0xd6: //0x6B
if(i2c_adr<=sizeof(struct _cmd)-1)
cmd.buffer[i2c_adr++] = incoming;
else
#asm
NOP;
#endasm
break;
case 0xd8: //0x6C
case 0xda: //0x6D
case 0xdc: //0x6e
case 0xde: //0x6F
if(i2c_adr<=2)
dummy=incoming;
else
#asm
NOP;
#endasm
break;
default:
break;
}
}
}
if(state >= 0x80) //RPi Master is requesting data
{
switch(MatchAddress)
{
case 0xd1: //0x68
if(i2c_adr<=sizeof(struct _rtc)-1)
i2c_write_slave(RPI_I2C, rtc.buffer[i2c_adr++]);
else
i2c_write(RPI_I2C, 0x00);
break;
case 0xd3: //0x69
if(i2c_adr<=sizeof(struct _stat)-1)
{
i2c_write_slave(RPI_I2C, stat.buffer[i2c_adr]);
slaveWriteData=picostat.buffer[i2c_adr];
i2c_adr++;
}
else
i2c_write_slave(RPI_I2C, 0x00);
break;
case 0xd5: //0x6A
if(i2c_adr<=sizeof(struct _rtc)-1)
{
i2c_write_slave(RPI_I2C, rtc.buffer[i2c_adr++]);
}
else
i2c_write_slave(RPI_I2C, 0x00);
break;
case 0xd7: //0x6B
slaveWriteData=0x6B;
if(i2c_adr<=sizeof(struct _cmd)-1)
{
i2c_write_slave(RPI_I2C, cmd.buffer[i2c_adr++]);
}
else
i2c_write_slave(RPI_I2C, 0x00);
break;
case 0xd9: //0x6C
case 0xdb: //0x6D
case 0xdd: //0x6E
case 0xdf: //0x6F
if(i2c_adr<=2)
i2c_write_slave(RPI_I2C, 0x00);
else
i2c_write_slave(RPI_I2C, 0x00);
break;
default:
break;
}
}
}
|
Thank you in advance for your help !! |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19503
|
|
Posted: Tue Jun 20, 2023 7:38 am |
|
|
First thing, what you post is very flawed. You are holding the bus when
it should not be held, and releasing it when it should be held.
Now a source for an extended I2C_ISR_state (designed to support
more than 256 bytes), was posted here (by me) a little while ago. Search
for i2c_isr_state16. If this is changed to use an int8 it gives the same code
as the supplied function.
Then, can you read the devid from the working and faulty chips? None
of the I2C errata apply to different versions. They all apply to all versions
of the chip, and checking with device editor, suggests that CCS have
already included fixes for the published errata. Two possibilities then
exist:
1) You have found a new erratum.
2) The chips you have are faulty.
I'd be very suspicious of the latter,
You should talk to Microchip, quoting the specific manufacture batch ID
and the devid. They may well simply replace the chips. |
|
|
PICmodule
Joined: 26 Oct 2021 Posts: 32
|
|
Posted: Tue Jun 20, 2023 8:58 am |
|
|
Hi,
My answer is in the text
First thing, what you post is very flawed. You are holding the bus when
it should not be held, and releasing it when it should be held.
What do you mean, I followed examples provided by CCS, as also this (exactly this) routine was working with previous batch of micro-controller. Can you please explain what I'm making wrong
Now a source for an extended I2C_ISR_state (designed to support
more than 256 bytes), was posted here (by me) a little while ago. Search
for i2c_isr_state16. if this is changed to use an int8 it gives the same code
as the supplied function.
OK, I found it and study it. Thank you
Then, can you read the devid from the working and faulty chips. None
of the I2C errata apply to different versions. They all apply to all versions
of the chip, and checking with device editor,
OK. I will check. However it is not possible that IC are faulty and ONLY I2C is not working properly. More precise the first red is always good (after reset), also if I decrease dramatically the internal oscillator from 32 MHz to 2 MHz seems to be working.
1) You have found a new erratum.
2) The chips you have are faulty.
I'd be very suspicious of the latter,
You should talk to Microchip, quoting the specific manufacture batch ID
and the devid. They may well simply replace the chips.
Ad (1) I checked and seems this errata is the latest one, however check again.
Ad (2) As all other functions are fine, difficult to me to believe that I2C1 is faulty in 750 ICs. All of them I bought from the Microchip directly, I have another 3000 pcs
Please answer to the first remark you made, made this is the problem
Thank you very much |
|
|
PICmodule
Joined: 26 Oct 2021 Posts: 32
|
|
Posted: Tue Jun 20, 2023 10:35 am |
|
|
I modified your function to 8bit
however the results are the same
Code: |
pi@rpi:~ $ sudo i2cget -y 1 0x69 0x38
0x4e
pi@rpi:~ $ sudo i2cget -y 1 0x69 0x38
0x02
pi@rpi:~ $ sudo i2cget -y 1 0x69 0x38
0x08
pi@rpi:~ $ sudo i2cget -y 1 0x69 0x38
0x20
pi@rpi:~ $ sudo i2cget -y 1 0x69 0x38
0x80
|
The first read is proper each next is faulty, on this processor, on former one all are good
Last edited by PICmodule on Tue Jun 20, 2023 10:38 am; edited 1 time in total |
|
|
PICmodule
Joined: 26 Oct 2021 Posts: 32
|
|
Posted: Tue Jun 20, 2023 10:37 am |
|
|
Can you please explain what do you mean with
First thing, what you post is very flawed. You are holding the bus when
it should not be held, and releasing it when it should be held.
This is working well with former processor, but not with current. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19503
|
|
Posted: Wed Jun 21, 2023 12:28 am |
|
|
You have the hold and release reversed:
Code: |
if(state <= 0x80) //Master is sending data
{
if(state == 0x80)
{
incoming = i2c_read(RPI_I2C); //Passing 2 as parameter, causes the function to read the SSPBUF without releasing the clock
}
else
{
incoming = i2c_read(RPI_I2C,2);
}
|
Now look at the CCS example:
Code: |
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();
|
You have it holding the clock on the transactions that don't want to hold
but not holding it on the one that does...
Exactly the opposite to what the example shows. |
|
|
PICmodule
Joined: 26 Oct 2021 Posts: 32
|
|
Posted: Wed Jun 21, 2023 1:06 am |
|
|
Hi,
I already corrected it in the mean time, but still not working. More specifically working in the former micro controller without any problem (both versions) and NOT working on the new batch.
Actually, checking the driver from Microchip that seems to be more stable on both micro controllers, today expect to be back to you with more details or even solution. Lets hope |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19503
|
|
Posted: Wed Jun 21, 2023 7:31 am |
|
|
OK.
Now if you study the errata, none of the I2C errata change between chip
versions, but a couple of the oscillator and CPU ones do.
Have you read the ID's.
What are the faulty chips actually doing?. I'm wondering if you have
perhaps got a problem like a slow rise time on the supply, and the chip
is actually triggering a brownout during boot, which is therefore causing
an issue if the new batch is one of the ones that does not correctly handle
the brownout reset. Have you got PUT enabled?. Have you got BROWNOUT
enabled?/ |
|
|
PICmodule
Joined: 26 Oct 2021 Posts: 32
|
|
Posted: Wed Jun 21, 2023 8:42 am |
|
|
Yes, the ID is the same on both batches 0x750B
If we use the CCS library, always the first read is proper after reset. ALWAYS.
Each next reading is damaged. In example first read is 0x4e, next is 0x02, then 0x08 etc. Doing Reset, again the first is 0x4e. I sent you simplified routine, without extra variables I m using for monitoring. Yes, it is next step to check OSC, this is what I'm using.
Quote: | #use delay(internal=32Mhz, pll_wait, AUX:crystal=32768Hz, clock=32768Hz, ACT=SOSC) |
I realized that if decrease the OSC to 4 or better 2 MHz system is much more stable, and can get more reads (practically always). However it is not a solution.
The controller have typed the following:
OLD and good
FJ128GA705 2125 BTY
NEW and bad
FJ128GA705 1752 1HR
So definitely are not the same.
Yes, I have in mind that OSC can be problematic, however all other functions are working properly, tested many many times
Currently I'm testing the Microchip Library, and seems to be more stable, basically stable in read (always the same) but can not do write yet. In next hours will share with you the results.
Totally crazy situation.
Thank you for your help. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19503
|
|
Posted: Wed Jun 21, 2023 10:28 am |
|
|
Remove the ACT section.
The 2016 datasheet removed this option from the FRC oscillator.
Try without, and see what happens. |
|
|
PICmodule
Joined: 26 Oct 2021 Posts: 32
|
|
Posted: Wed Jun 21, 2023 10:45 am |
|
|
yesss |
|
|
PICmodule
Joined: 26 Oct 2021 Posts: 32
|
|
Posted: Wed Jun 21, 2023 1:32 pm |
|
|
Hi,
I ran the same software on both PCBs (first on the good processor, and then on the bad processor) with different results
See below what I ran
Clock setup
Code: |
#use delay(internal=32MHz, AUX:crystal=32768Hz, clock=32768Hz)
|
Monitoring code
Code: |
sprintf(printdata,"\n\r I2C1CONL:%X I2C1CONH:%X I2C1STAT:%X I2C1TRN:%X i2c_running:%X", I2C1CONL, I2C1CONH, I2C1STAT, I2C1_TRANSMIT_REG, run_status.i2c_running); debug_printing();
sprintf(printdata,"\n\r\n\r ctr:%X slaveWriteData:%X slaveWriteData0:%X slaveWriteData1:%X", ctr, slaveWriteData, slaveWriteData0, slaveWriteData1); debug_printing();
I2C1STAT_reg=I2C1STAT;
sprintf(printdata,"\n\r\n\r I2C1STAT_reg.ACKSTAT: %U", bit_test(I2C1STAT_reg, 15)); debug_printing();
sprintf(printdata,"\n\r I2C1STAT_reg.TRSTAT: %U", bit_test(I2C1STAT_reg, 14)); debug_printing();
sprintf(printdata,"\n\r I2C1STAT_reg.ACKTIM: %U", bit_test(I2C1STAT_reg, 13)); debug_printing();
sprintf(printdata,"\n\r I2C1STAT_reg.BCL: %U", bit_test(I2C1STAT_reg, 10)); debug_printing();
sprintf(printdata,"\n\r I2C1STAT_reg.GCSTAT: %U", bit_test(I2C1STAT_reg, 9)); debug_printing();
sprintf(printdata,"\n\r I2C1STAT_reg.ADD10: %U", bit_test(I2C1STAT_reg, 8)); debug_printing();
sprintf(printdata,"\n\r I2C1STAT_reg.IWCOL: %U", bit_test(I2C1STAT_reg, 7)); debug_printing();
sprintf(printdata,"\n\r I2C1STAT_reg.I2COV: %U", bit_test(I2C1STAT_reg, 6)); debug_printing();
sprintf(printdata,"\n\r I2C1STAT_reg.D_A: %U", bit_test(I2C1STAT_reg, 5)); debug_printing();
sprintf(printdata,"\n\r I2C1STAT_reg.P_BIT: %U", bit_test(I2C1STAT_reg, 4)); debug_printing();
sprintf(printdata,"\n\r I2C1STAT_reg.S_BIT: %U", bit_test(I2C1STAT_reg, 3)); debug_printing();
sprintf(printdata,"\n\r I2C1STAT_reg.R_W: %U", bit_test(I2C1STAT_reg, 2)); debug_printing();
sprintf(printdata,"\n\r I2C1STAT_reg.RBF: %U", bit_test(I2C1STAT_reg, 1)); debug_printing();
sprintf(printdata,"\n\r I2C1STAT_reg.TBF: %U", bit_test(I2C1STAT_reg, 0)); debug_printing();
sprintf(printdata,"\n\r\n\r ",); debug_printing();
sprintf(printdata,"\n\r ",); debug_printing();
for(q=0; q<32; q++)
{
sprintf(printdata,"%2X ", EMULATE_EEPROM_Memory[q]); debug_printing();
restart_wdt();
}
sprintf(printdata,"\n\r ",); debug_printing();
for(q=0; q<32; q++)
{
sprintf(printdata,"%2X ", q); debug_printing();
restart_wdt();
}
sprintf(printdata,"\n\r -----------------------",); debug_printing(); |
and interrupt code
Code: |
#INT_SI2C NOCLEAR LEVEL=7
void normal_SI2C_isr(void)
{
unsigned int8 dummy;
static unsigned int8 incoming, state;
static unsigned int8 MatchAddress;
static unsigned int8 i2c_adr, adr_trn;
run_status.i2c_running++;
state=i2c_isr_state(RPI_I2C);
if(flags.bit.LPR_enter_mode==ON)
return;
if(state <= 0x80) //Master is sending data
{
if(state == 0x80)
{
incoming = i2c_read(RPI_I2C); //Passing 2 as parameter, causes the function to read the SSPBUF without releasing the clock
}
else
{
incoming = i2c_read(RPI_I2C,2);
}
EMULATE_EEPROM_Memory[ctr++]=incoming;
if(state == 1) //First received byte is address
i2c_adr = incoming;
adr_trn=i2c_adr;
if((state == 0) || (state == 0x80))
MatchAddress = incoming;
if(state >= 2 && state != 0x80) //Received byte is data
{
switch(MatchAddress)
{
case 0xd0: //0x68
if(i2c_adr<=sizeof((struct _rtc)-1))
rtc.buffer[i2c_adr++]=incoming;
if(i2c_adr==sizeof((struct _rtc)-1))
{
bcd_rtc_write();
rtc_rw_flag=WRITE;
}
break;
case 0xd2: //0x69
if(i2c_adr<=sizeof(struct _picostat)-1)
{
picostat.buffer[i2c_adr++] = incoming;
}
else
#asm
NOP;
#endasm
break;
case 0xd4: //0x6A
if(i2c_adr<=sizeof(struct _rtc)-1)
rtc.buffer[i2c_adr++] = incoming;
else
#asm
NOP;
#endasm
break;
case 0xd6: //0x6B
if(i2c_adr<=sizeof(struct _picocmd)-1)
picocmd.buffer[i2c_adr++] = incoming;
else
#asm
NOP;
#endasm
break;
case 0xd8: //0x6C
case 0xda: //0x6D
case 0xdc: //0x6e
case 0xde: //0x6F
if(i2c_adr<=2)
dummy=incoming;
else
#asm
NOP;
#endasm
break;
default:
break;
}
}
}
if(state >= 0x80) //RPi Master is requesting data
{
switch(MatchAddress)
{
case 0xd1: //0x68
if(i2c_adr<=sizeof(struct _rtc)-1)
i2c_write_slave(RPI_I2C, rtc.buffer[i2c_adr++]);
else
i2c_write(RPI_I2C, 0x00);
break;
case 0xd3: //0x69
if(adr_trn<=sizeof(buffer_Memory)-1)
{
slaveWriteData=adr_trn;
i2c_write_slave(RPI_I2C, picostat.buffer[adr_trn]);
slaveWriteData0=picostat.buffer[adr_trn];
adr_trn++;
slaveWriteData1=adr_trn;
}
else
i2c_write_slave(RPI_I2C, 0x00);
break;
case 0xd5: //0x6A
if(i2c_adr<=sizeof(struct _rtc)-1)
{
i2c_write_slave(RPI_I2C, rtc.buffer[i2c_adr++]);
}
else
i2c_write_slave(RPI_I2C, 0x00);
break;
case 0xd7: //0x6B
slaveWriteData=0x6B;
if(i2c_adr<=sizeof(struct _picocmd)-1)
{
i2c_write_slave(RPI_I2C, picocmd.buffer[i2c_adr++]);
}
else
i2c_write_slave(RPI_I2C, 0x00);
break;
case 0xd9: //0x6C
case 0xdb: //0x6D
case 0xdd: //0x6E
case 0xdf: //0x6F
if(i2c_adr<=2)
i2c_write_slave(RPI_I2C, 0x00);
else
i2c_write_slave(RPI_I2C, 0x00);
break;
default:
i2c_write_slave(RPI_I2C, 0x00);
break;
}
}
clear_interrupt(INT_SI2C);
}
|
I added some variables to monitor results. What I got:
GOOD processor
I2C1CONL:B3C0 I2C1CONH:0 I2C1STAT:8034 I2C1TRN:1 i2c_running:4
ctr:3 slaveWriteData:39 slaveWriteData0:1 slaveWriteData1:3A
I2C1STAT_reg.ACKSTAT: 1
I2C1STAT_reg.TRSTAT: 0
I2C1STAT_reg.ACKTIM: 0
I2C1STAT_reg.BCL: 0
I2C1STAT_reg.GCSTAT: 0
I2C1STAT_reg.ADD10: 0
I2C1STAT_reg.IWCOL: 0
I2C1STAT_reg.I2COV: 0
I2C1STAT_reg.D_A: 1
I2C1STAT_reg.P_BIT: 1
I2C1STAT_reg.S_BIT: 0
I2C1STAT_reg.R_W: 1
I2C1STAT_reg.RBF: 0
I2C1STAT_reg.TBF: 0
Stored incoming data
Code: | EMULATE_EEPROM_Memory[ctr++]=incoming; |
D2 38 D3
BAD Processor
I2C1CONL:B3C0 I2C1CONH:0 I2C1STAT:802D I2C1TRN:1 i2c_running:4
ctr:3 slaveWriteData:39 slaveWriteData0:1 slaveWriteData1:3A
I2C1STAT_reg.ACKSTAT: 1
I2C1STAT_reg.TRSTAT: 0
I2C1STAT_reg.ACKTIM: 0
I2C1STAT_reg.BCL: 0
I2C1STAT_reg.GCSTAT: 0
I2C1STAT_reg.ADD10: 0
I2C1STAT_reg.IWCOL: 0
I2C1STAT_reg.I2COV: 0
I2C1STAT_reg.D_A: 1
I2C1STAT_reg.P_BIT: 0
I2C1STAT_reg.S_BIT: 1
I2C1STAT_reg.R_W: 1
I2C1STAT_reg.RBF: 0
I2C1STAT_reg.TBF: 1
Stored incoming data
Code: | EMULATE_EEPROM_Memory[ctr++]=incoming; |
D2 38 D3
Now will decrease the clock to see |
|
|
PICmodule
Joined: 26 Oct 2021 Posts: 32
|
|
Posted: Wed Jun 21, 2023 1:40 pm |
|
|
same results (even worst - as also the first byte is wrong)
with
Code: | #use delay(internal=4MHz, AUX:crystal=32768Hz, clock=32768Hz) |
or
Code: | #use delay(internal=8MHz, AUX:crystal=32768Hz, clock=32768Hz) |
|
|
|
PICmodule
Joined: 26 Oct 2021 Posts: 32
|
|
Posted: Wed Jun 21, 2023 4:53 pm |
|
|
No way with CCS, and the worst is that I d not know why.
So implementing the Microchip handler, where at least I can read values via I2C.
Now implementing the writing, also.
Code: |
///////////////////////////////////////////////////////////////////////////////
/////////////// INTERRUPT SERVICE /////////////////////////
///////////////////////////////////////////////////////////////////////////////
//NOCLEAR, LEVEL=n, HIGH, FAST, ALT, CLR_FIRST
#INT_SI2C NOCLEAR LEVEL=7
void mcsi2c_interrupt()
{
unsigned int8 dummy;
static int1 prior_address_match = false;
static int1 not_busy = true;
// NOTE: The slave driver will always acknowledge
// any address match.
run_status.i2c_running++;
switch(i2c1_slave_state)
{
case S_SLAVE_IDLE:
case S_SLAVE_RECEIVE_MODE:
/* When at S_SLAVE_RECEIVE_MODE this mode there
will be two types of incoming transactions:
1. Data sent by master
2. A restart or start detection
But from the point of view of the firmware, there is
no difference between S_SLAVE_IDLE and S_SLAVE_RECEIVE_MODE
states, since the types of incoming transactions will be
the same so we share the code here.
*/
// case of 7-bit address detected
if(((I2C1_10_BIT_ADDRESS_ENABLE_BIT == 0) && (I2C1_DATA_NOT_ADDRESS_STATUS_BIT == 0))
|| // case of general address call detected
((I2C1_GENERAL_CALL_ENABLE_BIT == 1) && (I2C1_GENERAL_CALL_ADDRESS_STATUS_BIT == 1)))
{
if (I2C1_READ_NOT_WRITE_STATUS_BIT == 0)
{
// it is a write, go to receive mode
/*
switch(I2C1_RECEIVE_REG)
{
case 0xd0: //0x68 0x58 0x48
//case 0xb0:
//case 0x90:
MatchAddressWSet=0x68;
break;
case 0xd2: //0x69 0x59 0x49
//case 0xb2:
//case 0x92:
MatchAddressWSet=0x69;
break;
case 0xd4: //0x6A 0x5A 0x4A
//case 0xb4:
//case 0x94:
MatchAddressWSet=0x6A;
break;
case 0xd6: //0x6B 0x5B 0x4B
//case 0xb6:
//case 0x96:
MatchAddressWSet=0x6B;
break;
default:
//MatchAddressWSet=0xAA;
break;
}
*/
I2C1_StatusCallback(I2C1_SLAVE_RECEIVE_REQUEST_DETECTED);
// Receive the data if valid
I2C1_ReceiveProcess();
i2c1_slave_state = S_SLAVE_RECEIVE_MODE;
}
else
{
// read the receive register only when
// we are ready for the next transaction.
// this one is a dummy read
// it is a write, go to receive mode
/*
switch(I2C1_RECEIVE_REG)
{
case 0xd0: //0x68 0x58 0x48
//case 0xb0:
//case 0x90:
MatchAddressRGet=0x68;
break;
case 0xd2: //0x69 0x59 0x49
//case 0xb2:
//case 0x92:
MatchAddressRGet=0x69;
break;
case 0xd4: //0x6A 0x5A 0x4A
//case 0xb4:
//case 0x94:
MatchAddressRGet=0x6A;
break;
case 0xd6: //0x6B 0x5B 0x4B
//case 0xb6:
//case 0x96:
MatchAddressRGet=0x6B;
break;
default:
//MatchAddressRGet=0xAA;
break;
}
*/
dummy = I2C1_RECEIVE_REG;
// it is a read, go to transmit mode
I2C1_StatusCallback(I2C1_SLAVE_TRANSMIT_REQUEST_DETECTED);
// during this portion, the master is expecting the
// slave for a reply. So the returned status of
// the callback at this point cannot be used to
// delay the reply if needed.
// In other words, the slave has to reply to the master.
// Therefore, the transmit will be performed.
I2C1_TransmitProcess();
i2c1_slave_state = S_SLAVE_TRANSMIT_MODE;
}
}
else if
(
// CASE of 10 - bit high address detected
((I2C1_10_BIT_ADDRESS_ENABLE_BIT == 1) &&
(I2C1_DATA_NOT_ADDRESS_STATUS_BIT == 0)
))
{
if(I2C1_READ_NOT_WRITE_STATUS_BIT == 0)
{
// it is the detection of high byte address of
// 10 - bit address, go to detection of low byte address
prior_address_match = false;
i2c1_slave_state = S_SLAVE_LOW_BYTE_ADDRESS_DETECT;
}
else // IF (I2C1_READ_NOT_WRITE_STATUS_BIT == 1)
{
if(prior_address_match == true)
{
// it is the detection of high byte
// address of 10 - bit address, but the next
// transaction is read transaction (so it
// is a restart) .
// set the transmit REGISTER with the data
// to transmit then go to transmit mode
I2C1_StatusCallback (I2C1_SLAVE_TRANSMIT_REQUEST_DETECTED) ;
// during this portion, the master is expecting the
// slave FOR a reply. So the returned status of
// the callback at this point cannot be used to
// delay the reply IF needed.
// In other words, the slave has to reply to the master.
// Therefore, the transmit will be performed.
I2C1_TransmitProcess () ;
i2c1_slave_state = S_SLAVE_TRANSMIT_MODE;
}
else
{
// it is the detection of high byte address of
// 10 - bit address, but next transaction is a write.
// go to detection of low byte address
prior_address_match = false;
i2c1_slave_state = S_SLAVE_LOW_BYTE_ADDRESS_DETECT;
}
}
// dummy read is needed
dummy = I2C1_RECEIVE_REG;
}
// this IF statement is to make sure we only save incoming
// data when we are truly in receiving mode
if(i2c1_slave_state == S_SLAVE_RECEIVE_MODE)
{
// CASE of data received
if(I2C1_DATA_NOT_ADDRESS_STATUS_BIT == 1)
{
// check IF we are overflowing the receive buffer
if (I2C1_RECEIVE_OVERFLOW_STATUS_BIT != 1)
{
I2C1_ReceiveProcess();
not_busy = I2C1_StatusCallback(I2C1_SLAVE_RECEIVED_DATA_DETECTED);
}
else
{
// overflow detected!
// read the buffer to reset the buffer full flag
// and clear the overflow bit
// then DO nothing so the master
// will resend the data
dummy = I2C1_RECEIVE_REG;
I2C1_RECEIVE_OVERFLOW_STATUS_BIT = 0;
}
}
}
break;
CASE S_SLAVE_LOW_BYTE_ADDRESS_DETECT:
// Note that this state will only get
// executed when 10 - bit address is set
// we send receive request but we DO not actually know
// IF the next one is a data from master since the
// next one can be a restart with a transmit request.
// When that happens, the next state will take care of it.
// This is just the nature of i2c bus protocol.
not_busy = I2C1_StatusCallback(I2C1_SLAVE_10BIT_RECEIVE_REQUEST_DETECTED);
// set this flag to indicate we have
// full 10 - bit address detection
prior_address_match = true;
if(not_busy)
{
// dummy read is needed
dummy = I2C1_RECEIVE_REG;
}
i2c1_slave_state = S_SLAVE_RECEIVE_MODE;
break;
case S_SLAVE_TRANSMIT_MODE:
// this is the state where an ACK or NACK is expected
// to occur after the slave has placed data to the
// transmit REGISTER.
// IF the transaction was ACK'ed, more data needs to be sent
// IF the transaction was NACK'ed then we don't need to send
// more data
if (I2C1_ACKNOWLEDGE_STATUS_BIT == 0)
{
// prepare next data
I2C1_StatusCallback (I2C1_SLAVE_TRANSMIT_REQUEST_DETECTED) ;
// transmit more data
I2C1_TransmitProcess () ;
}
else //IF (I2C1_ACKNOWLEDGE_STATUS_BIT == 1)
{
// no more data to be sent so we go to idle state
i2c1_slave_state = S_SLAVE_IDLE;
}
break;
default:
// should never happen, IF we ever get here stay here forever
// while(1);
break;
}
I2C1_RELEASE_SCL_CLOCK_CONTROL_BIT = 1;
// clear the slave interrupt flag
clear_interrupt(INT_SI2C);
}
|
Code: | static unsigned int8 i2c1_slaveWriteData = 0xAA;
unsigned int1 I2C1_StatusCallback(I2C1_SLAVE_DRIVER_STATUS status)
{
// this emulates the slave device memory where data written to slave
// is placed and data read from slave is taken
static unsigned int8 address, addrByteCount;
static unsigned int1 addressState = true;
switch(status)
{
case I2C1_SLAVE_TRANSMIT_REQUEST_DETECTED:
// set up the slave driver buffer transmit pointer
I2C1_ReadPointerSet(&EMULATE_EEPROM_Memory[address]);
address++;
break;
case I2C1_SLAVE_RECEIVE_REQUEST_DETECTED:
addrByteCount = 0;
addressState = true;
//i2c_state_str='R';
// set up the slave driver buffer receive pointer
I2C1_WritePointerSet(&i2c1_slaveWriteData);
break;
case I2C1_SLAVE_RECEIVED_DATA_DETECTED:
slaveWriteData=0xAA;
if (addressState == true)
{
// get the address of the memory being written
if (addrByteCount == 0)
{
//address = (i2c1_slaveWriteData << 8) & 0xFF00;
addrByteCount++;
}
else if(addrByteCount == 1)
{
address = address | i2c1_slaveWriteData;
addrByteCount = 0;
addressState = false;
}
}
else if(addressState == false)
{
// set the memory with the received data
EMULATE_EEPROM_Memory[0] = 0xaa; //i2c1_slaveWriteData;
}
break;
case I2C1_SLAVE_10BIT_RECEIVE_REQUEST_DETECTED:
// do something here when 10-bit address is detected
// 10-bit address is detected
break;
default:
break;
}
return true;
} |
This is working on both processors, tomorrow should be ready also the writing hopefully |
|
|
PICmodule
Joined: 26 Oct 2021 Posts: 32
|
|
Posted: Thu Jun 22, 2023 4:09 pm |
|
|
I made finally procedure that is working fine for a read/write on both processors types
Code: | sudo i2cget -y 1 0x69 0x04 |
return 0x05
and after
Code: | sudo i2cset -y 1 0x69 0x04 0xaa |
return 0xaa
Code: |
/*
Function Name: SI2C1Interrupt
Description : This is the ISR for I2C1 Slave interrupt.
Arguments : None
*/
//NOCLEAR, LEVEL=n, HIGH, FAST, ALT, CLR_FIRST
#INT_SI2C NOCLEAR LEVEL=7
void MCSI2C1Interrupt(void)
{
unsigned int8 dummy; //used for dummy read
static unsigned int8 MatchAddress;
static unsigned int8 i2c_adr;
static unsigned int8 i2c_data;
run_status.i2c_running++;
if((I2C1_READ_NOT_WRITE_STATUS_BIT == 0)&&(I2C1_DATA_NOT_ADDRESS_STATUS_BIT == 0)) //Address matched
{
MatchAddress = I2C1_RECEIVE_REG; //dummy read
AddrFlag = 1; //next byte will be address
}
if((I2C1_READ_NOT_WRITE_STATUS_BIT == 0)&&(I2C1_DATA_NOT_ADDRESS_STATUS_BIT == 1)) //check for data
{
if(AddrFlag)
{
AddrFlag = 0;
DataFlag = 1; //next byte is data
i2c_adr=I2C1_RECEIVE_REG;
I2C1_RELEASE_SCL_CLOCK_CONTROL_BIT = 1; //Release SCL1 line
}
else if(DataFlag)
{
i2c_data = (unsigned int8)I2C1_RECEIVE_REG; // store data into RAM
AddrFlag = 0; //end of tx
DataFlag = 0;
EMULATE_EEPROM_Memory[i2c_adr]=i2c_data;
I2C1_RELEASE_SCL_CLOCK_CONTROL_BIT = 1; //Release SCL1 line
}
}
if((I2C1_READ_NOT_WRITE_STATUS_BIT == 1)&&(I2C1_DATA_NOT_ADDRESS_STATUS_BIT == 0))
{
dummy = I2C1_RECEIVE_REG;
I2C1_TRANSMIT_REG = EMULATE_EEPROM_Memory[i2c_adr]; //i2c_data; //Read data from RAM & send data to I2C master device
I2C1_RELEASE_SCL_CLOCK_CONTROL_BIT = 1; //Release SCL1 line
while(I2C1_TRANSMITTER_BUFFER_STATUS_BIT); //Wait till all
}
I2C1_RELEASE_SCL_CLOCK_CONTROL_BIT = 1; //Release SCL1 line
clear_interrupt(INT_SI2C);
}
|
Can anyone comment it.
However this is not working when doing
Code: | sudo i2cget -y 1 0x69 0x04 w |
return 0xff05
and here I do not know why, any ideas ? |
|
|
|
|
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
|