Library 1 – sterownik silnika krokowego na STM32F429-DISCO (part 1).

Niniejszym wpisem chciałbym zapoczątkować cykl postów opisujących bibliotekę do zarządzania pracą silnika krokowego. W tej części zajmę się krótkim opisem projektu, podłączeniem silnik-L6258 (płytka P46d)-STM32F429_DISCO-PC oraz konfiguracją peryferiów mikrokontrolera.

Projekt do pobrania z: https://github.com/PiotrPoterala/stm32f429i-disco_stepper_motor

Wykorzystane technologie:

  • C++11,
  • RTOS: RTX5.

Cechy:

  • Obsługa driverów silników krokowych dysponujących interfejsem równoległym opartym na:
    • parze sygnałów dir/clock,
    • parze sygnałów zegarowych przesuniętych w fazie + informacja o poziomie prądu płynącego przez dane uzwojenie,
  • Obsługa interfejsu UART do komunikacji z PC.

Zależności:

Podłączenie systemu:

Rysunek 1-1

Pliki konfiguracyjne (config.h, config.cpp):

Konfiguracja zegara
config.cpp
void RCC_Config(void){

    SystemInit();
	
    RCC->CR |= RCC_CR_HSEON;
    while(!(RCC->CR & RCC_CR_HSERDY)) 
			;
    RCC->APB1ENR |= RCC_APB1ENR_PWREN;
    PWR->CR |= PWR_CR_VOS;

    RCC->CR&=~RCC_CR_PLLON;
    while(RCC->CR & RCC_CR_PLLRDY);
    RCC->PLLCFGR|=RCC_PLLCFGR_PLLSRC;
    RCC->PLLCFGR=(RCC->PLLCFGR & ~RCC_PLLCFGR_PLLM) | RCC_PLLCFGR_PLLM_DIV4;
    RCC->PLLCFGR=(RCC->PLLCFGR & ~RCC_PLLCFGR_PLLN) | RCC_PLLCFGR_PLLN_MUL180;
    RCC->PLLCFGR=(RCC->PLLCFGR & ~RCC_PLLCFGR_PLLP) | RCC_PLLCFGR_PLLP_DIV2;
    RCC->CR|=RCC_CR_PLLON;
    while(!(RCC->CR & RCC_CR_PLLRDY)) 
			;
	
   
    PWR->CR |= PWR_CR_ODEN;
    while(!(PWR->CSR & PWR_CSR_ODRDY));
    PWR->CR |= PWR_CR_ODSWEN;
    while(!(PWR->CSR & PWR_CSR_ODSWRDY));    

    FLASH->ACR = FLASH_ACR_PRFTEN | FLASH_ACR_ICEN | FLASH_ACR_DCEN | FLASH_ACR_LATENCY_5WS;

    RCC->CFGR=(RCC->CFGR & ~RCC_CFGR_SW) | RCC_CFGR_SW_PLL;
    RCC->CFGR |= RCC_CFGR_HPRE_DIV1;
    RCC->CFGR |= RCC_CFGR_PPRE2_DIV2;
    RCC->CFGR |= RCC_CFGR_PPRE1_DIV4;

    /* Wait till the main PLL is used as system clock source */
    while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS ) != RCC_CFGR_SWS_PLL);

    SystemCoreClockUpdate();
		
    RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN;
    RCC->AHB1ENR |= RCC_AHB1ENR_GPIOCEN;	
    RCC->AHB1ENR |= RCC_AHB1ENR_GPIODEN;
    RCC->AHB1ENR |= RCC_AHB1ENR_GPIOEEN;	
    RCC->AHB1ENR |= RCC_AHB1ENR_GPIOGEN;
		
    RCC->APB2ENR|=RCC_APB2ENR_USART1EN;
}

