Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: I2C LPC2xxx
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
GetSmart
Есть исходник, работающий через I2C с термометром. Тестирую его без FreeRTOS - работает стабильно и долго. Запускаю Ось - глючит сильно, и иногда работает. I2C работает через прерывание. Компилятор CW. Под Осью оно описано так:
Код
void vI2C_ISR_Wrapper( void )
{
    /* Save the context of the interrupted task. */
    portSAVE_CONTEXT();

    /* Call the handler.  This must be a separate function from the wrapper
    to ensure the correct stack frame is set up. */
    vI2C_ISR_Handler();

    /* Restore the context of whichever task is going to run next. */
    portRESTORE_CONTEXT();
}

без оси так:
Код
void vI2C_ISR_Handler( void )
{
    asm("STMDB    SP!,{R0-R12,LR}");        // пролог для IRQ
...
    VICVectAddr = 0;        /* Acknowledge Interrupt */
    asm(    "LDMIA    SP!,{R0-R12,LR}    \n"    // эпиолог для IRQ
        "SUBS    PC,LR,#4    ");
}

Прерывания в обоих случаях внутри обработчиков запрещены. Начинка прерывания была взята из примеров с сайта NXP, хотя немного переделана. Параллельно с работой I2C прерывания работает FIQ с частотой 8 КГц. FIQ работает стабильно под осью и без оси, и на глюки в обоих вариантах (с осью/без) не влияет.

Вопрос: куда копать? Может кто описать особенности "написания программы" под FreeRTOS ? В том смысле, что вот этого например делать нельзя, или на вот это нужно обратить особое внимание, или ещё что-нить. Проект большой, так что выложить бОльшие куски кода пока не могу.
HARMHARM
Посмотрите как сделано в примерах, идущих с FreeRTOS под ваш контроллер. Есть разница в оформлении прерываний?
Я так понимаю, что это ARM. Это ARM7? Нужно ли вообще сохранять контекст внутри прерывания?
zltigo
Цитата(GetSmart @ Sep 25 2009, 18:51) *
глючит сильно

Исчерпывающе sad.gif.
Цитата
Может кто описать особенности "написания программы" под FreeRTOS ?

Да нет никаких особенных особенностей.



Цитата(HARMHARM @ Sep 25 2009, 21:50) *
Нужно ли вообще сохранять контекст внутри прерывания?

Подозреваю, что для столь медленного девайса, как I2C термометр это (обеспечение вызова переключения контекста из обработчика) по любому излишество.
GetSmart
Цитата(zltigo @ Sep 26 2009, 02:01) *
Исчерпывающе sad.gif.

smile.gif
Правильнее было бы написать, что принимаются неправильные данные по i2c. Вероятнее всего криво написанный обработчик, точнее сама его начинка, а не прологи/эпилоги. Я с того времени накатал простенький обработчик i2c. Вот, если кто обнаружит ошибки - буду признателен. Проц LPC2368
CODE
void vI2C_ISR_Handler( void )
{
asm("STMDB SP!,{R0-R12,LR}"); // пролог для IRQ

switch ( I20STAT )
{
case 0x08: // передан первый START, далее передать SLA
case 0x10: // передан повторный START без STOP-a
// I20CONCLR = STA; //???
I20CONSET = AA;
I2CMasterState = I2C_STARTED;
if (WrIndex < I2CWriteLength) // если есть данные для передачи
I20DAT = I2CMasterAddr;
else I20DAT = I2CMasterAddr | 0x01; // иначе будет чтение данных
break;

case 0x18: // принят ACK после SLA+W
case 0x28: // принят ACK после Byte Send
I2CMasterState = DATA_ACK;
if (WrIndex < I2CWriteLength)
{ I20DAT = I2CBuffer[WrIndex++];
I20CONSET = AA;
}
else if (I2CReadLength != 0) // если требуется что-то прочитать
{ I20CONSET = STA | AA; // повторить START для чтения данных
}
else
{ I20CONSET = STO | AA; // завершить обмен по I2C
I2CMasterState = DATA_NACK; // реально - удачное завершение обмена
}
break;

case 0x50: // передан ACK после Byte Receive
case 0x58: // передан NACK после Byte Receive (проверить реально ли NACK ?)
if (RdIndex < I2CReadLength)
I2CBuffer[RdIndex++] = I20DAT;
case 0x40: // принят ACK после SLA+R
// I2CMasterState = DATA_ACK;
if ((RdIndex+1) < I2CReadLength) I20CONSET = AA; // будет ACK // если есть место куда ложить байты
else if ((RdIndex+1) == I2CReadLength) I20CONCLR = AA; // будет NACK // если есть место куда ложить байты
else
{ I20CONSET = STO | AA; // завершить обмен по I2C
I2CMasterState = DATA_NACK; // реально - удачное завершение обмена
}
break;

case 0x20: // после SLA+W принят NACK
case 0x30: // после Byte Send принят NACK
case 0x48: // после SLA+R принят NACK
I20CONSET = STO | AA;
// case 0x38: // потеря арбитража
default:
I2CMasterState = DATA_ERROR; // завершение обмена
break;
}

I20CONCLR = SI;

VICVectAddr = 0; /* Acknowledge Interrupt */
asm( "LDMIA SP!,{R0-R12,LR} \n" // эпиолог для IRQ
"SUBS PC,LR,#4 ");
}


И ещё я не понял, как мастер узнаёт когда передавать 9 клоков после передачи SLA+R и получении ACK ? Проц взводит флаг SI, I20STAT становится = 0x40, входит в прерывание. С какого момента начинают передаваться клоки - сразу после доступа к I20CONSET/I20CONCLR или по сбросу SI или ещё когда? И после приёма байта когда мастер начинает вырабатывать 9 клоков - аналогично предыдущему случаю или сразу после чтения I20DAT ? Или может проц вырабатывает 8 клоков, и только после записи AA вырабатывает 9-ый. Осцилла нет да сроки поджимают очень, а так бы проверил.

Цитата(zltigo @ Sep 26 2009, 02:01) *
Подозреваю, что для столь медленного девайса, как I2C термометр это (обеспечение вызова переключения контекста из обработчика) по любому излишество.

То есть, во FreeRTOS можно (рекомендуется?) делать IRQ без обёрток portSAVE_CONTEXT() ? То есть самым обыкновенным способом, как я сделал в примере без оси?
aaarrr
Цитата(GetSmart @ Sep 26 2009, 01:28) *
То есть, во FreeRTOS можно (рекомендуется?) делать IRQ без обёрток portSAVE_CONTEXT() ? То есть самым обыкновенным способом, как я сделал в примере без оси?

Можно. Если переключение контекста в обработчике не нужно, то эта обертка - пустая трата времени и памяти.
zltigo
Цитата(GetSmart @ Sep 25 2009, 23:28) *
То есть, во FreeRTOS можно (рекомендуется?) делать IRQ без обёрток portSAVE_CONTEXT() ? То есть самым обыкновенным способом, как я сделал в примере без оси?

Ни нафиг не сдались, если не преключать контекст из обработчика прерывания. Для только перепланировки есть отдельная группа функций "from isr". Ваш обработчик не читал. Образчик своего когда-то на на форуме выкладывал. Пользуюсь постоянно в основном для EEPROМ в том числе и на высоких скоростях.
P.S.
Увлечение asm вставками зачем?
GetSmart
Цитата(zltigo @ Sep 26 2009, 03:55) *
Увлечение asm вставками зачем?

Я тут уже отчитывался по кривому коду, генерируемому CW 1.7.9 http://electronix.ru/forum/index.php?showt...st&p=651216
Вот такой прототип обратботчика

void NameIntr() __attribute__((interrupt("IRQ")));

правильно работает только на 0 уровне оптимизации, то есть с самым тормознутым кодом. На уровнях 1 и выше приходится делать ручные вставки.

Цитата(zltigo @ Sep 26 2009, 03:55) *
Образчик своего когда-то на на форуме выкладывал.

Вот этот?
http://electronix.ru/forum/index.php?showt...ost&p=90212
А он для 2368 подойдёт? Там ничего не поменяли?

Я злой sad.gif
На Manual 2368. Где там указано, что при статусе 0x08/0x10 нужно сбрасывать STA (I20CONCLR = STA) ?
В разделе (((10.6 Master states->10.6.1 State : 0x08))) нету такого. И ещё непонятно зачем почти для всех статусов нужно записывать AA в I2CONSET.
Зря я NXP-шников защищал когда-то.
zltigo
Цитата(GetSmart @ Sep 26 2009, 00:33) *
На Manual 2368...

Не читал smile.gif контроллер I2C не менялся со времен филипсовских 51. В первых мануалах на LPC2114 даже вообще не описывали никак.
Цитата
Вот этот?

Да, лабораторная работа, так сказать. Реальный отличается, но не принципиально.
GetSmart
Грёбаный компилятор CW. Я щас с ума сойду от таких ошибок. Оптимизация = level1

Упс. Там мой косяк. Написал ненароком if (WrIndex >= I2CWriteLength) tmp | 0x01;
А компилер даже не заругался.
aaarrr
Цитата(GetSmart @ Sep 26 2009, 03:14) *
Грёбаный компилятор CW. Я щас с ума сойду от таких ошибок.

Может, сменить/починить инструмент, коли все так запущено?
GetSmart
Цитата(aaarrr @ Sep 26 2009, 05:23) *
Может, сменить/починить инструмент, коли все так запущено?

А на что его сменить? Студия-то неплохая, компилятор (внешний, GNU) - ховно.

Цитата(zltigo @ Sep 26 2009, 05:02) *
Да, лабораторная работа, так сказать. Реальный отличается, но не принципиально.

