|
|
  |
переключение контента+TimeOut I2C, Как выявить зависание |
|
|
|
May 29 2017, 09:35
|
Частый гость
 
Группа: Участник
Сообщений: 91
Регистрация: 3-07-11
Пользователь №: 66 028

|
Добрый день, есть функция чтение температуры из термодатчика Lm75ad во время ожидания ожидания флага передаю управления другому процессу portYIELD(); Так вот если замкнуть линии I2C то процесс чтения температуры зависает, а остальное все работает. Так вот как по феншую сделать отработку зависания ? Пока только одна идея перед каждый ожидание засекать время, и в диспетчере смотреть больше оно таймаута или нет, но мне это не нравиться тем что это надо прятать в дефайны, что не айс, или код "загромождать". Если другие способы определения ?
uint8_t OS_Lm75ad_Read(short unsigned int* dataout,const unsigned char addr){ static short unsigned int tmp[2]; static short unsigned int* dataout_temp; //------------------------------------------------------------------------------------ LED_DEBUG_ON dataout_temp=dataout; while(I2C_GetFlagStatus(I2C_LM75AD, I2C_FLAG_BUSY)){portYIELD();}; LED_DEBUG_OFF //------------------------------------------------------------------------------------ I2C_GenerateSTART(I2C_LM75AD, ENABLE); /* check start bit flag */ while(!I2C_CheckEvent(I2C_LM75AD, I2C_EVENT_MASTER_MODE_SELECT)){portYIELD();}; LED_DEBUG_ON //----------------------SEND_ADDR_Write------------------------------------------------------- I2C_Send7bitAddress(I2C_LM75AD,(addr), I2C_Direction_Transmitter); while(!I2C_CheckEvent(I2C_LM75AD, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)){portYIELD();}; //----------------------POINT------------------------------------------------------------------ I2C_SendData(I2C_LM75AD,LM75AD_ADDR_REG_Temp); //Регист Temp(температура) while(!I2C_CheckEvent(I2C_LM75AD, I2C_EVENT_MASTER_BYTE_TRANSMITTED)){portYIELD();}; LED_DEBUG_ON //----------------------RE-START------------------------------------------------------------------- I2C_GenerateSTART(I2C_LM75AD, ENABLE); /* check start bit flag */ while(!I2C_CheckEvent(I2C_LM75AD, I2C_EVENT_MASTER_MODE_SELECT)){portYIELD();}; LED_DEBUG_OFF //-------------------Send_addr_read------------------------------------------------------ I2C_Send7bitAddress(I2C_LM75AD, (addr), I2C_Direction_Receiver); while(!I2C_CheckEvent(I2C_LM75AD, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED)){portYIELD();}; LED_DEBUG_ON //------------------------------------------------------------------------------------------ while(!I2C_CheckEvent(I2C_LM75AD, I2C_EVENT_MASTER_BYTE_RECEIVED)){portYIELD();}; LED_DEBUG_OFF tmp[0]=I2C_ReceiveData(I2C_LM75AD); //------------------------------------------------------------------------------------------ while(!I2C_CheckEvent(I2C_LM75AD, I2C_EVENT_MASTER_BYTE_RECEIVED)){portYIELD();}; LED_DEBUG_ON tmp[1]=I2C_ReceiveData(I2C_LM75AD); //------------------------------------------------------------------------------------------ I2C_GenerateSTOP(I2C_LM75AD, ENABLE); /*stop bit flag*/ I2C_AcknowledgeConfig(I2C_LM75AD, ENABLE); while(I2C_GetFlagStatus(I2C_LM75AD, I2C_FLAG_BUSY)){portYIELD();}; LED_DEBUG_OFF //------------------------------------------------------------------------------------------ *dataout_temp=(tmp[0]<<8)|tmp[1]; NOP;NOP;NOP;NOP;NOP; LED_DEBUG_ON //------------------------------------------------------------------------------------------ }
|
|
|
|
|
May 30 2017, 02:20
|
Местный
  
Группа: Свой
Сообщений: 206
Регистрация: 11-07-12
Из: Новосибирск
Пользователь №: 72 716

|
Cчeтчик с условием таймаута можно запрятать в функцию portYIELD, возвращать 0, если надо продолжать попытки, или не 0 если таймаут. Вызывать, например, так:
while ( !(!I2C_GetFlagStatus(I2C_LM75AD, I2C_FLAG_BUSY) || portYIELD()) ); //Если I2C_GetFlagStatus вернет 1, будет вызываться portYIELD. Цикл будет повторяться, пока portYIELD возвращает 0.
while( !(I2C_CheckEvent(I2C_LM75AD, I2C_EVENT_MASTER_MODE_SELECT) || portYIELD()) ); //Если I2C_CheckEvent вернет 0, будет вызываться portYIELD. Цикл будет повторяться, пока portYIELD возвращает 0.
|
|
|
|
|
May 30 2017, 05:13
|
Местный
  
Группа: Свой
Сообщений: 206
Регистрация: 11-07-12
Из: Новосибирск
Пользователь №: 72 716

|
Цитата(pokk @ May 30 2017, 10:37)  А где перезапустить счетчик ? Что бы для последующих ожиданий флагов был новый отсчет таймаута. B начале функции чтения температуры, чтобы после появления неисправности остальные циклы не выполнялись. А в конце функции проверять был ли достигнут таймаут, т.е. наличие неисправности.
|
|
|
|
|
May 31 2017, 02:33
|
Частый гость
 
Группа: Участник
Сообщений: 91
Регистрация: 3-07-11
Пользователь №: 66 028

|
firew0rker, спасибо за помощь примерно то что я и хотел.
Только теперь возникла другая проблема, как можно повторно узнать о наличии аварии точнее о переходе из аварии в норму ?
Дело вот в чем, помимо термодатчика на I2C у меня еще подключен LCD через расширитель порта(только линия DATA), управляющие выводы идут напрямую от процессора, так вот в момент замыкания происходит следующее: 1) в момент замыкания (при маленьком таймауте 2-5ms) на расширитель идет полная фигня, по этому он выдает на выходе нули т.е на LCD приходит Data=0,а так как управляющие выводы работают от процессора то LCD их и принимает, и выводит "корябозябру".
Если увеличивать таймаут больше периода обновления LCD то такого естественно не происходит. Но я хочу что бы момент замыкания не было видно и он максимально быстро отрабатывался.
PS: Флаг BERR и BUSY не помогают. BUSY ставиться только при замыкании на ноль, а BERR вообше не разу не выставился сколько бы не замыкал линию.
BERR – ошибка шины. Устанавливается при обнаружении сигнала start или stop в ”неуместном” месте. Для сброса BERR необходимо записать в него 0.
Сообщение отредактировал pokk - May 31 2017, 02:39
|
|
|
|
|
May 31 2017, 04:32
|
Частый гость
 
