Problem with I2C

Hi, I'm trying to interface a Toshiba 16bit MCU with another IC(call this IC2), with the MCU being a slave transmitter. The IC2 expects a slave EEPROM at a certain address, and I've setup the MCU to be at this address. The problem is that the MCU isn't interrupting or acknowledging the signals all the time. I've looked at the SDA/SCL waveforms and while IC2 is sending the first device address(with wr direction), the MCU doesn't ACK the address, even though it does interrupt at the end of the address. IC2 hence immediately sends the device address again, and only this time does the MCU ACK it. This is followed by a dummy word address(0x00) then another device address(with rd direction), and the actual 16 byte data.

At the end of each of the addresses, the MCU is interrupting, as well as the end of the 1st data byte, but after that the MCU stops going into the ISR, so IC2 is getting all 0xff which is wrong. In fact, even the 1st data byte is wrong even though I write the data into the serial buffer in the ISR.

Does anyone know what could be wrong? This is the first time I'm working with I2C and isn't as straightfoward as I thought.

Reply to
galapogos
Loading thread data ...

More commonly known as the "master".

Perhaps the slave is not initializing to the proper state. Consider having the master generate a signal sequence to 'reset' the I2C bus. Is the master generating a proper start condition?

More evidence that one or the other end is not initializing properly.

The master does not send "the actual 16 byte data" during a read. It only supplies the clock (which the slave is allowed to stretch). The slave (the device read from) supplies the data during the read.

It's hard to provide meaningful feedback regarding these low level details without knowing what MCU you are using and seeing your code.

--
Dan Henry
Reply to
Dan Henry

Yup, IC2 is the master receiver in the data transaction

Perhaps.I'm following the MCU's datasheet as best I can but it isn't very comprehensive. I can't have the master generate anything since it's fixed function ASIC that sends the I2C signals once it receives its reset signal. I have however verified that the signals do correspond correctly to the intended behavior, i.e. it matches the waveform on the datasheet exactly except for the resent device address.

Yes I know that. The slave isn't sending the actual data though.

The MCU that I'm using is a Toshiba tmp91cp27ug. It's part of Toshiba's

16bit TLCS-900/L1 series.
Reply to
galapogos

No the RESENT device address is correct you are NOT decoding it correctly and examining the EEPROM datasheet on how it is accessed. The vast majority of I2C EEPROM devices MUST be addressed in this way to perform a random read of any location in the I2C EEPROM. Basic structure of random read to EEPROM

Send I2C device address as WRITE Send INTERNAL EEPROM address Stop or send start condition Send I2C device address as READ Read one or more bytes of data.

This done as every byte read from an EEPROM increments its INTERNAL address pointer.

The slave MCU is not handling I2C correctly, for many reasons. You have not said how the I2C is handled in this MCU is it by a special controller bit banging software or other software?

See above as they obviously only want to read location 00 and 01. Basically as the EEPROM's internal address pointer would read out address 02 at the next read, so to read address 00 again requires setting the internal counter back to 0 or reading enough bytes for the internal counter to wraparound.

Put an actual EEPROM on the ASIC and do a detailed analysis of the timing of the I2C transactions that occur, and you may well find the ASIC is getting away with working. Note what rise and fall times you have, all timing of ALL high and low states. Until you have done this the rest is meaningless.

I have seen some ASICs that access I2C EEPROMs, and the timing leaves a lot to be desired for meeting the I2C or I2C EEPROM specs. Even saw one where analysis shows that the timing of I2C clock (SCL) changed during an EEPROM write data cycle where the 8 clock cycles for the byte written had a clock speed twice as fast as any other transaction. Things like that can screw up some badly designed I2C controllers. I have seen some ASICs not send correct ACKs or even ignore ALL ACKs, so carry on regardless even if no EEPROM present.

This suggests your software is not processing I2C transactions correctly and reenabling interupts or doing two reads BEFORE the data has arrived.

Altenatively the hardware controller cannot handle the I2C transactions from the ASIC correctly.

Does it have a built in I2C controller?

