Skocz do zawartości

[Kurs] Kurs programowania STM32 część 2 - pierwszy projekt


lukpep

Pomocna odpowiedź

Na początku - wielkie podziękowania za kurs - jest bardzo ciekawy - nie spotkałem niczego podobnego do tej pory.

Jak widzę kroczymy podobnymi ścieżkami - mam do Ciebie pytanie - czy w kursie dojdziesz do uruchomienia ethernetu i serwera www? Kiedy to nastąpi? 😉

Ja właśnie się z tym borykam - staram się robić to na podstawie książki "STM32 w sieci ethernet". Pracuję podobnie jak Ty w TrueStudio - utknąłem jednak na skompilowaniu lwIP do wspólnej biblioteki liblwip4.a - nie potrafię tego zrozumieć. Autor nie pokazuje dokładnie jak to zrobić.

Czy mógłbyś pokazać jak wygląda struktura katalogów z dodaną biblioteką (bazowałeś na lwIP?)? Ewentualnie co zmieniałeś w ustawieniach projektu? Po wrzuceniu "niby" wszystkich plików do projektu wywala mi błędy, że nie wie co to pbuf (tak jakby nie widział pliku nagłówkowego pbuf.h)

pozdrawiam,

Link do komentarza
Share on other sites

Jak widzę kroczymy podobnymi ścieżkami - mam do Ciebie pytanie - czy w kursie dojdziesz do uruchomienia ethernetu i serwera www? Kiedy to nastąpi?

Hmmm nie wiem 😉 w pracy mam goracy okres itp - aczkolwiek jest to tematem mojej pracy dyplomowej wiec jakos tam bujam sie z tym tematem 😉 Nastapi dodatkowe opoznienie - ale o tym za chwile.

utknąłem jednak na skompilowaniu lwIP do wspólnej biblioteki liblwip4.a - nie potrafię tego zrozumieć. Autor nie pokazuje dokładnie jak to zrobić.

nie ma takiej potrzeby - autor to robi po prostuzeby przyspieszyc kompilacje plikow ktorych potem w sumie juz nie modyfikujesz. Mozesz korzystac normalnie z biblioteki nie kompilujac jej do pliku posredniego.

Owszem korzystam z lwIP. Biblioteke gdzies tam sobie wrzucilem i dodalem w ustawieniach projektu sciezke na ta lokalizacje wskazujaca. Troszke okrezna droga sie to robi poniewaz w wersji lite TS ma poblokowane sporo kontrolek w GUI np do dodawania stalych kompilacji itp - ale mozna do obejsc:

PROJECT->PROPERTIES (pojawi się okno)

C/C++ Genreal->Paths and Symbolis i tam sa zakładki

w których można coś dodawać.

A co do przyczyny opoznien to w zwiazku z trwajacym konkursem, do ktorego zachecal mnie Trecker nastepny odcinek kursu poswiecony zostanie robotyce - mam starego robota z kilkoma czujnikami (emitery IR, czujniki IR, transoptory odbiciowe, fototranzystory) mostkiem L298 i dwoma serwami przerobionymi na silniki DC. Oryginalnie chodzilo to na atmedze 8L ale calosc przepne na STMa (moze niezbyt estetycznie 😉 ) i pokaze w jakis sposob oprogramowac 🙂

Link do komentarza
Share on other sites

Witam

Czy ktoś mógłby rozwiać moje wątpliwości ? Mianowicie zastanawia mnie jedna rzecz. Mam skonfigurowane APB1 = 36MHz, APB2 = 72MHz. I chcę teraz użyć Timera 4 do odmierzania czasu (ile czasu rzeczywiście są wykonywane pewne funkcje czy tam fragmenty kodu). Z teorii wynika, że Timer 4 jest podpięty pod APB1 czyli jest taktowany z f=36MHz. Czyli jeśli mój timer zliczy mi powiedzmy do 3400 to będzie to wskazywało na ok 0,095 ms (licznik zlicza do 65535 i jest bez preskalera). I tyle też otrzymuję. Czy teraz mi ktoś może powiedzieć dlaczego jak użyję Timera 1 do tego samego pomiaru, to otrzymuję ten sam wynik (3400) ? Gdzie Timer 1 jest podpięty pod szynę APB2 taktowaną 72Mhz, czyli wynik powinien być 2x większy. W książce K.Paprockiego jest to pomieszane kompletnie. Poniżej configi Timera 4 i zegarów.

