Forum: Mikrocontroller und Digitale Elektronik STM32F1: Clock und PortClock Settings


von DraconiX (Gast)


Lesenswert?

Ich bin gerade ein bissle am Rätselraten... und zwar initialisiere ich 
den µC mit folgenden Clocks:
1
 
2
void SystemInit(void)
3
{
4
    // 64Mhz using the HSI oscillator divided by 2 with 16x PLL, lowspeed I/O runs at 32Mhz
5
    WRITE_REG(RCC->CFGR,RCC_CFGR_PLLMULL16 + RCC_CFGR_PPRE1_DIV2);
6
    // Flash latency 2 wait states
7
    MODIFY_REG(FLASH->ACR, FLASH_ACR_LATENCY, FLASH_ACR_LATENCY_1);
8
    // Enable PLL
9
    SET_BIT(RCC->CR, RCC_CR_PLLON);
10
    // Wait until PLL is ready
11
    while(!READ_BIT(RCC->CR, RCC_CR_PLLRDY)) {}
12
    // Select PLL as clock source
13
    MODIFY_REG(RCC->CFGR, RCC_CFGR_SW, RCC_CFGR_SW_PLL);
14
}

Den Portpin PORTA5 (LED) wie folgt:
1
int SetPinA5()
2
{
3
  //CFN5 Output Push/Pull
4
  *(volatile uint32_t *)0x40010800 &= ~(1<<22);
5
  
6
  //MODE5 Output 50Mhz (max 32Mhz) 
7
  *(volatile uint32_t *)0x40010800 |= (1<<20);
8
  *(volatile uint32_t *)0x40010800 |= (1<<21);
9
10
  return 0;
11
}


Nun zu folgendem Problem, wenn ich nun einen Pin toggeln lasse in meiner 
Main() komme ich nur auf 2Mhz, so ziemlich ganz genau - ganz egal was in 
GPIOA_CRL steht.
1
int main(void)
2
{
3
    SET_BIT(RCC->APB2ENR, RCC_APB2ENR_IOPAEN);
4
    SetPinA5();
5
6
    while(1)
7
    {
8
      GPIOA->ODR ^= SPIN5;
9
    }
10
}


Setze ich den Takt weiter runter, Standard 8Mhz, macht sich dies 
natürlich auf dem Portpin bemerkbar und er toggelt mit 335khz.

Kann mir einer sagen warum dies so ist? Selbst meine Mega32U4 Pins haben 
da schneller getoggelt bei 16Mhz.

von Kanack (Gast)


Lesenswert?

Es gibt schon genug andere, die sich darüber ausgetobt haben:
https://vjordan.info/log/fpga/stm32-bare-metal-start-up-and-real-bit-banging-speed.html

Wohlgemerkt die BRR und BSRR Register sind atomar.

Also versuche nochmals mit:
1
while(1)
2
    {
3
      GPIOA->BRR = SPIN5;
4
      GPIOA->BSRR = SPIN5;
5
      GPIOA->BRR = SPIN5;
6
      GPIOA->BSRR = SPIN5;
7
      GPIOA->BRR = SPIN5;
8
      GPIOA->BSRR = SPIN5;
9
    }

von Christopher J. (christopher_j23)


Lesenswert?

1. Du hast den prefetch-buffer für den Flash nicht aktiviert, d.h. bei 
zwei wait-states läuft dein Programm effektiv nur mit einem drittel des 
Systemtaktes.

2.
DraconiX schrieb:
> while(1)
>     {
>       GPIOA->ODR ^= SPIN5;
>     }

Schau dir doch einfach mal den generierten Assembler hierzu an. Die 
Veroderung von GPIO->ODR ist ein "read, modify, write" auf eine 
"volatile uint32_t. Da gehen schon paar Takte drauf und dazu kommt noch 
eine Instruktion wegen der Schleife. Per BSRR (Bit Set Reset Register) 
geht es schneller.

3.
DraconiX schrieb:
> //MODE5 Output 50Mhz (max 32Mhz)
>   *(volatile uint32_t *)0x40010800 |= (1<<20);

Die Angaben zum "Output Speed" beziehen sich eigentlich nur auf die 
Flankensteilheit (slew rate). Abgesehen davon ist
> *(volatile uint32_t *)0x40010800 |= (1<<20);
sehr unleserlich.

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.