Forum: Mikrocontroller und Digitale Elektronik STM32F103RBT6 Pin toggeln


von bluebird (Gast)


Lesenswert?

Schönen Nachmittag liebes Forum,

bin seit kurzem Besitzer eines ST Nucleo Board mit einem STM32F103RBT6 
drauf. Bin im Moment dabei mich mit der Materie vertraut zu machen und 
habe dazu auf den maximal möglichen Systemtakt umgestellt (64 MHz mit 
HSI--> internal Highspeed signal). Das hab ich dann auch mit dem MCO-Pin 
--> Clock Output kontrolliert und konnte die 64 MHz feststellen.
Jetzt wollt ich gucken wie schnell ich einen Pin toggeln kann, doch 
leider findet kein Wechsel 0-->1 bzw. 1-->0 statt, was jedoch vor den 
Takteinstellungen funktioniert hat. :C

Hier der Code...
1
#include "stm32f10x.h"
2
#include "stm32f10x_gpio.h"
3
#include "stm32f10x_rcc.h"
4
5
int main(void)
6
{
7
  RCC_DeInit();
8
  RCC_PLLCmd(DISABLE);
9
  RCC_PLLConfig(RCC_PLLSource_HSI_Div2,RCC_PLLMul_16);  //(HSI_CLK /2)* 16
10
  RCC_PLLCmd(ENABLE);
11
  RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
12
13
  RCC_HCLKConfig(RCC_SYSCLK_Div1);
14
  RCC_PCLK1Config(RCC_HCLK_Div2);
15
  RCC_PCLK2Config(RCC_HCLK_Div1);
16
17
  GPIO_InitTypeDef  GPIO_InitStructure;
18
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
19
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
20
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
21
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
22
  GPIO_Init(GPIOC, &GPIO_InitStructure);
23
24
    while(1)
25
    {
26
      GPIOC->BRR = GPIO_Pin_9;
27
      GPIOC->BSRR = GPIO_Pin_9;
28
    }
29
}

... und meine Frage an was dies liegen könnte.
Vielen Dank schon mal im voraus.

von W.S. (Gast)


Lesenswert?

bluebird schrieb:
> ... und meine Frage an was dies liegen könnte.

Zuerst an der verwendeten ST-Lib und dann an dir, nämlich daß du diese 
überhaupt verwendest, und dann nochmal an dir, daß du selbige 
verwendest, OHNE all dem, was da abgeht (oder eben nicht abgeht), mal 
gründlich nachzusteigen.