// Konfiguracja Timera 4
TIM_TimeBaseStructure.TIM_Period = 65535;	//65535+1
TIM_TimeBaseStructure.TIM_Prescaler = 0;	//fclk = 36MHz/2^0 = 36MHz
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //0
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure);

// Konfiguracja kanalu 1  Timera 4  - Mierzenie czasu do ok 2 ms
TIM_OCInitStructure2.TIM_OCMode = TIM_OCMode_Timing;
TIM_OCInitStructure2.TIM_OutputState = TIM_OutputState_Disable;
TIM_OCInitStructure2.TIM_Pulse = 65535; // t = 2^16/36MHz = 1,8204 ms
TIM_OCInitStructure2.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OC1Init(TIM4, &TIM_OCInitStructure2);
TIM_OC1PreloadConfig(TIM4, TIM_OCPreload_Disable);
if(HSEStartUpStatus == SUCCESS)
 {
   FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);

   // zwloka dla pamieci Flash
   FLASH_SetLatency(FLASH_Latency_2);

   // HCLK = SYSCLK
   RCC_HCLKConfig(RCC_SYSCLK_Div1); 

   // PCLK2 = HCLK
   RCC_PCLK2Config(RCC_HCLK_Div1); 

   // PCLK1 = HCLK/2
   RCC_PCLK1Config(RCC_HCLK_Div2);

   // ADCCLK = PCLK2/8 = 72/8 = 9 MHz
   RCC_ADCCLKConfig(RCC_PCLK2_Div8);

   // PLLCLK = 8MHz * 9 = 72 MHz
   RCC_PLLConfig(RCC_PLLSource_PREDIV1, RCC_PLLMul_9);

   // Wlacz PLL 
   RCC_PLLCmd(ENABLE);

   // Czekaj az PLL poprawnie sie uruchomi
   while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);

   // PLL bedzie zrodlem sygnalu zegarowego
   RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);

   // Czekaj az PLL bedzie sygnalem zegarowym systemu
   while(RCC_GetSYSCLKSource() != 0x08);

// Wlaczenie zegarow dla wszystkich uzywanych peryferi:
  	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC | RCC_APB2Periph_AFIO | RCC_APB2Periph_SPI1 | RCC_APB2Periph_USART1 | RCC_APB2Periph_TIM1 | RCC_APB2Periph_ADC1, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2 | RCC_APB1Periph_PWR | RCC_APB1Periph_BKP | RCC_APB1Periph_TIM2 | RCC_APB1Periph_TIM3 | RCC_APB1Periph_TIM4, ENABLE);
Link do komentarza
Share on other sites

Zobacz jak jest skonstruowany system zegarowy. Jeżeli taktujesz APB1 przez jakiś dzielnik, to automatycznie timery mają taktowanie pomnożone razy 2. Wiec twoje oba timery taktowane są f=72MHz.

Link do komentarza
Share on other sites

Zarejestruj się lub zaloguj, aby ukryć tę reklamę.
Zarejestruj się lub zaloguj, aby ukryć tę reklamę.

jlcpcb.jpg

jlcpcb.jpg

Produkcja i montaż PCB - wybierz sprawdzone PCBWay!
   • Darmowe płytki dla studentów i projektów non-profit
   • Tylko 5$ za 10 prototypów PCB w 24 godziny
   • Usługa projektowania PCB na zlecenie
   • Montaż PCB od 30$ + bezpłatna dostawa i szablony
   • Darmowe narzędzie do podglądu plików Gerber
