Skip to main content
Topic: [fixed CODE added]PIC16F182x as I2C slave bulk read problems (Read 3420 times) previous topic - next topic

[fixed CODE added]PIC16F182x as I2C slave bulk read problems

I've been working on the Bus Pirate Demo Board v5...it features a PIC16f that emulates varius different ICs such as I2C EEProms, ADCsm DAC etc...

and I'm stuck on the I2C EEPROM :( Ii emmulates 24LC type single byte adressed EEPROMS (so 256 bytes of space)
I got it to work fine for single and bulk writes...while the Read operations only work in singles...bulk read always returns giberish for all the data flowing the first byte...

Does anyone have a working example of a I2C slave configured PIC that supports bulk reads....(using HW MSSP module)..
Here's the code...
Code: [Select]
void initI2C(void)
{

    // init I2C slave, 7bit address, 100KHz
   
SSP2BUF=0x00;          // clear buffer
    SSP2STAT=0x80;          // 100KHZ
    SSP2MSK=I2CADDMASK;    // and mask; this will allow multiple instances
    SSP2CON1=0x36;          // SSP1EN|!clockstretching|7bit mode /w int
    SSP2CON3|=0b11000000;
}


// main loop + statemachine
// EEPROM
void I2CEEworker(void)
{ unsigned char token, addr, temp, addressed,ff;

addr=0x00;
addressed=0;


    SSP2ADD=I2CADDEE; // Set slave addres
SSP2CON1bits.SSPEN=1;
    while(1)
    {
        //i2c state machine
        if(SSP2IF)
        {
token=SSP2STAT&I2CSTATMASK;

            if(SSP2STATbits.S) // start condition

            {
LED1ON;

switch(token)
                {
                    case MWA:              // master write address
                        temp=SSP2BUF; // temp holds I2Caddress
                        break;
                    case MWD:              // master write data
                        if(!addressed)
{
addr=SSP2BUF;
addressed=1;
}
else
{
eeBuf[addr++]=SSP2BUF;
}
                        break;
                    case MRA:              // master read addres
                        temp=SSP2BUF;
I2CWrite(eeBuf[addr]);
break;
                    case MRD:              // master read data
                        if(!addressed)
{
temp=SSP2BUF;
I2CWrite(eeBuf[addr++]);
addressed =1;
}
else
{
I2CWrite(eeBuf[addr++]);
}
                        break;
                }
            }
            else if(SSP2STATbits.P) // STOP condition
            { LED1OFF;
addressed=0;
                asm("NOP");
            }
            SSP2IF=0;
            //SSP2CON1bits.SSPEN=1;
            /*if(token!=MRD)*/SSP2CON1bits.CKP=1; //release SCL line
        }
    }
}


// outputs a byte on the bus and releases the clk line
void I2CWrite(unsigned char c)
{
    do
    {
        SSP2CON1bits.WCOL=0;
        SSP2BUF=c;
    } while(SSP2CON1bits.WCOL);
    SSP2CON1bits.CKP=1; // release SCL line
}

best regards FIlip.

Re: PIC16F182x as I2C slave bulk read problems

Reply #1
The check if we got an address isn't necessary for reading as we already got a memory address. (you set the address by the last write command or it is zero)

I guess the I2CWrite in the MRA state is goofing up. I think if you leave it out (you dont need to send anything back when you are addressed) it will work.

consider the BP commando:

