Hallo, ich probiere schon länger mein 32STMF4 Discovery board zu zu bewegen das Mikrofonsignal(MP45DT02) auf den Kopfhörerausgang(CS43L22) durch zu schieben, und zwischen durch DSP zu machen. Nach anfänglichen versuchen die STM32Cube Beispiele nach gcc zu portieren und um zu bauen, bekam ich code von jemanden der genau dies gemacht hat um einen audio codec aus zu probieren. Ich habe nur die Quellen bekommen, keine Makefiles oder Linkerscripte. Ich kann mittlerweile alles mit arm-none-eabi-gcc und meinen Makefiles compilieren, und das DMA und IRQ handlich scheint auch richtig implementiert zu sein, jedoch läuft es auf dem board nicht. immerhin lief es mal, und das Board ist für genau dieses Aufgabe gebaut worden. Frage: hat jemand das am laufen ? Anbei die Quellen.
:
Bearbeitet durch User
Ich schlag mich jetzt schon eine ganze Weile mit dem CS43L22 rum, allerdings nicht mit dem Onboard Mikro, das kann ich für mein Projekt (4-Spur Multitracker Retrofit) nicht brauchen. Aber es lohnt sich, das ganze schrittweise anzugehen, das fängt mit dem richtigen Clocksetup an. Ich wühle mich nicht durch dein TAR.GZ, aber es ist wichtig, die I2S Clock erneut einzustellen, da sie von vielen Startup Codes falsch oder gar nicht gesetzt wird, und man sollte das Setup dann auch überprüfen. Man beachte auch die STM Fussnote, die Clock für I2S auf 2 Mhz statt auf 1 MHz zu setzen, da das Jittern so weniger wird. Ausserdem enthält der I2C Startup Code für den Cirrus Chip einige undokumentierte Sequenzen, ohne die es nicht geht. Der Chip sollte vor allem auch resetted werden. Ohne eine serielle Konsole wäre ich dem Mist übrigens nicht auf die Spur gekommen, bau dir sowas am besten mit ein. Uwe B. hat das meiste des CS43 Setup in seinem Code schon drin, hier ein Auszug:
1 | /* now lets init the Cirrus I2S DAC */
|
2 | /* first the I2C setup */
|
3 | uint16_t MS_Init_CS42L22(void) { |
4 | uint16_t error = 0; |
5 | GPIO_SetBits(DRIVE_GPIO_PORT,CS43_RST_PIN); |
6 | Delay(50); // lets settle the chip |
7 | error = I2C_WriteByte(CODEC_I2C_ADRESS,0x02, 0x01); // power off |
8 | if (error) return error; |
9 | error = I2C_WriteByte(CODEC_I2C_ADRESS,0x00, 0x99); // init sequence by datasheet |
10 | if (error) return error; |
11 | error = I2C_WriteByte(CODEC_I2C_ADRESS,0x47, 0x80); // undocumented registers |
12 | if (error) return error; |
13 | error = I2C_WriteByte(CODEC_I2C_ADRESS,0x32, 0xBB); // have to be written |
14 | if (error) return error; |
15 | error = I2C_WriteByte(CODEC_I2C_ADRESS,0x32, 0x3B); // |
16 | if (error) return error; |
17 | error = I2C_WriteByte(CODEC_I2C_ADRESS,0x00, 0x00); // register 0 is not in the datasheet |
18 | if (error) return error; |
19 | return 0; |
20 | }
|
Sodann geht es weiter mit dem normalen dokumentierten I2C Setup, das ich hier jetzt nicht schreibe, siehe dazu das Datenblatt des Cirrus. Ok, spätestens jetzt muss die I2S Clock konfiguriert werden:
1 | void I2S_PLL_Config(uint16_t N,uint16_t R) { |
2 | // Set PLL Clock for I2S
|
3 | RCC_PLLI2SCmd(DISABLE); |
4 | RCC_I2SCLKConfig(RCC_I2S2CLKSource_PLLI2S); |
5 | // RCC->CFGR &= ~RCC_CFGR_I2SSRC;
|
6 | /* Configure PLLI2S */
|
7 | RCC_PLLI2SConfig(N,R); |
8 | /* Enable PLLI2S */
|
9 | RCC_PLLI2SCmd(ENABLE); |
10 | /* Wait till PLLI2S is ready */
|
11 | while (RCC_GetFlagStatus(RCC_FLAG_PLLI2SRDY)==RESET){}; |
12 | // BlinkLED(1);
|
13 | }
|
Das hat mich beinahe wahnsinnig gemacht. Alle Leute behaupteten, das hier PLL_N = 271 und PLL_R = 2 sein sollten - weit daneben bei mir. Für meine gewünschte Samplerate von 48kHz waren
1 | uint16_t PLL_N = 129,PLL_R = 3; |
Man muss dazu sagen, das ich alle I2S Geräte als Slaves mit Masterclock vom STM32F4 betreibe. So, als nächstes stellte sich heraus, das die Init Funktion von CMSIS 'vergass', das M_CLK Output Bit zu setzen, also:
1 | #define I2SDIV 0x0103;
|
2 | /* now set the parameters for the I2S Interface itself */
|
3 | I2S_StructInit(&I2S_InitStructure); |
4 | I2S_InitStructure.I2S_Mode = I2S_Mode_MasterTx; |
5 | I2S_InitStructure.I2S_Standard = I2S_STANDARD; |
6 | I2S_InitStructure.I2S_MCLKOutput = ENABLE; |
7 | I2S_InitStructure.I2S_AudioFreq = I2S_AudioFreq_48k; |
8 | I2S_InitStructure.I2S_DataFormat = I2S_DataFormat_16b; |
9 | I2S_InitStructure.I2S_CPOL = I2S_CPOL_Low; |
10 | I2S_Init(SPI3,&I2S_InitStructure); |
11 | // set the MCLK Output enable bit and prescaler, cause the initfunction is bugged
|
12 | SPI3->I2SPR = I2S_MCLKOutput_Enable | I2SDIV; |
Nach den ganzen Problemen hatte ich erstmal gründlich die Lust verloren und habe nur noch den TX Empty Interrupt fürs SPI3 konfiguriert konfiguriert, um Samples aus dem Speicher zu spielen, damit wenigstens erstmal was zu hören ist. Wenn ich wieder Bock habe, geht es an die DMA.
1 | // Configure the I2S Tx empty IRQ
|
2 | NVIC_InitStructure.NVIC_IRQChannel = SPI3_IRQn; |
3 | NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x0a; |
4 | NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; |
5 | NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; |
6 | NVIC_Init(&NVIC_InitStructure); |
7 | SPI_I2S_ITConfig(SPI3, SPI_I2S_IT_TXE,ENABLE); |
8 | I2S_Cmd(SPI3,ENABLE); |
Ich benutze als ADC einen CS5331 auf I2S2, der so gut wie keinen Setup braucht, sondern lediglich eine Masterclock. Die 12 bitter des STM32 klingen nicht so schlecht, haben aber Störgeräusche drauf, was mich nicht wundert bei dem kleinen Die des STM32. Als Test habe ich in ein externes include eine 48 Byte lange Sinustabelle mit 16 bit Tiefe gepackt, die mir der Cirrus abspielt, so bin ich dem Samplerate Kram auf die Spur gekommen. Im Moment spielt er nun 2 Buffer für Kanal 1 und Kanal 2, die per ISR vom CS5331 ADC gefüllt werden - ein 2 Kanal Echogerät, wenn man so will. Mit dem Mikro musst du dich jetzt selber rumschlagen :-P
:
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.