cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F103C8T6 sending data over I2C via DMA

BratSinot
Associate

Greetings!

I have "blue pil" stm32f103c8t6 and I want to send data over I2C via DMA. "Classic" way is working fine (I'm sending data to 2004 display through PCF8574 extender), but I can't get it working with DMA.

BTF flag isn't set and the loop becomes infinite. Looked up through debug and saw that TxE flag is set.

Have no idea what I'm doing wrong.

I use libopencm3:

#define IS_SET(a, b)  (((a) & (b)) != 0)
#define NOT_SET(a, b) (!IS_SET(a, b))
 
#define PCF8574_I2C_ADDRESS 0b0100111
 
int main(void) {
    rcc_clock_setup_pll(&rcc_hse_configs[RCC_CLOCK_HSE16_72MHZ]);
    rcc_periph_clock_enable(RCC_GPIOB); // I2C2
    rcc_periph_clock_enable(RCC_I2C2);
    rcc_periph_clock_enable(RCC_DMA1);
    gpio_set_mode(GPIOB, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_ALTFN_OPENDRAIN, GPIO_I2C2_SCL | GPIO_I2C2_SDA);
    // # 72MHz / 8 => 9000000 counts per second
    systick_set_clocksource(STK_CSR_CLKSOURCE_AHB_DIV8);
    // # 9000000/9000 = 1000 overflows per second - every 1ms one interrupt
    // # SysTick interrupt every N clock pulses: set reload to N-1
    systick_set_reload(8999);
    systick_counter_enable();
    systick_interrupt_enable();
 
    dma_channel_reset(DMA1, DMA_CHANNEL1);
    dma_enable_memory_increment_mode(DMA1, DMA_CHANNEL1);
    dma_set_read_from_memory(DMA1, DMA_CHANNEL1);
    dma_disable_transfer_error_interrupt(DMA1, DMA_CHANNEL1);
    dma_set_peripheral_address(DMA1, DMA_CHANNEL1, (uint32_t)&I2C2_DR);
 
    i2c_enable_dma(I2C2);
    i2c_set_clock_frequency(I2C2, 36);
    i2c_set_ccr(I2C2, 0x1e);
    i2c_set_trise(I2C2, 0x0b);
    i2c_peripheral_enable(I2C2);
    while ( NOT_SET(I2C_CR1(I2C2), I2C_CR1_PE) );
 
    DATA[0] = 0x1;
    DATA[1] = 0x2;
    DATA[2] = 0x3;
    DATA[3] = 0x4;
    DATA[4] = 0x5;
    DATA[5] = 0x6;
    DATA[6] = 0x7;
    DATA[7] = 0x8;
 
    // # write
    while ( IS_SET(I2C_SR2(I2C2), I2C_SR2_BUSY) );
    i2c_send_start(I2C2);
    while ( NOT_SET(I2C_SR1(I2C2), I2C_SR1_SB) );
    i2c_send_7bit_address(I2C2, PCF8574_I2C_ADDRESS, I2C_WRITE);
    while ( NOT_SET(I2C_SR1(I2C2), I2C_SR1_ADDR) );
    (void)I2C_SR2(I2C2);
    dma_set_memory_address(DMA1, DMA_CHANNEL1, (uint32_t)&DATA[0]);
    dma_set_number_of_data(DMA1, DMA_CHANNEL1, 8);
    dma_enable_channel(DMA1, DMA_CHANNEL1);
    while ( NOT_SET(I2C_SR1(I2C2), I2C_SR1_BTF) ); // hangs with TxE flag
    dma_clear_interrupt_flags(DMA1, DMA_CHANNEL1, DMA_IFCR_CTCIF1);
    i2c_send_stop(I2C2);
 
    do {
 
    } while ( true );
 
    return 0;
}

0 REPLIES 0