galapogos wrote:
> galapogos wrote:
> > Paul Carpenter wrote:
> > > On 6 Dec, in article
> > > <1165421691.608742.42950@l12g2000cwl.googlegroups.com>
> > > goister@gmail.com "galapogos" wrote:
> > >
> > > >Paul Carpenter wrote:
> > > >> On 6 Dec, in article
> > > >> <1165400403.987854.72700@16g2000cwy.googlegroups.com>
> > > >> goister@gmail.com "galapogos" wrote:
> > > ....
> > > >> >I then tried to access the EEPROM with my MCU set as a master. I was
> > > >> >able to get all the way to step 6, but after that, my MCU was still in
> > > >> >master transmitter mode rather than master receiver mode. I have to set
> > > >> >the master to transmit mode for it to send the 2nd device address in
> > > >> >step 5. I thought that the direction bit sent in step 5 would reset the
> > > >> >MCU to be in receiver mode but it didn't. Therefore I'm unable to
> > > >> >continue on to step 7. In fact, I had to hack things up quite a bit to
> > > >>
> > > >> NO direction changes YOU must code, I would suggest when you are sending
> > > >> a READ address (last bit of address = 1), after the ACK then YOU must change
> > > >> the direction.
> > > >
> > > >How do I detect this though. I send the READ address at interrupt n,
> > > >but I expect the ACK at interrupt n+1, so I would need some way of
> > > >detecting something at n+1 to change direction, and the address is long
> > > >gone by then so I can't detect. Other than using the global counter or
> > > >some other global variable I can't think of a way to do so.
> > >
> > > Either from main program flow or knowing how many bytes are being
> > > sent/received. You must have some form of state knowledge, even if your
> > > higher level code is waiting for interupts to complete. I assume you have
> > > some form of flag for how many bytes received. The data in the data
> > > register at addressed or ACK time should be the address including a
> > > READ/WRITE bit to set flow for next bytes.
> > >
> > > Most people run with simple functions and state variables, so they know
> > > that they are receiving an I2C address, having done that note what type
> > > of address and action accordingly.
> > >
> > > Unless your MCU is very busy doing other things I would in this case
> > > test first using code that monitors an interupt flag to signify you have
> > > been Addressed as Slave, then drop to a linear function to test things
> > > first as in
> > >
> > > If I2C address write mode
> > > Read 'n' bytes of EEPROM internal address
> > > SEND ACK
> > > Read 'n' bytes of write data
> > > Send ACK
> > > (if anytime stop or start detected exit)
> > > else
> > > switch mode to transmit
> > > send data byte
> > > Wait for ACK/NOACK
> > > if ACK repeat send data
> > > if NACK wait for stop/start condition
> > > (if anytime stop or start detected
> > > switch to receive mode
> > > exit)
> > >
> > > The waits, sends and receive would be functions. get it working this way
> > > first then look at ways to put it into an interupt function with state
> > > variables about next state, current state, count of bytes if known.
> >
> > Is the above program flow for the MCU emulating as a slave EEPROM to
> > the master ASIC? I was trying to get the MCU working as a master to an
> > external slave EEPROM to get things working since I thought it would be
> > easier. The above program flow doesn't make sense in this context.
> >
> > > Starting with interupt functions for I2C is probably trying to run before
> > > you can walk.
> >
> > I thought interrupts would be easier since the interrupts are well
> > defined(occurs after every ACK), but I'll see if I can do it polling
> > style.
> >
> > > If you are master you should know from your program flow what you are
> > > trying to achieve. Write as a bunch of linear calls and code to test
> > > handling of I2C controller first, start as master talking to EEPROM
> > > to write a byte, then reset the address and read the byte back.
> > >
> > > >> >even get it working till step 6. For example, I didn't know how to
> > > >> >correctly detect when to restart in step 5, so I detected this by
> > > >> >having a global interrupt counter and restarting when the counter is a
> > > >> >certain value.
> > > >>
> > > >> You send the start condition using the controller to send a start then
> > > >> the Read address. When your MCU is master you do not detect it you
> > > >> generate it.
> > > >
> > > >I think you misunderstood me. I know when conceptually to start and
> > > >restart, and I'm doing this in main(). However, in my ISR, I do a bunch
> > > >of status bit detection to determine what I should do at any given
> > > >time.
> > > >
> > > >On my restart, when I'm sending the READ address in main(), I have to
> > > >keep my status as a master transmitter since I'm sending the READ
> > > >address to the master. However, I think because of this, at the end of
> > > >the ACK for the READ address, I'm still going into the isr code section
> > > >for master transmitter, which is to send more data. Instead, I should
> > > >be going into the master receive code section where the serial buffer
> > > >is free to accept incoming data. Makes sense? Or am I thinking of it
> > > >totally the wrong way?
> > >
> > > You need to determine as a aslave from the LRB (Last received bit) or
> > > a flag when as master that you have sent a read or write address I think
> > > you are expecting too much from a simple I2C controller, all the ones
> > > I have seen expect a lot of control software and state variables, especially
> > > for timeouts and other error trapping.
> > >
> > > >> >I'm sure there must be a proper way of detecting when to restart but I
> > > >> >can't figure out how. As far as my MCU goes, it still thinks it's in
> > > >> >master transmitter mode after sending the device/word address, so I
> > > >> >don't know how to tell it to restart at that point.
> > > >>
> > > >> You do the following steps
> > > >>
> > > >> generate a start coindition
> > > >> transmit the read address,
> > > >> get ACK
> > > >> Change mode to receive
> > > >> Receive bytes
> > > >> last byte Set NOACK
> > > >> Send Stop
> > > >
> > > >Aren't you missing the 1st start condition? i.e.
> > >
> > > No I was talking about after the first Write transaction. The Toshiba
> > > manual does have sections on generating restarts (may not be well written
> > > but it is there)..
> > >
> > > If detecting as a slave see the manual and BB bit for start/stop detection.
> > >
> > > ....
> > > >Like I said, I'm doing fine until step 5. I can do step 7, but then I
> > > >fall into the wrong code segment inside my ISR(master transmitter
> > > >instead of master receiver), and I'm not sure where exactly I can
> > > >change my control/status bit to receive. What I'm thinking is I can't
> > > >change it at the start of step 7 since I'm still transmitting, but the
> > > >next point I can change it is in in the ISR after step 8, and that's
> > > >too late since I'm already supposed to be in receive mode in that stage
> > > >right? I can't change it in the ISR after step 8 since my ISR wouldn't
> > > >know that the READ address was previously sent. All it knows about the
> > > >outside world is what the MCU status bits reveal, which are the
> > >
> > > Whatever you do you will need some way of tracking either as a master
> > > talking to EEPROM, or as a slave emulating a EEPROM what type of
> > > transaction you are doing. probably what state you are in as well
> > > (waiting ack, receiving byte, receiving address, idle....).
> >
> > I am having trouble with the MCU as a master talking to a slave EEPROM.
> > I added a volatile i2c global state variable and tracking/changing it
> > as the program runs, and I was again stuck at the point when the READ
> > address is sent. If I try to change the direction from transmit to
> > receive at that point, for some reason the MCU stops generating a clock
> > and hence I don't receive anything from the EEPROM. I tried reading the
> > buffer to a temp variable as well as pulling the PIN high. These did
> > not work, contrary to Fig 3.11.15 of the datasheet where it claims that
> > when TRX=0, setting PIN to 1 will cause the MCU to output a serial
> > clock pulse to the SCL to transfer new 1-word of data. In fact, even if
> > I set the TRX bit to what it already is, SCL becomes HIGH all the way.
> > It seems like I can't even touch the TRX bit at all!
> >
> > Now if I leave the TRX bit alone, SCL continues pumping, but the MCU is
> > in master transmitter mode and will pump the buffer to SDA, which isn't
> > what I want if I want to read from the EEPROM.
>
> I tried coding it linear style rather than using interrupts, and again
> I'm getting stuck after the restart, right after the read address is
> sent by the MCU to the EEPROM. Whenever I modify the TRX bit, SCL will
> stop. I looked at the restart documentation, and it says that after a
> restart I should generate a new start condition by following 3.11.6(2)
> under Master. In that section it states the steps that I should follow
> to generate a start bit. This is identical to the first start bit that
> I generated, and consists of the following instructions
>
> SBI0CR1 |= 0x10; // set SBI0CR1<ACK> to 1
> SBI0DBR = 0xa1; // send READ address
> SBI0CR2 = BIN_11111000; // write "1" to MST, TRX, BB, PIN
>
> That section also states that "when an interrupt request generate, the
> <TRX> is changed according to the direction bit only when an
> acknowledge signal is returned from the slave device." This seems to
> suggest that TRX changes are automatic rather than me changing it. I
> verified that I'm indeed getting an ACK from the slave by looking at my
> logic analyzer timing waveform as well as checking that the LRB right
> after the read address is sent is "0". Since I'm getting an ACK and my
> direction bit is 1, why isn't TRX being reset to 0? Is there a bug with
> my emulator or am I misunderstanding the datasheet?
I wish there was a way to edit posts, but anyway, after getting stuck
in the above situation, I decided to give linear coding a go with the
MCU as the slave and the ASIC as the master. After going at it a few
times, I actually managed to get the MCU to send data to the ASIC! I
didn't even use any state flags or byte count. The handshaking sequence
is hardcoded as per the expected timing diagram, and the how many bytes
is determined by checking the LRB status bit. Also, I didn't even need
to change the TRX bit after the 2nd device address is sent by the ASIC.
As I suspected, the MCU does this automatically, presumably by checking
the 8th(direction) bit of the transmission and seeing if it's a 1 or a
0. I don't know why this doesn't work when the MCU is in master mode
though.
In any case, the current code, though lengthy and messy, is sufficient
for my application, but I will probably try and clean it up and make it
more general purpose rather than hard coded, and maybe implement it
with interrupts.
I noticed that in the ASIC's datasheet as well as the logic analyzer,
after the transmission is done and the ASIC sends its STOP bit, the SCL
line is kept low, therefore the bus is not freed. Is this weird or
normal? It doesn't really matter in this case I guess since there are
only 2 devices on the bus and only 1 transaction being performed.
I also noticed that between the end of every MCU ACK and the start of
every data byte sent, there is a glitch on the SDA line where it goes
to HIGH for a very short period of time(<half a clock period) and then
comes down again(if the data bit is 0). According to the I2C specs the
data on the SDA line must be stable during the HIGH period of the
clock, so does that mean that this glitch is ok since it only occurs
for a part of the LOW period of the clock?