Skip to main content
BratSinot
Visitor II
March 8, 2022
Question

STM32F103C8T6 sending data over I2C via DMA

  • March 8, 2022
  • 0 replies
  • 807 views

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;
}

This topic has been closed for replies.