Hallo,
es ist sehr speziell aber ich suche jemand, der exakt mal das realisiert
hat und mir den Source Code der Datei mmc_stm32F1.c und .h schicken
kann.
Und zwar geschrieben mit der veralteten StdPeripheral Library für den
STM31F1xx, weil ich EmBitz 1.1 benutze als IDE, mich nur mit dieser
auskenne und im reinen Hobby Bereich HAL nicht neu "lernen" möchte (weil
alles ja auch so geht), CubeMX gilt das gleiche für. ChanFatFs hat zwar
selbst Code dafür veröffentlicht aber dieser basiert auf
Registeraufrufen einer stm31F1xx.h und ist mit EmBitz nicht
kompilierbar, weil das eben eine IDE ist, die eine eigene Umgebung
mitbringt. Vermutlich hat er das als normales GCC Projekt geschrieben
mit make File, Linker File usw. ohne eine IDE sondern rein Konsole.
In Kürze:
ChanFatFs Treiber für SD Karten
Datei mmc_stm32F1.c
kompiliert unter EmBitz IDE 1.1. durch
benutz die StdPeripheral Librarys als Unterbau
Ich möchte nur eine SD Karte dran pappen und wissen dass es läuft :-)
Christian
Diese Routinen von ihm sind IMHO falsch, sie berücksichtigen nicht die
Abfrage von wesentlichen Flags der SPI. Das läuft nur durch, solange die
CPU "langsamer" ist als die SPI, z.b. bei O0 Optimierung, mit O3 klappt
es dann oft nicht mehr. Daran habe ich mich mal totgesucht früher. Vor
dem Eintritt in eine SPI Routine muss der Status abgefragt werden, oder
nachher. Jedenfalls so nicht.
1
/* Receive multiple byte */
2
static
3
voidrcvr_spi_multi(
4
BYTE*buff,/* Pointer to data buffer */
5
UINTbtr/* Number of bytes to receive (even number) */
6
)
7
{
8
WORDd;
9
10
11
SPIx_CR1&=~_BV(6);
12
SPIx_CR1|=(_BV(6)|_BV(11));/* Set SPI to 16-bit mode */
13
14
SPIx_DR=0xFFFF;
15
btr-=2;
16
do{/* Receive the data block into buffer */
17
while(SPIx_SR&_BV(7));
18
d=SPIx_DR;
19
SPIx_DR=0xFFFF;
20
buff[1]=d;buff[0]=d>>8;
21
buff+=2;
22
}while(btr-=2);
23
while(SPIx_SR&_BV(7));
24
d=SPIx_DR;
25
buff[1]=d;buff[0]=d>>8;
26
27
SPIx_CR1&=~(_BV(6)|_BV(11));/* Set SPI to 8-bit mode */
28
SPIx_CR1|=_BV(6);
29
}
30
31
32
#if _USE_WRITE
33
/* Send multiple byte */
34
static
35
voidxmit_spi_multi(
36
constBYTE*buff,/* Pointer to the data */
37
UINTbtx/* Number of bytes to send (even number) */
38
)
39
{
40
WORDd;
41
42
43
SPIx_CR1&=~_BV(6);
44
SPIx_CR1|=(_BV(6)|_BV(11));/* Set SPI to 16-bit mode */
45
46
d=buff[0]<<8|buff[1];
47
SPIx_DR=d;
48
buff+=2;
49
btx-=2;
50
do{/* Receive the data block into buffer */
51
d=buff[0]<<8|buff[1];
52
while(SPIx_SR&_BV(7));
53
SPIx_DR;
54
SPIx_DR=d;
55
buff+=2;
56
}while(btx-=2);
57
while(SPIx_SR&_BV(7));
58
SPIx_DR;
59
60
SPIx_CR1&=~(_BV(6)|_BV(11));/* Set SPI to 8-bit mode */
Christian J. schrieb:> Diese Routinen von ihm sind IMHO falsch, sie berücksichtigen nicht die> Abfrage von wesentlichen Flags der SPI.
Da magst du sehr Recht haben.
Wenn man gugelt findet man schon 2017 Einträge von dir, richtig?
Christian J. schrieb:> Vor dem Eintritt in eine SPI Routine muss der Status abgefragt> werden, oder nachher.
Sehr richtig. Daher mach ich das wie im Anhang dargestellt, das
sollte funktionieren. Tatsächlich muss "man" mehr warten als
man vermuten sollte, auch wenn es unplausibel erscheint. Man
muss auch immer das SPI-Datenregister lesen, auch wenn man
SPI schreiben möchte, sonst kommt die Maschine ausser tritt.
Daher nur eine universelle Byte-Routine für Lesen und Schreiben.
Paar kleine Anpassungen für deinen Zweck wirst du machen müssen,
aber das wirst du schon schaffen. 16-Bit Transfers sind hier
nicht nötig und machen die Sacher nur komplizierter aber nicht
spürbar schneller.
Hi,
ja gut, aufgepasst, 2017 habe ich das Thema schonmal bearbeitet aber die
Sache im Zuge eines Umzuges ausser Sicht verloren. Jezt erst greife ich
sie wieder auf und versuche wieder ins Thema zu kommen. Da war damals
mal was...es klappte nicht.
Und damit hatte es zu tun, weil die CPU nicht einfach in eine laufende
Prime Cell eingreifen kann, wenn die sich in einem Zustand befindet, der
völlig unbekannt ist. Nur mit den Flags gab es Debatten, diese ominöse
BSY Flag, RXE war da noch und TXE.
while ((SPI1->SR & SPI_I2S_FLAG_TXE ) == 0) { /* wait */ };
while ((SPI1->SR & SPI_I2S_FLAG_BSY) != 0) { /* wait */ };
Danke erstmal für den Code, schaue ich mir an.
Bei mir sieht es etwas komplexer aus, möglicherweise auch auch nicht
richtig eben. Und die xmit ist auch anders.
1
/* Exchange a byte */
2
staticuint8_txchg_spi(uint8_tdat)/* Data to send */
3
{
4
while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_TXE)==RESET);/* Wait for SPIz Tx buffer empty */
5
SPI_I2S_SendData(SPI1,dat);/* Send SPI1 data */
6
while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_RXNE)==RESET);/* Wait for SPI1 data reception */
7
returnSPI_I2S_ReceiveData(SPI1);/* Read SPI1 received data */
8
}
1
#if _USE_WRITE
2
/* Send multiple byte */
3
staticvoidxmit_spi_multi(constuint8_t*buff,/* Pointer to the data */
4
uint32_tbtx)/* Number of bytes to send (even number) */
Das SPI_I2S_FLAG_BSY Flag dominiert, daher ist es beim Lesen
der Datenregisters unnötig und "fehlerschwanger" nur das
SPI_I2S_FLAG_RXNE Flag auszuwerten. Bei "not busy" ist dagegen
garantiert dass das gelesene Byte bereits zur Verfügung steht
und die Maschine für weitere Operationen bereit ist.
Ok.... ich habe es mal "umgeschrieben" für die API, auch wenn der
Compiler da den gleichen Senf draus macht, ich kann es leichter lesen
1
/* Exchange a 16 Bit Value */
2
inline__attribute__((__always_inline__))uint8_txchg_spi(uint16_tdat)/* Data to send */
3
{
4
SPI_I2S_SendData(SPI1,dat);/* Send SPI1 data */
5
while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_TXE)==RESET);/* Wait for SPI1 data reception */
6
while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_BSY)==RESET);/* Wait for SPIz Tx buffer empty */
7
returnSPI_I2S_ReceiveData(SPI1);/* Read SPI1 received data */
8
}
Und Du hast das getestet? das läuft so? Denn es vergeudet ja eigentlich
Zeit, wenn die CPU wartet, bis etwas raus ist und dann erst weitermacht.
Es wäre besser das alles nur beim Eintritt zu prüfen. Aber der Return
Wert steht ja erst zur Verfügung, wenn der State durchgelaufen ist...
also doch warten.... glaube man kann nur beim Senden zeit sparen, wenn
man den Empfang nicht auswertet.
habe noch keine Hardware, alles nur Code ohne Prüfung am Objekt....
Christian J. schrieb:> Denn es vergeudet ja eigentlich> Zeit, wenn die CPU wartet, bis etwas raus ist und dann erst weitermacht.
Ich habe lang genug damit gespielt und kann mich nur wiederholen.
jo mei schrieb:> Tatsächlich muss "man" mehr warten als> man vermuten sollte, auch wenn es unplausibel erscheint. Man> muss auch immer das SPI-Datenregister lesen, auch wenn man> SPI schreiben möchte, sonst kommt die Maschine ausser tritt.
Und ich habe oft genug die SPI Maschine ausser Tritt gebracht
ohne es zu verstehen.
Christian J. schrieb:> auch wenn der Compiler da den gleichen Senf draus macht
Wenn du die SPL Calls verwendest kannst du tatsächlich Pech
haben und das Zeug läuft langsamer ..... wenn der Compiler
nicht optimiert oder wenn er es nicht rafft bei Optimierung
da ausreichend Inline-Code draus zu machen.
jo mei schrieb:> Ja ok, dekrementieren vergessen.
Also ist der Code nicht aus einer laufenden Anwendung heraus genommen?
Sorry,wenn ich bohre aber meist findet sich dann leider noch mehr (ich
war früher beim TÜV, angeboren :-)
Außerdem würde die Routine wohl einmal zu wenig durchlaufen, die holt
nur numbytes-1 Daten rein aber das habe ich jetzt nicht geprüft.
Die SPL Calls werden aufgelöst, das sieht man im ASM beim Debuggen. Man
darf aber nicht size opt einstellen, sondern maximale Geschwindigkeit.
Sonst nimmer er sie rein.
Nr.7 ist das BSY Flag, das benutzt er als einziges und zum Abschluss
nochmal.
Was ist mit SPI_DR; Das wird doch weg optimiert, wenn es nicht volatile
ist.
Doof, dass an dem bisschen das Funktionieren des gesamten Code hängt,
weil das ganz unten läuft... stimmt das nicht klappt gar nichts. Da
kommt es auf jedes Bit und jede Mikrosekunde an.