/* Konfiguration für das Testboard mit STM32F302RBT6 */ #include "StdTypes.h" #include "STM32F302xB.h" #include "startup.h" #include "config.h" /**************** symbolische Port-Pin Eigenschaften **************************/ /* Pro Port gibt es ein const word array[pinanzahl], wo alle relevanten Eigenschaften der Pins gespeichert sind. Diese Arrays werden vom Setup interpretiert und ergeben dann alle moder, otyper, ospeedr, pupdr, afrh und afrl zum Einstellen der Ports. Struktur eines word's: bits: 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 np - - - - |pu,pd| |speed| od |mode| |--Alt-Fu--| */ // Alternativfunktionen, kommt in GPIOx_AFRL/AFRH #define AF0 0 #define AF1 1 #define AF2 2 #define AF3 3 #define AF4 4 #define AF5 5 #define AF6 6 #define AF7 7 #define AF8 8 #define AF9 9 #define AF10 10 #define AF11 11 #define AF12 12 #define AF13 13 #define AF14 14 #define AF15 15 // mode, kommt in GPIOx_MODER #define IN (0<<4) // GPIO IN #define OUT (1<<4) // GPIO OUT #define ALT (2<<4) // Alternative Fkt. #define ANA (3<<4) // analog // Open Drain, kommt in GPIOx_OTYPER #define OD (1<<6) // open drain // Portgeschwindigkeit, kommt in GPIOx_OSPEED #define LoSpeed (0<<7) #define MedSpeed (1<<7) #define HiSpeed (3<<7) // Pullup, Pulldown oder nix, kommt in GPIOx_PUPDR (nur Ports A und B) #define PullUP (1<<9) #define PullDN (2<<9) // vorhanden, unbelegt, oder nicht #define nopin (1<<15) #define unconnected (1<<15) const word wfPortA[16] = { /* P.0 */ OUT, /* P.1 */ ALT + MedSpeed + AF1, // TIM2_CH2 /* P.2 */ OUT, /* P.3 */ ALT + MedSpeed + AF9, // TIM15_CH2 /* P.4 */ OUT, /* P.5 */ OUT, /* P.6 */ ALT + MedSpeed + AF2, // TIM3_CH1 /* P.7 */ OUT, // /* P.8 */ ALT + AF0 + HiSpeed, // Systemtakt zum Test /* P.9 */ ALT + MedSpeed + AF7, // USART1_TX /* P.10 */ ALT + MedSpeed + AF7, // USART1_RX /* P.11 */ ALT + HiSpeed + AF14, // USB_DM /* P.12 */ ALT + HiSpeed + AF14, // USB_DP /* P.13 */ ALT + HiSpeed + AF0, // SWDIO /* P.14 */ ALT + HiSpeed + AF0, // SWCLK /* P.15 */ OUT, // USB_ON }; const word wfPortB[16] = { /* P.0 */ OUT, /* P.1 */ OUT, /* P.2 */ OUT, /* P.3 */ ALT + MedSpeed + AF7, // USART2_TX /* P.4 */ ALT + MedSpeed + PullUP + AF7, // USART2_RX /* P.5 */ OUT, /* P.6 */ IN + PullUP, // /* P.7 */ ALT + MedSpeed + AF2, // TIM4_CH2 /* P.8 */ OUT + HiSpeed + OD, /* P.9 */ OUT + HiSpeed + OD, /* P.10 */ unconnected, /* P.11 */ unconnected, /* P.12 */ OUT + HiSpeed, // Pin 33 = nur zum Testen /* P.13 */ unconnected, /* P.14 */ unconnected, /* P.15 */ unconnected, }; const word wfPortC[16] = { /* P.0 */ unconnected, /* P.1 */ OUT, // /* P.2 */ OUT, // /* P.3 */ OUT, // /* P.4 */ OUT, // /* P.5 */ IN + PullUP, // /* P.6 */ OUT, /* P.7 */ IN + PullUP, /* P.8 */ OUT, /* P.9 */ unconnected, /* P.10 */ IN + PullUP, // /* P.11 */ IN + PullUP, // /* P.12 */ IN + PullUP, // /* P.13 */ IN + PullUP, // /* P.14 */ unconnected, /* P.15 */ unconnected, }; // für PortD.2 und PortF.4 lohnt sich keine komplette Tafel const word wfPortD[3] = { /* P.0 */ nopin, /* P.1 */ nopin, /* P.2 */ IN, }; const word wfPortF[5] = { /* P.0 */ nopin, /* P.1 */ nopin, /* P.2 */ nopin, /* P.3 */ nopin, /* P.4 */ OUT, }; struct pinmode { dword moder; dword otyper; dword ospeedr; dword pupdr; qword afrhl; }; // portweise Pinmode Setup void PimoSetup (struct pinmode* Pim, const word tafl[], int maxpin) { struct pinmode iPim; int i; word w; iPim.moder = 0; iPim.otyper = 0; iPim.ospeedr = 0; iPim.pupdr = 0; iPim.afrhl = 0; i = maxpin; while (i >= 0) { w = tafl[i]; iPim.moder = iPim.moder << 2; iPim.otyper = iPim.otyper << 1; iPim.ospeedr = iPim.ospeedr << 2; iPim.pupdr = iPim.pupdr << 2; iPim.afrhl = iPim.afrhl << 4; if ((w & (1<<15)) == 0) { iPim.moder |= ((w>>4) & 3); iPim.otyper |= ((w>>6) & 1); iPim.ospeedr |= ((w>>7) & 3); iPim.pupdr |= ((w>>9) & 3); iPim.afrhl |= w & 15; } --i; } *Pim = iPim; } /* Routine zum eventuellen Oszillografieren beim System-Startup zwecks Fehlersuche. benutztes Pin = PortC.4 Ausgabe: ein Startimpuls und mehrere Folgeimpulse (stage-->Anzahl) */ void monitor (int stage) { word w, u; int i; w = GPIOC_ODR & ~(1<<4); u = w | (1<<4); GPIOC_ODR = u; GPIOC_ODR = w; i = stage; while(i) { GPIOC_ODR = w; GPIOC_ODR = u; --i; GPIOC_ODR = u; } GPIOC_ODR = w; } void sysconfig (void) { struct pinmode PMD; long i; // erstmal die benötigten Takte einschalten RCC_AHBENR = (1<<17) | // Port A enable (1<<18) | // Port B enable (1<<19) | // Port C enable (1<<20) | // Port D enable (1<<22); // Port F enable RCC_APB2ENR = (1<<16) | // TIM15 enable (1<<14) | // USART1 enable 1; // Sys Cfgen RCC_APB1ENR = (1<<23) | // USB (1<<21) | // I2C1 (1<<17) | // USART2 enable (1<<2) | // TIM4 enable (1<<1) | // TIM3 enable 1; // TIM2 enable // Ports aufsetzen PimoSetup(&PMD, wfPortA, 15); GPIOA_MODER = PMD.moder; GPIOA_OTYPER = PMD.otyper; GPIOA_OSPEEDR = PMD.ospeedr; GPIOA_PUPDR = PMD.pupdr; GPIOA_AFRL = PMD.afrhl; GPIOA_AFRH = PMD.afrhl >> 32; PimoSetup(&PMD, wfPortB, 15); GPIOB_MODER = PMD.moder; GPIOB_OTYPER = PMD.otyper; GPIOB_OSPEEDR = PMD.ospeedr; GPIOB_PUPDR = PMD.pupdr; GPIOB_AFRL = PMD.afrhl; GPIOB_AFRH = PMD.afrhl >> 32; PimoSetup(&PMD, wfPortC, 15); GPIOC_MODER = PMD.moder; GPIOC_OTYPER = PMD.otyper; GPIOC_OSPEEDR = PMD.ospeedr; GPIOC_AFRL = PMD.afrhl; GPIOC_AFRH = PMD.afrhl >> 32; PimoSetup(&PMD, wfPortD, 2); GPIOD_MODER = PMD.moder; GPIOD_OTYPER = PMD.otyper; GPIOD_OSPEEDR = PMD.ospeedr; GPIOD_AFRL = PMD.afrhl; GPIOD_AFRH = PMD.afrhl >> 32; PimoSetup(&PMD, wfPortF, 4); GPIOF_MODER = PMD.moder; GPIOF_OTYPER = PMD.otyper; GPIOF_OSPEEDR = PMD.ospeedr; GPIOF_AFRL = PMD.afrhl; GPIOF_AFRH = PMD.afrhl >> 32; // USB erstmal passiv schalten GPIOA_BSRR = (1<<15); /* PA15 von Hand auf High setzen wg. Transistor + 1k5 an D+ */ monitor(1); // Takt aufsetzen: System = 72 MHz RCC_CIR = 0; // keine Interrupts für PLL usw. RCC_CR = 0x83 | (1<<16); // Resetwerte, interner 8 MHz RC-Oszi ein und Quarzoszi ein while ((RCC_CR & 2)==0) // warten auf ready vom RC-Oszi { monitor(2); } // RCC_CFGR vorläufig setzen RCC_CFGR = (7<<24) | // 7 = PLL:2 an MCO = PA.8 zur Beobachtung per Oszillograf (1<<22); // USBPRES, 72MHz/1.5-->48MHz // so, eigentlich sollte jetzt der interne 8 MHz RC-Oszi den Takt angeben RCC_CR &= ~(1<<24); // PLL aus, um sie einstellen zu können RCC_CFGR2 = 0; // Clock für ADC aus, Vorteiler für PLL auf 1:1 RCC_CFGR3 = (1<<22) | // Clock für Timer + UART's auf SysClk Takt (1<<20) | (1<<18) | (1<<16) | 1; // RCC_CFGR fertig setzen bis auf PLL-Auswahl RCC_CFGR = (1<<16) | // Quarz-Oszi als Input für PLL (4<<11) | // APB2 Vorteiler auf :2 (72-->36 MHz) (4<<8) | // APB1 Vorteiler auf :2 (72-->36 MHz) (0<<17) | // Quarz nicht :2 teilen vor der PLL (4<<18) | // PLL Teiler: 4--> x6, also 12MHz*6-->72MHz (7<<24) | // 7 = PLL:2 an MCO = PA.8 zur Beobachtung (1<<22) | // USBPRES, 72MHz/1.5-->48MHz 0; // warten auf Quarz-Oszillator while (!(RCC_CR & (1<<17))) // warten auf ready vom ext. Quarz-Oszi { monitor(3); } // PLL einschalten und warten auf Einschwingen RCC_CR |= (1<<24); // PLL einschalten while (!(RCC_CR & (1<<25))) // warten auf ready von PLL { monitor(4); --i; } // wichtig: die nötigen Waitstates einschalten FLASH_ACR = 0x32; // 2 Waitstates ab 48 MHz // Finale RCC_CFGR = (RCC_CFGR & 0xFFFFFF00) | 2; // mutig die PLL als Systemtakt einschalten monitor(5); // Restbedenken: an MCO = PA.8 liegen jetzt 36 MHz an. // Man kann dies jetzt oszillografieren, sollte es aber dann abschalten, // falle es nicht wirklich gebraucht wird // Alternative: MCO erst garnicht einschalten } /* ende */