#include "stm32f446xx.h" #include "ADC_Interrupt.h" /* * CPU 180MHz Takt, 8MHz ext. Clock. AHB 180MHz, APB1 45MHz und APB2 90MHz * Flash 5 Wait States, Overdrive on * ADC1 für Eingang auf PA6, DAC2 aus Ausgang auf PA5 * ADC2 für Touch-Panel * Timer4 PWM als Trigger für ADC, Timer 5 als Trigger für DAC-Ausgabe, Timer 2 für Zeitmessungen * DMA2 Stream 0, Channel 0 für ADC1 im Dual-Buffer-Mode * UART2 für Debugzwecke, PA2 ist TxD und PA3 ist RxD * * Achtung! Auf dem Nucleo-Board ist die User-LED mit PA5 (Analogausgang) verbunden, * diese Verbindung muss aufgetrennt werden (Widerstand auslöten), sonst gibt es Verzerrungen durch LED-Strom. * * Interrupt auf DMA ADC komplett (Position 56, Adresse 0x0000 0120) */ void Peripherie_Clk_enable(void) { RCC->AHB1ENR = RCC->AHB1ENR | 0x006400FF; // Peripherie AHB1: DMA1&2, Backup, GPIO RCC->APB1ENR = RCC->APB1ENR | 0x3002000F; // Peripherie APB1: DAC, PWR, UART2, TIM2..5 RCC->APB2ENR = RCC->APB2ENR | 0x00004700; // Peripherie APB2: System Controller, ADC1..3, Timer4 } void GPIO_init(void) { GPIOA->BSRR = 3; // WR und RD vom LCD High GPIOA->MODER = GPIOA->MODER | 0x031A5; // PA0, PA1, PA4 als DigOut, PA6 analog (DAC2), PA2 TxD, PA3 RxD UART2 //GPIOA->OSPEEDR = GPIOA->OSPEEDR | 0x003F030F; // PA0,1,4,8,9,10 High Speed für LCD GPIOA->AFR[0] = 0x7700; // PA2 TxD, PA3 RxD UART2 (AF7) // PB: 0 als Output für LCD, PB9 als Output für Tests (SDA/D14) GPIOB->BSRR = 1; // PB0 High GPIOB->MODER = 0; GPIOB->MODER = GPIOB->MODER | 0x40001; //GPIOB->OSPEEDR = GPIOB->OSPEEDR | 0x00300FC3; // PB 0,3,4,5,10 High Speed für LCD // PC: 1 als Output für LCD GPIOC->MODER = GPIOC->MODER | 4; //GPIOC->OSPEEDR = GPIOC->OSPEEDR | 0x0000C00C; // PC 1,7 High Speed für LCD GPIOA->ODR = 0xFFFF; // PA0, 1, 5 auf High GPIOB->ODR = 1; // LCD CS auf High } void PLL_init(void) { RCC->APB1ENR = RCC->APB1ENR | 0x10000000; // PWR-Clock einschalten RCC->CR = RCC->CR | 0x50000; // ext. Clock ein RCC->CFGR = RCC->CFGR | 0x9401; // ext. Clock als SysClk, APB2 90MHz, APB1 45MHz // PLL für 180MHz mit 8 MHz ext. Clock // Clk = 8MHz * PLLN / PLLM / PLLP // M = 4, damit 2MHz PLL input, damit N = 180 und P = 2 // PLLR = 3, wird nicht benötigt (ist für I2S), PLLQ = 15 (nicht benötigt, USB) RCC->PLLCFGR = 0x3F402D04; RCC->CR = RCC->CR | 0x1000000; // Overdrive aktivieren, damit 180MHz möglich sind PWR->CR = PWR->CR | 0x10000; while ((PWR->CSR & 0x10000) == 0); PWR->CR = PWR->CR | 0x20000; // Umschalten auf PLL-Takt RCC->CFGR = (RCC->CFGR & ~3) | 2; RCC->CR = RCC->CR & ~1; // int. Oszillator (HSI) aus } void UART_init(void) { // USART2 für Debugzwecke (PA2 Txd und PA3 RxD): 57600 Baud, 8 Bit, 1 Stoppbit, keine Parität // Teilfaktor = 45E6 / 16 / Baudrate USART2->BRR = (48 << 4)+13; USART2->CR1 = 0x200C; } void ADC_init(void) { // ADC1 ADC->CCR =0x10000; // Teiler 4 ADC1->CR2 = 0x19000301; // Trigger T4, DMA ein ADC1->SQR3 = 6; // Kanal PA6, 1 Kanal ADC1->LTR = 40; // untere Grenze Analog Watchdog (Übersteuerungsanzeige) ADC1->HTR = 4050; // obere Grenze ADC1->CR1 = ADC1->CR1 | 0x800000; // Analog Watchdog ein // ADC2 für Touch-Screen: PB0(IN8): X (RS Low und D0 High), PA4(IN4): Y (CS High und D1 Low) ADC2->CR2 = 1; // ADC2 ein ADC2->SMPR2 = 0x2002000; // 28 Sample-Zyklen für Kanal 4 und 8 ADC2->SQR3 = 8; // Kanal 8 } void DMA_init(void) { // DMA ADC1: DMA2 Stream 0, Kanal 0, 20 Sample, Dual-Buffer DMA2_Stream0->CR = 0x74D10; // 16bit-Transfer, Doppelbuffer, Interrupt am Ende DMA2_Stream0->NDTR = ADC_DMA_getBufferLength(); // Elemente pro Transfer DMA2_Stream0->PAR = (uint32_t)(&(ADC1->DR)); // Quellenadresse DMA2_Stream0->M0AR = ADC_DMA_getBufferAddress(); DMA2_Stream0->M1AR = ADC_DMA_getBufferAddress() + 2*ADC_DMA_getBufferLength(); DMA2_Stream0->CR = DMA2_Stream0->CR | 1; // DMA starten // Interrupt konfigurieren //NVIC->ISER[1] = 0x01000000; // Interrupt 56 freigeben NVIC_EnableIRQ(DMA2_Stream0_IRQn); } void Timer_init(void) { const int Prescaler = 90; // Vorteiler ab 90MHz für Samplingfrequenz A/D-Wandler (1MHz) // Anzahl Samples pro Interrupt extern const int ADC_BUFFER_LENGTH; //Timer 4 für 1MHz Takt (A/D-Samplingfrequenz), T4 läuft mit 90MHz! TIM4->ARR = Prescaler - 1; TIM4->CR2 = TIM4->CR2 | 32; TIM4->CCMR2 = 0x7000; TIM4->CCR4 = Prescaler/2; // Pulsweite für Trigger ADC TIM4->CCER = 0x1000; // PWM Kanal 4 enable für Trigger ADC1 TIM4->CR1 = 1; // Timer enable // Timer 5 für Trigger D/A-Wandler (50kHz), um Jitter zu vermeiden TIM5->ARR = Prescaler * ADC_BUFFER_LENGTH - 1; // Periode = A/D-Samplingfrequenz * Dezimationsfaktor TIM5->CR2 = TIM5->CR2 | 32; // TIM5->CCMR2 = 0x7000; // TIM5->CCR4 = 450; // Pulsweite für Trigger ADC // TIM5->CCER = 0x1000; // PWM Kanal 4 enable für Trigger ADC1 TIM5->CR1 = 1; // Timer enable // Timer 2 als 32bit-Zähler für Software-Timeouts, Zeitbasis 0.1ms (Teilfaktor 9000) TIM2->PSC = 8999; // 90MHz/9000 = 10kHz Taktrate = 0.1ms Zeitbasis TIM2->CNT = 0xffffff00; TIM2->ARR = 0xffffffff; // max. Periode TIM2->CR1 = TIM2->CR1 | 1; } void DAC_init(void) { // DAC2 ohne Buffer, Trigger von Timer 5 DAC->CR = 0x1F0000; } void CPU_init(void) { // Flash Wait States und Cache FLASH->ACR = 0x700 + 5; // 5 Wait-Zyklen für 180MHz Takt und 3.3V PLL_init(); Peripherie_Clk_enable(); GPIO_init(); UART_init(); ADC_init(); DMA_init(); DAC_init(); Timer_init(); } volatile uint32_t getTimer(void) { return TIM2->CNT; } void delay(uint32_t time) { uint32_t oldTime; oldTime = TIM2->CNT; while((TIM2->CNT - oldTime) < time); }