Kod: Zaznacz cały
#include "stm32f10x.h"
int main(void)
{
RCC->APB2ENR = RCC_APB2ENR_IOPBEN;
RCC->APB2ENR |= RCC_APB2ENR_AFIOEN;
AFIO->MAPR |= AFIO_MAPR_SWJ_CFG_JTAGDISABLE;
GPIOB->CRL |= GPIO_CRL_MODE3;
GPIOB->CRL &= ~GPIO_CRL_CNF3_0;
GPIOB->CRL |= GPIO_CRL_MODE4;
GPIOB->CRL &= ~GPIO_CRL_CNF4_1;
GPIOB->CRL |= GPIO_CRL_MODE5;
GPIOB->CRL &= ~GPIO_CRL_CNF5_0;
while(1)
{
GPIOB->ODR |= GPIO_ODR_ODR3;
GPIOB->ODR |= GPIO_ODR_ODR4;
GPIOB->ODR |= GPIO_ODR_ODR5;
GPIOB->ODR &= ~GPIO_ODR_ODR3;
GPIOB->ODR &= ~GPIO_ODR_ODR4;
GPIOB->ODR &= ~GPIO_ODR_ODR5;
}
}
Kod nie robi nic szczególnego. Ot, macha pinami PB3, PB4, PB5, całkowicie bez opóźnień. Ustawienia zegara dla całego systemu są domyślne jak dla gołej płytki Nucleo.
Taka postać kodu da nam następujący przebieg. Kanał 1, czerwony to PB3, a kanał 2, żółty to PB4.
Jak widać oscyloskop zmierzył częstotliwość ~655kHz, co jest dość małą wartością jak na szybkie przecież procesory z rdzeniem ARM. Widać też, że sygnały są przesunięte względem siebie, bo modyfikujemy je kolejno. Zmieńmy zatem nieco kod by wyeliminować przesunięcia i zobaczymy jak taka zmiana wpłynie na przebiegi.
Kod: Zaznacz cały
GPIOB->ODR |= (GPIO_ODR_ODR3 | GPIO_ODR_ODR4 | GPIO_ODR_ODR5);
GPIOB->ODR &= ~(GPIO_ODR_ODR3 | GPIO_ODR_ODR4 | GPIO_ODR_ODR5);
Sterując piny w tym samym czasie pozbyliśmy się przesunięcia, a i uzyskana częstotliwość uległa znacznemu zwiększeniu.
Teraz oscyloskop zmierzył już ~1,67MHz. To więcej niż 2 krotny przyrost. Czy można z takiego programu wycisnąć więcej? Skorzystajmy z innego podejścia do zmianach w porcie. Dalej będzie to programowa zmiana, ale tym razem wykorzystamy szybkie zerowanie i ustawianie bitów za pomocą rejestru BSRR.
Kod: Zaznacz cały
GPIOB->BSRR |= (GPIO_BSRR_BS3 | GPIO_BSRR_BS4 | GPIO_BSRR_BS5);
GPIOB->BSRR |= (GPIO_BSRR_BR3 | GPIO_BSRR_BR4 | GPIO_BSRR_BR5);
Pomiar nie wykazuje kolejnego przyśpieszenia operacji. Coś jest nie tak...
No tak! Popełniliśmy niezłą gafę. Przecież przy rejestrze BSRR nie musimy wykonywać operacji read-modify-write jaką wymusi operacja OR na rejestrze. Od tego jest ten rejestr by dostęp do niego był szybki, a zmiany za jego pomocą były realizowane równie szybko. Zmieńmy zatem to migiem na bardziej poprawną wersję.
Kod: Zaznacz cały
GPIOB->BSRR = (GPIO_BSRR_BS3 | GPIO_BSRR_BS4 | GPIO_BSRR_BS5);
GPIOB->BSRR = (GPIO_BSRR_BR3 | GPIO_BSRR_BR4 | GPIO_BSRR_BR5);
Teraz uzyskaliśmy już wynik ~2,88MHz. Jest to ponad 4 razy szybciej niż w kodzie pierwszym.
EDIT:
Okazuje się, że kod z wykorzystaniem jeszcze jednego rejestru "specjalnej troski", ale tylko do zerowania pozwala nam na uzyskanie dodatkowych kilkunastu kHz więcej.
Kod: Zaznacz cały
GPIOB->BSRR = (GPIO_BSRR_BS3 | GPIO_BSRR_BS4 | GPIO_BSRR_BS5);
GPIOB->BRR = (GPIO_BRR_BR3 | GPIO_BRR_BR4 | GPIO_BRR_BR5);
Wszystkie kody kompilowane z brakiem optymalizacji i jako Release. Znalazłem współpracujący Pendrive więc nowe kompilacje i nowe zrzuty.