pokk 0 9 ноября, 2015 Опубликовано 9 ноября, 2015 · Жалоба Добрый день, не как не могу понять почему виснет I2C в stm32f103, запускается работает работает потом бац зависло. //============================================================================== PT_THREAD(Send_data_fsm(struct pt *pt,unsigned char data1,unsigned char data2)){ static unsigned char data[2]; //--------------------------------------------------------------------------- if(pt->lc!=0){ //Не первый запуск if(GetTimers(I2C_TimeOut)>TIMEOUT_I2C){ Send_MSG(MSG_I2C_REBOOT); ResetTimers(I2C_TimeOut); } } //--------------------------------------------------------------------------- PT_BEGIN(pt); ResetTimers(I2C_TimeOut); data[0]=data1; data[1]=data2; /* initiate start sequence */ while(TakeMutex(I2C_MUTEX)){PT_YIELD(pt);} I2C_GenerateSTART(I2C2, ENABLE); /* check start bit flag */ while(!I2C_GetFlagStatus(I2C2, I2C_FLAG_SB)){PT_YIELD(pt);}; /*send write command to chip*/ I2C_Send7bitAddress(I2C2, I2C_ADDR_LCD_KEY_LED, I2C_Direction_Transmitter); /*check master is now in Tx mode*/ //-------------------------------------------------------------------------- while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)){}; //Spead=400KHz delay=1000 clock Spead=1KHz delay=65000 clock /*mode register address*/ I2C_SendData(I2C2, data[0]); //-------------------------------------------------------------------------- /*wait for byte send to complete*/ while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED)){PT_YIELD(pt);}; //3600 Speed=100Khz /*clear bits*/ I2C_SendData(I2C2, data[1]); //-------------------------------------------------------------------------- /*wait for byte send to complete*/ while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED)){PT_YIELD(pt);}; //-------------------------------------------------------------------------- /*generate stop*/ I2C_GenerateSTOP(I2C2, ENABLE); while(I2C_GetFlagStatus(I2C2, I2C_FLAG_STOPF)){PT_YIELD(pt);}; GiveMutex(I2C_MUTEX); PT_END(pt); } //============================================================================== Виснет на проверке: while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)){}; //Spead=400KHz delay=1000 clock I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED содержит флаги( BUSY, MSL, ADDR, TXE, TRA) Более глубокое копание показало что всё дело в флаге ADDR. Изменение куска кода на I2C2->CR1 |= I2C_CR1_START; while (!(I2C2->SR1 & I2C_SR1_SB)){}; (void) I2C2->SR1; I2C2->CR1|=I2C_CR1_ACK; I2C2->DR = I2C_ADDR_LCD_KEY_LED; while (!(I2C2->SR1 & I2C_SR1_ADDR)){}; (void) I2C2->SR1; (void) I2C2->SR2; Нечего не дало всё так же может пару тысяч раз отправить байт потом повиснуть на проверке I2C_SR1_ADDR. while (!(I2C2->SR1 & I2C_SR1_ADDR)){}; При пошаговой отладке в IAR заметил что до while (!(I2C2->SR1 & I2C_SR1_ADDR)){}; флаг ADDR взводится, но как только начинаешь проверку он сбрасывается и соответственно там всё виснет. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
pokk 0 13 ноября, 2015 Опубликовано 13 ноября, 2015 (изменено) · Жалоба Сил уже нету с i2c разбираться, ни в какую он не хочет стабильно работать. Уже весь проект перелопатил все сторонние воздействия от кода исключил, осталась только одна функция отправки данных по i2c которая крутится в цикле. Проблема в следующем программа всё так же зависает на строчке while (!(I2C2->SR1 & I2C_SR1_ADDR)){}; Причём это происходит совсем неявно т.е может спокойно передаться 1000 посылок, потом зависнуть, а в следующий раз (после рестарта) штук 50 передаться. Так же выявил, что стабильность передачи зависит от задержки между пакетами, и вот тут начинается самое весёлое. без задержки всё работает(отправляется пакетов больше 10000) потом при какой-то магической задержки перестаёт работать(количество отправленных пакетов <100 в основном 15-60), а при увеличения её продолжает работать. Так эти задержки относятся и коду т.е если за комментировал какое-то условие(для строба синхронизации) то работает обратно вернул не работает :shock: int main(void){ GPIO_InitTypeDef GPIO_InitStructure; I2C_InitTypeDef I2C_InitStructure; //============================================================================== //I2C_Setup_fsm(&ModeDisplayUpdate); RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB| RCC_APB2Periph_AFIO , ENABLE);// /* I2C2 SDA and SCL configuration */ GPIO_StructInit(&GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10|GPIO_Pin_11; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD; //GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD; //GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_Init(GPIOB, &GPIO_InitStructure); /*SCL is pin06 and SDA is pin 07 for I2C2*/ GPIO_StructInit(&GPIO_InitStructure); GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; GPIO_Init(GPIOB, &GPIO_InitStructure); //I2C_DeInit(I2C2); // I2C_Cmd(I2C2,DISABLE); // GPIO_DeInit(GPIOB); // GPIO_AFIODeInit(); /* I2C2 configuration */ I2C_StructInit(&I2C_InitStructure); 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 = I2C_SPEED ; I2C_Init(I2C2, &I2C_InitStructure); // I2C2->CR1&=~I2C_CR1_SMBUS; // I2C MODE enable // I2C2->CR2|=I2C_CR2_FREQ_2; // Peripheral clock frequency 36MHz // I2C2->CR2|=I2C_CR2_FREQ_4; // Peripheral clock frequency 36MHz // I2C2->CCR&=~I2C_CCR_CCR; // Clear CCR bit field // I2C2->CCR|=0x64; // CCR=I2C_freq_clock/(2*I2C_freq_speed) = 36000000/(2*100000) - just for standart MODE (not fast) {see Ref.M. p.752} // I2C2->CCR&=~I2C_CCR_FS; //Standart Mode I2C // I2C2->TRISE|=20; // rise_time = 1000ns, T_pclk1=28ns (1/36000000) => TRISE=rise_time/T_pclk1 {see Ref.M. p.753} // I2C2->CR1|=I2C_CR1_PE;// peripheral enable // I2C_AcknowledgeConfig(I2C2, ENABLE); //------------------------------------------------------------------------------ /*enable I2C*/ //I2C_Cmd(I2C2,ENABLE); //============================================================================== //==============================Главный цикл==================================== //============================================================================== while(1){ //--------------------------------------------------------------------------- //I2C2->CR1|=I2C_CR1_PE;// peripheral enable //--------------Cтроб для синхронизации с осциллографом(поиска места обрыва)-- if(TEST_delay123>=CounterPascet-1){ TEST_DELAY_OFF } //--------------------------------------------------------------------------- I2C2->CR1 |= I2C_CR1_START; //--------------------------------------------------------------------------- while (!(I2C2->SR1 & I2C_SR1_SB)){}; //EV5: SB=1, cleared by reading SR1 register followed by writing DR register with Address. (void) I2C2->SR1; I2C2->DR = I2C_ADDR_LCD_KEY_LED; //---------------------------------------------------------------------------------------------- while (!(I2C2->SR1 & I2C_SR1_ADDR)){}; //EV6:ADDR=1, cleared by reading SR1 register followed by reading SR2. (void)I2C2->SR1; (void)I2C2->SR2; while (!(I2C2->SR1 & I2C_SR1_TXE)){}; //EV8_1:TxE=1, shift register empty, data register empty, write Data1 in DR. I2C2->DR = 0xAA; //---------------------------------------------------------------------------------------------- while (!(I2C2->SR1 & I2C_SR1_TXE)){}; //EV8:TxE=1, shift register not empty, dataregister empty, cleared by writing DR register I2C2->DR = 0xff; //---------------------------------------------------------------------------------------------- while (!(I2C2->SR1 & I2C_SR1_TXE)){}; while (!(I2C2->SR1 & I2C_SR1_BTF)){} //EV8_2:TxE=1, BTF = 1, Program Stop request. TxE and BTF are cleared by hardware by the Stop condition I2C2->CR1 |= I2C_CR1_STOP; //---------------------------------------------------------------------------------------------- while(I2C_GetFlagStatus(I2C2, I2C_FLAG_STOPF)); //--------------Cтроб для синхронизации с осциллографом(поиска места обрыва)-------------------- if(TEST_delay123>=CounterPascet-1){ TEST_DELAY_ON } //I2C2->CR1&=~I2C_CR1_PE;// peripheral disable //----------МАГИЧЕСКИЕ ЗАДЕРЖКИ------------------------------------------------------------- //----------Сделал увеличение что бы было сразу было понятно работает или нет--------------- delay123=TEST_delay123; //delay123=27; //delay1=1; //delay123=60; //delay123=11; while(delay123--); TEST_delay123++; if(TEST_delay123>=0xFFFF){TEST_delay123=0xFFFF;} ////------------------------------------------------------------------------------------------------ } } PS: В момент зависания на осциллограмме видно, что стартовый бит выставился, а вот адрес даже не начал передаваться. Изменено 13 ноября, 2015 пользователем pokk Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
esaulenka 7 13 ноября, 2015 Опубликовано 13 ноября, 2015 · Жалоба У меня тоже нестабильно работало. Подумал-подумал, и решил, что бит сброса I2C в периферии не просто так. Все ожидания - не while (), а циклы с таймаутом. При превышении таймаута - сброс периферии и повторная попытка (до трёх штук). Работает, на помехи в линии и прочие тыканья пинцетом по контактам реагирует адекватно. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
pokk 0 13 ноября, 2015 Опубликовано 13 ноября, 2015 · Жалоба У меня тоже нестабильно работало. Подумал-подумал, и решил, что бит сброса I2C в периферии не просто так. Я уже тоже об этом думаю, но если бы он глючил, то это бы не зависело от кода особенно от наличия нопов. У меня изначально было всё с таймаутами и тд. потом в процессе отладки всё по удалял. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
gerber 8 13 ноября, 2015 Опубликовано 13 ноября, 2015 · Жалоба Вполне возможно, что в какой-то момент на шине происходит ошибка (с точки зрения контроллера), например, фиксируется липовое "старт" условие посреди адреса (misplaced start condition), из-за близких фронтов и емкостных свойств линий. Поэтому ждать нужно не только ADDR бита, но и возможных битов ошибок, в особенности BERR. Проскакивание таких редких ошибок наблюдал лично на STM32F103. То же самое касается слейва, с которым вы работаете, он тоже неидеален, и в какой-то момент по своим внутренним причинам можеть не подтвердить вам адрес (NACK), и вы до посинения будете его ожтдать в бесконечном цикле, так работать нельзя, конечно. И ещё момент - работать поллингом с контроллером I2C крайне плохо, статусные регистры "не любят", когда их задалбывают чтениями и могут сбросить нужный бит ADDR "в глубине души". С этим я тоже сталкивался, правда, на других контроллерах, но "раз в год и палка стреляет". Всегда нужно работать с прерываниями, как по основным, так и по ошибочным событиям, в обработчике прерывания один раз прочитать статусный регистр и последовательно разобрать в нём установленные биты. Всё. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
x893 60 13 ноября, 2015 Опубликовано 13 ноября, 2015 · Жалоба можно всегда посмотреть как в HAL или CPAL это делается. Без таймоута в поллинге конечно опасно это делать. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AHTOXA 18 13 ноября, 2015 Опубликовано 13 ноября, 2015 · Жалоба Все ожидания - не while (), а циклы с таймаутом. При превышении таймаута - сброс периферии и повторная попытка (до трёх штук). +1. Ещё полезно при затыке подёргать клоками, держа линию данных в единице, чтоб сбросились машины состояний устройств на шине. А что там раскорячивается - фиг его знает. Слишком сложная периферия. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
adnega 11 13 ноября, 2015 Опубликовано 13 ноября, 2015 · Жалоба Errata sheet для I2C у F103 довольно толстый раздел. Не пробовали там поискать причины? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
x893 60 13 ноября, 2015 Опубликовано 13 ноября, 2015 · Жалоба У NXP есть мануал как инициализировать I2C после ошибки/сброса Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
toweroff 1 13 ноября, 2015 Опубликовано 13 ноября, 2015 · Жалоба У NXP есть мануал как инициализировать I2C после ошибки/сброса а зачем оно? у ТС - STM32 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AHTOXA 18 13 ноября, 2015 Опубликовано 13 ноября, 2015 · Жалоба а зачем оно? у ТС - STM32 А NXP (philips) придумали I2C :) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться