Forum: Mikrocontroller und Digitale Elektronik STm32F103: Beispielcode der Chan FatFs zum Laufen bekommen


von Christian J. (Gast)


Lesenswert?

Hallo,

ich hoffe, dass ich im richtigen Film bin. Ich habe mir das STM32F100 
beispiel der Chat Fat in Embitz importiert und kann es problemlos 
kompilieren.

Allerdings weiss ich nicht, ob der STM32F103C8 uC des Bluepill Boads mit 
dem Beispiel 100% komptibel ist.

Normalerweise benutze ich diese Includes und binde damit alle CMSIS und 
StdPeriphLib Ressourcen des F103 ein.

#include "stm32f10x_conf.h"
#include "system_stm32f10x.h"

Chan benutzt

#include "stm32f100.h"

Da stehen nur Registerdefintionen drin an welcher Adresse wo was ist 
aber es werden keine StdPeriphLibs eingebunden.

Die beiden sind nicht gegeneinander austauschbar oder gleichzeitig 
benutzbar, es erscheinen hunderte Fehlermeldungen.

Hardware habe ich noch keine aufgebaut, frage trotzdem schon mal, da 
eine evtl Portierung nahezu unmöglich ist, da Chan nur auf Registerebene 
Makros geschrieben hat, ich aber generell die StdPeriph Lib benutze.

Gruss,
Christian

von Christian J. (Gast)


Lesenswert?

Hat sich echt noch niemand mit diesem SD Karten System befasst auf einem 
kleinen STM32 Board? Und das nicht auf Arduino Basis sondern unter 
Verwendung der StdPeriph Library.

Knmisch....

von Christopher J. (christopher_j23)


Lesenswert?

Christian J. schrieb:
> Und das nicht auf Arduino Basis sondern unter Verwendung der StdPeriph
> Library.

Mach dich doch mal von der Library-Schubladendenke frei.
FatFS ist so strukturiert, dass das eigentliche FS von den 
Hardwarezugriffen entkoppelt ist. Guckst du hier unter "Media Access 
Interface"
http://elm-chan.org/fsw/ff/00index_e.html

D.h. du musst nur die Funktionen wie disk_read, disk_write, disk_status, 
etc. für deine Hardware implementieren. Ob überhaupt und wenn ja, was 
für eine Library du für diese Funktionen verwendest ist dem FS-Layer 
komplett egal.

Beispiele dafür gibt es im Internet massenweise und natürlich auch für 
STM32. Hier das erstbeste was ich gefunden habe (mit einfachem SPI): 
https://github.com/g4lvanix/STM32F4-workarea/blob/master/Project/FatFS/lib/ff/src/diskio.c

von grundschüler (Gast)


Lesenswert?

am einfachsten ist foolproof - bitbanging. Da muss nur der io-teil 
angepasst werden. Wennn das läuft, ist die Umstellung auf spi einfach.

von B.A. (Gast)


Lesenswert?

Am besten wäre aber ein DMA-Beispiel, dann gibt es keine periodischen 
Aussetzer immer wenn der 512Byte Block geschrieben wird.

Funktioniert das mit SPI auch mit den neuen, großen SD-Karten?
Es gibt doch glaube ich eine SD-Bibliothek im HAL der STM32 Bibliothek.

von Christian J. (Gast)


Lesenswert?

grundschüler schrieb:
> am einfachsten ist foolproof - bitbanging.

Am Besten ist ein DMA gesteuertes SPI Transfer mit maximalen 20 Mhz was 
noch so eben auf einem Lochraster durchgeht. Ich kann das selbst 
schreiben aber das dauert mit Testen halt 3-4 Tage je abends  daher 
fragte ich ob es vielleicht schon jemand gemacht hat.

Ich bin den Code durch, den kann man so übernehmen und alles weglöschen 
was er mit diesen Registern angestellt hat, wo mir jeder Nerv zu fehlen 
würde da die Bits einzeln nachzugucken.