Zobacz również » Film z fabryki PCBWay

Jako że jestem nowy na forum, witam wszystkich 😉

Bardzo fajny tutorial, przede wszystkim konkretnie wszystko przedstawione. Oby tak dalej, liczę na co najmniej kilka kolejnych części 😃 ARM-y stają się coraz bardziej popularne wśród amatorów, więc na pewno warto żeby taki kompleksowy poradnik był na forum.

Ale do rzeczy. W dokumentacji, tuż pod schematem zegarów, znalazłem zapis

When the HSI is used as a PLL clock input, the maximum system clock frequency that can be achieved is 64 MHz.

Dobrze rozumiem, że aby osiągnąć częstotliwość 72 MHz, trzeba skorzystać z HSE? Chcę być co do tego pewny. Testował to ktoś może?

Link do komentarza
Share on other sites

Cytat:

When the HSI is used as a PLL clock input, the maximum system clock frequency that can be achieved is 64 MHz.

Dobrze rozumiem, że aby osiągnąć częstotliwość 72 MHz, trzeba skorzystać z HSE? Chcę być co do tego pewny. Testował to ktoś może?

zgadza sie. To nawet wynika z ilustracji ktora wyzej wlepilem. HSI mozesz podac albo odrazu na SYSCLK (i masz zegar 8MHz) albo podzielone przez 2 wpuscic na petle PLL1. Max mnoznik petli PLL1 zalezy od rodziny prockow - dla CL (connectivity line - moj) i dla VL (value line - taniocha) wynosi 9 czyli wyciagnalbys 4*9 = max 36 MHz z HSI. W pozostalych rodzinach max mnoznik to 16 wiec wyciagniesz 4*16 = 64 MHz na SYSCLK z HSI.

  • Lubię! 1
Link do komentarza
Share on other sites

Udało mi się uruchomić stos lwIP - trochę z nim jeszcze walczę, ale mam inny problem dotyczącym działania portu szeregowego (sprawdzilem i wykluczam elektronikę). Korzystając z Twojej inicjacji zegarów:

  RCC_DeInit();
  // Wlacz HSE
  RCC_HSEConfig(RCC_HSE_ON);
  // Czekaj za HSE bedzie gotowy
  HSEStartUpStatus = RCC_WaitForHSEStartUp();
  if(HSEStartUpStatus == SUCCESS)
  {
        FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
        // zwloka dla pamieci Flash
        FLASH_SetLatency(FLASH_Latency_2);
        // HCLK = SYSCLK
        RCC_HCLKConfig(RCC_SYSCLK_Div1);
        // PCLK2 = HCLK
        RCC_PCLK2Config(RCC_HCLK_Div1);
        // PCLK1 = HCLK/2
        RCC_PCLK1Config(RCC_HCLK_Div2);
        // PLLCLK = 8MHz * 9 = 72 MHz
        RCC_PLLConfig(RCC_PLLSource_PREDIV1, RCC_PLLMul_9);
        // Wlacz PLL
        RCC_PLLCmd(ENABLE);
        // Czekaj az PLL poprawnie sie uruchomi
        while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);
        // PLL bedzie zrodlem sygnalu zegarowego
        RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
        // Czekaj az PLL bedzie sygnalem zegarowym systemu
        while(RCC_GetSYSCLKSource() != 0x08);
  }

Konfiguracja i wysyłanie danych:

