Хочется начать словами мистера Зорга из фильма "Пятый элемент"... только не могу решить какой: первой фразой "I am little disappointed" или финальной "I am very disappointed".
Когда надумал применить PRS для сенсора линии и начал смотреть... оказалось, что этот модуль на efm32gg не имеет ничего общего с PRS модулем на efr32bg. Структура другая и возможности, тоже совсем другие. И тогда, я подумал, что подключение энкодера к таймерам я могу выполнить не "снаружи", а внутри. Тем самым освободив один вывод микроконтроллера. Немного потыркавшись удалось, соединить пин PB3, который шел на WTIMER0_CC0 c TIMER0_CC0, который я хотел соединить перемычкой через порт PD1, и который, в результате этого высвободился. Правда, выяснилась несколько неприятная особенность. Не все выводы можно так "перекинуть". Например, взбреди мне в голову протащить выводы PE8, PE9, PE10, PE11 - я смог бы протащить только один из них. Но пока мне нужно было протащить только один - всё сработало прекрасно. И, кстати, этот PRS имеет возможность вывести сигнал наружу.
Когда же я стал разбираться с сенсором отражения, оказалось... не знаю, случайно ли, но несколько выводов зарезервированных для него имеют связь с таймерами 2 и 3. Таким образом, я могу половину сигналов получить в "пропорциональном формате". Вот что хорошо с таймерами в EFM32 - то, что их можно легко синхронизировать. Назначил таймер 2 ведущим , а 3 - ведомым и как только дал команду запустить таймер 2, сразу же и таймер 3 запустился. А вот что плохо, что у таймеров предделители очень слабые - только степени 2. Из-за этого нельзя получить точно нужные интервалы и частоты.
Так как я высвободил один вывод порта, была мысль сделать заряд конденсаторов сенсора аппаратным. Напомню, как предполагается работать этому сенсору:
Спойлер

