c - Embedded software program block, I2C? -
i have experienced strange problem in developing application st microelectronics inemo. applications consists in:
- gyroscope reading spi
- accelerometer , magnetometer (in same device) reading i2c
- attitude estimation algorithm
- pd functions
- data receiving usart, interrupt without dma
- sending of logging packet, usart
the loop triggered timer @ 100hz. program works (i have tested usart debug prints) until start sending data usart: initial guess that, since fact enables receiving of interrupts, causes problem i2c bus arbitrage mechanism. guess derived when have succeeded in debugging problem (that time dependent), usart prints, have detected last print before accelerometer of magnetometer prints (the first call in code). additionally, if enable verbose debug prints via usart have mentioned problem occurs in fewer occasions, while if disable , send logging packet problem occurs , immediately. can give me idea of can cause of problem? thanks
edit: attach i2c code:
#define dma_buffer_size 196 #define force_critical_sec /** * @brief dma initialization structure variable definition. */ dma_inittypedef i2cdma_initstructure; /** * @brief volatile variable definition i2c direction. */ __io uint32_t i2cdirection = i2c_direction_tx; void inemoi2cinit(i2c_typedef* i2cx, uint32_t i2cxspeed) { i2c_inittypedef i2c_initstructure; gpio_inittypedef gpio_initstructure; /* enable gpio clocks */ rcc_apb2periphclockcmd(rcc_apb2periph_gpiob|rcc_apb2periph_afio, enable); /* configure i2c pins: scl , sda */ if(i2cx==i2c2) { rcc_apb1periphclockcmd(rcc_apb1periph_i2c2, enable); gpio_initstructure.gpio_pin = gpio_pin_10 | gpio_pin_11; } else { gpio_pinremapconfig(gpio_remap_i2c1,enable); rcc_apb1periphclockcmd(rcc_apb1periph_i2c1, enable); gpio_initstructure.gpio_pin = gpio_pin_8 | gpio_pin_9; } gpio_initstructure.gpio_speed = gpio_speed_50mhz; gpio_initstructure.gpio_mode = gpio_mode_af_od; gpio_init(gpiob, &gpio_initstructure); /* i2c configuration */ i2c_initstructure.i2c_mode = i2c_mode_i2c; i2c_initstructure.i2c_dutycycle = i2c_dutycycle_2; i2c_initstructure.i2c_ownaddress1 = 0x00; i2c_initstructure.i2c_ack = i2c_ack_enable; i2c_initstructure.i2c_acknowledgedaddress = i2c_acknowledgedaddress_7bit; i2c_initstructure.i2c_clockspeed = i2cxspeed; /* apply i2c configuration after enabling */ i2c_init(i2cx, &i2c_initstructure); /* i2c peripheral enable */ i2c_cmd(i2cx, enable); /* enable dma if required */ #if (defined(i2c1_use_dma_tx) || defined(i2c1_use_dma_rx)) if (i2cx==i2c1) inemoi2cdmainit(i2c1); #endif #if (defined(i2c2_use_dma_tx) || defined(i2c2_use_dma_rx)) if (i2cx==i2c2) inemoi2cdmainit(i2c2); #endif } void inemoi2cdmainit(i2c_typedef* i2cx) { /* enable dma1 clock */ rcc_ahbperiphclockcmd(rcc_ahbperiph_dma1, enable); /* i2c tx dma channel configuration */ i2cdma_initstructure.dma_memorybaseaddr = (uint32_t)0; /* parameter configured durig communication */ i2cdma_initstructure.dma_dir = dma_dir_peripheraldst; /* parameter configured durig communication */ i2cdma_initstructure.dma_buffersize = 0xffff; /* parameter configured durig communication */ i2cdma_initstructure.dma_peripheralinc = dma_peripheralinc_disable; i2cdma_initstructure.dma_memoryinc = dma_memoryinc_enable; i2cdma_initstructure.dma_peripheraldatasize = dma_memorydatasize_byte; i2cdma_initstructure.dma_memorydatasize = dma_memorydatasize_byte; i2cdma_initstructure.dma_mode = dma_mode_normal; i2cdma_initstructure.dma_priority = dma_priority_veryhigh; i2cdma_initstructure.dma_m2m = dma_m2m_disable; if(i2cx==i2c2) { i2cdma_initstructure.dma_peripheralbaseaddr = (uint32_t)i2c2_dr_address; #ifdef i2c2_use_dma_tx dma_deinit(i2c2_dma_channel_tx); dma_init(i2c2_dma_channel_tx, &i2cdma_initstructure); #endif #ifdef i2c2_use_dma_rx /* i2c2 rx dma channel configuration */ dma_deinit(i2c2_dma_channel_rx); dma_init(i2c2_dma_channel_rx, &i2cdma_initstructure); #endif } if(i2cx==i2c1) { i2cdma_initstructure.dma_peripheralbaseaddr = (uint32_t)i2c1_dr_address; #ifdef i2c1_use_dma_tx dma_deinit(i2c1_dma_channel_tx); dma_init(i2c1_dma_channel_tx, &i2cdma_initstructure); #endif #ifdef i2c1_use_dma_rx /* i2c1 rx dma channel configuration */ dma_deinit(i2c1_dma_channel_rx); dma_init(i2c1_dma_channel_rx, &i2cdma_initstructure); #endif } void inemoi2cdmaconfig(i2c_typedef* i2cx, uint8_t* pbuffer, uint32_t lbuffersize, uint32_t ldirection) { /* initialize dma new parameters */ if (ldirection == i2c_direction_tx) { /* configure dma tx channel buffer address , buffer size */ i2cdma_initstructure.dma_memorybaseaddr = (uint32_t)pbuffer; i2cdma_initstructure.dma_dir = dma_dir_peripheraldst; i2cdma_initstructure.dma_buffersize = (uint32_t)lbuffersize; if(i2cx==i2c2) { i2cdma_initstructure.dma_peripheralbaseaddr = (uint32_t)i2c2_dr_address; dma_cmd(i2c2_dma_channel_tx, disable); dma_init(i2c2_dma_channel_tx, &i2cdma_initstructure); dma_cmd(i2c2_dma_channel_tx, enable); } else { i2cdma_initstructure.dma_peripheralbaseaddr = (uint32_t)i2c1_dr_address; dma_cmd(i2c1_dma_channel_tx, disable); dma_init(i2c1_dma_channel_tx, &i2cdma_initstructure); dma_cmd(i2c1_dma_channel_tx, enable); } } else /* reception */ { /* configure dma rx channel buffer address , buffer size */ i2cdma_initstructure.dma_memorybaseaddr = (uint32_t)pbuffer; i2cdma_initstructure.dma_dir = dma_dir_peripheralsrc; i2cdma_initstructure.dma_buffersize = (uint32_t)lbuffersize; if(i2cx==i2c2) { i2cdma_initstructure.dma_peripheralbaseaddr = (uint32_t)i2c2_dr_address; dma_cmd(i2c2_dma_channel_rx, disable); dma_init(i2c2_dma_channel_rx, &i2cdma_initstructure); dma_cmd(i2c2_dma_channel_rx, enable); } else { i2cdma_initstructure.dma_peripheralbaseaddr = (uint32_t)i2c1_dr_address; dma_cmd(i2c1_dma_channel_rx, disable); dma_init(i2c1_dma_channel_rx, &i2cdma_initstructure); dma_cmd(i2c1_dma_channel_rx, enable); } } } void inemoi2cbufferreaddma(i2c_typedef* i2cx, uint8_t caddr, uint8_t* pcbuffer, uint8_t creadaddr, uint8_t cnumbytetoread) { __io uint32_t temp = 0; __io uint32_t timeout = 0; /* enable i2c errors interrupts */ i2cx->cr2 |= i2c_it_err; /* set msb of register address in case of multiple readings */ if(cnumbytetoread>1) creadaddr |= 0x80; #ifdef force_critical_sec __disable_irq(); #endif #ifdef usart_debug2 usart1_printf("flag busy\r\n"); #endif timeout = 0xffff; /* while bus busy */ while(i2c_getflagstatus(i2cx, i2c_flag_busy)){ if (timeout-- == 0) return; } /* send start condition */ i2c_generatestart(i2cx, enable); #ifdef usart_debug2 usart1_printf("master mode\r\n"); #endif timeout = 0xffff; /* test on ev5 , clear */ while(!i2c_checkevent(i2cx, i2c_event_master_mode_select)){ if (timeout-- == 0) return; } /* send lsm303dlh address read */ i2c_send7bitaddress(i2cx, caddr, i2c_direction_transmitter); timeout = 0xffff; /* test on ev6 , clear */ while(!i2c_checkevent(i2cx, i2c_event_master_transmitter_mode_selected)){ if (timeout-- == 0) return; } /* clear ev6 setting again pe bit */ i2c_cmd(i2cx, enable); /* send lsm303dlh_magn's internal address write */ i2c_senddata(i2cx, creadaddr); #ifdef usart_debug2 usart1_printf("byte transmitted\r\n"); #endif timeout = 0xffff; /* test on ev8 , clear */ while(!i2c_checkevent(i2cx, i2c_event_master_byte_transmitted)){ if (timeout-- == 0) return; } /* configure i2cx dma channel */ inemoi2cdmaconfig(i2cx, pcbuffer, cnumbytetoread, i2c_direction_rx); /* set last bit have nack on last received byte */ i2cx->cr2 |= 0x1000; /* enable i2c dma requests */ i2c_dmacmd(i2cx, enable); timeout = 0xffff; /* send start condition */ i2c_generatestart(i2cx, enable); timeout = 0xffff; /* wait until sb flag set: ev5 */ while(!i2c_checkevent(i2cx, i2c_event_master_mode_select)) { if (timeout-- == 0) return; } timeout = 0xffff; /* send lsm303dlh address read */ i2c_send7bitaddress(i2cx, caddr, i2c_direction_receiver); timeout = 0xffff; /* wait until addr set: ev6 */ while(!i2c_checkevent(i2cx, i2c_event_master_receiver_mode_selected)) { if (timeout-- == 0) return; } /* clear addr flag reading sr2 register */ temp = i2cx->sr2; if(i2cx == i2c2) { timeout = 0xffff; /* wait until dma end of transfer */ while (!dma_getflagstatus(dma1_flag_tc5)){ if (timeout-- == 0) return; } /* disable dma channel */ dma_cmd(i2c2_dma_channel_rx, disable); /* clear dma transfer complete flag */ dma_clearflag(dma1_flag_tc5); } else { /* wait until dma end of transfer */ #ifdef usart_debug2 usart1_printf("end transfer\r\n"); #endif timeout = 0xffff; while (!dma_getflagstatus(dma1_flag_tc7)){ if (timeout-- == 0) return; } /* disable dma channel */ dma_cmd(i2c1_dma_channel_rx, disable); /* clear dma transfer complete flag */ dma_clearflag(dma1_flag_tc7); } /* disable ack last byte */ i2c_acknowledgeconfig(i2cx, disable); /* send stop condition */ i2c_generatestop(i2cx, enable); #ifdef usart_debug2 usart1_printf("stop bit\r\n"); #endif timeout = 0xffff; /* make sure stop bit cleared hardware before cr1 write access */ while ((i2cx->cr1 & 0x0200) == 0x0200){ if (timeout-- == 0) return; } /* enable acknowledgement ready reception */ i2c_acknowledgeconfig(i2cx, enable); #ifdef force_critical_sec __enable_irq(); #endif } void inemoi2cbufferwritedma(i2c_typedef* i2cx, uint8_t caddr, uint8_t* pcbuffer, uint8_t cwriteaddr, uint8_t cnumbytetowrite) { __io uint32_t temp = 0; __io uint32_t timeout = 0; static uint8_t pcdmabuffer[dma_buffer_size+1]; /* set 1 msb of register address in case of multiple byte writing */ if(cnumbytetowrite>1) cwriteaddr |= 0x80; pcdmabuffer[0]=cwriteaddr; memcpy(&pcdmabuffer[1],pcbuffer,cnumbytetowrite); /* enable error */ i2cx->cr2 |= i2c_it_err; timeout = 0xffff; /* configure dma channel i2cx transmission */ inemoi2cdmaconfig(i2cx, pcdmabuffer, cnumbytetowrite+1, i2c_direction_tx); /* enable dma i2c */ i2c_dmacmd(i2cx, enable); /* send start condition */ i2c_generatestart(i2cx, enable); /* wait until sb flag set: ev5 */ while(!i2c_checkevent(i2cx, i2c_event_master_mode_select)) { if (timeout-- == 0) return; } timeout = 0xffff; /* send lsm303dlh address write */ i2c_send7bitaddress(i2cx, caddr, i2c_direction_transmitter); /* wait until addr set: ev6 */ while(!i2c_checkevent(i2cx, i2c_event_master_transmitter_mode_selected)) { if (timeout-- == 0) return; } /* clear addr flag reading sr2 register */ temp = i2cx->sr2; /* disable dma1 channel */ if(i2cx == i2c2) { /* wait until dma end of transfer */ while (!dma_getflagstatus(dma1_flag_tc4)); /* disable dma channel */ dma_cmd(i2c2_dma_channel_tx, disable); /* clear dma transfer complete flag */ dma_clearflag(dma1_flag_tc4); } else { /* wait until dma end of transfer */ while (!dma_getflagstatus(dma1_flag_tc6)); /* disable dma channel */ dma_cmd(i2c1_dma_channel_tx, disable); /* clear dma transfer complete flag */ dma_clearflag(dma1_flag_tc6); } /* ev8_2: wait until btf set before programming stop */ while(!i2c_checkevent(i2cx, i2c_event_master_byte_transmitted)); /* send stop condition */ i2c_generatestop(i2cx, enable); /* make sure stop bit cleared hardware before cr1 write access */ while ((i2cx->cr1 & 0x0200) == 0x0200); }
i see while loops have timeout, don't:
while ((i2cx->cr1 & 0x0200) == 0x0200);
make loops timeout, , make note error condition occurs (it needs investigated - if don't know reason, come haunt later).
hardware can bit buggy @ times, possible you're doing correctly, still doesn't work. check errata (for stm32 i2c , i2c slaves) documented bugs.
a few years ago came across issue i2c lines stay low, , had reconfigure pins gpio, bit-bang bits out, , switch i2c operation.
Comments
Post a Comment