Quarz oder RC-Oszillator
Inzwischen habe ich eine kleine Platine für den CH32V003 entworfen, die
auch einen CH340N und einen USB-Anschluss enthält Auf der Platine ist
auch ein Quarz, der über einen Jumper eingeschaltet werden kann. Wenn
der Quarz verwendet wird, stehen die beiden Anschlüsse A1 und A2 nicht
mehr als ADC-Eingänge zur Verfügung. Ich kann also wählen, ob ich die
genauere Taktfrequenz brauche oder mehr ADC-Kanäle.
Der CH32V003 besitzt eine Überwachungsfunktion für den Quarzoszillator.
Wenn er nicht anschwingt, wird automatisch auf den internen
RC-Oszillator umgeschaltet. Der Controller arbeitet dann nur noch mit
24 MHz. Wenn man den Quarz im laufenden Betrieb entfernt oder auf
andere Art abschaltet, wird ein System-Reset ausgeführt und damit ein
Neustart des Quarzoszillators versucht. Dabei gibt es ein Timeout. Ohne
den Quarz wird dann der interne Takt von 24 MHz verwendet. Bei
Eigenbauprojekten ist es oft günstiger, ohne einen Quarz auszukommen
und den internen RC-Oszillator mit 24 MHz zu verwenden. Laut Datenblatt
hat man dann eine Toleranz von -1,2% bis + 1,6%, was noch gut für eine
serielle Schnittstelle ausreicht. Ein Vorteil ist dabei, dass man zwei
Portanschlüsse frei behält, nämlich PA1 und PA2.
Man kann ein Programm so schreiben, dass es wahlweise mit einem
24-MHz-Quarz bei 48 MHz läuft, aber auch ohne Quarz mit 48 MHz
funktioniert. Dazu muss man allerdings selbst aktiv werden und die
Verdoppler-PLL für den RC-Oszillator einschalten. Und auch die
Verwendung von PA1 und PA2 muss man selbst wieder in den Normalzustand
für die Verwendung als IO-Ports umschalten, wenn man sie verwenden
will. In der Datei system_ch32v00x.c kann man sehen, welche Schritte
nötig waren, um den Quarzoszillator zu aktivieren. Sie müssen nun in
umgekehrter Reihenfolge rückgängig gemacht werden.
Das Projekt Quarz zeigt die automatische Taktumschaltung am Beispiel
einer einfachen LED-Ansteuerung. Hier werden jeweils alle vorhandenen
Ausgänge an PC und PA angesteuert. Startet man das Programm mit einem
24-MHz-Quarz, bleiben die Ausgaben an PA1 und PA2 wirkungslos, weil
hier der Quarz angeschlossen ist. Nur am Port C erscheint zuerst ein
zwei Sekunden langer Impuls an allen Ausgängen und dann das Hochzählen
der Ausgänge.
//Quarz, oder RC-Oszillator
#include "debug.h"
int main(void){
u8 n = 0;
Delay_Init();
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
u32 HSEStatus = RCC->CTLR & (1 << 17); // Bit 17: HSERDY
if (HSEStatus == 0) { //Quarz schwingt nicht
FLASH->ACTLR &= (uint32_t)((uint32_t)
~FLASH_ACTLR_LATENCY);
FLASH->ACTLR |= (uint32_t)FLASH_ACTLR_LATENCY_1;
RCC->CFGR0 |= (uint32_t)RCC_HPRE_DIV1;
RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_PLLSRC));
RCC->CFGR0 |= (uint32_t)(RCC_PLLSRC_HSI_Mul2);
RCC->CTLR |= RCC_PLLON;
while((RCC->CTLR & RCC_PLLRDY) == 0) {}
RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_SW));
RCC->CFGR0 |= (uint32_t)RCC_SW_PLL;
while ((RCC->CFGR0 & (uint32_t)RCC_SWS) !=
(uint32_t)0x08) {}
RCC->CTLR &= ~((uint32_t)RCC_HSEON); //HSE aus
AFIO->PCFR1 &= ~(1<<15); //PA12 als IO-Ports
RCC->APB2PCENR &= ~RCC_AFIOEN; //Quarz abschalten
}
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,
ENABLE);
GPIOC->CFGLR = 0x22222222; // PC Output
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,
ENABLE);
GPIOA->CFGLR = 0x22222222; // PA Output
GPIOC->OUTDR = 255;
Delay_Ms(2000);
while(1){
GPIOC->OUTDR = n;
GPIOA->OUTDR = n;
n++;
Delay_Ms(250);
}
}
Nun kann man den Quarz entfernen oder abschalten, indem man den Jumper
abzieht oder einen der Anschlüsse PA1 oder PA2 kurz an GND legt. Sofort
erscheint wieder der zwei Sekunden lange Startimpuls, woran man den von
der Oszillatorüberwachung ausgelösten Reset erkennt. Danach, sieht man
das Blinken der LEDs mit der gleichen Frequenz wie mit dem Quarz.
Zusätzlich kann man nun zwei LEDs an PA1 und PA2 anschließen. Auch hier
funktionieren jetzt die Ausgaben. Sie werden auch als IO-Ports
verwendet, wenn man gleich ohne den Quarz startet.