void UART4_Configuration()
{
	USART_InitTypeDef USART_InitStructure;
	GPIO_InitTypeDef GPIO_InitStructure;

	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART4, ENABLE);

	GPIO_InitStructure.GPIO_Pin             = GPIO_Pin_10;
	GPIO_InitStructure.GPIO_Speed           = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode            = GPIO_Mode_AF_PP;
	GPIO_Init(GPIOC, &GPIO_InitStructure);

	GPIO_InitStructure.GPIO_Pin             = GPIO_Pin_11;
	GPIO_InitStructure.GPIO_Mode            = GPIO_Mode_IN_FLOATING;
	GPIO_Init(GPIOC, &GPIO_InitStructure);

	USART_InitStructure.USART_BaudRate      = 9600;
	USART_InitStructure.USART_WordLength    = USART_WordLength_8b;
	USART_InitStructure.USART_StopBits      = USART_StopBits_1;
	USART_InitStructure.USART_Parity        = USART_Parity_No;
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
	USART_InitStructure.USART_Mode          = USART_Mode_Rx | USART_Mode_Tx;

	USART_Init(UART4, &USART_InitStructure);
	USART_Cmd(UART4, ENABLE);
}
void UART4_PutChar(char value)
{
	USART_SendData(UART4, value);
	while(USART_GetFlagStatus(UART4, USART_FLAG_TXE) == RESET);
}
void UART4_PutString(char * s)
{
	while(*s)
		UART4_PutChar(*s++);
}

A wywołanie w funkcji main wygląda tak:

	  UART4_Configuration();
	  UART4_PutString("PORT4");

Ale nie dostaję "PORT4", tylko jakieś krzaczki.. Program na PC raczej dobry, bo na ZL30arm dane widzę dobrze.. Widzisz jakiś problem w kodzie?

Jeszcze próbuję przemapować port USART2 i zrobić to samo i wysłać dane z PD5, ale nie udaje mi się tego zrobić:

		GPIO_PinRemapConfig(GPIO_Remap_USART2, ENABLE);
		//LCDwrite("\nTest3 LCD");
		RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);

Inicjowanie portu:

	USART_InitTypeDef USART_InitStructure;
	GPIO_InitTypeDef GPIO_InitStructure;

	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD, ENABLE);
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);

	GPIO_InitStructure.GPIO_Pin             = GPIO_Pin_5;
	GPIO_InitStructure.GPIO_Speed           = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode            = GPIO_Mode_AF_PP;
	GPIO_Init(GPIOD, &GPIO_InitStructure);

	GPIO_InitStructure.GPIO_Pin             = GPIO_Pin_6;
	GPIO_InitStructure.GPIO_Mode            = GPIO_Mode_IN_FLOATING;
	GPIO_Init(GPIOD, &GPIO_InitStructure);

	USART_InitStructure.USART_BaudRate      = 9600;
	USART_InitStructure.USART_WordLength    = USART_WordLength_8b;
	USART_InitStructure.USART_StopBits      = USART_StopBits_1;
	USART_InitStructure.USART_Parity        = USART_Parity_No;
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
	USART_InitStructure.USART_Mode          = USART_Mode_Rx | USART_Mode_Tx;

	USART_Init(USART2, &USART_InitStructure);
	USART_Cmd(USART2, ENABLE);

Wysyłanie danych analogicznie jak wcześniej - efekt, żadnych danych na porcie.

Link do komentarza
Share on other sites

Rozpoczynam zabawę z armami. Posiadam stm32f103vct6 i do programowania używam CooCox ide. Mam pytanie co do fragmenu:

RCC_DeInit();

// Wlacz HSE

RCC_HSEConfig(RCC_HSE_ON);

// Czekaj za HSE bedzie gotowy

HSEStartUpStatus = RCC_WaitForHSEStartUp();

if(HSEStartUpStatus == SUCCESS)

{

FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);

// zwloka dla pamieci Flash

FLASH_SetLatency(FLASH_Latency_2);

// HCLK = SYSCLK

RCC_HCLKConfig(RCC_SYSCLK_Div1);

// PCLK2 = HCLK

RCC_PCLK2Config(RCC_HCLK_Div1);

// PCLK1 = HCLK/2

RCC_PCLK1Config(RCC_HCLK_Div2);

// PLLCLK = 8MHz * 9 = 72 MHz

RCC_PLLConfig(RCC_PLLSource_PREDIV1, RCC_PLLMul_9);

// Wlacz PLL

RCC_PLLCmd(ENABLE);

// Czekaj az PLL poprawnie sie uruchomi

