cancel
Showing results for 
Search instead for 
Did you mean: 

I2C EEPROM Read with DMA

stst9183
Associate II
Posted on April 30, 2010 at 12:03

I2C EEPROM Read with DMA

11 REPLIES 11
stst9183
Associate II
Posted on May 17, 2011 at 13:49

Hello again - problem solved. It works now but only with using stop after the first write of the random read sequence. Otherwise the bus hangs. The other solution is Software Reset and reinit i2c.

Thanks anyway,

Joachim

chikos332
Associate II
Posted on May 17, 2011 at 13:49

Hi Joachim,

I have some questions please:

You have two sequences: 

  1) Start-SlaveAdd-Ack-MemAdd-Ack

  2) reStart-SlaveAdd-Ack-Data1-Data2-...

 - Are you doing both sequences in DMA or just the second one?

 - Is the MemAdd on 1 byte or 2 Bytes ?

 - Do you send ''write'' SlaveAdd in the first sequence and ''read'' SlaveAdd in the second one ?

I'm interested to know how you did to implement the solution because I have similar issue and I don't think that resetting or stopping would be the right solution ?

Thanks.

stst9183
Associate II
Posted on May 17, 2011 at 13:49

Hello chikos,

I have 2 functions

void fram_write(uint16_t address, uint8_t* buffer, uint32_t length);

void fram_read(uint16_t address, uint8_t* buffer, uint32_t length);

fram_write does the following using DMA:

1) Start-SlaveAdd-Ack-MemAdd-Ack-Stop

fram_read does the following using DMA:

1) fram_write(address, NULL, 0)

2) Start-SlaveAdd-Ack-Data1-Ack-Data2-..Ack- DataN-NACK-Stop

So to answer your questions:

- Are you doing both sequences in DMA or just the second one?

Both sequences uses DMA - I am using semaphores, so the cpu can do other things while the I2C periphery does it´s job

 - Is the MemAdd on 1 byte or 2 Bytes ?

Good question. This is the stupid thing because it didn´t work for me 😉 - I used 1 Byte Addressing (Datasheet of 16kbit FRAM) but mounted was a 64kbit with 2 Byte Addressing ... well my fault ... :p

But i´ts easy to switch from 1byte addressing to 2 byte addressing

 - Do you send ''write'' SlaveAdd in the first sequence and ''read'' SlaveAdd in the second one ?

Yes. Look at:

http://www.ramtron.com/files/datasheets/FM24CL64_ds.pdf

Page 7. Figure 9

The only difference is that before the 2nd start in the sequence. My implementation transferes a Stop additionally. But thats no problem.

I tried it without the stop but I did not find any other solution than  make a I2C_SoftwareResetCmd and reinit. And that was to hot for me. With the stop the I2C periphery releases the SCL line and with it the busy flag.

I made tests and it works without any problems and pretty fast.

For the implemenation the appnote from st helps very much.

But! I don´t know if other memory devices (eeprom etc) support this stop... Well I think it should not be any problem but I really don´t know.

Hope I could help. If you have any questions - ask 😉

- Joachim

Singh.Harjit
Senior II
Posted on May 17, 2011 at 13:49

Can you add more details on how you are using DMA for address? The data sheet says that you have to read the status register to clear the addr bit. Also, when do you set the stop flag? Thanks.

From: stuempfl.joachim

Posted: Saturday, May 01, 2010 11:05 AM

Subject: I2C EEPROM Read with DMA

Hello chikos,

I have 2 functions

void fram_write(uint16_t address, uint8_t* buffer, uint32_t length);

void fram_read(uint16_t address, uint8_t* buffer, uint32_t length);

fram_write does the following using DMA:

1) Start-SlaveAdd-Ack-MemAdd-Ack-Stop

fram_read does the following using DMA:

1) fram_write(address, NULL, 0)

2) Start-SlaveAdd-Ack-Data1-Ack-Data2-..Ack- DataN-NACK-Stop

So to answer your questions:

- Are you doing both sequences in DMA or just the second one?

Both sequences uses DMA - I am using semaphores, so the cpu can do other things while the I2C periphery does it´s job

 - Is the MemAdd on 1 byte or 2 Bytes ?

Good question. This is the stupid thing because it didn´t work for me 😉 - I used 1 Byte Addressing (Datasheet of 16kbit FRAM) but mounted was a 64kbit with 2 Byte Addressing ... well my fault ... :p

But i´ts easy to switch from 1byte addressing to 2 byte addressing

 - Do you send ''write'' SlaveAdd in the first sequence and ''read'' SlaveAdd in the second one ?

Yes. Look at:

http://www.ramtron.com/files/datasheets/FM24CL64_ds.pdf

Page 7. Figure 9

The only difference is that before the 2nd start in the sequence. My implementation transferes a Stop additionally. But thats no problem.

I tried it without the stop but I did not find any other solution than  make a I2C_SoftwareResetCmd and reinit. And that was to hot for me. With the stop the I2C periphery releases the SCL line and with it the busy flag.

I made tests and it works without any problems and pretty fast.

For the implemenation the appnote from st helps very much.