W powyższym przykładzie brak Standard Peripheral Library od ST. Uważam, że wspomniana biblioteka wprowadza zbyt dużo niepotrzebnych „zawiłości” w postaci konieczności tworzenia nikomu niepotrzebnych struktur do zainicjowania konkretnych peryferiów. Dużo czytelniejszym wydaje mi się operowanie „bezpośrednio” na rejestrach (z wykorzystaniem biblioteki CMSIS-CORE), tym bardziej, że w „manualach” są one naprawdę dobrze opisane. Konfiguracja zegara jest jednak bodaj jedynym miejscem, gdzie wspieram się CubeMX’em – jest fajnym kalkulatorem wartości poszczególnych mnożników i dzielników sygnału zegarowego. Zaznaczamy z jakiego źródła będziemy pobierać sygnał zegarowy (tutaj z kwarcu o częstotliwości rezonansu 8MHz). W PLL Source Mux wybieramy HSE, w System Clock Mux PLLCLK, następnie w okienku HCLK wpisujemy maksymalną częstotliwość taktowania rdzenia (tutaj 180MHz), po czym wciskamy Enter i następuje przeliczenie wszystkich wartości mnożników/dzielników.

Konfiguracja GPIO

Wszystkie wyjścia skonfigurowane jako wyjścia typu push-pull. Jedynym wyjątkiem jest pin PD7 podłączony do wejścia *EN płytki P46d skonfigurowany jako „otwarty kolektor”. PA9 oraz PA10 ustawione zostały jako wejścia/wyjścia alternatywne (w tym przypadku obsługują linie TX, RX komunikacji USART).

config.h
/**
 * Keil project for stepper motor driver
 
 * @author  Piotr Poterała
 * @email   poterala.piotr@gmail.com
 * @website http://zappp.pl
 * @version v1.0
 * @ide     Keil uVision 5
 * @license GNU GPL v3
 *	
@verbatim
   ----------------------------------------------------------------------
    Copyright (C) Piotr Poterała, 2021c
    
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    any later version.
     
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
    
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
   ----------------------------------------------------------------------
@endverbatim
 */
#ifndef _CONFIG_H
	#define _CONFIG_H

	#include "stm32xx.h"

	#define NVIC_PriGroup_0         ((uint32_t)0x7) /*!< 0 bits for pre-emption priority	 bits for subpriority */
	#define NVIC_PriGroup_1         ((uint32_t)0x6) /*!< 1 bits for pre-emption priority	3 bits for subpriority */
	#define NVIC_PriGroup_2         ((uint32_t)0x5) /*!< 2 bits for pre-emption priority	2 bits for subpriority */
	#define NVIC_PriGroup_3         ((uint32_t)0x4) /*!< 3 bits for pre-emption priority	1 bits for subpriority */
	#define NVIC_PriGroup_4         ((uint32_t)0x3) /*!< 4 bits for pre-emption priority 0 bits for subpriority */
																															0 bits for subpriority */
	#define RCC_PLLCFGR_PLLN_V40	0x2800
	#define RCC_PLLCFGR_PLLR_V2		0x0
	#define RCC_PLLCFGR_PLLM_V2		0x10
	
	#define RCC_PLLCFGR_PLLM_DIV4			4
	#define RCC_PLLCFGR_PLLN_MUL180		(180<<6)
	#define RCC_PLLCFGR_PLLP_DIV2			0x0
	

	#define  USART_BSTOP_CLR   0xCFFF           
	#define  USART_BSTOP_1     0x0000          
	#define  USART_BSTOP_2     0x2000  


	#define GPIO_AFR_AF0				0x0
	#define GPIO_AFR_AF1				0x1
	#define GPIO_AFR_AF2				0x2
	#define GPIO_AFR_AF3				0x3
	#define GPIO_AFR_AF4				0x4
	#define GPIO_AFR_AF5				0x5
	#define GPIO_AFR_AF6				0x6
	#define GPIO_AFR_AF7				0x7
	#define GPIO_AFR_AF8				0x8
	#define GPIO_AFR_AF9				0x9
	#define GPIO_AFR_AF10				0xA
	#define GPIO_AFR_AF11				0xB
	#define GPIO_AFR_AF12				0xC
	#define GPIO_AFR_AF13				0xD
	#define GPIO_AFR_AF14				0xE
	#define GPIO_AFR_AF15				0xF

	#define IO_SET_REG1(REG, PIN, SETS) ((REG & ~(0x1<<(PIN))) | ((SETS)<<(PIN)))
	#define IO_SET_REG2(REG, PIN, SETS) ((REG & ~(0x3<<(PIN*2))) | ((SETS)<<(PIN*2)))
        #define IN_SET_REG(REG, PIN, SETS) (REG->MODER=IO_SET_REG2(REG->MODER, PIN, IO_IN), REG->PUPDR=IO_SET_REG2(REG->PUPDR, PIN, SETS))

        #define OUT_SET_REG(REG, PIN, TYPE, SPEED) (REG->MODER=IO_SET_REG2(REG->MODER, PIN, IO_OUT), REG->OTYPER=IO_SET_REG1(REG->OTYPER, PIN, TYPE), REG->OSPEEDR=IO_SET_REG2(REG->OSPEEDR, PIN, SPEED))
        #define ALT_SET_REG(REG, PIN, SPEED) (REG->MODER=IO_SET_REG2(REG->MODER, PIN, IO_ALT), REG->OTYPER&=~(1<<PIN), REG->OSPEEDR=IO_SET_REG2(REG->OSPEEDR, PIN, SPEED))

	void RCC_Config(void);
	void NVIC_Config(void);
	void GPIO_Config(void);
	void USART_Config(void);