Ich poste dir hier mal nen Ausschnitt aus einem älteren 
STM32F103-Projekt:
{c]
void Do_Config (void)
{ long L;

  RCC->CIR      = 0;           /* alle RCC-Interrupts ausschalten */
  RCC->APB1RSTR = 0;           /* evtl. Reset's beseitigen */
  RCC->APB2RSTR = 0;
  FLASH->ACR  = (1<<4);        /* Flash-Prefetch-Buffer einschalten */
  RCC->CFGR   = (5<<24);       /* MCO=HSI, sonst nix.. erstmal */
  RCC->AHBENR = 0xFFFF;        /*  */
  RCC->APB2ENR = 0xFFFFFFFF;
  RCC->APB2ENR = 0xFFFF;

  GPIOG->CRL = wf_GPIOG_CRL;
  GPIOG->CRH = wf_GPIOG_CRH;

  GPIOG->ODR &= ~(1<<6);
  L = 10000; while (--L);


/* zuerst Takterzeugung aufsetzen.
     nach einem Hardware-Reset sind folgende Bits gesetzt:
     in RCC_CR     = HSIRDY, HSION, HSITRIM = 8
     in RCC_AHBENR = FLITFEN, SRAMEN
     in RCC_CSR    = PORRSTF, PINRSTF
     Vorsicht: nach irgendwelchen Software-Resets muß das nicht so sein!
 */
  RCC->CR    =  (8<<2)|1;          /* Umschalten auf HSI = interne 8 MHz 
*/
  while ((RCC->CR & 2)==0);        /* warten auf HSIRDY (wird von 
Hardware gesetzt) */


  /* so, jetzt ist RCC im Urzustand wie nach einem Hardware-Reset */

  RCC->CR |= (1<<16);       /* externen 6 MHz Oszillator HSE einschalten 
*/
  L = 5000;
  while (L)
  { --L; if (RCC->CR & (1<<17)) goto _hse_rdy; }         /* wenn ext. 
Oszi ready */
  _hse_rdy:


  if (L)                          /* wenn wir nicht vergeblich auf HSE 
gewartet haben.. */
  {  FLASH->ACR  = (1<<4)|2;      /* Prefetch-Buffer + 2 Waits bei 72 
MHz  */
     RCC->CFGR   = (7<<24)|       /* MCO=1/2PLL */
                   (0<<22)|       /* UsbClk=PLL/1.5 */
                   (10<<18)|      /* PLL = 12*HSE (6*12=72) */
                   (1<<16)|       /* PllSource=HSE */
                   (3<<14)|       /* AdcTakt=PCLK2/8 */
                   (4<<11)|       /* APB2=Hclk/2=36MHz */
                   (4<<8);        /* APB1=Hclk/2=36MHz */

     RCC->CR    |= (1<<24);       /* PLL einschalten */

     while ((RCC->CR & (1<<25))==0);           /* warten auf PLLRDY */
     RCC->CFGR  = (RCC->CFGR & 0xFFFFFFFC)|2;  /* PLL als Taktquelle 
wählen */
     do { L = RCC->CFGR & (3<<2);
        } while (L!= (2<<2));               /* warten bis PLL=Taktquelle 
*/
  }

  RCC->AHBENR = wf_AHBENR;    /* AHB enables  */
  RCC->APB1ENR = wf_APB1ENR;  /* APB1 enables */
  RCC->APB2ENR = wf_APB2ENR;  /* APB2 enables */


  Backup-Domain enables:
    sind nach Reset erstmal schreibgeschützt. Entsperren mit PWR->CR 
(1<<8) auf hi  */
  if ((RCC->BDCR & 2)==0)          /* wenn 32kHz Oszi nicht ready ist */
  { PWR->CR |= (1<<8);
    RCC->BDCR = (1<<16)|(1<<15)|1; /* RTC Reset, enable, 32kHz on */
    RCC->BDCR = (1<<15)|(1<<8)|1;  /* RTC enable, LSE als Quelle, 32kHz 
on
  }


/*  Pin-Funktionen aufsetzen */
 GPIOA->CRL = wf_GPIOA_CRL;
 GPIOA->CRH = wf_GPIOA_CRH;

 GPIOB->CRL = wf_GPIOB_CRL;
 GPIOB->CRH = wf_GPIOB_CRH;

 GPIOC->CRL = wf_GPIOC_CRL;
 GPIOC->CRH = wf_GPIOC_CRH;

 GPIOD->CRL = wf_GPIOD_CRL;
 GPIOD->CRH = wf_GPIOD_CRH;

 GPIOE->CRL = wf_GPIOE_CRL;
 GPIOE->CRH = wf_GPIOE_CRH;

 GPIOF->CRL = wf_GPIOF_CRL;
 GPIOF->CRH = wf_GPIOF_CRH;

 GPIOG->CRL = wf_GPIOG_CRL;
 GPIOG->CRH = wf_GPIOG_CRH;

/* Pin-Remap */
 AFIO->MAPR = wf_AFIO_MAPR;
[/c]

Ist nicht zum blinden Kopieren gedacht, sondern um mal zu sehen, wie 
ich vor 4..5 Jahren daran gegangen bin. Meine Nicht-ungarische Notation 
ist ganz einfach: wf_Register meint "Wert für Register" und ist woanders 
definiert. Beispiel:
1
#define wf_APB2ENR  (en2_AFIO) | (en2_IOPA<<2) | (en2_IOPB<<3) | (en2_IOPC<<4) | (en2_IOPD<<5) | (en2_IOPE<<6) | (en2_IOPF<<7) | (en2_IOPG<<8) | \
2
        (en2_ADC1<<9) | (en2_ADC2<<10) | (en2_TIM1<<11) | (en2_SPI1<<12) | (en2_TIM8<<13) | (en2_USART1<<14) | (en2_ADC3<<15)
(mal sehen, ob das hier so kommt wie in der Quelle...)
Natürlich kann man das auch anders machen, also streng dich mal an und 
lies das RefMan.

W.S.

von bluebird (Gast)


Lesenswert?

So vielen Dank W.S. für deine ausführliche Antwort. Ich hab des ganze 
jetzt selbst mal über die Registerebene gemacht (war zum Zeitpunkt 
deiner Antwort schon dabei das RM zu studieren) und muss sagen, dass es 
nicht an der ST-Lib oder ähnlichen Library Problemen gelegen hat. Denn 
ab einer bestimmten SYSCLK Frequenz (bei mir ab 56 MHz = HSI/2 * 14) hat 
der µC scheinbar keine Lust mehr den Pin Zustand zu wechseln.
Das resultiert bei mir in einer bis jetzt max. Togglefrequenz von 
4,7MHz, wobei ich im DB gelesen habe, dass diese bis zu 18MHz betragen 
kann.

von Markus S. (acepilot)


Lesenswert?

Ist jetzt nur mal ein Schuss ins Blaue, aber ließ dir mal in dem RM die 
Seite 57 durch, ab dem letzten dritte. Ab einer bestimmtem Clockfrequenz 
muss für den Flashspeicher noch eine Wartezeit eingestellt werden. 
Soweit ich informiert bin kann das schon zu solchen Verhalten führen.

Das Eval Board hat doch bestimmt auch einen externen Quartz drauf, 
funktioniert es mit dem, natürlich auch dort unter berücksichtigung der 
Waitstates für den flash.

von W.S. (Gast)


Lesenswert?

Zwei Dinge:
1.
 FLASH->ACR  = (1<<4)|2;      /* Prefetch-Buffer + 2 Waits
Du solltest das gepostete verstehen. Ab einer bestimmten Clockfrequenz 
sind mehrere Waitstates erforderlich.

2.
Schau dir an, welche Portadressen du benutzt. Ich hab jetzt das 
betreffende RefMan nicht auswendig gelernt, aber bei vielen Typen gibt 
es neben den klassischen Portzugängen GPIOx auch schnellere Zugänge, die 
beginnen dann mit FGPIO... oder so ähnlich - obendrein gucke nach, 
welchen Takt du für die GPIO's aufgesetzt hast. Oft ist das Fcpu/2 oder 
noch weniger.

W.S.

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.