Forum: Mikrocontroller und Digitale Elektronik [STM32F4] I2S macht nichts PLL-Clock-Problem?!


von Mampf F. (mampf) Benutzerseite


Lesenswert?

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

: Bearbeitet durch User
von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

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).

: Bearbeitet durch User
von Mampf F. (mampf) Benutzerseite


Lesenswert?

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! :)

: Bearbeitet durch User
von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

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).

von Mampf F. (mampf) Benutzerseite


Lesenswert?

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 :'(

von Mampf F. (mampf) Benutzerseite


Lesenswert?

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 ... :(

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

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.

von Mampf F. (mampf) Benutzerseite


Lesenswert?

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!

: Bearbeitet durch User
Beitrag #5055212 wurde vom Autor gelöscht.
von Mampf F. (mampf) Benutzerseite


Lesenswert?

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!

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

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.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.