# I2C - eeprom\_dma

Source: [https://docs.qualcomm.com/doc/80-58740-4/topic/i2c-eeprom-dma.html](https://docs.qualcomm.com/doc/80-58740-4/topic/i2c-eeprom-dma.html)

This demo mainly introduces how I2C uses DMA to read and write eeprom.

## Hardware connection

The GPIO used in this demo refers to `board_i2c0_gpio_init`. Connect
                the eeprom module to the development board. The specific pin connection method is as
                follows (taking QCC743 as an example):

| Signal | eeprom signal |
| --- | --- |
| SCL(GPIO14) | SCL |
| SDA(GPIO15) | SDA |
| GND | GND |
| VCC | VCC |

## Software implementation

For more detailed code, please refer to
                    examples/peripherals/i2c/i2c\_eeprom\_dma.

    board_init();Copy to clipboard

- `board_init` turns on the I2C IP clock and select the I2C
                        clock source and frequency division.

    board_i2c0_gpio_init();Copy to clipboard

- Configure related pins as `I2C` function

    /* Send and receive buffer init */
    for (size_t i = 0; i < 32; i++) {
        ((uint8_t *)send_buffer)[i] = i;
        ((uint8_t *)receive_buffer)[i] = 0;
    }
    
    i2c0 = qcc74x_device_get_by_name("i2c0");
    
    qcc74x_i2c_init(i2c0, 400000);
    qcc74x_i2c_link_txdma(i2c0, true);
    qcc74x_i2c_link_rxdma(i2c0, true);Copy to clipboard

- Initialize send and receive buffers
- Get the `i2c0` handle and initialize the i2c0 frequency to
                        400K
- `qcc74x_i2c_link_txdma(i2c0, true)` enables I2C Tx DMA
                        function
- `qcc74x_i2c_link_rxdma(i2c0, true)` enables I2C Rx DMA
                        function

    /* Write page 0 */
    dma0_ch0 = qcc74x_device_get_by_name("dma0_ch0");
    
    struct qcc74x_dma_channel_config_s tx_config;
    
    tx_config.direction = DMA_MEMORY_TO_PERIPH;
    tx_config.src_req = DMA_REQUEST_NONE;
    tx_config.dst_req = DMA_REQUEST_I2C0_TX;
    tx_config.src_addr_inc = DMA_ADDR_INCREMENT_ENABLE;
    tx_config.dst_addr_inc = DMA_ADDR_INCREMENT_DISABLE;
    tx_config.src_burst_count = DMA_BURST_INCR1;
    tx_config.dst_burst_count = DMA_BURST_INCR1;
    tx_config.src_width = DMA_DATA_WIDTH_32BIT;
    tx_config.dst_width = DMA_DATA_WIDTH_32BIT;
    qcc74x_dma_channel_init(dma0_ch0, &tx_config);
    
    qcc74x_dma_channel_irq_attach(dma0_ch0, dma0_ch0_isr, NULL);Copy to clipboard

- For Tx, the DMA configuration is as follows: the transfer direction
                        (direction) is memory to peripheral (MEMORY\_TO\_PERIPH), the source request
                        (src\_req) is memory, and the target request (dst\_req) is
                        DMA\_REQUEST\_I2C0\_TX
- Call `qcc74x_dma_channel_init(dma0_ch0, &tx_config)` to
                        initialize DMA
- Call `qcc74x_dma_channel_irq_attach(dma0_ch0, dma0_ch0_isr,
                            NULL)` to register DMA channel 0 interrupt

    struct qcc74x_dma_channel_lli_pool_s tx_llipool[20]; /* max trasnfer size 4064 * 20 */
    struct qcc74x_dma_channel_lli_transfer_s tx_transfers[1];
    tx_transfers[0].src_addr = (uint32_t)send_buffer;
    tx_transfers[0].dst_addr = (uint32_t)DMA_ADDR_I2C0_TDR;
    tx_transfers[0].nbytes = 32;
    qcc74x_dma_channel_lli_reload(dma0_ch0, tx_llipool, 20, tx_transfers, 1);
    
    msgs[0].addr = 0x50;
    msgs[0].flags = I2C_M_NOSTOP;
    msgs[0].buffer = subaddr;
    msgs[0].length = 2;
    
    msgs[1].addr = 0x50;
    msgs[1].flags = I2C_M_DMA;
    msgs[1].buffer = NULL;
    msgs[1].length = 32;
    qcc74x_i2c_transfer(i2c0, msgs, 2);
    
    qcc74x_dma_channel_start(dma0_ch0);
    Copy to clipboard

- Allocate twenty lli memory pools, which can transfer up to 4064 \* 20
                        bytes
- Configure a piece of memory (tx\_transfers) for transmission, the source
                        address (src\_addr) is the memory address (send\_buffer) where the sent data
                        is stored, and the destination address (dst\_addr) is the I2C TxFIFO address
                        (DMA\_ADDR\_I2C0\_TDR)
- Call `qcc74x_dma_channel_lli_reload(dma0_ch0, tx_llipool, 20,
                            tx_transfers, 1)` to initialize
- Call `qcc74x_i2c_transfer(i2c0, msgs, 2)` to enable I2C
                        transfer
- Call `qcc74x_dma_channel_start(dma0_ch0)` to start DMA
                        transfer

    /* Read page 0 */
    dma0_ch1 = qcc74x_device_get_by_name("dma0_ch1");
    
    struct qcc74x_dma_channel_config_s rx_config;
    
    rx_config.direction = DMA_PERIPH_TO_MEMORY;
    rx_config.src_req = DMA_REQUEST_I2C0_RX;
    rx_config.dst_req = DMA_REQUEST_NONE;
    rx_config.src_addr_inc = DMA_ADDR_INCREMENT_DISABLE;
    rx_config.dst_addr_inc = DMA_ADDR_INCREMENT_ENABLE;
    rx_config.src_burst_count = DMA_BURST_INCR1;
    rx_config.dst_burst_count = DMA_BURST_INCR1;
    rx_config.src_width = DMA_DATA_WIDTH_32BIT;
    rx_config.dst_width = DMA_DATA_WIDTH_32BIT;
    qcc74x_dma_channel_init(dma0_ch1, &rx_config);
    
    qcc74x_dma_channel_irq_attach(dma0_ch1, dma0_ch1_isr, NULL);Copy to clipboard

- For Rx, the DMA configuration is as follows: the transfer direction
                        (direction) is peripheral to memory (PERIPH\_TO\_MEMORY), the source request
                        (src\_req) is DMA\_REQUEST\_I2C0\_RX, and the target request (dst\_req) is
                        memory
- Call `qcc74x_dma_channel_init(dma0_ch1, &rx_config)` to
                        initialize DMA
- Call `qcc74x_dma_channel_irq_attach(dma0_ch1, dma0_ch1_isr,
                            NULL)` to register DMA channel 1 interrupt

    struct qcc74x_dma_channel_lli_pool_s rx_llipool[20];
    struct qcc74x_dma_channel_lli_transfer_s rx_transfers[1];
    rx_transfers[0].src_addr = (uint32_t)DMA_ADDR_I2C0_RDR;
    rx_transfers[0].dst_addr = (uint32_t)receive_buffer;
    rx_transfers[0].nbytes = 32;
    
    qcc74x_dma_channel_lli_reload(dma0_ch1, rx_llipool, 20, rx_transfers, 1);
    
    msgs[1].addr = 0x50;
    msgs[1].flags = I2C_M_DMA | I2C_M_READ;
    msgs[1].buffer = NULL;
    msgs[1].length = 32;
    qcc74x_i2c_transfer(i2c0, msgs, 2);
    
    qcc74x_dma_channel_start(dma0_ch1);Copy to clipboard

- Allocate twenty lli memory pools, which can transfer up to 4064 \* 20
                        bytes
- Configure a piece of memory (rx\_transfers) for transmission, the source
                        address (src\_addr) is the I2C RxFIFO address (DMA\_ADDR\_I2C0\_RDR), and the
                        destination address (dst\_addr) is the memory address (receive\_buffer) where
                        the received data is stored.
- Call `qcc74x_dma_channel_lli_reload(dma0_ch1, rx_llipool, 20,
                            rx_transfers, 1)` to initialize
- Call `qcc74x_i2c_transfer(i2c0, msgs, 2)` to enable I2C
                        transfer
- Call `qcc74x_dma_channel_start(dma0_ch1)` to start DMA
                        transfer

    while (dma_tc_flag1 == 0) {
    }
    while ((qcc74x_i2c_get_intstatus(i2c0) & I2C_INTSTS_END) == 0) {
    }
    qcc74x_i2c_deinit(i2c0);Copy to clipboard

- After data transfer is completed, reset the I2C module

    /* Check read data */
    for (uint8_t i = 0; i < 32; i++) {
        if (((uint8_t *)send_buffer)[i] != ((uint8_t *)receive_buffer)[i]) {
            printf("check fail, %d write: %02x, read: %02x\r\n", i, ((uint8_t *)send_buffer)[i], ((uint8_t *)receive_buffer)[i]);
        }
    }Copy to clipboard

- Check whether the data sent and read are consistent

## Experimental phenomena

Press the RST button and after the data transfer is completed, “write over”, “read
                over” and “check over” are printed.

**Parent Topic:** [I2C](https://docs.qualcomm.com/doc/80-58740-4/topic/i2c.html)

Last Published: Feb 10, 2025

[Previous Topic
I2C - eeprom](https://docs.qualcomm.com/bundle/publicresource/80-58740-4/topics/i2c-eeprom.md) [Next Topic
I2C - eeprom\_interrupt](https://docs.qualcomm.com/bundle/publicresource/80-58740-4/topics/i2c-eeprom-interrupt.md)