Is the data sheet easily available on the web?

What is your code for handling the I2C functions?

I strongly suspect your code for this.

--
Paul Carpenter          | paul@pcserviceselectronics.co.uk
    PC Services
              GNU H8 & mailing list info
             For those web sites you hate
Reply to
Paul Carpenter

Yes, this is exactly what the master IC is doing, so the master's doing it correctly. The internal EEPROM word address is a dummy address of

0x00

The MCU has an I2C controller, so I'm not bit banging it.

Yup, I'm pretty sure it's the software but I'm just not sure how to fix it.

Yes

Yes, it is available at

formatting link

The exact datasheet isn't available on that page, but datasheets for identical MCUs can be obtained at

formatting link
** and
formatting link

Yup I'm pretty sure it's my code too since this is the first time I'm writing I2C code. I'm just not sure what's wrong, or even what I need to do. Basically what I'm doing is I have an initI2C function that initializes the SFRs to the desired values(8bit word, ACK generation, slave transmitter operation mode, setting of the slave address, etc), and then I have a serial interrupt service routine that checks the various status bits and decides what to do in each case.

Reply to
galapogos

.....

Can you forget the word 'dummy' it is NOT a dummy address. The EEPROM has lots of locations so which location to read is sent as an address from your ASIC to say WHICH location to READ (or write). So the address is an actual real address INSIDE the EEPROM. I have seen 256byte to 64kbyte EEPROMs used.

The resent address is how the ASIC talks to the EEPROM and is determined by the EEPROM specification, read that datasheet, as that is what you are trying to emulate in your MCU and software.

IT is *important* you understand how the EEPROM works. Then you can understand what the I2C transactions are, so you can get your software to emulate the EEPROM.

...

Have you or are you going to do this it is important to realise what is actually happening, so you can then check it against what your software results are. Then you can confirm your software is working correctly.

...

Will see if I can get it later.

There may be slight differences between the I2C controller implementations between MCU's or they could be the same. This is an unknown.

You have an understanding problem here, hence the data corruption.

Sequence in ROUGH OUTLINE

Init controller (slave address, ACk generation SLAVE RECEIVER mode)

Interupt routine Address decode WRITE (ASIC writes to EEPROM) Leave in RECEIVER mode and receive all bytes and action first 'n' bytes as address to 'write' to (EEPROM internal address) you will need a volatile to store the pseudo address pointer. Any further bytes you will have to store in you EEPROM emulation (if the ASIC does writes). Stop End transaction READ no ack END transaction Start/Repeated start Stay in slave Receiver

Address decode READ (ASIC reads from EEPROM) Set mode SLAVE TRANSMITTER For subsequent data bytes Send byte pointed to by pseudo address pointer Increment psudo address transmitter

Error conditions END transaction and set some error flag in your software

How you determine end of I2C transaction and signal to your software depends on many other attributes.

You are reading 0xFF mainly because you are transmitting when you should be receiving!

--
Paul Carpenter          | paul@pcserviceselectronics.co.uk
    PC Services
              GNU H8 & mailing list info
             For those web sites you hate
Reply to
Paul Carpenter

===SNIP===

===SNIP===

Although I've now taken a glance at the datashtte, It's hard to provide meaningful feedback regarding these low level details without seeing your code.

You did say above that you are initializing to slave transmitter mode. I assume that to mean that SBIOCR2=1. I would think you'd want to initialize the slave to be a receiver first (SBIOCR2=0), then let the hardware control TRX like it says in 3.11.5(6).

--
Dan Henry
Reply to
Dan Henry

Does the slave EEPROM require 8bit or 16 bit addresses?

-- Michael N. Moran (h) 770 516 7918

5009 Old Field Ct. (c) 678 521 5460 Kennesaw, GA, USA 30144
formatting link

"So often times it happens, that we live our lives in chains and we never even know we have the key." The Eagles, "Already Gone"

The Beatles were wrong: 1 & 1 & 1 is 1

Reply to
Michael N. Moran