De facto bleiben einzig und allein 2 SPI Routinen übrig, eine für 
Einzelbytes und eine führ mehrere. Die Einstellungen der SPI kenne ich 
aber nicht, da die ganz erheblich konfigurierbar sind, jeder Idle State 
usw. Diese Kartenn hängen sich auch gern mal auf, daher muss ich einen 
Reset vorsehen an der Stromversorgung. Mit P Kanal Mosfet oder 
ähnlich....

von Christian J. (Gast)


Lesenswert?

Christopher J. schrieb:
> Hier das erstbeste was ich gefunden habe (mit einfachem SPI):
> 
https://github.com/g4lvanix/STM32F4-workarea/blob/master/Project/FatFS/lib/ff/src/diskio.c

Ist leider nicht kompatibel zu der aktuellen Version, bzw wurd das total 
umgemodelt, der Header sieht komplett anders aus.  Der Code ist eh Müll, 
die Transferroutine ist nicht vollständig, es fehlen die Init Routinen 
für die SPI usw. Keine Ahnung wieso jemand so einen Schrott öffentlich 
macht.

Ich werde da wohl selbst mal Hand anlegen müssen.......

von Christian J. (Gast)


Lesenswert?

B.A. schrieb:
> Funktioniert das mit SPI auch mit den neuen, großen SD-Karten?
> Es gibt doch glaube ich eine SD-Bibliothek im HAL der STM32 Bibliothek.

Die HAL Lib basiert glaube ich auch auf dieser Chan Fat. Und 
idealerweise betreibt man diese Karten auch mit einer SDIO und nicht 
einer SPI. Einige Chipse wie der F200 haben die auch und natürlich auch 
die großen F4 und F7. Nur damit erreicht man maximalen Durchsatz.

Für meine kleine Anwendung reicht es aber vollkommen die per SPI zu 
betreiben. Long Filenames und Codepages muss ich eh drauf verzichten, 
das kompilat ist dann 80kb gross und damit zu gross für den F103.

von Christopher J. (christopher_j23)


Lesenswert?

Christian J. schrieb:
> Ich werde da wohl selbst mal Hand anlegen müssen.......

So war das auch gemeint.

Christian J. schrieb:
> Ist leider nicht kompatibel zu der aktuellen Version, bzw wurd das total
> umgemodelt, der Header sieht komplett anders aus.  Der Code ist eh Müll,
> die Transferroutine ist nicht vollständig, es fehlen die Init Routinen
> für die SPI usw. Keine Ahnung wieso jemand so einen Schrott öffentlich
> macht.

Das der Code hübsch ist habe ich nie behauptet und noch nicht einmal, 
dass er funktioniert. Keine Ahnung wo der Typ seine SPI initialisiert. 
Ist mir auch ehrlich gesagt völlig wurscht. Es ging nur um das Prinzip 
und das hat sich meines Wissens nach nicht verändert. diskio.h ist immer 
noch der gleiche und die folgenden Funktionen musst du implementieren:
1
DSTATUS disk_initialize (BYTE pdrv);
2
DSTATUS disk_status (BYTE pdrv);
3
DRESULT disk_read (BYTE pdrv, BYTE*buff, DWORD sector, UINT count);
4
DRESULT disk_write (BYTE pdrv, const BYTE* buff, DWORD sector, UINT count);
5
DRESULT disk_ioctl (BYTE pdrv, BYTE cmd, void* buff);
6
DWORD get_fattime (void);

von Christian J. (Gast)


Lesenswert?

Christopher J. schrieb:
> diskio.h ist immer
> noch der gleiche und die folgenden Funktionen musst du implementieren:

Nee, die hat sich schwer verändert :-) Er hat vielem anderen Namen 
gegeben usw. Und je tiefer man ändert, desto mehr Fehler. Ich koüpiere 
mir jetzt meine SPI Routinen in das Demoprojekt rein, was ja an einem 
VT100 Terminal läuft und schaue mal weiter. Er ändert zb auch den SPI 
Mode von 16 Bit auf 8 Bit und wieder zurück. Hat ja auch seinen Grund. 
Da kommen dann nämlich 2 Bytes raus und nicht eines. Diese Karten 
arbeiten aber laut MMC Spec mit 8 Byte Datenworten.

