Forum: Mikrocontroller und Digitale Elektronik Funktionsgenerator mit STM32 VL Discovery


von Toni (Gast)


Lesenswert?

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. :)

von Markus M. (Firma: EleLa - www.elela.de) (mmvisual)


Lesenswert?

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.

von Sven Wagner (Gast)


Lesenswert?

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

von Toni (Gast)


Lesenswert?

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?

von Toni L. (tliesche)


Lesenswert?

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?

von Sven Wagner (Gast)


Lesenswert?

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

von Toni L. (tliesche)


Lesenswert?

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 :(

von Toni L. (tliesche)


Lesenswert?

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
Noch kein Account? Hier anmelden.