Группа: Участник
Сообщений: 91
Регистрация: 3-07-11
Пользователь №: 66 028

|
Цитата Если ваш ЖК-модуль на основе контроллера HD44780, то в DDRAM символы с кодами 00...07 - это переопределяемые символы. При инициализации занулите их, т. е. сделайте пробелами, чтобы при получении кода 0 выводился пробел а не крякозабра. так и есть в 0 ячейка стоит символ градуса, по нему и сужу что там 0 на дате приходит =)) Цитата Что надо обнаруживать: наличие и исправность датчика, или КЗ на I2C? Что бы вся периферия на I2C работала гарантированно и после КЗ что бы нечего не зависало, и в случае какой либо помехи,её не было заметно. Но вообще хочу сделать по полной и наличие датчиков на линии тоже, и в случае выхода одного из строя что бы все остальное работало. (над последним пока ещё думаю как это сделать,пока останавливаюсь на том что, если много раз зависал в одной функции то перейти на более медленный опрос этой функции раз в 10 секунд, или вообще выключить её опрос)
|
|
|
|
|
May 31 2017, 08:29
|
Профессионал
    
Группа: Свой
Сообщений: 1 123
Регистрация: 8-03-09
Из: Днепр
Пользователь №: 45 848

|
Цитата(pokk @ May 31 2017, 07:32)  (1) . . .. , и в случае выхода одного из строя что бы все остальное работало. (2) . . . .если много раз зависал в одной функции то перейти на более медленный опрос этой функции раз в 10 секунд, или вообще выключить её опрос) (1) если датчик закоротит одну из линий I2C - то естественно, "ляжет" вся шина. И с этим ничего не сделаешь. Шина I2C - внутрисхемный интерфейс, и если датчик висит на проводе более 10 см - готовьтесь к проблемам. Чтоб ОНО таки работало, проверьте подтягивающие резисторы I2C. Они должны быть (для надежной рабты периферии, в соотв-ии с миним. требованиями стандарта) R = 4.7 ... 10 кОм. ОНО будет, конечно, работать и на 100к, но помехоустойчивать будет приближаться к 0. Снижать вниз R нельзя, можно попалить выходные узлы как мастера, так и слейвов. Экранируйте провод линии - если они внешние для прибора. Для работы с длинной внешней шиной I2C есть спец. микросхемы-драйверы. (2) не используйте Код while( USCI_I2C_RDY_ ) { } - прямой путь к завесам в нем. лучше так Код MyTimer.Start(1000); while( USCI_I2C_RDY ) // бит периферийного узла I2C { if( MyTimer.IsElaps() ) { RetCode = eI2C_ERR_RDY; break; } } Завесы при работе с периферией I2C вполне возможны. slave может войти в "ступор" (ожидание) и ваш софт получит коллизию - навечно, до второго пришествия Reset. Вывести шину из этого состояния софтово можно принудительной подачей 9 clk (узел I2C отключить. ногодрыг SCK) Вообще, если что-то не работает или "глючит" - 99 проц. - вина аффтара софта и железа  Не устраняйте последствия, найдите и устраните причину сбойной работы.
|
|
|
|
|
May 31 2017, 10:02
|
Частый гость
 