Ich meine nur, eine korrekt SPI Rotuine sieht so aus:
1
uint8_t SPI_TransferByte(uint8_t data)
2
{
3
    while (SPI_I2S_GetFlagStatus(RF_SPI, SPI_I2S_FLAG_TXE) == RESET);  /* Wait for SPIz Tx buffer empty */
4
    SPI_I2S_SendData(RF_SPI,data);                                     /* Send RF_SPI data */
5
    while (SPI_I2S_GetFlagStatus(RF_SPI, SPI_I2S_FLAG_RXNE) == RESET); /* Wait for RF_SPI data reception */
6
    while (SPI_I2S_GetFlagStatus(RF_SPI, SPI_I2S_FLAG_BSY) == SET);    /* Wait for RF_SPI Busy Flag cleared */
7
    return SPI_I2S_ReceiveData(RF_SPI);                                /* Read RF_SPI received data */
8
}

und nicht so, die funktioniert wohl nur zufällig, aber eben kein 
robuster Code

static BYTE xchg_spi (BYTE dat)
{
  SPIx_DR = dat;
  return (BYTE)SPIx_DR;
}

Und Probleme scheint es noch jede Menge zu geben: 
http://elm-chan.org/fsw/ff/bd/

von Leo C. (rapid)


Lesenswert?

Christian J. schrieb:
> Long Filenames und Codepages muss ich eh drauf verzichten, das kompilat
> ist dann 80kb gross und damit zu gross für den F103.

Da muss man ja nicht mal auf einem mickrigen ATmega drauf verzichten, 
mit zwei SD-Karten gleichzeitig im Zugriff.

von Christian J. (Gast)


Lesenswert?

Leo C. schrieb:
> Da muss man ja nicht mal auf einem mickrigen ATmega drauf verzichten,
> mit zwei SD-Karten gleichzeitig im Zugriff.

Scheinbar aber doch...... bei mir kompiliert es zu 80kb mit Os 
Einstellung. Bisschen viel wie ich finde. Aber es werden auch alle 
Routinen eingebunden aus dem Demofile, was man real ja nie braucht, eine 
handvoll reicht ja komplett.

von Leo C. (rapid)


Lesenswert?

Bin gerade nicht zuhause und nachschauen ist mir zu umständlich. Sieht 
aber für mich so aus, als hättest Du japanische Codepages aktiviert. 
Vielleicht kannst Du die rauswerfen und ein oder zwei westliche 
aktivieren.

http://elm-chan.org/fsw/ff/doc/appnote.html#lfn

von Christopher J. (christopher_j23)


Lesenswert?

Christian J. schrieb:
> Christopher J. schrieb:
>> diskio.h ist immer
>> noch der gleiche und die folgenden Funktionen musst du implementieren:
>
> Nee, die hat sich schwer verändert :-)

Also irgendwie meinen wir dann wohl verschiedene diskio.h, weil die aus 
der aktuellen R0.13 ist quasi identisch mit der aus dem oben von mir 
verlinkten Github-Repo von vor vier Jahren. Selbst die teilweise 
zerhackte Formatierung ist noch die selbe.

Christian J. schrieb:
> static BYTE xchg_spi (BYTE dat)
> {
>   SPIx_DR = dat;
>   return (BYTE)SPIx_DR;
> }

Ich hab ehrlich gesagt keine Ahnung wo du das her hast aber ja, sieht 
nicht sonderlich robust aus.

von Christian J. (Gast)


Angehängte Dateien:

Lesenswert?

Moin,

soll ja auch einen Nutzen für die Googler der Zukunft bringen, 
wenngleich der Code nicht getestet wurde, sondern stur übersetzt in die 
Schreibweise der StdPeriph Libs, da wo nötig und alle Bezüge auf die 
STM32F100.h sind entfernt, da die nicht kompatibel ist.

Also hier das diskio.c Modul für den STM32F103C8 Chip, ungeprüft aber 
dafür sorgfältig umgesetzt.

von NichtWichtig (Gast)


Lesenswert?