#endif
config.cpp
void GPIO_Config(void)
{
//port A
	ALT_SET_REG(GPIOA, Pin9, IO_OUT_HS);
	GPIOA->AFR[1]=(GPIOA->AFR[1] & ~(0xF<<((Pin9-8)*4))) | (GPIO_AFR_AF7<<((Pin9-8)*4)); //USART1 TX
	ALT_SET_REG(GPIOA, Pin10, IO_OUT_HS);
	GPIOA->AFR[1]=(GPIOA->AFR[1] & ~(0xF<<((Pin10-8)*4))) | (GPIO_AFR_AF7<<((Pin10-8)*4));	//USART1 RX
	
//port C
	OUT_SET_REG(GPIOC, Pin11, IO_PP, IO_OUT_HS);
	OUT_SET_REG(GPIOC, Pin12, IO_PP, IO_OUT_HS);
	OUT_SET_REG(GPIOC, Pin13, IO_PP, IO_OUT_HS);

//port D
	OUT_SET_REG(GPIOD, Pin2, IO_PP, IO_OUT_HS);
	OUT_SET_REG(GPIOD, Pin4, IO_PP, IO_OUT_HS);
	OUT_SET_REG(GPIOD, Pin5, IO_PP, IO_OUT_HS);
	OUT_SET_REG(GPIOD, Pin7, IO_OD, IO_OUT_HS);

//port E	
	OUT_SET_REG(GPIOE, Pin2, IO_PP, IO_OUT_HS);
	OUT_SET_REG(GPIOE, Pin3, IO_PP, IO_OUT_HS);
	OUT_SET_REG(GPIOE, Pin4, IO_PP, IO_OUT_HS);
	OUT_SET_REG(GPIOE, Pin5, IO_PP, IO_OUT_HS);
	OUT_SET_REG(GPIOE, Pin6, IO_PP, IO_OUT_HS);


//port G	
	OUT_SET_REG(GPIOG, Pin13, IO_PP, IO_OUT_HS);	//LED1
	OUT_SET_REG(GPIOG, Pin14, IO_PP, IO_OUT_HS);	//LED2
	
	
	
	PIN_CLR(PORT_LED, LED1);
	PIN_CLR(PORT_LED, LED2);

}
Konfiguracja USART

USART skonfigurowany został tak aby:

  • Ramka składała się z: 8 bitów danych, 1 bitu stopu, bez parzystości,
  • Prędkość transmisji wynosiła 9600 bodów na sekundę
config.cpp
void USART_Config(void){
	double divider = 0x00;
	
	USART1->CR1&=~USART_CR1_PCE;		//parity: no		
	USART1->CR1&=~USART_CR1_M;			//8 data bits
	USART1->CR2=(USART1->CR2 & USART_BSTOP_CLR) | USART_BSTOP_1;			//1 stop bit

	USART1->CR1&=~USART_CR1_OVER8; //oversampling=16 

  divider = ((double)90000000 / (16*9600));		//PLCK1/(16*BAUD) for oversampling=16    
  USART1->BRR |= (uint16_t)divider << 4;
  USART1->BRR |= (uint16_t)((divider-(uint16_t)divider)*16);

	USART1->CR1|=USART_CR1_TE;
	USART1->CR1&=~USART_CR1_TXEIE;
	USART1->CR1|=USART_CR1_RE;
	USART1->CR1|=USART_CR1_RXNEIE;
	USART1->CR1|=USART_CR1_UE;	

}

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *