|
|
  |
Работа с IrDA |
|
|
|
Dec 15 2013, 19:05
|
Гуру
     
Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882

|
Цитата(d7d1cd @ Dec 15 2013, 18:21)  Подскажите, возможно ли организовать обмен, не используя прерывания и таймер? Вообще без использования таймера или каких-то временных отметок - нельзя. Точнее можно, то нужно писать на ASM и очень сильно постараться, чтобы выдержать времянки циклов и скомпенсировать все задержки при переходах. Если же все же задействовать функционал TimerA, к пинам которого у вас подключен трансивер IRDA, то можно реализовать аппаратно-программный UART. См. принцип реализации в application note Implementing IrDA With The MSP430 или MSP430C112 IrDA SIR Encoder/Decoder. P.S. а чего это вы через полтора+ года вернулись к тому, с чего начинали? Разве нельзя было изменить схему и подключить трансивер IrDA к выводам USCI, коль уж и кристалл вы уже поменяли?
|
|
|
|
|
Dec 16 2013, 17:12
|
Местный
  
Группа: Участник
Сообщений: 442
Регистрация: 26-11-10
Пользователь №: 61 199

|
Спасибо за подсказки. Изменить схему подключения к сожалению нельзя (хотя очень хочется). Я пишу на ассемблере. Думаю, что выдержать временные циклы будет не так сложно, ведь известно сколько тактов занимает та или иная инструкция, а частота тактирования мне известна. Есть другой камень преткновения: физический принцип работы инфракрасного канала. Мне необходимо организовать обмен на скорости 9600 бит/с, без проверки на четность/нечетность, 1 стоп-бит. Подскажите, правильно ли я рассуждаю. 1. Чтобы передать байт, надо кроме 8 бит данных передавать старт и стоп биты. 2. Старт бит - это 1, стоп бит - это 0. 3. Передача 1 по инфракрасному каналу - это отсутствие импульса, передача 0 это наличие импульса. 4. Длительность импульса должна быть 3/16 от времени, приходящегося на передачу 1 бита на скорости 9600. 5. Длительность передачи 1 бита: 1 / 9600 = 0,0001 с; длительность импульса: 0,0001 * 3 / 16 = 0,00002 с. 6. Импульс должен произойти в любом месте отрезка времени передачи бита.
|
|
|
|
|
Dec 16 2013, 19:16
|
Гуру
     
Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882

|
Цитата(d7d1cd @ Dec 16 2013, 22:12)  Подскажите, правильно ли я рассуждаю. Почти правильно. Уровни UART не просто определяются как лог.1. и лог.0, а именуются MARK (неактивный уровень, лог.1 на выходе UART) и SPACE (активный, лог.0 на выходе UART). SPACE в IrDA передается импульсом, MARK - отсутствием импульса. START-бит передается как SPACE, т.е. наличием импульса. Иначе как вы определите начало символа? STOP-бит передается уровнем MARK (отсутствием импульса). Последний пункт у вас неверный. Импульс должен передаваться не в любом месте битового интервала, а строго посередине его. Насчет легкости реализации. Учитывайте, что если вы не будете использовать аппаратные возможности TimerA, то вам придется делать polling (опрос входа) RX как минимум 16*9600=153600 раз/с. Т.е. с учетом циклов и переходов MCLK у вас (навскидку/грубо) должен быть не менее 4МГц и кратен битовой частоте передачи/приема.
|
|
|
|
|
Dec 18 2013, 14:48
|
Местный
  
Группа: Участник
Сообщений: 442
Регистрация: 26-11-10
Пользователь №: 61 199

|
Цитата(rezident @ Dec 16 2013, 23:16)  Последний пункт у вас неверный. Импульс должен передаваться не в любом месте битового интервала, а строго посередине его. В указанном документе MSP430C112 IrDA SIR Encoder/Decoder я узнал, что инфракрасный импульс должен передаваться не строго посередине битового интервала, а должен начаться строго посередине этого интервала. Чем больше я думаю о реализации своего "чисто программного" обмена, тем больше понимаю, что не так уж это просто  . Хочу следовать Вашему совету и использовать таймер А. У таймера будут прерывания. Так как я планирую выполнять полную перезапись флешь памяти, то использовать вектора прерываний нельзя. Значит надо делать постоянный опрос флага прерывания таймера. Правильно? Или же можно перенести таблицу прерываний в RAM (где то читал, что так можно сделать на некоторых МК)?
|
|
|
|
|
Dec 18 2013, 16:36
|
Гуру
     
Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882

|
Цитата(d7d1cd @ Dec 18 2013, 19:48)  В указанном документе MSP430C112 IrDA SIR Encoder/Decoder я узнал, что инфракрасный импульс должен передаваться не строго посередине битового интервала, а должен начаться строго посередине этого интервала. Да, это так. Согласен. Цитата(d7d1cd @ Dec 18 2013, 19:48)  У таймера будут прерывания. Так как я планирую выполнять полную перезапись флешь памяти, то использовать вектора прерываний нельзя. Значит надо делать постоянный опрос флага прерывания таймера. Правильно? Не обязательно. Прерывания должы быть запрещены лишь во время записи/стирания Flash. А между циклами записи/стирания - пожалуйста. Приняли по прерываниям в буфер, запретили прерывание, записали буфер во Flash, разрешили прерывание и т.д. Вот только переписывать сектор с векторами прерываний при таком раскладе не рекомендуется. При неудачном стечении обстоятельств можно получить нерабочий кристалл, который только через BSL можно будет стереть. Цитата(d7d1cd @ Dec 18 2013, 19:48)  Или же можно перенести таблицу прерываний в RAM (где то читал, что так можно сделать на некоторых МК)? В сериях MSP430F5xxx/6xxx есть аппаратная поддержка ремапа векторов прерываний в ОЗУ. У других серий можно реализовать программную эмуляцию ремапа, но опять же в обоих случаях сектор с векторами прерываний переписывать не стоит.
|
|
|
|
|
Dec 18 2013, 17:28
|
Местный
  
Группа: Участник
Сообщений: 442
Регистрация: 26-11-10
Пользователь №: 61 199

|
Цитата(rezident @ Dec 18 2013, 20:36)  Не обязательно. Прерывания должны быть запрещены лишь во время записи/стирания Flash. А между циклами записи/стирания - пожалуйста. Приняли по прерываниям в буфер, запретили прерывание, записали буфер во Flash, разрешили прерывание и т. д. Вот только переписывать сектор с векторами прерываний при таком раскладе не рекомендуется. При неудачном стечении обстоятельств можно получить нерабочий кристалл, который только через BSL можно будет стереть. Переписывать сектор с векторами, наверное, все-таки надо. Ведь при штатном режиме работы таймер используется для других целей и у этих целей будет свой обработчик прерывания, который находится во флешь, а при загрузочном режиме обработчик прерывания находится в RAM... Скажите, а чем плох метод циклического опроса флага наличия прерывания таймера? И имеет ли он право на существование?
|
|
|
|
|
Dec 26 2013, 14:09
|
Гуру
     
Группа: Свой
Сообщений: 2 702
Регистрация: 14-07-06
Пользователь №: 18 823

|
Цитата(d7d1cd @ Dec 21 2013, 19:28)  Но тема не закрыта. У кого как. В связи с появлением люминесцентных ламп, излучающих в ИК диапазоне я тему закрыл. Выкладываю исходник "как есть". Там какие-то мои макросы управления портами, спросите если будет интересно. Да, одна неприятная особенность этого всего - необходимость работы вложенных прерываний, поэтому прочитайте про новые лампы еще раз и хорошенько подумайте.. Код #define MaxBoudrate 115200
#define Boudrate 38400
#define IrdaPeriod (XT2CLK/Boudrate) //32 #define MinIrdaPeriod (XT2CLK/MaxBoudrate) //32
#define IrdaPulse (MinIrdaPeriod*3/16) //6
unsigned int irda_rx_mask=1; unsigned int irda_tx_mask=1; unsigned int irda_rx_data; unsigned int irda_tx_data;
#define LastRxMask 0x200 #define LastTxMask 0x400
char irda_rx_byte; char irda_rx_flag;
void SendByteViaIrda(char B) { OffFunction(IrdaRxInterrupt); irda_tx_data = (((unsigned int)B)<<2)|0xFC01; TACTL = TASSEL_2 + TACLR + MC_0; // Timer A counts SMCLK clocks continuos Stop TACCR2= IrdaPeriod-IrdaPulse-1; // TA2 active irda_tx_mask=1; TACCTL1 = 0; // disable interrupt for receiving TACCTL0 = CCIE+CCIFG; // enable interrupt for transmittion TACCTL2 = OUTMOD_3; TACTL |= MC_1; // timer start to "UP" mode
for (;;) { if (irda_tx_mask>LastTxMask) { TACCTL0=0; InitIrdaReceiveMode(); return; } } }
#pragma vector=TIMERA0_VECTOR __interrupt void TimerA_modul0(void) { if (irda_tx_mask<=LastTxMask) irda_tx_mask=irda_tx_mask<<1; else TACCTL0=0; // no more interrupts if (irda_tx_data & irda_tx_mask) OffFunction(CCTL2); else OnFunction(CCTL2); }
void TimerAConfiguration(void) { __bic_SR_register OSCOFF; TACTL = TASSEL_2 + TACLR + MC_0; // Timer A counts SMCLK clocks TACCTL0 = 0; // module 0 configuration, enable interrupt later TACCR0 = IrdaPeriod; // period of timer overflow TACTL |= MC_1; // timer start to "UP" mode }
void InitIrdaReceiveMode(void) { P2IFG=0; P2IES=0x80; P2IE=0x80; TACCR0=IrdaPeriod-1; // period TACCR1=IrdaPeriod/2; // change mask TACCR2=IrdaPeriod+2; // never happens irda_rx_data=0xffff; irda_rx_mask=0x0001; TACTL = TASSEL_2 + TACLR + MC_0; TACCTL1=CCIE; irda_rx_byte=0; P2IFG=0; P2IE=0x80; }
#pragma vector=TIMERA1_VECTOR __interrupt void TimerA_modul2(void) { irda_rx_mask=irda_rx_mask<<1; if (irda_rx_mask==LastRxMask) { irda_rx_byte=(char)(irda_rx_data>>1); TACTL = TASSEL_2 + TACLR + MC_0; irda_rx_data=0xffff; irda_rx_mask=0x0001; irda_rx_flag=1; } TACCTL1 &= ~(unsigned int)CCIFG; }
#pragma vector=PORT2_VECTOR __interrupt void IrdaRxPulse(void) { irda_rx_data&=~irda_rx_mask; TACTL|= MC_1; P2IFG=0; }
--------------------
Уходя, оставьте свет...
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|