Christian J. schrieb:
> Ich meine nur, eine korrekt SPI Rotuine sieht so aus:
> uint8_t SPI_TransferByte(uint8_t data)
> {
>     while (SPI_I2S_GetFlagStatus(RF_SPI, SPI_I2S_FLAG_TXE) == RESET);
> /* Wait for SPIz Tx buffer empty */
>     SPI_I2S_SendData(RF_SPI,data);
> /* Send RF_SPI data */
>     while (SPI_I2S_GetFlagStatus(RF_SPI, SPI_I2S_FLAG_RXNE) == RESET);
> /* Wait for RF_SPI data reception */
>     while (SPI_I2S_GetFlagStatus(RF_SPI, SPI_I2S_FLAG_BSY) == SET);
> /* Wait for RF_SPI Busy Flag cleared */
>     return SPI_I2S_ReceiveData(RF_SPI);
> /* Read RF_SPI received data */
> }

So kann man natürlich auch die CPU Power verbrennen ...
3 while-loops in Folge ...

Smart ist anders.

von Frickelfritze (Gast)


Lesenswert?

NichtWichtig schrieb:
> Smart ist anders.

Ahnung haben ist auch anders.

von grundschüler (Gast)


Lesenswert?

Frickelfritze schrieb:
> Ahnung haben ist auch anders.

Für die mit wenig Ahnung: Kannst du den Sinn der drei whiles erklären?

von Christian J. (Gast)


Lesenswert?

Vielleicht einfach mal drueber nachdenken....  Zettel dazu nehmen, 
ueberlegen dass verschiedene Takte existieren.... dann kommt man drauf 
:-)

von Frickelfritze (Gast)


Lesenswert?

grundschüler schrieb:
> Für die mit wenig Ahnung: Kannst du den Sinn der drei whiles erklären?

Nur weil du zu faul bist Datenblatt und Sourcecode (SPL) selbst
zu lesen? Nö Danke.

Wer meint es schneller und besser machen zu können der darf
gerne seine Kreationen hier kundtun.

Ansonsten gilt das was Christian schon geschrieben hat.

Christian J. schrieb:
> Ich meine nur, eine korrekt SPI Rotuine sieht so aus:

Allerhöchstens kann man sich über das letzte Warten
streiten (/* Wait for RF_SPI Busy Flag cleared */)

Wer wirklich Zeit sparen will kann die Aufrufe von

SPI_I2S_SendData(RF_SPI,data);
und
SPI_I2S_ReceiveData(RF_SPI);

mit direkten Register-Operationen beschleunigen.

von Christian J. (Gast)


Lesenswert?

Frickelfritze schrieb:
> grundschüler schrieb:
> Für die mit wenig Ahnung: Kannst du den Sinn der drei whiles erklären?
> SPI_I2S_SendData(RF_SPI,data);
> und
> SPI_I2S_ReceiveData(RF_SPI);
>
> mit direkten Register-Operationen beschleunigen.

Die reduziert der Compiler auf genau eine Registeroperation. Da bleibt 
nicht mal ein Call uebrig. Und den letzten brauchst Du nur formal 
korrekt, es geht auch ohne.

von Christopher Johnson (Gast)


Lesenswert?

grundschüler schrieb:
> Frickelfritze schrieb:
>> Ahnung haben ist auch anders.
>
> Für die mit wenig Ahnung: Kannst du den Sinn der drei whiles erklären?

Das ist im Grunde einfach nur blockierender Datenaustausch per SPI, also 
ohne Interrupt oder DMA.

Im Prinzip steht es ja schon in den Kommentaren:
1. Warten bis das TXE-Flag ("TX buffer empty") im Statusregister gesetzt 
ist, damit man etwas ins SPI-Datenregister schreiben kann
2. Schreiben der Daten (in dem Fall 8 Bit) ins Datenregister
3. Warten bis das RXNE-Flag ("RX buffer not empty") im Statusregister 
gesetzt ist, weil erst dann die empfangenen Daten im Datenregister 
liegen
4. Warten bis das BUSY-Flag im Statusregister gelöscht ist
5. Lesen der empfangenen Daten (8 Bit) aus dem Datenregister

Punkt 4. ist tatsächlich überflüssig aber um die anderen beiden 
while-Schleifen kommt man nicht herum, es sei denn man nutzt Interrupts 
oder DMA. Da der TO wohl nur gelegentlich ein paar Byte auf die SD-Karte 
schreiben will kommt es aber auf die Performance in dem Fall wohl nicht 
an.

Ohne Library, mit direktem Registeraufruf würde das in etwa so aussehen:
1
static uint8_t xchg_spi(uint8_t data)
2
{
3
    while (!(SPI1->SR & SPI_SR_TXE));  /* Wait for SPI1 Tx buffer empty */
4
    SPI1->DR = data;                   /* Send SPI1 data */
5
    while (!(SPI1->SR & SPI_SR_RXNE)); /* Wait for SPI1 data reception */
6
    return SPI1->DR;                   /* Return SPI1 received data */
7
}

Natürlich wäre es sinnvoll das nicht fix für SPI1 zu schreiben, sondern 
etwa SPIx als bezeichner zu nehmen und diesen per #define auf die 
gewünschte Schnittstelle zu setzen.

Von der Performance her geben sich die beiden Varianten (SPL oder 
Register) wahrscheinlich wirklich nichts, so lange der Compiler alle 
Funktionsaufrufe schön inlined aber ich persönlich finde die Variante 
mit dem direkten Registeraufruf tatsächlich auch leserlicher. Man sieht 
direkt, was wo passiert und wenn ich fremden Code habe und nicht 
verstehe was z.B. in der ersten Zeile passiert, dann muss ich nur das 
Manual öffnen, mit STRG+F nach "SPI_SR" suchen und schon weiß ich was 
abgeht.

von NichtWichtig (Gast)


Lesenswert?

Wenn ich was schreiben will warte ich doch nicht noch unsinnig auf ein 
Zeichen was mich nicht interessiert.

von Christian J. (Gast)


Lesenswert?

Lies bitte das Manual! RTFM. Diese Spi ist kein Kinderspielzeug sondern 
eim sehr komplexes Werkzeug.

von Christian J. (Gast)


Lesenswert?

Ich erreiche uebrigens 20 Mbyte/s mit meiner Loesung. Und laege ich 
nicht grad im Krankenhaus mit nem Smartphone wuerde ich da auch noch 
mehr zu schreiben.

von Holm T. (Gast)


Lesenswert?

Oha, was machst Du da?

Gruß und gute Besserung,

Holm

von avr (Gast)


Lesenswert?

Christian J. schrieb:
> Lies bitte das Manual! RTFM. Diese Spi ist kein Kinderspielzeug
> sondern
> eim sehr komplexes Werkzeug.

Deswegen muss man nicht arrogant werden. Außerdem kann man sehr wohl 
schreiben ohne RXNE auszuwerten. Nur beim nächsten Lesevorgang muss dann 
aufgepasst werden.

Und SPI ist nicht komplex - auch nicht beim STM32. Komplexität ist was 
ganz anderes.

von avr (Gast)


Lesenswert?

Christian J. schrieb:
> Ich erreiche uebrigens 20 Mbyte/s mit meiner Loesung.

20Mbit/s? 20MB/s erreichen nicht mal die neuen STM32H7. Selbst mit 
20Mbit/s bewegst du dich schon außerhalb der Spezifikation des 
STM32F103.

von Christian J. (Gast)


Lesenswert?

Holm T. schrieb:
> Oha, was machst Du da?
>
> Gruß und gute Besserung,
>
> Holm

Hoersturz..... bei der Arbeit im Büro. Scheiss Stress. und das Tippen 
auf diesem Miniteil hier ist ne Katastrophe.

von Christian J. (Gast)


Lesenswert?

avr schrieb:

> Selbst mit
> 20Mbit/s bewegst du dich schon außerhalb der Spezifikation des
> STM32F103.

Nicht ganz. Der AHB Takt an dem die SPI hängt spielt mit 36 Mhz (DIV2) 
bei einem Clock von 72 Mhz. Die SPI selbst wird durch DIV2 geclocked, 
also 18 Mhz. Die 18 Mhz liegen voll am Pin an, also sind mit etwas 
Verlusten rund 16-max 18 Mhz drin. Letztres aber nur per DMA. In Bytes 
sind das 2,2 MBytes/s. Da habe ich einen Fehler in der 10er Potenz 
gemacht, der aber auf die Flüchtigkeit "zwischen Tür uns Angel" 
geschoben werden kann.

von grundschüler (Gast)


Lesenswert?

Christopher Johnson schrieb:
> Ohne Library, mit direktem Registeraufruf würde das in etwa so aussehen:

Ich hatte auch schon einige Probleme mit dem stm-spi:

Beitrag "Re: Stm32f103 Problem mit Spi2"


mit
SPI2->DR = dat;
while (!(SPI2->SR & 1<<0));//0_rxne 1_txe 7_bsy// ok

ist es dann aber gegangen.

Die zusätzliche Abfrage

   while (!(SPI1->SR & SPI_SR_TXE));  /* Wait for SPI1 Tx buffer empty 
*/

scheint mir überflüssig. wenn rxne erfüllt ist muss der tx-buffer leer 
sein, weil die Übertragung abgeschlossen ist bevor die Funktion erneut 
aufgerufen wird. Vielleicht war aber genau das das Problem, das ich 
seinerzeit hatte.

von Christian J. (Gast)


Lesenswert?

grundschüler schrieb:

> SPI2->DR = dat;
> while (!(SPI2->SR & 1<<0));//0_rxne 1_txe 7_bsy// ok
>
> ist es dann aber gegangen.

Ich empfehle wirklich nur den den Standard APIs zu arbeiten wie 
StdPeriphLib oder HAL. Das ist erstens viel lesbarer und bei 
Autoergänzung auch kein zusätzlicher Schreibkram. Der Code ist (oft aber 
nicht immer) zwischen den Familien portierbar, wenn die Hardware gleich 
ist und das sind zb bei I2C fixe prime Cells. Zudem wird zb die HAL 
ständig weiter entwickelt und enthält sehr mächtige Funktionen. Wenn Du 
mal mit Systemen wie ChibiOS oder NuttX arbeitest wirst Du merken, dass 
das viel einfacher geht und vor allem deutlich lesbarer.

while (!(SPI1->SR & SPI_SR_TXE));  /* Wait for SPI1 Tx buffer empty

Dieser Aufruf muss am Anfang stehen, wenn Du keine Endabfrage hast, ob 
die Bits raus sind. Die SPI ist eine Statemachine, die Event Flags hat, 
welche bedient werden wollen.

von Christian J. (Gast)


Lesenswert?

Wenn Du das hier, eine Init Routine für einen ADC Wandler mit zyklischem 
DMA Zugriff, getriggert durch einen Timer, auf Registerebene kodierst 
blickst Du nachher komplett nicht mehr durch....
1
void Init_DMA_LDR()
2
{
3
    #define ADC1_DR_Address   0x4001244C    // ADC Regular Data Register
4
5
    GPIO_InitTypeDef    GPIO_InitStructure;
6
    ADC_InitTypeDef     ADC_InitStructure;
7
    DMA_InitTypeDef     DMA_InitStructure;
8
9
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);                       // GPIOA Clock enable
10
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);                       // ADC Clock enable
11
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
12
13
    // ADC Clock auf unter 14 Mhz bringen
14
    RCC_ADCCLKConfig(RCC_PCLK2_Div8);
15
16
    /* ADC Pin konfigurieren --------------------------------------------------*/
17
    GPIO_InitStructure.GPIO_Pin              = GPIO_Pin_0;                     // AN1 Pin (PA0) aktivieren
18
    GPIO_InitStructure.GPIO_Mode             = GPIO_Mode_AIN;                  // Analog Input
19
    GPIO_InitStructure.GPIO_Speed            = GPIO_Speed_50MHz;
20
    GPIO_Init(GPIOA, &GPIO_InitStructure);
21
22
    /* ADC1 configuration ------------------------------------------------------*/
23
    ADC_InitStructure.ADC_Mode               = ADC_Mode_Independent;           // ADC1 werkelt allein