while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);

// PLL bedzie zrodlem sygnalu zegarowego

RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);

// Czekaj az PLL bedzie sygnalem zegarowym systemu

while(RCC_GetSYSCLKSource() != 0x08);

}

}

Po skompilowaniu otrzymuję następujący błąd:

error: 'RCC_PLLSource_PREDIV1' undeclared (first use in this function)

Przejrzałem biblioteki i dla tego procesora RCC_PLLSource_PREDIV1 jest ukryte.

Tzn mam na myśli ten kod:

#if !defined (STM32F10X_LD_VL) && !defined (STM32F10X_MD_VL) && !defined (STM32F10X_HD_VL) && !defined (STM32F10X_CL)

#define RCC_PLLSource_HSE_Div1 ((uint32_t)0x00010000)

#define RCC_PLLSource_HSE_Div2 ((uint32_t)0x00030000)

#define IS_RCC_PLL_SOURCE(SOURCE) (((SOURCE) == RCC_PLLSource_HSI_Div2) || \

((SOURCE) == RCC_PLLSource_HSE_Div1) || \

((SOURCE) == RCC_PLLSource_HSE_Div2))

#else

#define RCC_PLLSource_PREDIV1 ((uint32_t)0x00010000)

#define IS_RCC_PLL_SOURCE(SOURCE) (((SOURCE) == RCC_PLLSource_HSI_Div2) || \

((SOURCE) == RCC_PLLSource_PREDIV1))

#endif /

*

I teraz jako że jestem początkujący mam pytanie:

Czy takie ustawienie rzeczywiście nie jest dla mojego procka czy też coś mam nie w porządku z biblioteką?

Link do komentarza
Share on other sites

Błąd wynika chyba z tego że nie dajesz informacji czym konkretnie pętla PLL ma być taktowana (masz 3 możliwości HSI podzielone przez 2, HSE i HSE podzielone przez 2).

Spróbuj zmienić na:

RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);
Link do komentarza
Share on other sites

Po tej zmianie kompiluje się bez błędów tylko powstaje pytanie czy ten pkod działa w ten sam sposób jak ten podany w kursie?

I jeszcze jedno pytanie dotyczące

RCC_PLLSource_HSE_Div1

Rozumiem, że w tym momencie na pętle PLL podaje całe HSE, natomiast po zmianie na Div2 podaje to dzielone na 2?

Link do komentarza
Share on other sites

Tylko tu jest ta niejasość, że z tego co napisał lukpep:

przed wlaczeniem PLL niezbedna jest konfiguracja - wybranie zrodla sygnalu oraz mnoznika, Wiec ustawiamy jako zrodlo sygnalu petli dzielnik PREDIV1... co jak? Czemu nie HSE? Otoz w lini Conectivity Line nie ma mozliwosci skorzystania bezposrednio z HSE jako zrodla dla petli PLL

nie mogę użyć sygnału HSE jako źródła dla pętli PLL.

Link do komentarza
Share on other sites

Dołącz do dyskusji, napisz odpowiedź!

Jeśli masz już konto to zaloguj się teraz, aby opublikować wiadomość jako Ty. Możesz też napisać teraz i zarejestrować się później.
Uwaga: wgrywanie zdjęć i załączników dostępne jest po zalogowaniu!

Anonim
Dołącz do dyskusji! Kliknij i zacznij pisać...

×   Wklejony jako tekst z formatowaniem.   Przywróć formatowanie

  Dozwolonych jest tylko 75 emoji.

×   Twój link będzie automatycznie osadzony.   Wyświetlać jako link

×   Twoja poprzednia zawartość została przywrócona.   Wyczyść edytor

×   Nie możesz wkleić zdjęć bezpośrednio. Prześlij lub wstaw obrazy z adresu URL.

×
×
  • Utwórz nowe...

Ważne informacje

Ta strona używa ciasteczek (cookies), dzięki którym może działać lepiej. Więcej na ten temat znajdziesz w Polityce Prywatności.