11 lipca 2018

Reorganizacja kodu

W tym wpisie planowałem omówić pamięć SDRAM, ale zanim do niej przejdę jeszcze jeden, krótki wpis.
Okazuje się, że pisanie wszystkiego w jednym pliku main.c całkiem dobrze się sprawdza dla krótkiego programu. Ale im kod jest dłuższy, tym trudniej sobie poradzić i pojawia się konieczność podzielenia programu na moduły.
Co więcej okazuje się, że te moduły zaczynają tworzyć pewną bibliotekę - co niestety sprowadza się do ponownego wynajdowania koła. Użycie rejestrów miało wyeliminować bibliotekę Cube HAL, czy StdPeriph, jednak po pewnym czasie kod zmienia się we własną bibliotekę...

Nie mam jednak wyjścia, muszę coś z kodem w main.c zrobić. Na początek wydzielę ostatnio napisany kod inicjalizujący pętlę PLL.
W tym celu kopiuję początek funkcji main() do nowego pliku pll.c:

#include "pll.h"
#include "stm32f429xx.h"

#define PLL_M           8uL             // 8 MHz / 8 = 1 MHz
#define PLL_N           336uL           // 336 MHz => hclk = 168 MHz
#define PLL_Q           7               // USB PLL => 336/7 = 48 MHz

void pll_init(void)
{
        RCC->CR |= RCC_CR_HSEON;
        while ((RCC->CR & RCC_CR_HSERDY) == 0) ;

        RCC->PLLCFGR = PLL_M | (PLL_N << 6) | RCC_PLLCFGR_PLLSRC_HSE | (PLL_Q << 24);
        RCC->CFGR |= RCC_CFGR_HPRE_DIV1 | RCC_CFGR_PPRE2_DIV2 | RCC_CFGR_PPRE1_DIV4;

        RCC->CR |= RCC_CR_PLLON;
        while ((RCC->CR & RCC_CR_PLLRDY) == 0) ;

        RCC->APB1ENR |= RCC_APB1ENR_PWREN;

        PWR->CR |= PWR_CR_ODEN;
        while ((PWR->CSR & PWR_CSR_ODRDY) == 0) ;

        PWR->CR |= PWR_CR_ODSWEN;
        while ((PWR->CSR & PWR_CSR_ODSWRDY) == 0) ;

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

        uint32_t cfgr = RCC->CFGR;
        cfgr &= ~RCC_CFGR_SW;
        cfgr |= RCC_CFGR_SW_PLL;
        RCC->CFGR = cfgr;
        while ((RCC->CFGR & RCC_CFGR_SWS ) != RCC_CFGR_SWS_PLL) ;
}

W pliku nagłówkowym pll.h umieszczam odpowiednie deklaracje:

#ifndef __PLL__
#define __PLL__

#define HCLK_FREQ       168000000uL
#define APB1_FREQ       (HCLK_FREQ/4)
#define APB2_FREQ       (HCLK_FREQ/2)

void pll_init(void);

#endif // __PLL__

Teraz program głowny po prostu wywołuje pll_init. Kod jest czytelniejszy, ale co ważniejsze w kolejnych programach mogę wykorzystać ten sam moduł pll.
Plik main.c:

#include <stdint.h>
#include <stdbool.h>
#include "stm32f429xx.h"
#include "pll.h"

volatile uint32_t ms_counter = 0;

void SysTick_Handler(void)
{
        if (ms_counter)
                ms_counter--;
}

void delay_ms(uint32_t ms)
{
        ms_counter = ms;
        while (ms_counter) ;
}

void usart_send(const char *s)
{
        while (*s) {
                while ((USART1->SR & USART_SR_TXE) == 0);
                USART1->DR = *s++;
        }
}

int main(int argc, char *argv[])
{
        pll_init();

        RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN | RCC_AHB1ENR_GPIOGEN;
        RCC->APB2ENR |= RCC_APB2ENR_USART1EN;

        GPIOG->MODER |= GPIO_MODER_MODE13_0|GPIO_MODER_MODE14_0;

        GPIOA->MODER |= GPIO_MODER_MODE9_1|GPIO_MODER_MODE10_1;
        GPIOA->AFR[1]  |= GPIO_AFRH_AFSEL9_0 | GPIO_AFRH_AFSEL9_1 | GPIO_AFRH_AFSEL9_2;
        GPIOA->AFR[1]  |= GPIO_AFRH_AFSEL10_0 | GPIO_AFRH_AFSEL10_1 | GPIO_AFRH_AFSEL10_2;

        SysTick->LOAD = HCLK_FREQ / 1000 - 1;
        SysTick->VAL = 0;
        SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk |
                        SysTick_CTRL_TICKINT_Msk |
                        SysTick_CTRL_ENABLE_Msk;

        USART1->BRR = APB2_FREQ / 115200;
        USART1->CR1 = USART_CR1_UE | USART_CR1_TE | USART_CR1_RE;

        usart_send("Hello world!\r\n");

        while (1) {
                GPIOG->BSRR = GPIO_BSRR_BS13;
                GPIOG->BSRR = GPIO_BSRR_BR14;
                delay_ms(500);

                GPIOG->BSRR = GPIO_BSRR_BS14;
                GPIOG->BSRR = GPIO_BSRR_BR13;
                delay_ms(500);

                usart_send("stm32f429\r\n");
        }

        return 0;
}

Jednak głównym powodem powstania tego wpisu jest nowy plik Makefile. Może nie nowy, ale zmieniony - tym razem będzie kompilowanych więcej plików źródłowych. Dodałem zmienną SOURCES, która przechowuje listę z plikami do skompilowania. Dzięki temu można łatwo dodać moduł pll, a w przyszłości również kolejne.
Plik Makefile wygląda teraz następująco:

CROSS_COMPILE = arm-none-eabi-

AS = $(CROSS_COMPILE)as
CC = $(CROSS_COMPILE)gcc
SIZE = $(CROSS_COMPILE)size

TARGET = bin/test07

SOURCES = src/main.c \
          src/pll.c

OBJECTS = $(SOURCES:src/%.c=obj/%.o)

CFLAGS=-mthumb -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -std=gnu11 -O0 \
        -ffunction-sections -fdata-sections -g -fstack-usage -Wall -specs=nano.specs

LDFLAGS=$(CFLAGS) -Wl,--gc-sections -specs=nosys.specs -Wl,-cref,-u,Reset_Handler \
        -Wl,-Map=$(TARGET).map -Tsrc/stm32f4_flash.ld

all: $(TARGET).elf
        $(SIZE) $<

$(TARGET).elf: $(OBJECTS) obj/startup_stm32f429xx.o
        $(CC) $(LDFLAGS) -o $@ $^

obj/%.o: src/%.c
        $(CC) $(CFLAGS) -o $@ -c $<

obj/startup_stm32f429xx.o: src/startup_stm32f429xx.s
        $(CC) $(CFLAGS) -o $@ -c $<

debug: $(TARGET).elf
        openocd -f board/stm32f429discovery.cfg -f interface/stlink-v2-1.cfg \
                -c "init; sleep 200; reset halt; wait_halt; \
                flash write_image erase $(TARGET).elf; \
                reset run; sleep 10; shutdown"

clean:
        rm -f bin/* obj/*

Brak komentarzy:

Prześlij komentarz