24
    ADC_InitStructure.ADC_ScanConvMode       = DISABLE;                        // Nur 1 Kanal, keine Scans
25
    ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;                        // Keine ständigen Wandlungen
26
    ADC_InitStructure.ADC_ExternalTrigConv   = ADC_ExternalTrigConv_None;      // Start mit Software, nicht durch Hardware
27
    ADC_InitStructure.ADC_DataAlign          = ADC_DataAlign_Right;            // Bits rechts ausrichten im Half-Word
28
    ADC_InitStructure.ADC_NbrOfChannel       = 1;                              // 1 Kanal sampeln
29
    ADC_Init(ADC1, &ADC_InitStructure);
30
31
    ADC_Cmd(ADC1, ENABLE);
32
33
    /* DMA1 Channel1 configuration ----------------------------------------------*/
34
    DMA_DeInit(DMA1_Channel1);
35
    DMA_StructInit(&DMA_InitStructure);
36
    DMA_InitStructure.DMA_DIR                   = DMA_DIR_PeripheralSRC;         // Peripherie ist Datenquelle
37
    DMA_InitStructure.DMA_PeripheralBaseAddr    = (uint32_t)ADC1_DR_Address;     // ADC Basisadresse Datenregister
38
    DMA_InitStructure.DMA_MemoryBaseAddr        = (uint32_t)LDR;                 // Memory Array Adresse
39
    DMA_InitStructure.DMA_PeripheralInc         = DMA_PeripheralInc_Disable;     // Auf Source ADC keine Inkrementierung
40
    DMA_InitStructure.DMA_MemoryInc             = DMA_MemoryInc_Enable;          // Auf Target Array inkrementieren
41
    DMA_InitStructure.DMA_BufferSize            = (uint16_t)LDR_HIST;            // Groesse des Arrays
42
    DMA_InitStructure.DMA_PeripheralDataSize    = DMA_PeripheralDataSize_HalfWord; // ADC Wandler 16 Bit
43
    DMA_InitStructure.DMA_MemoryDataSize        = DMA_MemoryDataSize_HalfWord;   // Memory auch 16 Bit
44
    DMA_InitStructure.DMA_Mode                  = DMA_Mode_Circular;             // Array circular füllen
45
    DMA_InitStructure.DMA_Priority              = DMA_Priority_Low;              // Niedrige Prio
46
    DMA_InitStructure.DMA_M2M                   = DMA_M2M_Disable;
47
    DMA_Init(DMA1_Channel1, &DMA_InitStructure);                                 // Mache Einstellungen
48
49
    /* Enable DMA1 Channel 1 */
50
    DMA_Cmd(DMA1_Channel1, ENABLE);
51
52
    /* ADC1 Sequencer Kanal 1 auf Rang 1 configuration */
53
    ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_71Cycles5);     // PA0
54
55
    /* Enable ADC1 reset calibaration register */
56
    ADC_ResetCalibration(ADC1);
57
58
    /* Check the end of ADC1 reset calibration register */
59
    while(ADC_GetResetCalibrationStatus(ADC1));
60
61
    /* Start ADC1 calibaration */
62
    ADC_StartCalibration(ADC1);
63
64
    /* Check the end of ADC1 calibration */
65
    while(ADC_GetCalibrationStatus(ADC1));
66
67
    /* Keine Triggerung durch Events etc */
68
    ADC_ExternalTrigConvCmd(ADC1, DISABLE);
69
70
    /* Erzeuge nach jeder Wandlung einen DMA Request */
71
    ADC_DMACmd(ADC1, ENABLE);
72
73
    /* Trigger die erste Wandlung, weitere Trigger durch ADC / DMA Interrupt */
74
    ADC_SoftwareStartConvCmd(ADC1, ENABLE);
75
}

von Karl K. (leluno)


Lesenswert?

Christian J. schrieb:
> Dieser Aufruf muss am Anfang stehen, wenn Du keine Endabfrage hast, ob
> die Bits raus sind.

Dieser Aufruf muss  n u r  am Anfang stehen, wenn Du keine Endabfrage 
hast ob
 die Bits raus sind.