У Вас там не всё гладко. Не формируется NACK на последнем принимаемом байте, из-за этого статуса 0x58 никогда не будет. А если (гипотетически) туда залетит прога, то зачем-то снова START формируется.
aaarrr
Цитата(GetSmart @ Sep 26 2009, 03:35) *
А на что его сменить?

На что-нибудь коммерческое. Или нельзя?
GetSmart
Цитата(aaarrr @ Sep 26 2009, 05:40) *
На что-нибудь коммерческое. Или нельзя?

А есть коммерческий под CW ? Саму студию пока низзя менять.
aaarrr
Хм. А в CW есть что-то уникальное?
GetSmart
Цитата(aaarrr @ Sep 26 2009, 05:54) *
Хм. А в CW есть что-то уникальное?

Скажем так: мой работодатель в него влюблён biggrin.gif
Ну и синтаксис у CW и IARа отличается прилично. А проект большой. Переделывать затруднительно. И ещё есть несколько причин против.
GetSmart
Спешу обрадовать (ся?) всех. Переписал это левой ногой писанный обработчик I2C и всё заработало под осью причём с кучей тредов и FIQ-ом. Теперь термометр и мост на OWI работают на 400 КГц I2C без единого глюка. Бывает же такое - кривой обработчик, но без оси работал тоже без глюков.

Вобщем получилась тема дубль 2 с моей старой темой - про глюки FIQ smile.gif
Если кому надо могу выложить обработчик прерывания I2C (только для мастера). Обработчик умеет в одном пакете передавать блок данных и сразу же принимать второй блок, не освобождая шину.
zltigo
Цитата(GetSmart @ Sep 26 2009, 01:35) *
У Вас там не всё гладко.

Может да, может нет. Разборки были много лет назад. Пока все устраивает.
IgorKossak
Цитата(GetSmart @ Sep 26 2009, 08:11) *
Если кому надо могу выложить обработчик прерывания I2C (только для мастера). Обработчик умеет в одном пакете передавать блок данных и сразу же принимать второй блок, не освобождая шину.

Конечно надо, буквально на следующей неделе буду этим заниматься. Отчего же сразу не выложили?
GetSmart
Выкладываю. Причесал его как следует. По объёму текста получился такой же как у zltigo.

Забыл там ещё вот это

typedef signed short Int16;

Ещё очепятку нашёл в строке 29. Надо исправить число 11 на 12 вот так:

SetCoupleBits(PINMODE1,12,2); // резист.подтяжка выкл для P0.28

Хотя для I2C эта подтяжка возможно вообще не используется.
GetSmart
Ещё немного отшлифовал и улучшил. Работает прекрасно на 400 КГц I2C @ 24 МГц LPC2368. 7 тредов, 1 FIQ 8 КГц (занимающее 25% времени проца). Уж не знаю чем ещё загрузить проц для тестирования.
GetSmart
Много думал...
До сих пор непонятно, нужно ли при приёме данных на последнем байте мастеру передавать NACK ? Судя по картинке из мануала на 2368 "Fig 113. Format and States in the Master Receiver mode" - нужно. Но если подумать, то слишком умный слэйв (проц например) может воспринять этот NACK как ошибку приёма. С обычными I2C слэйвами в виде перифирийных микросхем проблем нет в обоих вариантах (ACK/NACK). В то же время я видел чей-то официальный исходник для MCS-51 с программной реализацией I2C, в котором всегда при приёме последнего байта по I2C мастер передавал NACK.

_______________________

По поводу моих исходников. Там можно в дополнение к I2CEngine() сделать её асинхронную версию (как ReadFile()/WriteFile() в винде) и во время передачи пакета по I2C проц будет выполнять что-либо полезное, периодически проверяя статус I2CEngine.
aaarrr
Цитата(GetSmart @ Sep 28 2009, 01:45) *
До сих пор непонятно, нужно ли при приёме данных на последнем байте мастеру передавать NACK ? Судя по картинке из мануала на 2368 "Fig 113. Format and States in the Master Receiver mode" - нужно. Но если подумать, то слишком умный слэйв (проц например) может воспринять этот NACK как ошибку приёма.

По стандарту нужно:
Цитата
If a master-receiver is involved in a transfer, it must signal
the end of data to the slave- transmitter by not generating
an acknowledge on the last byte that was clocked out of
the slave.

Если слейв "слишком умный" для совместимости, то это его проблемы.
Цитата(GetSmart @ Sep 28 2009, 01:45) *
С обычными I2C слэйвами в виде перифирийных микросхем проблем нет в обоих вариантах (ACK/NACK).

Не всегда. С какими-то из слейвов у меня точно были проблемы из-за забытого NAK.
Увы, не вспомню уже, с какими именно. Возможно, это было с AD.
Qwertty
Из за отсутствия NAK имел проблемы с ds1307 при чтении ОЗУ. Вроде вполне распосраненная микросхема.
GetSmart
Если кто уже успел опробовать исходники - поделитесь впечатлениями и характеристиками работы/тестов.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.