cancel
Showing results for 
Search instead for 
Did you mean: 

standalone I2C (and I2C+DMA) behaviour on 0 byte read.

kuldeepdhaka9
Associate II
Posted on May 13, 2014 at 17:29

Code to test the behaviour of I2C in a 0-byte read transaction.

When  I2C_READ_BYTES = 1

everything works as expected (TC interrupt).

if dma is enabled, it will copy the data to buffer

when I2C_READ_BYTES = 0

this will generate ARLO (ariberation lost) or NACK (negative ACK).

but not TC.

NOTE: if DMA isnt enable while 1byte read, I2C will pull SCL low.

Another Question:

is NBYTES decremented by I2C peripherial after a successfully send/receive. (afai experience, it do NOT decrement the value).

&sharpinclude <stdlib.h>

&sharpinclude <libopencm3/stm32/rcc.h>

&sharpinclude <libopencm3/stm32/gpio.h>

&sharpinclude <libopencm3/stm32/f0/nvic.h>

&sharpinclude <libopencm3/stm32/dma.h>

&sharpinclude <libopencm3/stm32/syscfg.h>

&sharpinclude <libopencm3/stm32/i2c.h>

&sharpinclude <stdint.h>

//STM32F072

//tested on AT30TS75A (temp sensor)

//LM75 should work

//below code is only applicable to bus read only

&sharpdefine I2C_SLAVE_ADDR 0x91

&sharpdefine I2C_READ_BYTES 0

//uncomment for DMA

//&sharpdefine WITH_DMA

uint8_t i2c_buffer[I2C_READ_BYTES];

void i2c_do();

void i2c_init();

uint32_t timeout_counter;

void main()

{

    i2c_init();

    timeout_counter = 0;

    while(1) {

        if(timeout_counter == 0) {

            timeout_counter = 200000;

            timeout_counter = 200000;

            i2c_do();

        }

        //NOTE: uncomment below to perform repeated write

        timeout_counter--;

    }

}

void i2c_init()

{

    //pin

    rcc_periph_clock_enable(RCC_GPIOB);

    gpio_mode_setup(GPIOB, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO6 | GPIO7);

    gpio_set_af(GPIOB, GPIO_AF1, GPIO6 | GPIO7);

    &sharpifdef WITH_DMA

    //dma

    rcc_periph_clock_enable(RCC_DMA);

    //map dma cha6,7 to i2c

    //SYSCFG_CFGR1_I2C1_DMA_RMP = (1 << 27)

    rcc_periph_clock_enable(RCC_SYSCFG_COMP);

    SYSCFG_CFGR1 |= 1 << 27;

    

    //dma ch7 = i2c rx

    dma_channel_reset(DMA1, DMA_CHANNEL7);

    dma_set_priority(DMA1, DMA_CHANNEL7, DMA_CCR_PL_LOW);

    

    dma_set_memory_size(DMA1, DMA_CHANNEL7, DMA_CCR_MSIZE_8BIT);

    dma_set_peripheral_size(DMA1, DMA_CHANNEL7, DMA_CCR_PSIZE_8BIT);

    dma_enable_memory_increment_mode(DMA1, DMA_CHANNEL7);

    dma_set_read_from_peripheral(DMA1, DMA_CHANNEL7);

    dma_set_peripheral_address(DMA1, DMA_CHANNEL7, (uint32_t)&I2C1_RXDR);

    //dma_enable_transfer_complete_interrupt(DMA1, DMA_CHANNEL7);

    //dma_enable_transfer_error_interrupt(DMA1, DMA_CHANNEL7);

    //nvic_enable_irq(NVIC_DMA1_CHANNEL4_5_IRQ);

    &sharpendif

    //i2c

    rcc_periph_clock_enable(RCC_I2C1);

    I2C1_CR1 &= ~I2C_CR1_PE;

    while(I2C1_CR1 & I2C_CR1_PE);

    

    //enable dma rx, dma tx, err interr, transfer complete interr, stop intrr, NACK interru

    I2C1_CR1 = I2C_CR1_ERRIE | I2C_CR1_STOPIE | I2C_CR1_NACKIE | I2C_CR1_TCIE;

    I2C1_TIMEOUTR = 0;

    I2C1_OAR1 = 0;

    I2C1_OAR2 = 0;

    //8MHz, 100khz

    //PRESC = 1

    //SCLL = 0x13

    //SCLH = 0xF

    //SDADEL = 0x2

    //SCLDEL = 0x4

    I2C1_TIMINGR = (1 << 28) | (0x4 << 20) | \

        (0x2 << 16) | (0xF << 8) | (0x13 << 0);

    

    I2C1_CR1 |= I2C_CR1_PE;

    nvic_set_priority(NVIC_I2C1_IRQ, 2);

    nvic_enable_irq(NVIC_I2C1_IRQ);

}

&sharpifdef WITH_DMA

void dma1_channel4_5_isr(void)

{

    dma_clear_interrupt_flags(DMA1, DMA_CHANNEL7, DMA_GIF);

}

&sharpendif

//void i2c0_bulk_out(usbd_device *_usbd_dev, uint8_t _ep)

void i2c_do()

{

    //STOP i2c (if running)

    I2C1_CR1 &= ~I2C_CR1_PE;

    while(I2C1_CR1 & I2C_CR1_PE);

    &sharpifdef WITH_DMA

    //STOP dma (if running)

    dma_disable_channel(DMA1, DMA_CHANNEL7);

    &sharpendif

    

    I2C1_CR1 |= I2C_CR1_PE;

    &sharpifdef WITH_DMA

    DMA1_IFCR = DMA_IFCR_CGIF7;

    dma_set_memory_address(DMA1, DMA_CHANNEL7, (uint32_t)&i2c_buffer);

    dma_set_number_of_data(DMA1, DMA_CHANNEL7, I2C_READ_BYTES);

    //dma_enable_channel(DMA1, DMA_CHANNEL7);

    &sharpendif

    //address writing

    I2C1_CR2 = I2C_CR2_RD_WRN | I2C_SLAVE_ADDR | I2C_CR2_NBYTES_VAL(I2C_READ_BYTES) | I2C_CR2_AUTOEND | I2C_CR2_START;

}

uint32_t isr_times = 0;

uint32_t nack_times = 0;

uint32_t stop_times = 0;

uint32_t arlo_times = 0;

uint32_t berr_times = 0;

void i2c1_isr(void)

{

    uint32_t isr = I2C1_ISR;

    I2C1_ICR = isr & (I2C_ICR_TIMEOUTCF | I2C_ICR_NACKCF |

        I2C_ICR_STOPCF | I2C_ICR_ARLOCF | I2C_ICR_OVRCF | I2C_ICR_BERRCF);

    if(isr & I2C_ISR_NACKF)

        nack_times++;

    if(isr & I2C_ISR_STOPF)

        stop_times++;

    if(isr & I2C_ISR_BERR)

        berr_times++;

    if(isr & I2C_ISR_ARLO)

        arlo_times++;

    //if nack then STOP

    if(isr & I2C_ISR_NACKF) {

        I2C1_CR2 |= I2C_CR2_STOP;

    }

    //release the bus

    I2C1_CR1 &= ~I2C_CR1_PE;

    while(I2C1_CR1 & I2C_CR1_PE);

    &sharpifdef WITH_DMA

    dma_disable_channel(DMA1, DMA_CHANNEL7);

    &sharpendif

    isr_times++;

}

#stm32-i2c-dma
0 REPLIES 0