В начале цикла (за 10 мкс до 0) на фотосенсор с подключенным ему параллельно конденсатором подаётся напряжение питания, которое заряжает конденсатор. В момент 0 напряжение снимается и конденсатор начинает разряжаться через фотосенсор. Чем сильнее фотосенсор освещен - тем быстрее конденсатор разряжается.
Так вот, один из каналов ведущего таймера я определил для сигнала PWM, который и будет "последние 10 мкс цикла" давать активный уровень. Сначала думал поставить 8 транзисторов, которые будут коммутироваться этим сигналом. Но, для этих транзисторов надо слишком много места. Поставить микросхему типа 555ИР22 - проводов, вроде меньше, но места еще больше. Мне очень не хотелось делать так как это делают обычно путём простого перепрограммирования порта с ввода на вывод. Во первых в конфигурации порта нельзя отключить периферию - можно только в конфигурации периферии отключить порты. Но тут я подумал, а не задействовать ли PRS? Здесь же сигнал ШИМ можно завести в PRS и вывести на контакт... но, 1 сигнал только на 1 контакт. Хм, я могу этот сигнал раскидать на несколько сигналов PRS - но тут облом, не все нужные мне выводы могут подключаться к PRS. И даже те, что могут - часть подключается к одному и тому же каналу, т.е. разом оба задействовать нельзя. Хм, и получится ли выводить через PRS в порт, который уже подключен как вход захвата таймера??? А, чтобы не переконфигурировать порт с ввода на вывод, тут оказалось возможным сконфигурировать порт как WiredOR - если я туда выдаю лог.1 - на выводе есть напряжение, если лог.0 - то на выводе нет ничего и он работает просто на ввод. Поэтому просто по прерыванию ШИМ я вывожу 1 в порт, а по прерыванию по переполнению счетчика вывожу туда 0. Вот тут я получил, возможно, ответ на предыдущий вопрос - пока не были от выводов отключены
входы таймера, я туда
вывести ничего не мог.
Другой канал таймера назначил на "порог" срабатывания - граница между белым и черным.
Спойлер
И вот тут всплыла проблема. Во всех ранее использованных микроконтроллерах о факте срабатывания захвата можно было узнать по прерыванию (или флагу прерывания), но в этом микроконтроллере - нельзя. Флаг прерывания устанавливается только по переполнению, т.е. когда произошел захват, но предыдущее значение еще не было считано. В общем, я не понимаю как это всё должно работать. Получается, что у меня тахометр тоже работает с отставанием на 1 или 2 импульса. А даташит на эту тему через чур лаконичен. Пытался смотреть AN0014 - там еще меньше, от поиска в гугле толку мало - наверное очень малораспространённый микроконтроллер.
Кое как сейчас у меня что-то работает, но насколько хорошо и правильно - я не знаю. Так что я "very disappointed".
p.s. Провёл эксперимент. В обработчике тахометра сделал журналирование первых 1500 отсчетов. Записывал содержимое регистра захвата CCV и состояние счетчика CNT. Хм, данные актуальные - различаются примерно на 3 мкс - как раз войти в прерывание. Теперь не знаю что думать.
Дошло. Всё что написал - глупости. Есть прерывание. Просто спутал с другим.
Ну так вот, разобравшись с захватом таймеров, решил поэкспериментировать, как будет работать PRS на включение зарядки конденсаторов. Ресурсы распределены так:
Код: Выделить всё
// (robot's right)
// reflectance sensor 7 connected to PE.11 PRS3#2
// reflectance sensor 6 connected to PE.10 PRS2#2
// reflectance sensor 5 connected to PE.15 tim3cc1#0 PRS14#3
// reflectance sensor 4 connected to PE.14 tim3cc0#0 PRS13#2
// reflectance sensor 3 connected to PE.13 tim2cc2#3 PRS2#3
// reflectance sensor 2 connected to PE.5 tim3cc2#2
// reflectance sensor 1 connected to PE.9 PRS8#2
// reflectance sensor 0 connected to PE.8 PRS3#1
// (robot's left)
Получилось так что второй сенсор выхода PRS вообще не имеет, а нулевой и седьмой делят между собой третий канал, а третий и шестой - делят второй канал. Т.е. реально получается только 5 выводов могу подключить. Ну что же, подключаем:
Код: Выделить всё
CMU_ClockEnable(cmuClock_PRS, 1);
PRS->CH[2].CTRL = PRS_CH_CTRL_SOURCESEL_TIMER2 | PRS_CH_CTRL_SIGSEL_TIMER2CC1 | PRS_CH_CTRL_INV;
PRS->CH[3].CTRL = PRS_CH_CTRL_SOURCESEL_TIMER2 | PRS_CH_CTRL_SIGSEL_TIMER2CC1 | PRS_CH_CTRL_INV;
PRS->CH[8].CTRL = PRS_CH_CTRL_SOURCESEL_TIMER2 | PRS_CH_CTRL_SIGSEL_TIMER2CC1 | PRS_CH_CTRL_INV;
PRS->CH[13].CTRL = PRS_CH_CTRL_SOURCESEL_TIMER2 | PRS_CH_CTRL_SIGSEL_TIMER2CC1 | PRS_CH_CTRL_INV;
PRS->CH[14].CTRL = PRS_CH_CTRL_SOURCESEL_TIMER2 | PRS_CH_CTRL_SIGSEL_TIMER2CC1 | PRS_CH_CTRL_INV;
т.е. один сигнал с CC1 второго таймера соединил с 2, 3, 8, 13 и 14 каналами. Сам таймер в PRS формирует уровень, а не импульс:
Код: Выделить всё
TIMER2->CC[1].CTRL = TIMER_CC_CTRL_MODE_PWM | TIMER_CC_CTRL_PRSCONF_LEVEL;
Ну вот, а теперь назначаем сигналы на выводы и включаем:
Код: Выделить всё
PRS->ROUTELOC0 = PRS_ROUTELOC0_CH2LOC_LOC2 | PRS_ROUTELOC0_CH3LOC_LOC2;
PRS->ROUTELOC2 = PRS_ROUTELOC2_CH8LOC_LOC2;
PRS->ROUTELOC3 = PRS_ROUTELOC3_CH13LOC_LOC2 | PRS_ROUTELOC3_CH14LOC_LOC2;
PRS->ROUTEPEN = PRS_ROUTEPEN_CH2PEN | PRS_ROUTEPEN_CH3PEN | PRS_ROUTEPEN_CH8PEN |
PRS_ROUTEPEN_CH13PEN | PRS_ROUTEPEN_CH14PEN;
И как ни странно, всё работает. Даже те каналы, которые подключены ко входам захвата таймеров. Т.е. тут полная гармония, в отличии от случая, когда я вручную вывожу лог.1
Есть одна странность. Если у робота на MSP432 "порог" между черным и белым был в районе 800, то у этого в районе 300. Возможно, из-за того, что порог уровня лог.1/0 у EFM32 выше. Но я еще проверю. Но вот из-за этой "повышенной" чувствительности возникает проблема с влиянием паразитной засветки. И тут есть два решения или уменьшать паразитную засветку установив какого-либо типа ширму вокруг сенсоров, или "вычитать" помеху. Правда, для вычитания помехи требуется, чтобы все каналы давали пропорциональный сигнал (а не половина, как у меня сейчас). Так как у меня больше нет доступных таймеров, видимо, сенсор придется переделать на аналоговый и считывать ADC. Плату уже нарисовал, осталось собраться с духом и заказать платы.
Немного повозился с модулем CRC. Конфигурацию в EEPROM я защищаю контрольной суммой CRC32. Тут конечно, надо смотреть внимательно на порядок следования байт и бит. В MSP432 "правильная" контрольная сумма получалась, если биты писать прямо, а результат считывать с реверсного регистра. "Правильная контрольная сумма", эта та, которую если дабавить к текущей сумме в результате даст 0. Т.е. я считаю контрольную сумму без последних 4 байт и записываю эту сумму на их место. Затем, при считывании всех байт должен получиться 0, если данные не повреждены. Вот, а в EFM32 и писать, и читать надо было с "прямых" регистров, чтобы получилась бы такая же контрольная сумма.