Damit ist die oben ob dargestellte "korrekte SPI Rotuine" ziemlich 
aufgebläht. Wir sind uns einig, dass es auch mit weniger Code geht, 
nämlich einmal Abfrage TXE vor dem Aufruf der ersten spi-routine - wenn 
die Möglichkeit besteht, dass in tx irgendetwas stehen könnte - und dann 
nur noch rxne.


> Zudem wird zb die HAL ständig weiter entwickelt und enthält sehr
> mächtige Funktionen.

Nichts gegen Programme wie Arduino und Hal. es gibt code, der so 
kompliziert ist, dass man sich auf solche Programmierhilfen verlassen 
muss. Bei einer schlichten spi-routine weiß ich aber gerne, was mein 
Programm macht.

Sowas
/* Check the parameters */
  assert_param(IS_SPI_ALL_PERIPH(SPIx));
 ist völlig überflüssig.

von Christian J. (Gast)


Lesenswert?

Karl K. schrieb:
> Sowas
> /* Check the parameters */
>   assert_param(IS_SPI_ALL_PERIPH(SPIx));
>  ist völlig überflüssig.

Na.... wenn Du genauer hinschaust wirst du merken, dass das 
assert_param, was in jeder Funktion der StdPeriph steht nur ein Makro 
ist, das sich mit USE_FULL_ASSERT   1  ein und ausschalten lässt :-) Den 
zulässigen Wertebereich soll eine Funktion schon testen, das ist guter 
Programmstil.

von grundschüler (Gast)


Lesenswert?

Christian J. schrieb:
> Den
> zulässigen Wertebereich soll eine Funktion schon testen, das ist guter
> Programmstil.

Völlig überflüssig. Den zulässigen Wertebereich muss ein Programmierer 
immer beachten. Wenn der nicht stimmt, ist das Programmm Murks. 
Derartige Überwachungen des Programmierers haben in vielfach 
aufgerufenen Funktionen nichts zu suchen. Das gilt selbst dann, wenn man 
das irgendwo abschalten kann. Wer weiß das denn schon, dass man das 
abschalten und wo man das abschalten kann?

von Nop (Gast)


Lesenswert?

grundschüler schrieb:
> Wenn der nicht stimmt, ist das Programmm Murks.

Richtig. Dann muß man herausfinden, wo der Bug steckt, das nennt sich 
Debuggen, und dazu können Debug-Builds sehr hilfreich sein.

von Chris J. (Gast)


Lesenswert?

grundschüler schrieb:

> Völlig überflüssig. Den zulässigen Wertebereich muss ein Programmierer
> immer beachten. Wenn der nicht stimmt, ist das Programmm Murks.

Du bist aber auch ein kleiner Klugs..... Schon mal drüber nachgedacht, 
dass Software von einem Team geschrieben wird? Schon mal mit svn im Team 
gearbeitet? Mit Leuten, die gar nicht in Deinem Land leben? Dass Module 
nach dem V&V Modell der Qualitätssicherung geprüft werden müssen? Dass 
es sowas wie Verfikation und Validation gibt?

Ich habe Jahre für Automotive Software geschrieben nach MISRA Standard, 
ISO 25010, ISO 9126 und weiteren etlichen internen 
Codierungsrichtlinien....

von chris (Gast)


Lesenswert?

Chris J. schrieb:
> Ich habe Jahre für Automotive Software geschrieben nach MISRA Standard,
> ISO 25010, ISO 9126 und weiteren etlichen internen
> Codierungsrichtlinien....

Und trotzdem behauptest du immer wieder, dass der Compiler schuld ist, 
wenn dein Code nur ohne Optimierung funktioniert?
Vielleicht wären da ein paar Schulungen in C-Programmierung doch mal 
sinnvoll für dich.

Ich hoffe nur, dass du nicht irgendwas sicherheitsrelevantes z.B. von 
KFZ programmiert hast. Sonst fahren alle Autos beim nächsten 
Compilerupdate gegen den Baum. Aber da ist dann natürlich der Compiler 
dran schuld und nicht dein Code...

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.