Группа: Участник
Сообщений: 91
Регистрация: 3-07-11
Пользователь №: 66 028

|
Цитата (1) если датчик закоротит одну из линий I2C - то естественно, "ляжет" вся шина. И с этим ничего не сделаешь. С этим понятно я имел ввиду то что он по адресу не будет отвечать. Цитата Вообще, если что-то не работает или "глючит" - 99 проц. - вина аффтара софта и железа sm.gif Не устраняйте последствия, найдите и устраните причину сбойной работы. Да да автор виноват ибо нефиг пинцетом в шину тыкать, да на землю и питание её замыкать. Цитата Reset. Вывести шину из этого состояния софтово можно принудительной подачей 9 clk (узел I2C отключить. ногодрыг SCK) Клоки есть, но надо ещё сделать проверку уровня на линии после клока как посоветовал firew0rker.
|
|
|
|
|
May 31 2017, 10:55
|
Профессионал
    
Группа: Свой
Сообщений: 1 123
Регистрация: 8-03-09
Из: Днепр
Пользователь №: 45 848

|
Цитата(jcxz @ May 31 2017, 12:30)  Т.е. - заменить автора? Нет. Пока мы тут "бухтим как косм. корабли бороздят Большой Театр" ОН должен "расти на собой". Это не к ТС или к кому либо  Цитата(pokk @ May 31 2017, 13:02)  С этим понятно я имел ввиду то что он по адресу не будет отвечать. . . . При холодном старте 1. Проверка на "залипший" слейв. Если залипло - попытка сброса залипа. Если неудачно - LCD_Display("I2C fault", __LINE__); 2. Проверки на наличие и исправность всх имеющихся на шине slave Код for(. . . ) { if( I2C_SlaveIsConnect( slave_list[i] ) continue; else { LCD_Display("Slave error", i); while(1) {} } } 3. Надежность работы конечно зависит от типа-марки-произовдителя slave. Мне пока достаточно I2C_SlaveIsConnect( ADDR ) так как небыло необходимости. 4. Таймауты готовности slave (в смысле его внутреннего состояния). К примеру если это EEPROM в том или ином виде - то надо при последоватьельной записи потока данных выдерживать таймауты, пока в EEPROM пройдут внутренние операции (собственно запись). В вашем случае - время оцифровки. Пред любой операцией - читать регистры статуса напредмет готовности. ps - "Так вот если замкнуть линии I2C то процесс чтения температуры зависает, ... " Это понятно, на шине любое изменение (фронт, спад) отслеживается автоматами как master так и slave. Можно завесить все - если при этом вошел в коллизию (фактически из-за помехи) автомат master-а, или "зависнет" какой либо слейв - ожидая неизвестно чего, напр. после ложного "старта". Проверяйте HW - если глючек в нем, то копаться в софте бессмыслено.
Сообщение отредактировал k155la3 - May 31 2017, 11:00
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|