Guten Morgen,
ich hab da ein sehr seltsames Problem ...
Ich war mit ST's HAL unzufrieden und erstellte ein neues Projekt, das
ohne HAL auskommt.
Funktioniert im Prinzip besser, aber mein I2S macht nichts und ich
glaube, es liegt an der Clock-Configuration (warum weiter unten).
Hier der Initialisierungs-Code für die I2S:
1 | // stm32f429
| 2 |
| 3 | RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI3, ENABLE);
| 4 | RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
| 5 | RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);
| 6 | RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
| 7 | RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOG, ENABLE);
| 8 |
| 9 | /*Configure GPIO Pin : PG13 */
| 10 | GPIO_InitStruct.GPIO_Pin = GPIO_Pin_13;
| 11 | GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;
| 12 | GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
| 13 | GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
| 14 | GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
| 15 | GPIO_Init(GPIOG, &GPIO_InitStruct);
| 16 |
| 17 | GPIO_ResetBits(GPIOG, GPIO_Pin_13); // unmute
| 18 |
| 19 | /**I2S3 GPIO Configuration
| 20 | PA4 ------> I2S3_WS
| 21 | PD6 ------> I2S3_SD
| 22 | PB3 ------> I2S3_CK
| 23 | */
| 24 |
| 25 | GPIO_PinAFConfig(GPIOB, GPIO_Pin_3, GPIO_AF_SPI3);
| 26 | GPIO_PinAFConfig(GPIOD, GPIO_Pin_6, 5);//GPIO_AF_SPI3);
| 27 | GPIO_PinAFConfig(GPIOA, GPIO_Pin_4, GPIO_AF_SPI3);
| 28 |
| 29 | GPIO_InitStruct.GPIO_Pin = GPIO_Pin_4;
| 30 | GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;
| 31 | GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
| 32 | GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
| 33 | GPIO_InitStruct.GPIO_Speed = GPIO_Speed_100MHz;
| 34 | GPIO_Init(GPIOA, &GPIO_InitStruct);
| 35 |
| 36 | GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6;
| 37 | GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;
| 38 | GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
| 39 | GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
| 40 | GPIO_InitStruct.GPIO_Speed = GPIO_Speed_100MHz;
| 41 | GPIO_Init(GPIOD, &GPIO_InitStruct);
| 42 |
| 43 | GPIO_InitStruct.GPIO_Pin = GPIO_Pin_3;
| 44 | GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;
| 45 | GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
| 46 | GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
| 47 | GPIO_InitStruct.GPIO_Speed = GPIO_Speed_100MHz;
| 48 | GPIO_Init(GPIOB, &GPIO_InitStruct);
| 49 |
| 50 |
| 51 | I2S_InitTypeDef I2S_InitStruct;
| 52 | I2S_StructInit(&I2S_InitStruct);
| 53 |
| 54 | // wird in SetSysClock in system_stm32f4xx.c gemacht
| 55 | // testweise auch hier mal probiert, ändern aber nichts
| 56 | // RCC_PLLI2SConfig(172, 2, 7);
| 57 | // RCC_I2SCLKConfig(RCC_I2S2CLKSource_PLLI2S);
| 58 | // RCC_PLLI2SCmd(ENABLE);
| 59 | // RCC_GetFlagStatus(RCC_FLAG_PLLI2SRDY);
| 60 |
| 61 | I2S_InitStruct.I2S_Mode = I2S_Mode_MasterTx;
| 62 | I2S_InitStruct.I2S_Standard = I2S_Standard_Phillips;
| 63 | I2S_InitStruct.I2S_DataFormat = I2S_DataFormat_16b; /*I2S_DataFormat_16b;*/
| 64 | I2S_InitStruct.I2S_MCLKOutput = I2S_MCLKOutput_Disable;
| 65 | I2S_InitStruct.I2S_AudioFreq = I2S_AudioFreq_11k;//I2S_AudioFreq_44k;
| 66 | I2S_InitStruct.I2S_CPOL = I2S_CPOL_Low;
| 67 | I2S_Init(SPI3, &I2S_InitStruct);
| 68 | I2S_Cmd(SPI3, ENABLE);
| 69 |
| 70 | for (int i = 0; i < DMASIZE; i++) {
| 71 | dmabuf[i] = (int16_t) ((rand() % 40000) - 20000);
| 72 | }
| 73 | for (;;) {
| 74 | for (int i = 0; i < DMASIZE; i++) {
| 75 | SPI_I2S_SendData(SPI3, dmabuf[i]);
| 76 | while (!(SPI3->SR & SPI_I2S_FLAG_TXE))
| 77 | ; // wait until transmit complete
| 78 | }
| 79 | }
|
Die Schleife, die ganz unten zufällige Daten über I2S rausschicken soll
läuft im Prinzip - aber nicht im HAL-freien Projekt.
Auf keinem der I2S-Pins sieht man irgendwelche Pegel-wechsel.
Zu dieser Zeile hier: 1 | GPIO_PinAFConfig(GPIOD, GPIO_Pin_6, 5);//GPIO_AF_SPI3);
|
HAL hatte den PD6 mit AF5 statt AF6 initialisiert, was im HAL-Projekt
auch funktioniert. Keine Ahnung weshalb und im Manual hatte ich nichts
dazu gefunden ... Hat jemand vlt eine Idee? Hab beides ausprobiert, geht
beides nicht.
Hier noch die Initialisierung meiner Clocks (1 zu 1 aus der
system_stm32f4xx.c aus einem ST-CMSIS-Example-Code für I2S):
1 | // 168MHz HCLK, APB1 48MHz, APB2 96MHz
| 2 | #define PLL_M 4
| 3 | #define PLL_N 168
| 4 | #define PLL_P 2
| 5 | #define PLL_Q 7
| 6 |
| 7 | // 49,142MHz I2S
| 8 | #define PLLI2S_N 172
| 9 | #define PLLI2S_R 7
| 10 |
| 11 | static void SetSysClock(void)
| 12 | {
| 13 | /******************************************************************************/
| 14 | /* PLL (clocked by HSE) used as System clock source */
| 15 | /******************************************************************************/
| 16 | __IO uint32_t StartUpCounter = 0, HSEStatus = 0;
| 17 |
| 18 | /* Enable HSE */
| 19 | RCC->CR |= ((uint32_t)RCC_CR_HSEON);
| 20 |
| 21 | /* Wait till HSE is ready and if Time out is reached exit */
| 22 | do
| 23 | {
| 24 | HSEStatus = RCC->CR & RCC_CR_HSERDY;
| 25 | StartUpCounter++;
| 26 | } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
| 27 |
| 28 | if ((RCC->CR & RCC_CR_HSERDY) != RESET)
| 29 | {
| 30 | HSEStatus = (uint32_t)0x01;
| 31 | }
| 32 | else
| 33 | {
| 34 | HSEStatus = (uint32_t)0x00;
| 35 | }
| 36 |
| 37 | if (HSEStatus == (uint32_t)0x01)
| 38 | {
| 39 | /* Select regulator voltage output Scale 1 mode */
| 40 | RCC->APB1ENR |= RCC_APB1ENR_PWREN;
| 41 | PWR->CR |= PWR_CR_VOS;
| 42 |
| 43 | /* HCLK = SYSCLK / 1*/
| 44 | RCC->CFGR |= RCC_CFGR_HPRE_DIV1;
| 45 |
| 46 | #if defined (STM32F40_41xxx) || defined (STM32F427_437xx) || defined (STM32F429_439xx)
| 47 | /* PCLK2 = HCLK / 2*/
| 48 | RCC->CFGR |= RCC_CFGR_PPRE2_DIV2;
| 49 |
| 50 | /* PCLK1 = HCLK / 4*/
| 51 | RCC->CFGR |= RCC_CFGR_PPRE1_DIV4;
| 52 | #endif /* STM32F40_41xxx || STM32F427_437x || STM32F429_439xx */
| 53 |
| 54 | #if defined (STM32F401xx)
| 55 | /* PCLK2 = HCLK / 2*/
| 56 | RCC->CFGR |= RCC_CFGR_PPRE2_DIV1;
| 57 |
| 58 | /* PCLK1 = HCLK / 4*/
| 59 | RCC->CFGR |= RCC_CFGR_PPRE1_DIV2;
| 60 | #endif /* STM32F401xx */
| 61 |
| 62 | /* Configure the main PLL */
| 63 | RCC->PLLCFGR = PLL_M | (PLL_N << 6) | (((PLL_P >> 1) -1) << 16) |
| 64 | (RCC_PLLCFGR_PLLSRC_HSE) | (PLL_Q << 24);
| 65 |
| 66 | /* Enable the main PLL */
| 67 | RCC->CR |= RCC_CR_PLLON;
| 68 |
| 69 | /* Wait till the main PLL is ready */
| 70 | while((RCC->CR & RCC_CR_PLLRDY) == 0)
| 71 | {
| 72 | }
| 73 |
| 74 | #if defined (STM32F427_437xx) || defined (STM32F429_439xx)
| 75 | /* Enable the Over-drive to extend the clock frequency to 180 Mhz */
| 76 | PWR->CR |= PWR_CR_ODEN;
| 77 | while((PWR->CSR & PWR_CSR_ODRDY) == 0)
| 78 | {
| 79 | }
| 80 | PWR->CR |= PWR_CR_ODSWEN;
| 81 | while((PWR->CSR & PWR_CSR_ODSWRDY) == 0)
| 82 | {
| 83 | }
| 84 | /* Configure Flash prefetch, Instruction cache, Data cache and wait state */
| 85 | FLASH->ACR = FLASH_ACR_PRFTEN | FLASH_ACR_ICEN |FLASH_ACR_DCEN |FLASH_ACR_LATENCY_5WS;
| 86 | #endif /* STM32F427_437x || STM32F429_439xx */
| 87 |
| 88 | #if defined (STM32F40_41xxx)
| 89 | /* Configure Flash prefetch, Instruction cache, Data cache and wait state */
| 90 | FLASH->ACR = FLASH_ACR_PRFTEN | FLASH_ACR_ICEN |FLASH_ACR_DCEN |FLASH_ACR_LATENCY_5WS;
| 91 | #endif /* STM32F40_41xxx */
| 92 |
| 93 | #if defined (STM32F401xx)
| 94 | /* Configure Flash prefetch, Instruction cache, Data cache and wait state */
| 95 | FLASH->ACR = FLASH_ACR_PRFTEN | FLASH_ACR_ICEN |FLASH_ACR_DCEN |FLASH_ACR_LATENCY_2WS;
| 96 | #endif /* STM32F401xx */
| 97 |
| 98 | /* Select the main PLL as system clock source */
| 99 | RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
| 100 | RCC->CFGR |= RCC_CFGR_SW_PLL;
| 101 |
| 102 | /* Wait till the main PLL is used as system clock source */
| 103 | while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS ) != RCC_CFGR_SWS_PLL);
| 104 | {
| 105 | }
| 106 | }
| 107 | else
| 108 | { /* If HSE fails to start-up, the application will have wrong clock
| 109 | configuration. User can add here some code to deal with this error */
| 110 | }
| 111 |
| 112 | /******************************************************************************/
| 113 | /* I2S clock configuration */
| 114 | /******************************************************************************/
| 115 | /* PLLI2S clock used as I2S clock source */
| 116 | RCC->CFGR &= ~RCC_CFGR_I2SSRC;
| 117 |
| 118 | /* Configure PLLI2S */
| 119 | RCC->PLLI2SCFGR = (PLLI2S_N << 6) | (PLLI2S_R << 28);
| 120 |
| 121 | /* Enable PLLI2S */
| 122 | RCC->CR |= ((uint32_t)RCC_CR_PLLI2SON);
| 123 |
| 124 | /* Wait till PLLI2S is ready */
| 125 | while((RCC->CR & RCC_CR_PLLI2SRDY) == 0)
| 126 | {
| 127 | }
| 128 |
| 129 | }
|
Ganz unten wird die I2SPLL initialisiert.
Das sollte eigentlich passen, aber aus meinem I2S kommt nichts...
Wenn ich in einem funktionierenden HAL-Projekt die Clock-Configuration
durch die obige SetSysClock ersetze, dann funktioniert dort I2S auch
nicht mehr.
Muss wohl irgendwas mit dem Clock zu tun haben, hab es aber nicht
herausgefunden und nach einem Tag debugging bin ich mittlerweile völlig
ratlos.
VG
Mampf
Mampf F. schrieb:
> Muss wohl irgendwas mit dem Clock zu tun haben, hab es aber nicht
> herausgefunden und nach einem Tag debugging bin ich mittlerweile völlig
> ratlos.
Das hat mich beim STM32F407 (Dicovery Board) auch eine Weile
beschäftigt. Über die serielle habe ich mir dann die Register ausgegeben
und festgestellt, das der I2S Prescaler nicht richtig gesetzt wurde.
Mein Projekt nutzt allerdings 48kHz Samplefrequenz, deswegen sieht das
hier etwas anders aus: 1 | #define I2SDIV 0x0103;
| 2 | // init the Pins for I2S Alternate Function
| 3 | //...
| 4 |
| 5 | /* now set the parameters for the I2S Interface itself */
| 6 | I2S_StructInit(&I2S_InitStructure);
| 7 | I2S_InitStructure.I2S_Mode = I2S_Mode_MasterTx;
| 8 | I2S_InitStructure.I2S_Standard = I2S_Standard_Phillips;
| 9 | I2S_InitStructure.I2S_MCLKOutput = ENABLE;
| 10 | I2S_InitStructure.I2S_AudioFreq = I2S_AudioFreq_48k;
| 11 | I2S_InitStructure.I2S_DataFormat = I2S_DataFormat_16b;
| 12 | I2S_InitStructure.I2S_CPOL = I2S_CPOL_Low;
| 13 | I2S_Init(SPI3,&I2S_InitStructure);
| 14 | // set the MCLK Output enable bit and prescaler , cause the initfunction is bugged
| 15 | SPI3->I2SPR = I2S_MCLKOutput_Enable | I2SDIV;
| 16 | // Configure the I2S Tx empty IRQ
| 17 | // ...
|
Wenn du keine Masterclock brauchst, setzt du stattdessen nur den
Teilerwert ein ohne das gesetzte 'I2S_MCLKOutput_Enable' Bit.
Bei mir hat es sich bewährt, nach jedem Init irgendeiner Funktion einen
Ausgang blinken zu lassen (das Disco Board hat ja genug LEDs).
Matthias S. schrieb:
> Über die serielle habe ich mir dann die Register ausgegeben
> und festgestellt, das der I2S Prescaler nicht richtig gesetzt wurde.
Puh, hört sich auch nach viel Debugging-Freude an :)
Vielen Dank, ich geh gleich mal nachforschen, vlt hilft das bei mir
auch! :)
Mampf F. schrieb:
> Matthias S. schrieb:
>> Über die serielle habe ich mir dann die Register ausgegeben
>> und festgestellt, das der I2S Prescaler nicht richtig gesetzt wurde.
>
> Puh, hört sich auch nach viel Debugging-Freude an :)
>
> Hmm, das ist eigentlich seltsam ... Die I2S-Init-Routing liest die
> Clock-Prescaler der PLLI2S und errechnet daraus die Clock-Frequenz und
> ermittelt daraus die I2S-Interface-Einstellungen.
>
> Wenn die Prescaler vorher falsch waren, wär das I2S-Interface völlig
> falsch konfiguriert worden.
>
> Oder die Funktion macht den Prescaler selbst dann irgendwie kaputt.
>
> Ich muss gestehen, ich hab den PLL-Clock noch nicht nach einem I2S_Init
> durchgeführt, vlt wäre das des Rätsels Lösung gewesen.
>
> Danke schonmal!
Achso, noch eines, die I2SPLL sollte unbedingt konfiguriert werden,
nicht auf System Init verlassen: 1 | uint16_t PLL_N = 129,PLL_R = 3;
| 2 | void I2S_PLL_Config(uint16_t N,uint16_t R) {
| 3 | // Set PLL Clock for I2S
| 4 | RCC_PLLI2SCmd(DISABLE);
| 5 | RCC_I2SCLKConfig(RCC_I2S2CLKSource_PLLI2S);
| 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 | }
|
und du solltest darauf warten, das sie soweit ist (letzte Zeile).
Matthias S. schrieb:
> Achso, noch eines, die I2SPLL sollte unbedingt konfiguriert werden,
> nicht auf System Init verlassen
Vielen Dank, probier ich aus! :)
Kann leider erst morgen Bescheid geben, ob es was gebracht hat ...
Bastelkram in der Arbeit :'(
Jetzt hab ich es mal getestet ... es passiert trommelwirbel nichts :(
Keinen Mux gibt das I2S von sich ... Ich glaube, ich werde mir jetzt mal
funktionierende Beispiele suchen ...
Unglaublich, dass das Ding so rumzickt ... :(
Mampf F. schrieb:
> Keinen Mux gibt das I2S von sich ... Ich glaube, ich werde mir jetzt mal
> funktionierende Beispiele suchen ...
Ich habe zum Testen auch erstmal auf DMA verzichtet und lade SPI3->DR
per ISR für die Ausgabe bzw. hole mir von SPI2-DR per ISR den Input (das
Dings hier soll einen 4-Kanal Multitrack Recorder ersetzen). Das ist
schon eine Weile her, ich weiss aber, das ich mit dem Krams auch ganz
schön gekämpft habe.
Du wirst meinen Code nicht 1zu1 übernehmen können, weil hier alles auf
48kHz mit Masterclock konfiguriert ist, aber bei Interesse poste ichs
gerne mal.
Ohne die serielle Ausgabe fürs Debuggen wäre ich aber vermutlich nicht
drauf gekommen.
Den Stereo Ausgang macht bei mir der CS43L22 Chip auf dem Disco Board,
der ADC am Eingang ist ein CS5341.
Ich hab mich jetzt von dir inspirieren lassen und hab mir mal alle
Register von GPIOA-H, RCC und SPI3 quasi dumpen lassen ...
Das sieht dann so aus:
1 | *((uint32_t*) 0x40020000)=0xa8000200;
| 2 | *((uint32_t*) 0x40020004)=0x00000000;
| 3 | *((uint32_t*) 0x40020008)=0x0c000000;
| 4 | *((uint32_t*) 0x4002000c)=0x64000000;
| 5 | *((uint32_t*) 0x40020010)=0x0000f7df;
| 6 | *((uint32_t*) 0x40020014)=0x00000000;
| 7 | *((uint32_t*) 0x40020018)=0x00000000;
| 8 | <snip>
| 9 | *((uint32_t*) 0x4002387c)=0x00000000;
| 10 | *((uint32_t*) 0x40023880)=0x00000000;
| 11 | *((uint32_t*) 0x40023884)=0x70002b00;
|
Und tatsächlich ... Mit dem zusätzlichen Code funktioniert es auch.
Jetzt kommentier ich Stück für Stück aus, bis das I2S nicht mehr
funktioniert, dann müsste ich wissen, woran es liegt :)
WTF Das setzen der AFs hat nichts gemacht ...
u.A. GPIO_PinAFConfig(GPIOA, GPIO_Pin_4, GPIO_AF_SPI3);
Hmm, das ist ja oberseltsam!
Beitrag #5055212 wurde von einem Moderator gelöscht.
Ohmann, diese P****r!
GPIO_Pin_4 ist falsch bei GPIO_PinAFConfig ... Die GPIO_Pin_Teile sind
Bitmuster und die Funktion erwartet eine Pin-Nummer.
Den Designer der Library müsste man verprügeln, ganz ehrlich!
Mampf F. schrieb:
> GPIO_Pin_4 ist falsch bei GPIO_PinAFConfig
Ach, entschuldige, das hätte ich sehen müssen :-O Ja, man muss
stattdessen dann immer 'GPIO_PinSourceNN' übergeben.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
|