Hallo zusammen, zuerst einmal vorweg: Alles, was mit Hardware zu tun hat, ist definitiv nicht meine Stärke. Ich versuche gerade im Rahmen meines Studiums ein Semesterprojekt unter dem Thema "Funktionsgenerator" umzusetzen. Eingesetzt wird dabei das schon oben erwähnte Board von ST, die Einstellungen sollen auf ein 16x4 Display von Pollin ( TC1604A-01 ) ausgegeben werden und das eigentliche Signal ( Rechteck, Sinus, Sägezahn, Dreieck - einstellbar über das Menü ) über den internen 12bit DAC ausgegeben werden. Nun hab ich jedoch 2 Probleme: 1. Die Ausgänge der GPIO Pins reichen nicht, um an den Eingängen des LCD Displays einen Hi Pegel zu erzeugen ( Display läuft mit 5V Eingangsspannung, das Board selbst hängt am MicroUSB Stecker und führt die Masseleitung eben ab ). Die Ports werden korrekt angesteuert, erzeugen jedoch jeweils nur eine Spannung zwischen 2,2 und 2,5 Volt - die Schwelle liegt, wenn ich es richtig verstanden hab, jedoch irgendwo bei 3,5V. ( 0,7*VDD des Displays ) 2. Ich habe Google mal befragt, wie man den DAC aktiviert und bin dann über das struct DAC_InitTypeDef gestolpert und habe es wie folgt versucht, einzubinden DAC_InitStructure.DAC_Trigger = DAC_Trigger_Software; DAC_InitStructure.DAC_WaveGeneration = DAC_WaveGeneration_Noise; DAC_InitStructure.DAC_LFSRUnmask_TriangleAmplitude = AC_LFSRUnmask_Bits8_0; DAC_InitStructure.DAC_OutputBuffer = DAC_OutputBuffer_Enable; DAC_Init(DAC_Channel_1, &DAC_InitStructure); Jedoch findet der Compiler die structs für den DAC gar nicht ..\src\dacFunctions.c(8): error: #20: identifier "DAC_InitTypeDef" is undefined ..\src\dacFunctions.c(15): error: #20: identifier "DAC_Trigger_Software" is undefined ..\src\dacFunctions.c(16): error: #20: identifier "DAC_WaveGeneration_Noise" is undefined ..\src\dacFunctions.c(17): error: #20: identifier "DAC_LFSRUnmask_Bits8_0" is undefined ..\src\dacFunctions.c(18): error: #20: identifier "DAC_OutputBuffer_Enable" is undefined Da dieses Board leider nicht besonders gut dokumentiert ist, habe ich im Moment keine Idee, wo ich nach den benötigten Headerfiles suchen soll. Ich hoffe, ihr könnt mir dabei weiterhelfen. :)
Zu 1) Dafür braucht Du einen Pegelwandler, der die Signale auf 5V umsetzt. Hier mal einige Level Shifter IC's: - SN74LVC8T245 - SN74LVC2T45 - MAX3000 - MAX3375E (Biderectional) - TXB0104 (Biderectional) Alternative: Du nimmt ein EA-DOG Display mit 3x16 Zeichen, das kann auch über SPI Bus angesteuert werden (gibts bei Reichelt) und ist 3,3V tauglich. (Hab ich selbst mit STM32 im Einsatz.) Zu 2) Lese am Besten den Artikel STM32 einmal durch. Da stehen alle Tipps drin woher man die richtige Doku und auch den nötigen Quellcode/Header bekommt.
Markus Müller schrieb: > Dafür braucht Du einen Pegelwandler, der die Signale auf 5V umsetzt. Alternativ kann der jeweilige Ausgangspin hochohmig (tristate) geschalten werden. Dann brauchst Du nur ein paar pull-ups auf 5V. Wenn ich das richtig gesehen habe, sind die STM32 5V-tolerant. Ggf. kann auch das Display mit 4,5V oder 4V betrieben werden. Damit verändern sich auch die Schaltschwellen. Mit welcher Spannung läuft dein STM32? Grüße Sven
Vielen Dank schon mal für die schnellen Antworten. Ich versuch das jetzt erstmal zu meinem eigenen Verständnis zusammenzufassen: Um den benötigten Pegel zu erreichen, bräuchte ich entweder einen Pegelwandler - bei insgesamt 11 Ausgangspins ( DB0-DB7, RS, RW, EN ) wären das dann 11 Stück, da ich ja jede Leitung getrennt ansprechen muss. Oder alternativ mit folgender Schaltung PullUp für jeden Pin : http://www.elektronik-kompendium.de/public/schaerer/bilder/pullr_01.gif? Die meisten Pins sind 5 Volt tolerant, das hab ich gestern schon mal gelesen, ob das jetzt für die verwendeten gilt, weiß ich gerade nicht - könnte ich aber gegebenenfalls nachlesen und umschreiben. Das Board betreibe ich die meiste Zeit nur über das MicroUSB Kabel, alternativ über den 5Volt Anschluss. Die benötigte Betriebsspannung liegt bei 3,3 Volt - dafür gibt es nochmal einen zusätzlichen Anschluss. Welchen Anschluss ich jedoch verwende, ändert nichts an der Ausgangsspannung der GPIO Pins. Mir fällt gerade noch ein, dass die Ausgänge als Push-Pull konfiguriert sind - mit externem PullUp müsste ich sie dann sicher als Open-Drain konfigurieren oder?
Die beiden oben beschriebenen Probleme habe ich mittlerweile lösen können. Das Problem mit den zu niedrigen Eingangspegel habe ich dadurch umgangen, dass ich ab 2V schaltende AND- Gatter mit 5V Output zwischen geschaltet habe. Und beim DAC habe ich einfach vergessen, in der stm32f10x_conf.h die Kommentarstriche vor den Headerfiles zu entfernen - und dann die Dateien einzubinden in das Projekt bei Keil. Nun stehe ich allerdings vor einem weiteren Problem. Ich versuche, die Werte aus einem Array per DMA auf den DAC ausgeben zu lassen. Dabei hab ich mich bei dem Beispiel aus der Standardlibrary "DualModeDMA_SineWave" bedient und bis auf die kleinen Anpassungen alles 1:1 übernommen. Es kommt allerdings hinten am DAC nichts raus außer 0,07 V Offset. Setze ich das DHR12RD selbst, so kommen die korrekten Werte dabei heraus. ( nicht wundern, dass ich 50 mal den gleichen Wert im Array stehen hab, die werden später berechnet und ausgetauscht ) Der Timer TIM2 funktioniert ebenfalls und triggert den DAC korrekt. Also muss das Problem irgendwo beim DMA liegen - aber ich habe keine Ahnung wo: #include "stm32F10x.h" #include "STM32vldiscovery.h" #include "controlFunctions.h" #include "dacFunctions.h" #define DAC_DHR12RD_Address 0x40007420 // BASE 0x4000 7400 + Offset 0x20 ( TRM p. 206 ) ==> DAC Channel 1 Right aligned #define DACSTEPS 50 #define DAC1 GPIO_Pin_4 DAC_InitTypeDef DAC_InitStructure; DMA_InitTypeDef DMA_InitStructure; TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; vu16 funcValues[DACSTEPS] = { 4095, 4095, 4095, 4095, 4095, 4095, 4095, 4095, 4095, 4095, 4095, 4095, 4095, 4095, 4095, 4095, 4095, 4095, 4095, 4095, 4095, 4095, 4095, 4095, 4095, 4095, 4095, 4095, 4095, 4095, 4095, 4095, 4095, 4095, 4095, 4095, 4095, 4095, 4095, 4095, 4095, 4095, 4095, 4095, 4095, 4095, 4095, 4095, 4095, 4095 }; void dacInit() { // Starten der benötigten Clocks für DAC Ausgabe ( DMA, DAC, GPIOA, TIM2 ) RCC_AHBPeriphClockCmd( RCC_AHBPeriph_DMA1, ENABLE ); // DMA Channel ( direct memory access ) RCC_APB1PeriphClockCmd( RCC_APB1Periph_DAC, ENABLE ); // der DAC selbst RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA, ENABLE ); // GPIO Port A ( Ausgabe an PA04 ) RCC_APB1PeriphClockCmd( RCC_APB1Periph_TIM2, ENABLE ); // TIM2 Timer // Konfiguration des PA04 als Analog In, um parasitären Verbrauch vorzubeugen GPIO_StructInit( &GPIO_InitStructure ); GPIO_InitStructure.GPIO_Pin = DAC1; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; GPIO_Init( GPIOA, &GPIO_InitStructure ); // TIM2 Konfiguration TIM_TimeBaseStructInit( &TIM_TimeBaseStructure ); TIM_TimeBaseStructure.TIM_Period = 100; // Timer zählt bis 100 - irrelevant TIM_TimeBaseStructure.TIM_Prescaler = signalFreqDivs[curSignal.freq]; // 24 MHz / ( Prescaler + 1 ) = 10 kHz ( 100 Hz Signalfrequenz * 100 Signale je Periode ) TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV4; // 24 MHz Takt TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; // hochzählender Counter TIM_TimeBaseInit( TIM2, &TIM_TimeBaseStructure ); TIM_SelectOutputTrigger( TIM2, TIM_TRGOSource_Update ); // DAC Channel1 Konfiguration DAC_InitStructure.DAC_Trigger = DAC_Trigger_T2_TRGO; // Trigger auf TIM2 Timer DAC_InitStructure.DAC_WaveGeneration = DAC_WaveGeneration_None; // Keine Wave Generierung DAC_InitStructure.DAC_OutputBuffer = DAC_OutputBuffer_Enable; // Output Buffer aktiveren DAC_Init( DAC_Channel_1, &DAC_InitStructure ); // Direct Media Access konfigurieren DMA_StructInit( &DMA_InitStructure ); DMA_InitStructure.DMA_PeripheralBaseAddr = DAC_DHR12RD_Address; DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&funcValues; DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST; DMA_InitStructure.DMA_BufferSize = DACSTEPS; DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; DMA_InitStructure.DMA_Priority = DMA_Priority_High; DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; DMA_Init( DMA1_Channel4, &DMA_InitStructure ); DMA_Cmd( DMA1_Channel4, ENABLE ); // DAC Channel1 aktivieren, PA04 wird automatisch verbunden DAC_Cmd( DAC_Channel_1, ENABLE ); // DMA Zugriff für den DAC Channel1 aktivieren DAC_DMACmd( DAC_Channel_1, ENABLE ); // TIM2 Zähler aktivieren TIM_Cmd( TIM2, ENABLE ); } Sieht jemand, wo der Fehler liegen könnte? Oder hat einen Tipp, wie ich dem Fehler auf die Schliche kommen kann?
Toni Liesche schrieb: > Setze > ich das DHR12RD selbst, so kommen die korrekten Werte dabei heraus. Hast Du einen funktionierenden Debugger? Schau Dir doch mal an, auf welchen Wert der Lib-Code das DHR12RD-Register setzt. Grüße Sven
Sofern ich es von Hand setze ( DAC_SetChannel1Data( DAC_Align_12b_R, 0x0FFF ); ) kommt korrekt 0x00000FFF im DHR12RD Register an der Stelle 0x4000 7420. Der Wert wird einmalig gesetzt und vom DMA dann auch nicht mehr verändert. Kommentiere ich die Funktion aus, bleibt das Register konstant bei 0x0000 0000. Sprich: Der DMA Controller tut für mich augenscheinlich gar nichts :(
also ... ich weiß nicht, ob das ein Fehler ist, den ich gemacht hab, oder ob es irgendwie falsch zugeordnet wurde oder in der Dokumentation steht ... aber jetzt hab ich den DAC_Channel1 gegen DAC_Channel2 getauscht ... und der funktioniert wie gewünscht ... DMA läuft ... // Edit: Laut Dokumentation soll DMA1 sehr wohl für DAC_Channel1 und Channel2 funktionieren
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.