Hallo liebe Leute, Ich nehme mal Bezug auf meinen alten Thread Beitrag "Problem mit STM32 CubeMX I2S DMA" für eine Erweiterung meines ursprünglichen Problems. Nachdem I2S nun echt gut läuft und ich den damaligen (logischen) Fehler verstanden hatte hab ich mir gedacht : "Dann kann das ganze in Voll Duplex ja nicht mehr so schwer sein" ... hab ich gedacht. Falsch gedacht. Ich habe mittlerweile dank Google schonmal soviel heraus gefunden das es um das Übertragen für Vollduplex Übertragungen mit DMA separate Funktionen gibt, genauer eine einzige : HAL_I2SEx_TransmitReceive_DMA Macht auch sinn, denn man muß ja einen gleich großen Puffer fürs senden und empfangen bereitstellen und das gleichzeitig. Ich hab mal geschaut was diese Funktion bewirkt, und siehe da, die beiden DMA Interrupts für Receive und Transmit werden auch brav nacheinander aufgerufen. Was ich aber noch nicht so richtig verstanden habe bzw wo ich auch nicht so die Hilfe über Google ersuchen konnte ist folgendes : Beim Transmit habe ich ja zwei Callbacks. Eine für Buffer zu 50% übertragen und eine für Buffer zu 100% übertragen. Das scheint hier wohl wieder über den Haufen geworfen worden zu sein, denn die Flags die ich beim Durchsteppen im Debugger gesehen hab lösen nur einen Transfer Complete Interrupt aus. Eigentlich noch schlimmer, weil die Callback in der HAL die ja gerade für den FullDuplex Transfer zuständig ist laut Quellcode keinen Circular Mode unterstützt. Das würde aber dann auch heißen das es keine 50% und 100% Callbacks gibt anhand derer ich meine Buffer befüllen bzw leeren kann, bzw es überhaupt keine Callbacks gibt die nach einem Transfer aufgerufen werden. Das macht mich etwas stutzig. Irgendwie steh ich gerade auf dem Schlauch wie das ganze was ich beim HalfDuplex Transfer so schätzen gelernt hab (Callbacks bei Halb übertragen und ganz übertragen) bei FullDuplex anwenden soll, bzw ob das überhaupt möglich ist. Ist die Library da vllt einfach nur nicht "komplett" oder hab ich irgendwas grundsätzliches übersehen das es bei Voll Duplex anders laufen muss ? Ich finde auch keine richtig befriedigende Beispiele zum Thema "I2S Full Duplex DMA with STM32". Ich lese zwar von einigen Problemen, aber das scheint mir eher mit den Codecs zu tun zu haben, als vielmehr mit der verarbeitung von Receive und Transmit. Hat jemand von euch schonmal einen I2S Full Duplex Transfer mit DMA sauber ans laufen bekommen und damit z.b. mal Audio verarbeitet (Filter, Equalizer, Effekte usw) ?
Niemand ne Idee ? Ich komm da irgendwie nicht so richtig weiter und im ST Forum bekomm ich auch keine wirklich brauchbare antwort bis auf : "Ich nutze kein CubeMX". I2S Vollduplex mit DMA im Circular Mode muss doch gehen.
Mit Cube HAL stehst du ziemlich einsam da, das nutzt kaum jemand für mehr als die Initialisierung der Taktquellen.
Na ja ... ich hab schon ein paar Beispiele gesehen wo mit der StdPeriph gearbeitet, aber die wird ja soweit ich weiß nicht mehr unterstützt. Im Prinzip komm ich mit der Cube HAL schon relativ weit. Die DMA Interrupts werden abwechselnd aufgerufen. Nur die Verarbeitung endet im Nirvana. Schade das CubeMX nicht so genutzt wird. Das Tool ist schon recht schön aufgebaut und der erzeugte Quellcode gut verständlich, wenn auch etwas umfangreich, aber bei generischen Sachen ist der Quellcode ja immer etwas größer.
Rene B. schrieb: > Ich habe mittlerweile dank Google schonmal soviel heraus gefunden Tut mir leid das mal so sagen zu müssen aber ich halte deine Vorgehensweise für äußerst fragwürdig. Du stocherst zu sehr im Nebel herum, anstatt dich richtig mit der Materie vertraut zu machen. Es gibt für jede Controller-Familie ein HAL-User-Manual. Das würde ich unbedingt mal konsultieren. Ansonsten ist da noch das Reference-Manual und die Kapitel über SPI/I2S und DMA würde ich mir auch unbedingt mal durchlesen. Das Problem jedes Frameworks ist meines Erachtens nach, dass du irgendwann gar nicht mehr weißt, was wo passiert und genau diesen Eindruck habe ich bei dir und deinem Vorhaben. Das ist mir mit dem HAL jedoch selber auch schon so gegangen.
Christopher ... Es scheint nur so. Ich habe mir das User Manual der HAL bzw den Teil der HAL den ich für I2S Full Duplex per DMA benötige schon angeschaut. Nur war der Informationsgehalt nicht viel höher als das was ich ohnehin schon aus dem Quellcode lesen konnte. Das Reference Manual zu dem STM32F4 habe ich auch schon zu dem Thema gelesen, und auch recht gut verstanden, aber das zusammenspiel in der CubeMX ist leider nicht so wie erwartet. >Das Problem jedes Frameworks ist meines Erachtens nach, dass du >irgendwann gar nicht mehr weißt, was wo passiert Das Framework ist schon recht komplex, wobei der I2S Teil jetzt nicht so übermäßig kompliziert ist. Da ist der USB Stack schon ne Nummer größer. Das mit Google bezog sich auch mehr generell auf Beispiele zu I2S Full Duplex mit DMA. Wie gesagt, dort habe ich schon einige Beispiele gefunden, aber die stützen sich auf die StdPeriph Library, und meines Wissens nach wird die so nicht mehr unterstützt, daher die Hoffnung das jemand mir vllt sagen kann warum das mit der CubeMX nicht so richtig läuft bzw nicht unterstützt wird (was man bei durchsicht des Quellcodes nur so sagen kann, da bei den Handlern die letztendlich aufgerufen werden kein Circular Mode unterstützt wird, was mir gelinde gesagt merkwürdig vorkommt).
Kleine Korrektur: Du schreibst immer CubeMX, aber dein Abstraktions-Layer heißt "Cube HAL". CubeMX ist nur das Configurations-Tool dazu.
hi ähnliches Problem hier. Es ist scheinbar ein Bug... siehe auch diverse berihte mit gleichem Problem. die Stdlib funtkioniert hier etwas anders das man die register einzeln setzt. Was laut anderen leuten eh die bessere methode ist .. blah ... lassen wir das thema mal weit außen vor... Grundsätzlich sollte so eine Lib ja funktionieren´, egal welche methode man ansetzt , oder? Aber hier leider nicht. Der 50% interrupt wird zum 100% interrupt und der completeInterrupt kommt garnicht. Die Perhipherie kann es!! mit stdlib oder registersetzerei geht es. der HAL_I2SEx_TransmitReceive_DMA( ...) ruft einen anderen ISR Handler auf. der hat scheinbar einen bug
1 | static void I2SEx_TxRxDMACplt(DMA_HandleTypeDef *hdma) |
2 | {
|
3 | I2S_HandleTypeDef* hi2s = (I2S_HandleTypeDef*)((DMA_HandleTypeDef*)hdma)->Parent; |
4 | |
5 | /* if DMA is not configured in DMA_CIRCULAR mode */
|
6 | if((hdma->Instance->CR & DMA_SxCR_CIRC) == 0U) |
7 | {
|
8 | if (hi2s->hdmarx == hdma) |
9 | {
|
10 | /* Disable Rx DMA Request */
|
11 | if (((hi2s->Instance->I2SCFGR & SPI_I2SCFGR_I2SCFG) == I2S_MODE_MASTER_TX) ||\ |
12 | ((hi2s->Instance->I2SCFGR & SPI_I2SCFGR_I2SCFG) == I2S_MODE_SLAVE_TX)) |
13 | {
|
14 | CLEAR_BIT(I2SxEXT(hi2s->Instance)->CR2,SPI_CR2_RXDMAEN); |
15 | }
|
16 | else
|
17 | {
|
18 | CLEAR_BIT(hi2s->Instance->CR2,SPI_CR2_RXDMAEN); |
19 | }
|
20 | |
21 | hi2s->RxXferCount = 0U; |
22 | |
23 | if (hi2s->TxXferCount == 0U) |
24 | {
|
25 | hi2s->State = HAL_I2S_STATE_READY; |
26 | |
27 | HAL_I2SEx_TxRxCpltCallback(hi2s); |
28 | }
|
29 | }
|
30 | |
31 | if (hi2s->hdmatx == hdma) |
32 | {
|
33 | /* Disable Tx DMA Request */
|
34 | if (((hi2s->Instance->I2SCFGR & SPI_I2SCFGR_I2SCFG) == I2S_MODE_MASTER_TX) ||\ |
35 | ((hi2s->Instance->I2SCFGR & SPI_I2SCFGR_I2SCFG) == I2S_MODE_SLAVE_TX)) |
36 | {
|
37 | CLEAR_BIT(hi2s->Instance->CR2,SPI_CR2_TXDMAEN); |
38 | }
|
39 | else
|
40 | {
|
41 | CLEAR_BIT(I2SxEXT(hi2s->Instance)->CR2,SPI_CR2_TXDMAEN); |
42 | }
|
43 | |
44 | hi2s->TxXferCount = 0U; |
45 | |
46 | if (hi2s->RxXferCount == 0U) |
47 | {
|
48 | hi2s->State = HAL_I2S_STATE_READY; |
49 | |
50 | HAL_I2SEx_TxRxCpltCallback(hi2s); |
51 | }
|
52 | }
|
53 | }
|
54 | /* neu hinzugefüht ... */
|
55 | else
|
56 | {
|
57 | HAL_I2SEx_TxRxCpltCallback(hi2s); |
58 | }
|
59 | /* neu hinzugefüht ... */
|
60 | |
61 | }
|
und ganz wichtigdabei ... nur eine ISR aufrufen !! entweder RX oder TX aber nie beide!! sonst landen beide interrupts in der selben callBack
1 | void HAL_I2SEx_TxRxHalfCpltCallback(I2S_HandleTypeDef *hi2s) |
2 | {
|
3 | |
4 | }
|
5 | |
6 | void HAL_I2SEx_TxRxCpltCallback(I2S_HandleTypeDef *hi2s) |
7 | {
|
8 | |
9 | }
|
Interrupts ...
1 | HAL_NVIC_SetPriority(DMA1_Stream0_IRQn, 5, 0); |
2 | HAL_NVIC_EnableIRQ(DMA1_Stream0_IRQn); |
3 | // HAL_NVIC_SetPriority(DMA1_Stream5_IRQn, 5, 0);
|
4 | // HAL_NVIC_EnableIRQ(DMA1_Stream5_IRQn);
|
hier nur eine auswählen.
wer dringend die ISR brauch muss sich aus der structur dann raussuchen welcher ISR das gerade ist. oder manuell extra callbacks anlegen ...
Hallo ztrt, ja das deckt sich etwa mit meinen Erfahrungen bzw Beobachtungen. Wobei bei mir immer nur der Transfer Complete Interrupt aufgerufen wird bzw der DMA Controller nur das TC bit und das HT bit nie gesetzt hat. Aber auch mit deiner Ergänzung des Handlers klappt das nciht so wie gedacht. Wenn ich den I2S teil als Slave Half Duplex initialisiere, wird Half Transfer und Complete Transfer aufgerufen. Wenn ich dann jeweils die andere Hälfte mit einem Sinus befülle kommt der Sinus auch schön sauber heraus. Stelle ich dann nur auf Full Duplex Slave, mache die Ergänzung des Handlers wie von dir beschrieben wird nur der TXRXCplt aufgerufen. Daten werden zwar übertragen aber das ist nur völliges Gemüse was der Wandler ausspuckt. Nur wenn ich den Buffer mit nullen befülle ist Ruhe. Ich hatte vor längerer Zeit mal geschaut warum das HT Bit nicht gesetzt wird und gesehn das bei der Initialisierung mit HAL_I2SEx_TransmitReceive_DMA nur die Cplt Callback eingetragen wird, und die Half Cplt nicht. Außerdem gibt es da auch keine Implementierung für den Half Cplt Aufruf. Ich hab irgendwie das Gefühl das ist in der CubeMX schlicht und einfach nicht implementiert. Ich werd mal schauen ob ich ohne CubeMX weiter komme und den Full Duplex Betrieb irgendwie ans rennen bekomme. Gibt ja auch ein paar Beispiele. Und das das Hardwaremäßig funktionieren muss weiß ich da ich ja auch schon einige Demos gesehen habe für z.b. Effektgeräte. Wäre halt nur schön wenns auch mit CubeMX funktionieren würde. >Was laut anderen leuten eh die bessere methode ist .. blah ... >lassen wir das thema mal weit außen vor... Seh ich genauso. Ob von hand oder per CubeMX ... gehen muss es und so schlecht find ich die CubeMX jetzt nicht. Bisher hab ich noch alles ans laufen bekommen, selbst wenn kleinere Bugs da drinnen waren. Aber das mit dem I2S Full Duplex Slave ist wohl echt was größeres. Wenn du noch Hinweise hast, immer gerne ... Werd gleich auch mal den Code anhängen. Vllt fällt dir oder jemand anderem ja noch was auf. So schwer kanns ja nicht sein. Ist ja nicht so als wenn ich von hand nen selbstgeschriebenen TCP/IP Stack ans laufen bringen möchte ....
Ich habe mal Ergänzungen gemacht von denen ich meine das sie funktionieren müssten (nach meinem Verständnis der Cube HAL). Ich habe in der "stm32f4xx_hal_i2s_ex.c" die HalfCplt in der "HAL_I2SEx_TransmitReceive_DMA" nachgezogen ... /* Set the I2S Rx DMA transfer complete callback */ hi2s->hdmarx->XferCpltCallback = I2SEx_TxRxDMACplt; >>>>>>>>>>>>>>>>>>> nachgezogen damit das Half Transfer Bit gesetzt wird /* Set the I2S Rx DMA transfer complete callback */ hi2s->hdmarx->XferHalfCpltCallback = I2SEx_TxRxDMAHalfCplt; <<<<<<<<<<<<<<<<<<< /* Set the I2S Rx DMA error callback */ hi2s->hdmarx->XferErrorCallback = I2SEx_TxRxDMAError; /* Set the I2S Tx DMA transfer complete callback */ hi2s->hdmatx->XferCpltCallback = I2SEx_TxRxDMACplt; >>>>>>>>>>>>>>>>>>> nachgezogen damit das Half Transfer Bit gesetzt wird /* Set the I2S Rx DMA transfer complete callback */ hi2s->hdmatx->XferHalfCpltCallback = I2SEx_TxRxDMAHalfCplt; <<<<<<<<<<<<<<<<<<< ... sowie den Handler für den HalfCplt Interrupt die überhaupt nicht implementiert war .... __weak void HAL_I2SEx_TxRxHalfCpltCallback(I2S_HandleTypeDef *hi2s) { /* Prevent unused argument(s) compilation warning */ UNUSED(hi2s); } static void I2SEx_TxRxDMAHalfCplt(DMA_HandleTypeDef *hdma) { I2S_HandleTypeDef* hi2s = (I2S_HandleTypeDef*)((DMA_HandleTypeDef*)hdma)->Parent; HAL_I2SEx_TxRxHalfCpltCallback(hi2s); } Die Ergänzungen hab ich gemacht nachdem ich mir angeschaut habe wie es bei dem Half Duplex Slave das HT und TC Bit im DMA Interrupt gesetzt werden. So meine ich müsste es auch bei dem Full Duplex Slave gemacht werden. Wie gesagt : Meinem Verständnis nach, da der zweite DMA Kanal für RX ja "einfach nur" dazu geschaltet wird. Sprich : Ich möchte beim Full Duplex Slave erstmal denselben Sinus Ton ausgeben wie beim half Duplex Slave und dann schauen das ich beim Full Duplex Slave dem Empfänger die Daten des AD Wandlers des Codecs entlockt bekomme. Wie in deinem Hinweis habe ich nur den spi_tx DMA Interrupt zugelassen, und nicht auch noch den spi_ext_rx DMA Interrupt damit beide nicht denselben Handler aufrufen und die Callbacks dopppelt aufgerufen werden. Es werden nun beide Callbacks Routinen aufgerufen, aber direkt nacheinander ... Sprich : Sobald der DMA Interrupt kommt sind beide Flags (HT und TC) gesetzt und der geht nacheinander in die half transfer complete und transfer complete rein. Als wenn beide Flags IMMER gesetzt sind, was mich etwas verwundert weil wenn ich nur mit Half Duplex Slave arbeite und die Initialisierung per "HAL_I2S_Transmit_DMA" ebenfalls die halfcplt und cplt Callback einträgt funktioniert es das das erst das HT und dann das TC Bit gesetzt sind und die Callbacks schön nacheinander aufgerufen werden.
:
Bearbeitet durch User
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.