Well, I'm simply following what the datasheet calls it. The master IC's datasheet refers to the word address as a dummy word address, hence I call it as such. I do understand that you have to address any memory(in this case an EEPROM) with an actual physical address. In this case that address is 0x00 if I'm understanding the datasheet properly.

timing

meaningless.

I haven't dont this yet since I have no access to the setup over the weekend. I'm not sure if I can get an I2C compatible EEPROM either, but I'll try. Meanwhile I'll have to keep working with what I have.

Thanks!

I'm pretty sure they are the same. The only differences is that one is a mask version and the other is a flash version as well as differences in memory size, but I will check my datasheets again.

You mean the master IC is transmitting rather than the MCU? I don't think that's possible since it's a fixed function ASIC. My MCU is supposed to be the one transmitting, but I'm not getting any interrupts for me to put any data into the serial buffer for sending.

Reply to
galapogos

My ISR is basically implementing that table in the datasheet. Based on the status register bits I'm following what the table says, but as you can probably tell the english isn't very good and I'm having trouble understanding some of the details. Also, either SBIOCR1 or CR2 also doubles as SBIOSR, so it's both read and write. So you're saying I should treat SBIOCR2 as a status bit rather than a control bit?

Reply to
galapogos

Based on the master's datasheet, probably an 8bit address, since the master only provide an 8bit word address. I'm emulating the slave EEPROM with an MCU, so I'm guessing I'm free to support any word size as long as my ISR is written in such a way to support it.

Reply to
galapogos

No, I'm saying that when you write to SBIOCR2 to configure the I2C subsystem as a slave, that you initialize it as a receiver, not a transmitter. That means the initial SBIOCR2 value should have the TRX bit 0, not 1.

Reply to
google

Oh. I clearly haven't been reading very carefully. I assumed your MCU was the master.

Since your master is fixed, I guess you get to do what it wants :-) However, with the "probably" it doesn't sound like you know what it wants.

Word size? IIRC, I2C only transfers bytes, but I suppose you can consider consecutive bytes a "word". Either way, it seems to me that you need to do what the master expects and are not really "free to support any word size", though I realize that you may mean that you *can* support any word size required.

--
Michael N. Moran           (h) 770 516 7918
5009 Old Field Ct.         (c) 678 521 5460
Kennesaw, GA, USA 30144    http://mnmoran.org

"So often times it happens, that we live our lives in chains
  and we never even know we have the key."
The Eagles, "Already Gone"

The Beatles were wrong: 1 & 1 & 1 is 1
Reply to
Michael N. Moran

.....

If you do not always read the correct address, then your EEPROM may as well just be a register with one value, or a full EEPROM with just one value.

I2C EEPROMs are easily available and not difficult to add. Without double checking the real situation you will not be sure when things are working.

...

....

...

You have not understood I2C or your setup.

You are trying to make an EEPROM emulator which is a SLAVE device.

Your ASIC access the EEPROM so it is MASTER device.

On I2C a MASTER device CONTROLS the bus and transactions

Master device SENDS I2C address (SLAVE RECEIVES) A good Master device then RECEIVES the ACK bit (SLAVE SENDS)

If I2C address includes write bit = 0 (WRITE condition) Master device SENDS I2C data (SLAVE RECEIVES) A good Master device then RECEIVES the ACK bit (SLAVE SENDS) Repeat until all bytes SENT.

If I2C address is for READ condition Master devices SENDS I2C clock to clock data OUT of SLAVE (now in transmitter mode) (SLAVE SENDS) Master devices SENDS I2C data of ACK bit (SLAVE RECEIVES) - except on LAST byte Repeat until all bytes SENT.

Slave devices (like EEPROMs) spend the majority of their time in RECEIVE mode, listening for addresses and data to be written TO the slave device they ONLY chnage to transmitters when READING data OUT of the slave device.

For your MCU it MUST be in receiver mode to receive the I2C SDA line INTO its shift register for listening to addresses or for data WRITTEN to the device. Then change to transmit mode to connect the shift register OUTPUT to the I2C SDA line (and enable arbitration circuitry).