Code: [Select]
[ 0xA1 rr

After [ 0xA1 the MRA state is entered, the subsequent read are handled in the MRD state.

Re: [Solved]PIC16F182x as I2C slave bulk read problems

Reply #2
According to the Pics datasheet, as soon as you enter the address the slave needs to respond with a transmit...Yeah this is a problem to tweak it to work correctly, for now I got it to work with bulk reads but it sometimes skips a byte, or reads the same byte twice depending on the version of the I2C slaveI was running..

*anyway the above help request was for it to start working at all, and I figured out it's impossible with the BPv3 as it doesn't support clock stretching. Once I switched to the BPv4 it worked like a charm after a few tweaks, still have to get it to work constantly....

I'll post the full code here, once I get it buttoned up...
best regards FIlip.

Re: [fixed CODE added]PIC16F182x as I2C slave bulk read prob

Reply #3
Ok after some seriously long fight with a BPv3 bpv4, my measuring equpment, soldeing eqipment I finaly got the thing to work perfectly...

First thing for it to work with BPv3 the clock needs to be set to 32Mhz...[thanks Sjaak]

This is the basic code for I2C slave EEPROM emulation...

few notes...
*fill the eeBuf buffer at start  up in main from the EEPROM....
*from the start signal up to the stop signal only the eeBuf buffer is used, once a stop signal is recived, any bytes writen to the buffer are transferred to the EEPROM...reading is done only through the buffer...


I2C setup
Code: [Select]
void initI2C(void)

    // init I2C slave, 7bit address, 100KHz
 
    SSP2BUF=0x00;          // clear buffer
    SSP2STAT=0x80;          // 100KHZ
    SSP2MSK=I2CADDMASK;    // and mask; this will allow multiple instances
    SSP2CON1=0x36;          // SSP1EN|!clockstretching|7bit mode /w int
    SSP2CON3|=0b11000000; //ACK on, STOP interupt on
}


I2C worker CODE

Code: [Select]
void I2CEEworker(void)

unsigned char token,i, addr=0, temp=0, addressed=0,w=0;
 
 
  SSP2ADD=I2CADDEE;      // Set slave addres
  SSP2CON1bits.SSPEN=1;
  while(1)
  {
//i2c state machine
      if(SSP2IF) //waiting for interrupt (MWA,MWD,MRA,MRD, stop) no Start
      { 
      SSP2IF=0; //clearing the interrupt
token=SSP2STAT&I2CSTATMASK;
        if(SSP2STATbits.S)            // start condition
        { 
        LED1ON;
            switch(token)
            {
            case MWA:              // master write address
              temp=SSP2BUF;      // clears te BF flag
                  break;
              case MWD:              // master write data
              if(!addressed) //check if first byte
                  { 
                  addr=SSP2BUF; //recived data is moved to the EE address pointer
                    addressed=1; //flags that addres has been stored
                  }
                  else
                  { //if this is the second byte writes data to buffer
                  eeBuf[addr++]=SSP2BUF;
w++; //counts the number of bytes stored in the buffer
                  }
                  break;
case MRA:              // master read addres
                  temp=SSP2BUF; //clears the BF flag
SSP2BUF = eeBuf[addr++]; //sets up the first byte for transmision
                  break;
case MRD:              // master read data
temp=SSP2BUF; //clears the BF flag,
//adds new data to the buffer if ACD recived on previus transmision
if(SSP2CON2bits.ACKSTAT==0)SSP2BUF=eeBuf[addr++]; //subsequent transmision
break;
}
}
        else if(SSP2STATbits.P)        // STOP condition
        { 
LED1OFF;
            addressed=0; //clears the first byte write flag
if(w>0) //if data was writen to the buffer
{ //moves that data to the EEPROM
for(i=addr-w;i<addr-1;i++)
{
EEPROMwrite(i,eeBuf[i]);
}
}
w=0;
        asm("NOP");
}
        SSP2CON1bits.CKP=1;            //release SCL line
}
}
}

EEPROMwrite function

Code: [Select]
void EEPROMwrite (unsigned char addr, unsigned char data)
{
EEADRL=addr;
EEDATL=data;
EECON1bits.CFGS=0; // data eeprom/flash selected
EECON1bits.EEPGD=0; // data eeprom
EECON1bits.WREN=1; // start write

GIE=0; // disable interrupts
EECON2=0x55;
EECON2=0xAA; // magic sequence
EECON1bits.WR=1; // start writing
GIE=1;
while(EECON1bits.WR); // wait untill finished
}
best regards FIlip.