PIC16F18855 работает на половине тактовой частоты, когда я выключаю и включаю его слишком быстро

У меня есть плата с PIC16F18855, работающая на частоте 8 МГц от внешнего кристалла. Большую часть времени он работает нормально, но если его быстро отключить, он перезапустится на частоте 4 МГц. Основными симптомами этого являются такие вещи, как скорость передачи данных UART и частота PWM, падающая вдвое.

В частности, если я включу и выключу питание менее чем за ~ 2 секунды, он будет работать на более низкой частоте. Дольше и работает нормально. Когда я программирую плату, она перезагружается на частоте 4 МГц, а это означает, что мне нужно физически выключить и включить ее, прежде чем она заработает. Если я замкну контакт MCLR на землю, поведение будет непоследовательным - иногда он будет начинаться с 4 МГц, но обычно он начинается с 8 МГц.

У меня также был один случай, когда это занимало значительно больше времени, когда включение его в течение 10 минут после выключения заставляло его начинать с 4 МГц. Я не уверен, связана ли проблема, но я не могу воспроизвести эту ошибку в данный момент.

Изучая контакт OSC2/CLKOUT, я вижу, что сам кристалл все еще работает на частоте 8 МГц. С имеющимися у меня датчиками я не могу проверить контакт OSC1 без сброса микроконтроллера.

РЕДАКТИРОВАТЬ 1:

Когда плата работает на частоте 8 МГц, ее регистры OSCCONx:

OSCCON1: 0x70
OSCCON2: 0x70
OSCCON3: 0x10

и когда он работает на частоте 4 МГц, они:

OSCCON1: 0x70
OSCCON2: 0x60
OSCCON3: 0x00

Значит, он работает от внутреннего ВЧ-генератора. Посмотрим на это немного ближе. Зная это, я, возможно, смогу придумать обходной путь, но я бы предпочел выяснить причину проблемы.

OSCFRQ = 0x02, что является настройкой для 4 МГц, так что это определенно то, что происходит. Ужасным обходным решением было бы установить OSCFRQрегистр на значение 8 МГц, так что он работает одинаково в любом случае, но тогда я теряю точность кристалла. Это может не все испортить, но у меня есть некоторые чувствительные ко времени вещи, поэтому я предпочитаю использовать кристалл, если могу.

Какие у вас настройки OSCCONx?
OSCCON1: 0x70, OSCCON2: 0x70, OSCCON3: 0x10,
В этом чипе много источников тактовых импульсов и предделителей. RSTOSC тоже имеет значение. Завтра посмотрю, если никто не помог.
Включен ли в чипе обход отказа часов? Некоторые PIC будут использовать внутренний генератор 1: пока внешний генератор стабилизируется. и или 2: если внешний генератор выходит из строя. Если у вас есть эндоскоп, вы можете проверить, правильно ли колеблется кристалл. (это не будет гарантией, потому что пробник повлияет на цепь, но может вам что-то сказать).
Пробники, которые у меня есть, слишком сильно нагружают схему, чтобы я мог проверить входной контакт генератора. Я не совсем уверен, что вы имеете в виду под аварийным переключением часов, но по умолчанию он использует внутренний ВЧ-генератор (это удалось благодаря комментариям Спехро, он находится в редактировании). В настоящее время я пытаюсь выяснить, что вызывает это
Попробуйте установить для /PWRTE значение «0» (CONFIG2, бит 1). Это даст вашему напряжению питания 64 мс для стабилизации перед выходом из режима сброса.

Ответы (1)

Это не объяснение того, почему это происходило, но я нашел исправление. Первое, что я попробовал, это установить фьюз-биты для RSTOSC_EXT (т.е. #pragma fuses HS, RSTOSC_EXT) на основе того, что Спехро сказал в комментариях, но у меня это не сработало. Что я сделал, так это добавил следующее (обратите внимание, что OSCCON2 — это фактическая настройка, а OSCCON1 — это буфер):

if(OSCCON2 == 0x60){
    OSCCON1 = 0x60;
    OSCCON1 = 0x70;
}

Моя причина попробовать это: OSCCON2 является фактической настройкой и загрузит значение в OSCCON1, когда оно будет готово. Из моего предыдущего расследования я знал, что правильное значение было в OSCCON1, а OSCCON2 никогда его не загружал. Таким образом, предполагалось, что процесс загрузки где-то застрял, и загрузка значения из OSCCON2 в OSCCON1 заставит чип думать, что он загружен правильно. Это «отклеит» его, а затем позволит мне перезагрузить правильное значение без зависания.

Этот код находится в самом начале основной функции, после объявления переменных. Это решает проблему, но не объясняет, почему это происходит в первую очередь. Если кто-нибудь знает, что было причиной этого, и если есть лучшее решение, я все еще открыт для лучших ответов.