Why do I know this because I have done various I2C devices onto systems over the years and I am currently doing a similar thing for an ASIC, mine will probably end up in a CPLD. That is because the circumstances of this application will mean it is easier to do that way.

--
Paul Carpenter          | paul@pcserviceselectronics.co.uk
    PC Services
              GNU H8 & mailing list info
             For those web sites you hate
Reply to
Paul Carpenter

I understand all the way up to here.

OK, this means that like what Dan said previously I should initialize my MCU as a slave receiver initially rather than a slave transmitter. That might explain why the first device address is not acknowledged?

Reply to
galapogos

....

Yes. you only switch to transmit mode at the point in time when you need to send a byte (actually READING out) data. Then you switch back again to receive mode. Just like the bits above, when it says (SLAVE RECEIVES) the slave is in receive mode.

Ack bits should be handled by your software setting ack bit generation for address acknowledge so the hardware does it for you. As to whether your ASIC does anything with ACK bits, depends on the ASIC, having seen some that ignore incoming ACKs and always set ACK bit sending to '1' regardless of what it should be.

That is why Dan and me are saying you are transmitting when you should be receiving.

--
Paul Carpenter          | paul@pcserviceselectronics.co.uk
    PC Services
              GNU H8 & mailing list info
             For those web sites you hate
Reply to
Paul Carpenter

Cool. I initialized my MCU to a slave receiver and now it acknowledges the first device address, so there's no resending. I also managed to get the MCU to interrupt on all subsequent data bytes, but I'm still not able to send the correct data over. The data is either 0x80 of 0xfd

Reply to
galapogos

Here's my current pseudo code:

initI2C() { P6FC = 0x06; // set P61/62 to SDA/SCL function P6CR = 0x06; // set P61/62 to output IOP6 = 0x06; // set P61/62 to high SBI0BR1 = 0x80; // enable I2C I2C0AR = 0xa0; // 7bit slave address of MCU(1010000b) SBI0CR1 = 0x10; // Serial bus interface control register 1 SBI0CR2 = 0x18; // Serial bus interface control register 2 SBI0BR0 = 0x00; INTES2RTC = 0x04; // enable INTSBI interrupt, priority level 4 index = 0; // index into the data }

ISR() { if (SBI0SR_TRX == 0) { if ( (SBI0SR_AL == 0) && (SBI0SR_AAS == 0) ) { SBI0CR1 &= ~SBI0CR1_BC; junk = SBI0DBR; } else { junk = SBI0DBR; } } else { if ( SBI0SR_AAS && (SBI0SR_AD0 == 0) ) { SBI0CR1 &= ~SBI0CR1_BC; // sets word size as 8bits SBI0DBR = data[index++]; } else if ( (SBI0SR_AL == 0) && (SBI0SR_AAS == 0) && (SBI0SR_AD0 ==

0) ) { if (SBI0SR_LRB) { SBI0CR2 |= SBI0CR2_PIN; // pull PIN high SBI0CR2 &= ~SBI0CR2_TRX; // reset TRX } else { SBI0CR1 &= ~SBI0CR1_BC; // sets word size as 8bits SBI0DBR = data[index++]; } } } } }
Reply to
galapogos

Actually I know what the master wants, because in its datasheet there is the exact waveform/timing diagram, and I'm matching that against my output on the logic analyzer. The master actually provides an 8bit word address.

Yup that's what I meant. I can support any word size required but in this case I have to adhere to the master which provides an 8bit word address.

Reply to
galapogos

device.

OK scratch that. The data that is sent is actually always 0x80, and I'm not sure why that's the case. I'm sending 16 bytes of data over to the master, and the initial handshaking is all fine until I actually send data over by writing my data to my serial buffer SBI0DBR, but when I immediately copy this data over to another junk variable, it reads

0x80, and according to my logic analyzer waveform, it is also 0x80, so it looks like the MCU is indeed sending whatever is in the buffer, but the buffer isn't being updated with what I actually want to send...
Reply to
galapogos

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.