But! I don´t know if other memory devices (eeprom etc) support this stop... Well I think it should not be any problem but I really don´t know.

Hope I could help. If you have any questions - ask 😉

- Joachim

chikos332
Associate II
Posted on May 17, 2011 at 13:49

Hi,

That's exactly the point.

When you sue DMA, you have first to send the address in polling mode (without DMA) then to start transfer with DMA.

That's what I tried to do, and with generating re-start it seems to work properly and I don't need to do a STOP before sending/receiving data.

Is it what you did, or did you use the DMA even for Slave Address sending ?

Anyway, if it works correctly for you with STOP, that's fine. I just hope that all memories support this behavior...

stst9183
Associate II
Posted on May 17, 2011 at 13:49

Hi Harjit,

the slave address is still transfered in the I2C1_EV_IRQHandler as in appnote. The eeprom address byte(s) are transfered as normal data in DMA mode.You can also use the standard polling method for the 1. part of the random read sequence.

- Joachim

stst9183
Associate II
Posted on May 17, 2011 at 13:49

Hi chikos,

- When you sue DMA, you have first to send the address in polling mode (without DMA) then to start transfer with DMA.

That's what I tried to do, and with generating re-start it seems to work properly and I don't need to do a STOP before sending/receiving data.

Is it what you did, or did you use the DMA even for Slave Address sending ?

Yes I also use DMA for that (with the standard stop). I am sure if your method works this is a good method. I also tried this but a I2C_GenerateSTART didn´t put the peripery out of the busy mode.

I preffered this method because of multitasking - but I didn´t know it it is worth (I have to test this further) for the cpu to do context switching  etc while transfering the 3 bytes (1slave in interrupt, 2 address bytes in dma) ... This depends on the clocks of I2C and CPU

- Anyway, if it works correctly for you with STOP, that's fine. I just hope that all memories support this behavior...

Well I really do not know  and I do NOT recommend this method... 😉

-Joachim

najoua2
Associate
Posted on May 17, 2011 at 13:49

Hi Joachim,

It is not correct to send the slave address by DMA. The slave address should be sent using polling or interrupt. The reason is simple: after sending the address, the ADDR flag will be set and must be cleared by reading SR1 and SR2.

You said that you send the slave address and the address in the eeprom using DMA so the ADDR flag will not be reset -> that is why the line remains low (stretched because ADDR is set) and consequently you will not be able to generate a START.

The DMA requests (when enabled) are generated only for data transfer. DMA requests are generated by Data Register becoming empty in transmission and Data Register becoming full in reception.

All remaing events (SB, ADDR, etc..) should be managed by polling or interrupt .

Regards,

COM
stst9183
Associate II
Posted on May 17, 2011 at 13:49

Hi COM,

Oh sorry I did not answer chikos question correctly. I do not send the slave address in DMA. But I use DMA to transfer the 1st write part - the 2 eeprom address bytes - of the eeprom random read sequence. I do not use polling. The slave address bytes for the write and read are sent in the I2CEventHandler not in DMA of course. Otherwise DMA would not work either I guess because DMA would not know if to read or write ...

/**

  * @brief  This function handles I2C1 Event interrupt request.

  * @param  None

  * @retval : None

  */

void I2C1_EV_IRQHandler(void)

{

    /* ATTENTION this is highest priority - take care with OS API!!!*/

    switch (I2C_GetLastEvent(I2C1))

    {

    case I2C_EVENT_MASTER_MODE_SELECT:                 /* EV5 */

      if(iic_direction == IIC_DIRECTION_TRANSMITTER)

      {

        /* Master Transmitter ----------------------------------------------*/

        /* Send slave Address for write */

        I2C_Send7bitAddress(I2C1, fram_slave_Address, I2C_Direction_Transmitter);

      }

      else

      {

        /* Master Receiver -------------------------------------------------*/

        /* Send slave Address for read */

        I2C_Send7bitAddress(I2C1, fram_slave_Address, I2C_Direction_Receiver);

      

      }

      break;

        /* Master Transmitter --------------------------------------------------*/

        /* Test on I2C1 EV6 and first EV8 and clear them */

    case I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED:

        DMA_Cmd(DMA1_Channel6, ENABLE);

        break;

        /* Test on I2C1 EV8 and clear it */

    case I2C_EVENT_MASTER_BYTE_TRANSMITTING:

        break;

    case I2C_EVENT_MASTER_BYTE_TRANSMITTED:

        /*

        Clear the BTF Bit!!

        Cleared by software reading SR1 followed by either a read or write in the DR register or

        by hardware after a start or a stop condition in transmission or when PE=0.

        */

        I2C_GenerateSTOP(I2C1, ENABLE);

        I2C_ITConfig(I2C1, I2C_IT_EVT, DISABLE); /* In order to not have again a BTF event IT */

        break;

        /* Master Receiver -------------------------------------------------------*/

    case I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED:

        DMA_Cmd(DMA1_Channel7, ENABLE);

        break;

    case I2C_EVENT_MASTER_BYTE_RECEIVED:

        break;

    default:

        break;

    }

}

Regards,

Joachim