Compare commits

..

No commits in common. "be6759c99070ae2474949d74d1f662fce1b7074f" and "442fb2ee2adad4865adac7d8a5c7fc4085871ac5" have entirely different histories.

25 changed files with 22 additions and 11862 deletions

View file

@ -1,10 +0,0 @@
#ifndef CONFIG_H
#define CONFIG_H
#define LED_CFG GPIOD,2
#define REL_CFG GPIOD,4
#define SW__ON false
#define SW_OFF true
#endif // CONFIG_H

View file

@ -1,80 +0,0 @@
#include "system.h"
#include "usart.h"
static Usart * pInstance = nullptr;
static constexpr unsigned HCLK = 48'000'000u;
extern "C" void USART1_IRQHandler (void) __attribute__((interrupt));
void USART1_IRQHandler (void) {
if (pInstance) pInstance->irq();
};
Usart::Usart(const uint32_t _baud) noexcept : BaseLayer (), tx_ring () {
pInstance = this;
// 1. Clock Enable
RCC.APB2PCENR.modify([](RCC_Type::APB2PCENR_DEF & r) -> auto {
r.B.USART1EN = SET;
r.B.IOPDEN = SET;
return r.R;
});
// 2. GPIO Alternate Config - default TX/PD5, RX/PD6
GPIOD.CFGLR.modify([](GPIOA_Type::CFGLR_DEF & r) -> auto {
r.B.MODE5 = 1u;
r.B.CNF5 = 2u; // or 3u for open drain
r.B.MODE6 = 0u;
r.B.CNF6 = 1u; // floating input
return r.R;
});
// 4. NVIC
NVIC.EnableIRQ (USART1_IRQn);
// 5. USART registry 8.bit bez parity
USART1.CTLR1.modify([] (USART1_Type::CTLR1_DEF & r) -> auto {
r.B.RE = SET;
r.B.TE = SET;
r.B.RXNEIE = SET;
return r.R;
});
USART1.CTLR2.R = 0;
//USART1.CTLR3.B.OVRDIS = SET;
const uint32_t tmp = HCLK / _baud;
USART1.BRR.R = tmp;
USART1.CTLR1.B.UE = SET; // nakonec povolit globálně
}
void Usart::irq () {
volatile USART1_Type::STATR_DEF status (USART1.STATR); // načti status přerušení
char rdata, tdata;
if (status.B.TXE) { // od vysílače
if (tx_ring.Read (tdata)) { // pokud máme data
USART1.DATAR.B.DR = (uint8_t) tdata; // zapíšeme do výstupu
} else { // pokud ne
// Předpoklad je half-duplex i.e. RS485, jinak jen zakázat TXEIE
rdata = (USART1.DATAR.B.DR); // dummy read
USART1.CTLR1.modify([](USART1_Type::CTLR1_DEF & r) -> auto {
r.B.RE = SET; // povol prijem
r.B.TXEIE = RESET; // je nutné zakázat přerušení od vysílače
return r.R;
});
}
}
if (status.B.RXNE) { // od přijímače
rdata = (USART1.DATAR.B.DR); // načteme data
Up (&rdata, 1u); // a pošleme dál
}
}
uint32_t Usart::Down(const char * data, const uint32_t len) {
unsigned n = 0u;
for (n=0u; n<len; n++) {
if (!tx_ring.Write(data[n])) break;
}
USART1.CTLR1.modify([](USART1_Type::CTLR1_DEF & r) -> auto {
r.B.RE = RESET;
r.B.TXEIE = SET; // po povolení přerušení okamžitě přeruší
return r.R;
});
return n;
}
void Usart::SetRS485 (const bool polarity) const {
}
void Usart::SetHalfDuplex (const bool on) const {
}

View file

@ -1,21 +0,0 @@
#ifndef USART_H
#define USART_H
#include "fifo.h"
#include "baselayer.h"
/** @class Usart
* @brief Sériový port.
*
* Zde RS485, jen výstup.
*/
class Usart : public BaseLayer {
FIFO<char, 64> tx_ring;
public:
explicit Usart (const uint32_t baud = 9600) noexcept;
uint32_t Down (const char * data, const uint32_t len) override;
void SetRS485 (const bool polarity) const;
void irq (void);
void SetHalfDuplex (const bool on) const;
};
#endif // USART_H

View file

@ -1,9 +1,6 @@
# ch32v003 | stm32f051 # ch32v003
TARGET?= ch32v003 TARGET?= ch32v003
#TARGET?= stm32f051
TOOL ?= gcc TOOL ?= gcc
# do not use for ch32v003
#TOOL ?= clang
PRJ = example PRJ = example
@ -19,8 +16,8 @@ CFLAGS+= -I. -I./common -I./$(TARGET) -I/usr/include/newlib -DUSE_HSE=1
DEL = rm -f DEL = rm -f
# zdrojaky # zdrojaky
OBJS = main.o adcdma.o hdo.o OBJS = main.o adcclass.o hdo.o
OBJS += usart.o print.o OBJS += usartclass.o print.o
include $(TARGET)/$(TOOL).mk include $(TARGET)/$(TOOL).mk
BOBJS = $(addprefix $(BLD),$(OBJS)) BOBJS = $(addprefix $(BLD),$(OBJS))
@ -47,9 +44,9 @@ $(BLD)%.o: %.cpp
@$(CXX) -std=c++17 -fno-rtti -c $(CFLAGS) $< -o $@ @$(CXX) -std=c++17 -fno-rtti -c $(CFLAGS) $< -o $@
$(BLD): $(BLD):
mkdir $(BLD) mkdir $(BLD)
flash: $(BLD) $(PRJ).elf flash: $(PRJ).elf
minichlink -w $(PRJ).bin flash -b minichlink -w $(PRJ).bin flash -b
# vycisti # vycisti
clean: clean:
$(DEL) $(BLD)* *.lst *.bin *.elf *.map sin.c *~ $(DEL) $(BLD)* *.lst *.bin *.elf *.map sin.c *~
.PHONY: all clean flash .PHONY: all clean

View file

@ -1,8 +1,8 @@
#include "system.h" #include "system.h"
#include "oneway.h" #include "oneway.h"
#include "adcdma.h" #include "adcclass.h"
static AdcDma * pInstance = nullptr; static AdcClass * pInstance = nullptr;
extern "C" void DMA1_Channel1_IRQHandler( void ) __attribute__((interrupt)); extern "C" void DMA1_Channel1_IRQHandler( void ) __attribute__((interrupt));
void DMA1_Channel1_IRQHandler( void ) { void DMA1_Channel1_IRQHandler( void ) {
@ -90,7 +90,7 @@ static inline void AdcPostInit (void) noexcept {
}); });
} }
//////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////
AdcDma::AdcDma() noexcept : pL (buffer), pH (buffer + HALF_LEN), dst (nullptr) { AdcClass::AdcClass() noexcept : pL (buffer), pH (buffer + HALF_LEN), dst (nullptr) {
pInstance = this; pInstance = this;
EnableClock (); EnableClock ();
Timer2Init (1000u); Timer2Init (1000u);
@ -101,7 +101,7 @@ AdcDma::AdcDma() noexcept : pL (buffer), pH (buffer + HALF_LEN), dst (nullptr) {
// start timer // start timer
TIM2.CTLR1.B.CEN = SET; TIM2.CTLR1.B.CEN = SET;
} }
inline void AdcDma::send(const bool b) { inline void AdcClass::send(const bool b) {
if (!dst) return; if (!dst) return;
if (b) dst->Send (pH, HALF_LEN); if (b) dst->Send (pH, HALF_LEN);
else dst->Send (pL, HALF_LEN); else dst->Send (pL, HALF_LEN);

View file

@ -1,21 +1,21 @@
#ifndef ADCDMA_H #ifndef ADCCLASS_H
#define ADCDMA_H #define ADCCLASS_H
#include <stdint.h> #include <stdint.h>
class OneWay; class OneWay;
static constexpr unsigned HALF_LEN = 120u; static constexpr unsigned HALF_LEN = 120u;
static constexpr unsigned FULL_LEN = HALF_LEN * 2u; static constexpr unsigned FULL_LEN = HALF_LEN * 2u;
class AdcDma { class AdcClass {
uint16_t * pL; uint16_t * pL;
uint16_t * pH; uint16_t * pH;
uint16_t buffer [FULL_LEN]; uint16_t buffer [FULL_LEN];
OneWay * dst; OneWay * dst;
public: public:
explicit AdcDma () noexcept; explicit AdcClass () noexcept;
void attach (OneWay & d) { dst = & d; } void attach (OneWay & d) { dst = & d; }
void send (const bool b); void send (const bool b);
}; };
#endif // ADCDMA_H #endif // ADCCLASS_H

View file

@ -37,8 +37,8 @@ void Hdo::pass () {
cout << value << " \r"; cout << value << " \r";
value -= trigger; value -= trigger;
if (value > 0) led << SW__ON; // LED je zapojená proti VCC if (value > 0) led << false; // LED je zapojená proti VCC
else led << SW_OFF; else led << true;
// Konečné vyhodnocení. // Konečné vyhodnocení.
if (Decode (value, buf1)) { // Telegram OK. if (Decode (value, buf1)) { // Telegram OK.
HumanRead (buf1, buf2); // Převeď ho do čitelné podoby HumanRead (buf1, buf2); // Převeď ho do čitelné podoby

View file

@ -1,10 +1,9 @@
#ifndef HDO_H #ifndef HDO_H
#define HDO_H #define HDO_H
#include "gpio.h" #include "gpio.h"
#include "usart.h" #include "usartclass.h"
#include "print.h" #include "print.h"
#include "oneway.h" #include "oneway.h"
#include "config.h"
static constexpr int ISHIFT = 12; static constexpr int ISHIFT = 12;
/* Tady je ten výpočet proveden externě. /* Tady je ten výpočet proveden externě.
@ -29,7 +28,7 @@ static constexpr int TBUFLEN = 64;
class Hdo : public OneWay { class Hdo : public OneWay {
GpioClass led, relay; GpioClass led, relay;
Usart serial; UsartClass serial;
Print cout; Print cout;
FIFO<int, 8> data; FIFO<int, 8> data;
const int coeff; const int coeff;
@ -45,7 +44,7 @@ class Hdo : public OneWay {
public: public:
explicit Hdo (const char * command) noexcept : OneWay (), explicit Hdo (const char * command) noexcept : OneWay (),
led (LED_CFG), relay (REL_CFG), serial (115200u), cout (DEC), data(), coeff (1706), trigger (0x4000), led (GPIOD, 2), relay (GPIOD, 4), serial (115200u), cout (DEC), data(), coeff (1706), trigger (0x4000),
cmd (command), suma (0), bits (0), counter (0), status (WAIT_FOR_BEGIN) { cmd (command), suma (0), bits (0), counter (0), status (WAIT_FOR_BEGIN) {
/* trigger musí být nastaven tak do 1/3 až do 1/2 maximální vyhodnocené hodnoty (viz výpis) /* trigger musí být nastaven tak do 1/3 až do 1/2 maximální vyhodnocené hodnoty (viz výpis)
* Je nutné použít HSE, tj. krystal 24 HHz. Bez toho to fakt nechodí a to i na procesorech i.e. STM. * Je nutné použít HSE, tj. krystal 24 HHz. Bez toho to fakt nechodí a to i na procesorech i.e. STM.

View file

@ -1,4 +1,4 @@
#include "adcdma.h" #include "adcclass.h"
#include "hdo.h" #include "hdo.h"
/////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////
/* Tohle je trochu komplexnější příklad. /* Tohle je trochu komplexnější příklad.
@ -27,8 +27,8 @@
* !!! Krystal 24 MHz nutný !!! * !!! Krystal 24 MHz nutný !!!
* */ * */
/////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////
static AdcDma adc; static AdcClass adc;
static Hdo hdo ("A1B8DP1"); static Hdo hdo ("A1B8DP1");
int main () { int main () {
adc.attach(hdo); adc.attach(hdo);
for (;;) { for (;;) {

View file

@ -1 +0,0 @@
../stm32f051/

View file

@ -1,139 +0,0 @@
#ifndef ARMCM0_HDEF
#define ARMCM0_HDEF
/** @brief SYSTICK for Cortex-M0
* Není to moc domyšlené, před tt. hlavičkou je nutné mít definován NVIC a IRQn,
* což je v STM generované hlavičce většinou uděláno. NVIC_EnableIRQ je zjednodušen
* jen pro CM0, jinak se tam čaruje s PRIO_BITS, tady to není potřeba.
*/
// tohle je jediné, co je potřeba z core_cm0.h
static inline void NVIC_EnableIRQ (IRQn irq) {
NVIC.ISER.R = ((1 << (static_cast<uint32_t>(irq) & 0x1F)));
}
static constexpr uint32_t SysTick_LOAD_RELOAD_Msk = (0xFFFFFFUL); /*!< SysTick LOAD: RELOAD Mask */
// ////////////////////+++ SysTick +-+//////////////////// //
struct SysTick_DEF { /*!< 24Bit System Tick Timer for use in RTOS */
union CSR_DEF { //!< [0000](04)[0x00000004] SysTick Control and Status Register
enum ENABLE_ENUM /*: uint32_t */ {
ENABLE_0 = 0, //!< disabled
ENABLE_1 = 1, //!< enabled
};
enum TICKINT_ENUM /*: uint32_t */ {
TICKINT_0 = 0, //!< Enable SysTick Exception
TICKINT_1 = 1, //!< Disable SysTick Exception
};
enum CLKSOURCE_ENUM /*: uint32_t */ {
CLKSOURCE_0 = 0, //!< External Clock
CLKSOURCE_1 = 1, //!< CPU Clock
};
struct {
__IO ENABLE_ENUM ENABLE : 1; //!<[00] Enable SysTick Timer
__IO TICKINT_ENUM TICKINT : 1; //!<[01] Generate Tick Interrupt
__IO CLKSOURCE_ENUM CLKSOURCE : 1; //!<[02] Source to count from
uint32_t UNUSED0 : 13; //!<[03]
__IO ONE_BIT COUNTFLAG : 1; //!<[16] SysTick counted to zero
} B;
__IO uint32_t R;
explicit CSR_DEF () noexcept { R = 0x00000004u; }
template<typename F> void setbit (F f) volatile {
CSR_DEF r;
R = f (r);
}
template<typename F> void modify (F f) volatile {
CSR_DEF r; r.R = R;
R = f (r);
}
};
__IO CSR_DEF CSR ; //!< register definition
union RVR_DEF { //!< [0004](04)[0x00000000] SysTick Reload Value Register
struct {
__IO uint32_t RELOAD : 24; //!<[00] Value to auto reload SysTick after reaching zero
} B;
__IO uint32_t R;
explicit RVR_DEF () noexcept { R = 0x00000000u; }
template<typename F> void setbit (F f) volatile {
RVR_DEF r;
R = f (r);
}
template<typename F> void modify (F f) volatile {
RVR_DEF r; r.R = R;
R = f (r);
}
};
__IO RVR_DEF RVR ; //!< register definition
union CVR_DEF { //!< [0008](04)[0x00000000] SysTick Current Value Register
struct {
__IO uint32_t CURRENT : 24; //!<[00] Current value
} B;
__IO uint32_t R;
explicit CVR_DEF () noexcept { R = 0x00000000u; }
template<typename F> void setbit (F f) volatile {
CVR_DEF r;
R = f (r);
}
template<typename F> void modify (F f) volatile {
CVR_DEF r; r.R = R;
R = f (r);
}
};
__IO CVR_DEF CVR ; //!< register definition
union CALIB_DEF { //!< [000c](04)[0x00000000] SysTick Calibration Value Register
enum SKEW_ENUM /*: uint32_t */ {
SKEW_0 = 0, //!< 10ms calibration value is exact
SKEW_1 = 1, //!< 10ms calibration value is inexact, because of the clock frequency
};
enum NOREF_ENUM /*: uint32_t */ {
NOREF_0 = 0, //!< Ref Clk available
NOREF_1 = 1, //!< Ref Clk not available
};
struct {
__I uint32_t TENMS : 24; //!<[00] Reload value to use for 10ms timing
uint32_t UNUSED0 : 6; //!<[24]
__I SKEW_ENUM SKEW : 1; //!<[30] Clock Skew
__I NOREF_ENUM NOREF : 1; //!<[31] No Ref
} B;
__IO uint32_t R;
explicit CALIB_DEF () noexcept { R = 0x00000000u; }
template<typename F> void setbit (F f) volatile {
CALIB_DEF r;
R = f (r);
}
template<typename F> void modify (F f) volatile {
CALIB_DEF r; r.R = R;
R = f (r);
}
};
__IO CALIB_DEF CALIB ; //!< register definition
// methods :
bool Config (const uint32_t ticks) {
if (ticks > SysTick_LOAD_RELOAD_Msk) return false; // Reload value impossible
RVR.B.RELOAD = ticks - 1u; // set reload register
NVIC_EnableIRQ (SysTick_IRQn); // Enable Interrupt
CVR.B.CURRENT = 0; // Load the SysTick Counter Value
CSR.modify([](CSR_DEF & r) -> auto { // Enable SysTick IRQ and SysTick Timer
r.B.CLKSOURCE = CSR_DEF::CLKSOURCE_ENUM::CLKSOURCE_1;
r.B.TICKINT = CSR_DEF::TICKINT_ENUM ::TICKINT_1;
r.B.ENABLE = CSR_DEF::ENABLE_ENUM ::ENABLE_1;
return r.R;
});
return true; // Function successful
}
}; /* total size = 0x0010, struct size = 0x0010 */
static SysTick_DEF & SysTick = * reinterpret_cast<SysTick_DEF *> (0xe000e010);
static_assert (sizeof(struct SysTick_DEF) == 16, "size error SysTick");
#endif

File diff suppressed because it is too large Load diff

View file

@ -1,119 +0,0 @@
#include "STM32F0x1.h"
#include "CortexM0.h"
#include "gpio.h"
#include "adcdma.h"
#include "oneway.h"
static constexpr uint32_t AdcChanel = 2u;
static constexpr uint32_t AdcPin = 2u;
static inline void EnableClock (void) {
RCC.APB2ENR.B.ADCEN = SET;
RCC.AHBENR.B.DMA1EN = SET;
RCC.APB1ENR.B.TIM3EN = SET;
}
static inline void Timer3Init (uint32_t us) {
TIM3.PSC.R = 47u;
TIM3.ARR.R = us - 1u;
// Preload, enable
TIM3.CR1.B.ARPE = SET;
// TRGO update for ADC
TIM3.CR2.B.MMS = 2;
}
typedef __SIZE_TYPE__ size_t;
static inline void Dma1Ch1Init (void * ptr) {
// Enable DMA transfer on ADC and circular mode
ADC.CFGR1.B.DMAEN = SET;
ADC.CFGR1.B.DMACFG = SET;
// Configure the peripheral data register address
DMA1.CPAR1.R = reinterpret_cast<size_t> (&(ADC.DR));
// Configure the memory address
DMA1.CMAR1.R = reinterpret_cast<size_t> (ptr);
// Configure the number of DMA tranfer to be performs on DMA channel 1
DMA1.CNDTR1.R = FULL_LEN;
// Configure increment, size, interrupts and circular mode
DMA1.CCR1.modify([] (auto & r) -> auto {
r.B.MINC = SET;
r.B.MSIZE = 1u;
r.B.PSIZE = 1u;
r.B.HTIE = SET;
r.B.TCIE = SET;
r.B.CIRC = SET;
return r.R;
});
// Enable DMA Channel 1
DMA1.CCR1.B.EN = SET;
}
static inline void AdcCalibrate (void) {
// Ensure that ADEN = 0
// Clear ADEN
if (ADC.CR.B.ADEN != RESET) {
ADC.CR.B.ADEN = RESET;
}
// Launch the calibration by setting ADCAL
ADC.CR.B.ADCAL = SET;
// Wait until ADCAL=0
while (ADC.CR.B.ADCAL != RESET);
//__NOP();
//__NOP(); // This 2 NOPs are to ensure 2 ADC Cycles before setting ADEN bit
}
static inline void AdcInit (void) {
// PCLK / 2 - jitter
ADC.CFGR2.B.JITOFF_D2 = SET;
// Select TRG TIM3
ADC.CFGR1.modify([] (auto & r) -> auto {
r.B.EXTEN = 1u;
r.B.EXTSEL = 3u;
return r.R;
});
// Select CHSELx
ADC.CHSELR.R = (1 << AdcChanel);
// Select a sampling mode of 000
ADC.SMPR.R = 1u;
}
static inline void AdcStart (void) {
ADC.CR.B.ADEN = SET;
TIM3.CR1.B.CEN = SET;
ADC.CR.B.ADSTART = SET;
}
static AdcDma * Instance = nullptr;
AdcDma::AdcDma() noexcept : pL (buffer), pH (buffer + HALF_LEN), dst (nullptr) {
Instance = this;
EnableClock ();
AdcCalibrate();
GpioClass in (GpioPortA, AdcPin, GPIO_Mode_AN);
Timer3Init (1000);
NVIC_EnableIRQ (DMA1_CH1_IRQn);
Dma1Ch1Init (buffer);
AdcInit ();
AdcStart ();
}
/*
void AdcDma::dmaIrq (void) {
volatile DMA_ISR_s status (DMA1.ISR);
current = nullptr;
if (status.B.HTIF1) current = ptr_l;
if (status.B.TCIF1) current = ptr_h;
// znuluj příznaky
DMA1.IFCR.R = status.R;
if (!current) return;
// zpracuj data, pokud je potřeba
send (current, PERIOD);
~led;
}
*/
extern "C" void DMA1_Channel1_IRQHandler (void) {
volatile DMA1_Type::ISR_DEF status (DMA1.ISR);
// znuluj příznaky
DMA1.IFCR.R = status.R;
if (!Instance) return;
if (status.B.HTIF1 != RESET) Instance->send (false);
else if (status.B.TCIF1 != RESET) Instance->send (true);
}
inline void AdcDma::send(const bool b) {
if (!dst) return;
if (b) dst->Send (pH, HALF_LEN);
else dst->Send (pL, HALF_LEN);
}

View file

@ -1,30 +0,0 @@
# Use clang / llvm toolchain
CC = clang
CXX = clang++
# linker je vlastně ld.lld
LD = clang++
# Zde kvůli jednoduchosti použijeme arm-none-eabi-g++ jako linker.
# Clang nemá některé ABI funkce, toolchain je v zásadě kompatibilní,
# takže než to hledat někde po webu, raději použijeme rovnou libc.
# Bez složité matematiky jde použít ld.lld nebo přidat libaeabi-cortexm0.a
# LD = arm-none-eabi-g++
SIZE = llvm-size
DUMP = llvm-objdump
COPY = llvm-objcopy
CCPU = -mcpu=cortex-m0
MCPU = -mthumb $(CCPU)
TRIP = thumbv6-none-eabi
CFLAGS+= -Oz -flto
#CFLAGS+= -Wno-deprecated-volatile
CFLAGS+= --target=$(TRIP) $(MCPU)
LFLAGS+= --target=$(TRIP)
#LFLAGS+= $(MCPU)
#LFLAGS+= -nostartfiles
LFLAGS+= -nostdlib -lto-O3
LFLAGS+= -Wl,--Map=$(@:%.elf=%.map),--gc-sections
LDLIBS+= -L./stm32f051 -T script.ld
LDLIBS+= -L/usr/lib/gcc/arm-none-eabi/9.2.1/thumb/v6-m/nofp -lgcc
DFLAGS+= --triple=$(TRIP) $(CCPU)
OBJS += startup.o system.o gpio.o

View file

@ -1,10 +0,0 @@
#ifndef CONFIG_H
#define CONFIG_H
#define LED_CFG GpioPortA,0
#define REL_CFG GpioPortA,1
#define SW__ON true
#define SW_OFF false
#endif // CONFIG_H

View file

@ -1,21 +0,0 @@
# Use gcc / binutils toolchain
PREFIX = arm-none-eabi-
CC = $(PREFIX)gcc
CXX = $(PREFIX)g++
# linker je ld
LD = $(PREFIX)g++
SIZE = $(PREFIX)size
DUMP = $(PREFIX)objdump
COPY = $(PREFIX)objcopy
CFLAGS+= -Os -flto
CCPU = -mcpu=cortex-m0
MCPU = -mthumb $(CCPU)
CFLAGS+= $(MCPU)
LFLAGS+= $(MCPU)
LFLAGS+= -Wl,--Map=$(@:%.elf=%.map),--gc-sections
LFLAGS+= -nostartfiles -flto -O3
LDLIBS+= -L./stm32f051 -T script.ld
OBJS += startup.o system.o gpio.o

View file

@ -1,26 +0,0 @@
#include "gpio.h"
static constexpr uint32_t RCC_AHBENR_GPIOAEN = 1u << 17; /*!< GPIOA clock enable */
static constexpr uint32_t RCC_AHBENR_GPIOBEN = 1u << 18; /*!< GPIOB clock enable */
static constexpr uint32_t RCC_AHBENR_GPIOCEN = 1u << 19; /*!< GPIOC clock enable */
static constexpr uint32_t RCC_AHBENR_GPIODEN = 1u << 20; /*!< GPIOD clock enable */
static constexpr uint32_t RCC_AHBENR_GPIOFEN = 1u << 22; /*!< GPIOF clock enable */
static const GpioAssocPort cPortTab[] = {
{&GPIOA, RCC_AHBENR_GPIOAEN},
{&GPIOB, RCC_AHBENR_GPIOBEN},
{&GPIOC, RCC_AHBENR_GPIOCEN},
{&GPIOD, RCC_AHBENR_GPIODEN},
{&GPIOF, RCC_AHBENR_GPIOFEN},
};
GpioClass::GpioClass (GpioPortNum const port, const uint32_t no, const GPIOMode_TypeDef type) noexcept :
io(cPortTab[port].portAdr), pos(1UL << no), num(no) {
// Povol hodiny
RCC.AHBENR.R |= cPortTab[port].clkMask;
// A nastav pin (pořadí dle ST knihovny).
setSpeed (GPIO_Speed_Level_3);
setOType (GPIO_OType_PP);
setMode (type);
setPuPd (GPIO_PuPd_NOPULL);
}

View file

@ -1,142 +0,0 @@
#ifndef GPIO_H
#define GPIO_H
#include "STM32F0x1.h"
/**
* @brief General Purpose IO
*/
typedef enum {
GPIO_Mode_IN = 0x00, /*!< GPIO Input Mode */
GPIO_Mode_OUT = 0x01, /*!< GPIO Output Mode */
GPIO_Mode_AF = 0x02, /*!< GPIO Alternate function Mode */
GPIO_Mode_AN = 0x03 /*!< GPIO Analog In/Out Mode */
} GPIOMode_TypeDef;
typedef enum {
GPIO_OType_PP = 0x00,
GPIO_OType_OD = 0x01
} GPIOOType_TypeDef;
typedef enum {
GPIO_Speed_Level_1 = 0x01, /*!< Medium Speed */
GPIO_Speed_Level_2 = 0x02, /*!< Fast Speed */
GPIO_Speed_Level_3 = 0x03 /*!< High Speed */
} GPIOSpeed_TypeDef;
typedef enum {
GPIO_PuPd_NOPULL = 0x00,
GPIO_PuPd_UP = 0x01,
GPIO_PuPd_DOWN = 0x02
} GPIOPuPd_TypeDef;
/// Enum pro PortNumber
typedef enum {
GpioPortA,
GpioPortB,
GpioPortC,
GpioPortD,
GpioPortF
} GpioPortNum;
/// Asociace port Adress a RCC clock
struct GpioAssocPort {
GPIOF_Type * const portAdr;
const uint32_t clkMask;
};
/** @file
* @brief Obecný GPIO pin.
*
* @class GpioClass
* @brief Obecný GPIO pin.
*
* Ukázka přetížení operátorů. Návratové hodnoty jsou v tomto případě celkem zbytečné,
* ale umožňují řetězení, takže je možné napsat např.
@code
+-+-+-led;
@endcode
* a máme na led 3 pulsy. Je to sice blbost, ale funguje.
* Všechny metody jsou konstantní, protože nemění data uvnitř třídy.
* Vlastně ani nemohou, protože data jsou konstantní.
*/
class GpioClass {
public:
/** Konstruktor
@param port GpioPortA | GpioPortB | GpioPortC | GpioPortD | GpioPortF
@param no číslo pinu na portu
@param type IN, OUT, AF, AN default OUT
*/
explicit GpioClass (GpioPortNum const port, const uint32_t no, const GPIOMode_TypeDef type = GPIO_Mode_OUT) noexcept;
/// Nastav pin @param b na tuto hodnotu
const GpioClass& operator<< (const bool b) const {
if (b) io->BSRR.R = pos;
else io->BRR.R = pos;
return *this;
}
//![Gpio example]
/// Nastav pin na log. H
const GpioClass& operator+ (void) const {
io->BSRR.R = (uint32_t) pos;
return *this;
}
/// Nastav pin na log. L
const GpioClass& operator- (void) const {
io->BRR.R = pos;
return *this;
}
/// Změň hodnotu pinu
const GpioClass& operator~ (void) const {
io->ODR.R ^= pos;
return *this;
};
/// Načti logickou hodnotu na pinu
const bool get (void) const {
if (io->IDR.R & pos) return true;
else return false;
};
/// A to samé jako operátor
const GpioClass& operator>> (bool& b) const {
b = get();
return *this;
}
//![Gpio example]
void setMode (GPIOMode_TypeDef p) {
uint32_t dno = num * 2;
io->MODER.R &= ~(3UL << dno);
io->MODER.R |= (p << dno);
}
void setOType (GPIOOType_TypeDef p) {
io->OTYPER.R &= (uint16_t)~(1UL << num);
io->OTYPER.R |= (uint16_t) (p << num);
}
void setSpeed (GPIOSpeed_TypeDef p) {
uint32_t dno = num * 2;
io->OSPEEDR.R &= ~(3UL << dno);
io->OSPEEDR.R |= (p << dno);
}
void setPuPd (GPIOPuPd_TypeDef p) {
uint32_t dno = num * 2;
io->PUPDR.R &= ~(3UL << dno);
io->PUPDR.R |= (p << dno);
}
void setAF (unsigned af) {
unsigned int pd,pn = num;
pd = (pn & 7) << 2; pn >>= 3;
if (pn) {
io->AFRH.R &= ~(0xFU << pd);
io->AFRH.R |= ( af << pd);
} else {
io->AFRL.R &= ~(0xFU << pd);
io->AFRL.R |= ( af << pd);
}
}
private:
/// Port.
GPIOF_Type * const io;
/// A pozice pinu na něm, stačí 16.bit
const uint16_t pos;
/// pro funkce setXXX necháme i číslo pinu
const uint16_t num;
};
#endif // GPIO_H

View file

@ -1,94 +0,0 @@
/*
*/
/* Entry Point */
ENTRY(Vectors)
/* Generate a link error if heap and stack don't fit into RAM */
_Min_Heap_Size = 0; /* required amount of heap */
_Min_Stack_Size = 0; /* required amount of stack */
/* Specify the memory areas */
MEMORY {
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 64K
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 8K
}
/* Highest address of the user mode stack */
_estack = ORIGIN(RAM) + LENGTH(RAM);
/* Define output sections */
SECTIONS {
/* The startup code goes first into FLASH */
/* The program code and other data goes into FLASH */
.text :
{
. = ALIGN(4);
KEEP(*(.isr_vector)) /* Startup code */
. = ALIGN(4);
*(.text) /* .text sections (code) */
*(.text*) /* .text* sections (code) */
*(.rodata) /* .rodata sections (constants, strings, etc.) */
*(.rodata*) /* .rodata* sections (constants, strings, etc.) */
*(.glue_7) /* glue arm to thumb code */
*(.glue_7t) /* glue thumb to arm code */
*(.eh_frame)
*(.init)
*(.fini)
/* Pro použití statických konstruktorů v C++, KEEP musí být použit při gc */
. = ALIGN(4);
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(.ctors)) /* for clang */
KEEP (*(.init_array*))
PROVIDE_HIDDEN (__init_array_end = .);
. = ALIGN(4);
_etext = .; /* define a global symbols at end of code */
} >FLASH
/* used by the startup to initialize data */
_sidata = .;
/* Initialized data sections goes into RAM, load LMA copy after code */
.data : AT ( _sidata )
{
. = ALIGN(4);
_sdata = .; /* create a global symbol at data start */
*(.data) /* .data sections */
*(.data*) /* .data* sections */
. = ALIGN(4);
_edata = .; /* define a global symbol at data end */
} >RAM
/* Uninitialized data section */
. = ALIGN(4);
.bss :
{
/* This is used by the startup in order to initialize the .bss secion */
_sbss = .; /* define a global symbol at bss start */
__bss_start__ = _sbss;
*(.bss)
*(.bss*)
*(COMMON)
_ebss = .;
__bss_end__ = _ebss;
} >RAM
_end = .;
/* Remove information from the standard libraries */
/DISCARD/ :
{
/*
libc.a ( * )
libm.a ( * )
libgcc.a ( * )
*(.debug*)
*/
*(.comment*)
*(.ARM.*)
}
.ARM.attributes 0 : { *(.ARM.attributes) }
}

View file

@ -1,163 +0,0 @@
#include <stdint.h>
#if defined (__cplusplus)
extern "C" {
#endif
//! [InitStaticConstructors]
extern void (*__init_array_start)(); // definováno v linker skriptu
extern void (*__init_array_end) (); // definováno v linker skriptu
void static_init() {
void (**p)();
for (p = &__init_array_start; p < &__init_array_end; p++) (*p)();
}
//! [InitStaticConstructors]
#define WEAK __attribute__ ((weak))
#define ALIAS(f) __attribute__ ((weak, alias (#f)))
extern unsigned int _estack;
extern unsigned int _sidata;
extern unsigned int _sdata;
extern unsigned int _edata;
extern unsigned int _sbss;
extern unsigned int _ebss;
WEAK void Reset_Handler (void);
WEAK void DefaultHandler (void);
void NonMaskableInt_Handler (void) ALIAS(Default_Handler);
void HardFault_Handler (void) ALIAS(Default_Handler);
void MemoryManagement_Handler (void) ALIAS(Default_Handler);
void BusFault_Handler (void) ALIAS(Default_Handler);
void UsageFault_Handler (void) ALIAS(Default_Handler);
void SVCall_Handler (void) ALIAS(Default_Handler);
void DebugMonitor_Handler (void) ALIAS(Default_Handler);
void PendSV_Handler (void) ALIAS(Default_Handler);
void SysTick_Handler (void) ALIAS(Default_Handler);
void WWDG_IRQHandler (void) ALIAS(Default_Handler);
void PVD_IRQHandler (void) ALIAS(Default_Handler);
void RTC_IRQHandler (void) ALIAS(Default_Handler);
void FLASH_IRQHandler (void) ALIAS(Default_Handler);
void RCC_CRS_IRQHandler (void) ALIAS(Default_Handler);
void EXTI0_1_IRQHandler (void) ALIAS(Default_Handler);
void EXTI2_3_IRQHandler (void) ALIAS(Default_Handler);
void EXTI4_15_IRQHandler (void) ALIAS(Default_Handler);
void TSC_IRQHandler (void) ALIAS(Default_Handler);
void DMA1_CH1_IRQHandler (void) ALIAS(Default_Handler);
void DMA1_CH2_3_DMA2_CH1_2_IRQHandler (void) ALIAS(Default_Handler);
void DMA1_CH4_5_6_7_DMA2_CH3_4_5_IRQHandler (void) ALIAS(Default_Handler);
void ADC_COMP_IRQHandler (void) ALIAS(Default_Handler);
void TIM1_BRK_UP_TRG_COM_IRQHandler (void) ALIAS(Default_Handler);
void TIM1_CC_IRQHandler (void) ALIAS(Default_Handler);
void TIM2_IRQHandler (void) ALIAS(Default_Handler);
void TIM3_IRQHandler (void) ALIAS(Default_Handler);
void TIM6_DAC_IRQHandler (void) ALIAS(Default_Handler);
void TIM7_IRQHandler (void) ALIAS(Default_Handler);
void TIM14_IRQHandler (void) ALIAS(Default_Handler);
void TIM15_IRQHandler (void) ALIAS(Default_Handler);
void TIM16_IRQHandler (void) ALIAS(Default_Handler);
void TIM17_IRQHandler (void) ALIAS(Default_Handler);
void I2C1_IRQHandler (void) ALIAS(Default_Handler);
void I2C2_IRQHandler (void) ALIAS(Default_Handler);
void SPI1_IRQHandler (void) ALIAS(Default_Handler);
void SPI2_IRQHandler (void) ALIAS(Default_Handler);
void USART1_IRQHandler (void) ALIAS(Default_Handler);
void USART2_IRQHandler (void) ALIAS(Default_Handler);
void USART3_4_5_6_7_8_IRQHandler (void) ALIAS(Default_Handler);
void CEC_CAN_IRQHandler (void) ALIAS(Default_Handler);
void USB_IRQHandler (void) ALIAS(Default_Handler);
extern int main (void);
extern void SystemInit (void);
extern void SystemCoreClockUpdate (void);
#if defined (__cplusplus)
}; // extern "C"
#endif
typedef void (*handler) (void);
__attribute__ ((section(".isr_vector")))
handler Vectors[] = {
(handler) &_estack,
Reset_Handler,
NonMaskableInt_Handler,
HardFault_Handler,
MemoryManagement_Handler,
BusFault_Handler,
UsageFault_Handler,
0,
0,
0,
0,
SVCall_Handler,
DebugMonitor_Handler,
0,
PendSV_Handler,
SysTick_Handler,
WWDG_IRQHandler,
PVD_IRQHandler,
RTC_IRQHandler,
FLASH_IRQHandler,
RCC_CRS_IRQHandler,
EXTI0_1_IRQHandler,
EXTI2_3_IRQHandler,
EXTI4_15_IRQHandler,
TSC_IRQHandler,
DMA1_CH1_IRQHandler,
DMA1_CH2_3_DMA2_CH1_2_IRQHandler,
DMA1_CH4_5_6_7_DMA2_CH3_4_5_IRQHandler,
ADC_COMP_IRQHandler,
TIM1_BRK_UP_TRG_COM_IRQHandler,
TIM1_CC_IRQHandler,
TIM2_IRQHandler,
TIM3_IRQHandler,
TIM6_DAC_IRQHandler,
TIM7_IRQHandler,
TIM14_IRQHandler,
TIM15_IRQHandler,
TIM16_IRQHandler,
TIM17_IRQHandler,
I2C1_IRQHandler,
I2C2_IRQHandler,
SPI1_IRQHandler,
SPI2_IRQHandler,
USART1_IRQHandler,
USART2_IRQHandler,
USART3_4_5_6_7_8_IRQHandler,
CEC_CAN_IRQHandler,
USB_IRQHandler,
};
static inline void fillStack (void) {
register unsigned int *dst, *end;
dst = &_ebss;
end = &_estack;
while (dst < end) *dst++ = 0xDEADBEEFU;
}
void Reset_Handler(void) {
fillStack();
register unsigned int *src, *dst, *end;
/* Zero fill the bss section */
dst = &_sbss;
end = &_ebss;
while (dst < end) *dst++ = 0U;
/* Copy data section from flash to RAM */
src = &_sidata;
dst = &_sdata;
end = &_edata;
while (dst < end) *dst++ = *src++;
SystemInit();
SystemCoreClockUpdate(); // Potřebné pro USART
static_init(); // Zde zavolám globální konstruktory
main();
for (;;);
}
void Default_Handler (void) {
asm volatile ("bkpt 1");
}

View file

@ -1,232 +0,0 @@
#include "STM32F0x1.h"
#include "system.h"
#if !defined (HSE_VALUE)
#define HSE_VALUE ((uint32_t)8000000) /*!< Value of the External oscillator in Hz */
#endif /* HSE_VALUE */
#if !defined (HSI_VALUE)
#define HSI_VALUE ((uint32_t)8000000) /*!< Value of the Internal High Speed oscillator in Hz. */
#endif /* HSI_VALUE */
#define HSE_STARTUP_TIMEOUT ((uint16_t)0x5000) /*!< Time out for HSE start up */
//! [EnumExampleSW_EN_Def]
typedef enum {
USEHSI = 0, USEHSE, USEPLL
} SW_EN;
//! [EnumExampleSW_EN_Def]
typedef enum {
RCC_CFGR_PLLMUL2 = 0,
RCC_CFGR_PLLMUL3,
RCC_CFGR_PLLMUL4,
RCC_CFGR_PLLMUL5,
RCC_CFGR_PLLMUL6,
RCC_CFGR_PLLMUL7,
RCC_CFGR_PLLMUL8,
RCC_CFGR_PLLMUL9,
RCC_CFGR_PLLMUL10,
RCC_CFGR_PLLMUL11,
RCC_CFGR_PLLMUL12,
RCC_CFGR_PLLMUL13,
RCC_CFGR_PLLMUL14,
RCC_CFGR_PLLMUL15,
RCC_CFGR_PLLMUL16,
} PLLML_EN;
/* Select the PLL clock source */
//#define PLL_SOURCE_HSI // HSI (~8MHz) used to clock the PLL, and the PLL is used as system clock source
#define PLL_SOURCE_HSE // HSE (8MHz) used to clock the PLL, and the PLL is used as system clock source
//#define PLL_SOURCE_HSE_BYPASS // HSE bypassed with an external clock (8MHz, coming from ST-Link) used to clock
// the PLL, and the PLL is used as system clock source
uint32_t SystemCoreClock = 48000000;
const uint8_t AHBPrescTable[16] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9};
static void SetSysClock (void);
/**
* @brief Setup the microcontroller system.
* Initialize the Embedded Flash Interface, the PLL and update the
* SystemCoreClock variable.
* @param None
* @retval None
*/
extern "C"
void SystemInit (void) {
/* Set HSION bit */
RCC.CR.R |= (uint32_t) 0x00000001;
/* Reset SW[1:0], HPRE[3:0], PPRE[2:0], ADCPRE and MCOSEL[2:0] bits */
RCC.CFGR.R &= (uint32_t) 0xF8FFB80C;
/* Reset HSEON, CSSON and PLLON bits */
RCC.CR.R &= (uint32_t) 0xFEF6FFFF;
/* Reset HSEBYP bit */
RCC.CR.R &= (uint32_t) 0xFFFBFFFF;
/* Reset PLLSRC, PLLXTPRE and PLLMUL[3:0] bits */
RCC.CFGR.R &= (uint32_t) 0xFFC0FFFF;
/* Reset PREDIV1[3:0] bits */
RCC.CFGR2.R &= (uint32_t) 0xFFFFFFF0;
/* Reset USARTSW[1:0], I2CSW, CECSW and ADCSW bits */
RCC.CFGR3.R &= (uint32_t) 0xFFFFFEAC;
/* Reset HSI14 bit */
RCC.CR2.R &= (uint32_t) 0xFFFFFFFE;
/* Disable all interrupts */
RCC.CIR.R = 0x00000000u;
/* Configure the System clock frequency, AHB/APBx prescalers and Flash settings */
SetSysClock();
}
/**
* @brief Update SystemCoreClock according to Clock Register Values
* The SystemCoreClock variable contains the core clock (HCLK), it can
* be used by the user application to setup the SysTick timer or configure
* other parameters.
*
* @note Each time the core clock (HCLK) changes, this function must be called
* to update SystemCoreClock variable value. Otherwise, any configuration
* based on this variable will be incorrect.
*
* @note - The system frequency computed by this function is not the real
* frequency in the chip. It is calculated based on the predefined
* constant and the selected clock source:
*
* - If SYSCLK source is HSI, SystemCoreClock will contain the HSI_VALUE(*)
*
* - If SYSCLK source is HSE, SystemCoreClock will contain the HSE_VALUE(**)
*
* - If SYSCLK source is PLL, SystemCoreClock will contain the HSE_VALUE(**)
* or HSI_VALUE(*) multiplied/divided by the PLL factors.
*
* (*) HSI_VALUE is a constant defined in stm32f0xx.h file (default value
* 8 MHz) but the real value may vary depending on the variations
* in voltage and temperature.
*
* (**) HSE_VALUE is a constant defined in stm32f0xx.h file (default value
* 8 MHz), user has to ensure that HSE_VALUE is same as the real
* frequency of the crystal used. Otherwise, this function may
* have wrong result.
*
* - The result of this function could be not correct when using fractional
* value for HSE crystal.
* @param None
* @retval None
*/
extern "C"
void SystemCoreClockUpdate (void) {
uint32_t prediv1factor, pllmull;
//! [EnumExampleSW_EN_Use]
switch (RCC.CFGR.B.SWS) {
case USEHSI: /* HSI used as system clock */
SystemCoreClock = HSI_VALUE;
break;
case USEHSE: /* HSE used as system clock */
SystemCoreClock = HSE_VALUE;
break;
case USEPLL: /* PLL used as system clock */
/* Get PLL clock source and multiplication factor */
pllmull = RCC.CFGR.B.PLLMUL + 2u;
// ...
//! [EnumExampleSW_EN_Use]
if (RCC.CFGR.B.PLLSRC == RESET) {
/* HSI oscillator clock divided by 2 selected as PLL clock entry */
SystemCoreClock = (HSI_VALUE >> 1) * pllmull;
} else {
prediv1factor = RCC.CFGR2.B.PREDIV + 1;
/* HSE oscillator clock selected as PREDIV1 clock entry */
SystemCoreClock = (HSE_VALUE / prediv1factor) * pllmull;
}
break;
default: /* HSI used as system clock */
SystemCoreClock = HSI_VALUE;
break;
}
/* Compute HCLK clock frequency */
/* Get HCLK prescaler */
pllmull = AHBPrescTable[RCC.CFGR.B.HPRE];
/* HCLK clock frequency */
SystemCoreClock >>= pllmull;
}
/**
* @brief Configures the System clock frequency, AHB/APBx prescalers and Flash
* settings.
* @note This function should be called only once the RCC clock configuration
* is reset to the default reset state (done in SystemInit() function).
* @param None
* @retval None
*/
static void SetSysClock (void) {
/* SYSCLK, HCLK, PCLK configuration */
#if defined (PLL_SOURCE_HSI)
/* At this stage the HSI is already enabled */
/* Enable Prefetch Buffer and set Flash Latency */
Flash.ACR.setbit([] (auto & r) -> auto { // C++14
r.B.PRFTBE = SET;
r.B.LATENCY = SET;
return r.R;
});
RCC.CFGR.modify([] (auto & r) -> auto {
r.B.HPRE = 0;
r.B.PPRE = 0;
r.B.PLLSRC = RESET;
r.B.PLLXTPRE = RESET;
r.B.PLLMUL = RCC_CFGR_PLLMUL12;
return r.R;
});
/* Enable PLL */
RCC.CR.B.PLLON = SET;
/* Wait till PLL is ready */
while ((RCC.CR.B.PLLRDY) == RESET);
/* Select PLL as system clock source */
RCC.CFGR.B.SW = USEPLL;
/* Wait till PLL is used as system clock source */
while (RCC.CFGR.B.SWS != USEPLL);
#else
#if defined (PLL_SOURCE_HSE)
/* Enable HSE */
RCC.CR.B.HSEON = SET;
#elif defined (PLL_SOURCE_HSE_BYPASS)
/* HSE oscillator bypassed with external clock */
RCC.CR.B.HSEON = SET;
RCC.CR.B.HSEBYP = SET;
#endif /* PLL_SOURCE_HSE */
__IO uint32_t StartUpCounter = 0;
__IO uint32_t HSEStatus;
/* Wait till HSE is ready and if Time out is reached exit */
do {
HSEStatus = RCC.CR.B.HSERDY;
StartUpCounter++;
} while ((HSEStatus == RESET) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
HSEStatus = RCC.CR.B.HSERDY;
if (HSEStatus == SET) {
/* Enable Prefetch Buffer and set Flash Latency */
Flash.ACR.setbit([] (auto & r) -> uint32_t {
r.B.PRFTBE = SET;
r.B.LATENCY = SET;
return r.R;
});
RCC.CFGR.modify([] (auto & r) -> uint32_t {
r.B.HPRE = 0;
r.B.PPRE = 0;
r.B.PLLSRC = SET;
r.B.PLLXTPRE = RESET;
r.B.PLLMUL = RCC_CFGR_PLLMUL12;
return r.R;
});
/* Enable PLL */
RCC.CR.B.PLLON = SET;
/* Wait till PLL is ready */
while ((RCC.CR.B.PLLRDY) == RESET);
/* Select PLL as system clock source */
RCC.CFGR.B.SW = USEPLL;
/* Wait till PLL is used as system clock source */
while (RCC.CFGR.B.SWS != USEPLL);
} else {
/* If HSE fails to start-up, the application will have wrong clock
configuration. User can add here some code to deal with this error */
}
#endif /* PLL_SOURCE_HSI */
}

View file

@ -1,17 +0,0 @@
#ifndef __SYSTEM_STM32F0XX_H
#define __SYSTEM_STM32F0XX_H
#ifdef __cplusplus
extern "C" {
#endif
extern uint32_t SystemCoreClock; /*!< System Clock Frequency (Core Clock) */
extern void SystemInit(void);
extern void SystemCoreClockUpdate(void);
#ifdef __cplusplus
}
#endif
#endif /*__SYSTEM_STM32F0XX_H */

View file

@ -1,110 +0,0 @@
#include "STM32F0x1.h"
#include "CortexM0.h" // NVIC_EnableIRQ
#include "gpio.h"
#include "usart.h"
extern "C" uint32_t SystemCoreClock;
static Usart * Instance = nullptr;
void Usart::irq (void) {
volatile USART1_Type::ISR_DEF status (USART1.ISR); // načti status přerušení
char tdata;
volatile char rdata;
if (status.B.TC) { // od vysílače
if (tx_ring.Read (tdata)) { // pokud máme data
USART1.TDR.R = (uint32_t) tdata & 0xFFu;// zapíšeme do výstupu
} else { // pokud ne
//USART1.CR1.B.RE = SET; // povol prijem
USART1.CR1.B.TCIE = RESET; // je nutné zakázat přerušení od vysílače
}
}
if (status.B.RXNE) { // od přijímače
rdata = (USART1.RDR.R) & 0xFFu; // načteme data
(void) rdata; // zahodime
}
}
/// Voláno z čistého C - startup.c
extern "C" void USART1_IRQHandler (void) {
if (Instance) Instance->irq();
};
//! [MembersConstructorExample]
Usart::Usart(const uint32_t baud) noexcept : BaseLayer(), tx_ring() {
//! [MembersConstructorExample]
if (Instance) return; // Chyba - jedina instance
Instance = this;
// 1. Clock Enable
RCC.APB2ENR.B.USART1EN = SET;
// 2. GPIO Alternate Config
GpioClass txp (GpioPortA, 9, GPIO_Mode_AF);
GpioClass rxp (GpioPortA, 10, GPIO_Mode_AF);
txp.setAF (1);
rxp.setAF (1);
// 4. NVIC
NVIC_EnableIRQ (USART1_IRQn);
uint32_t tmp = 0;
// 5. USART registry 8.bit bez parity
USART1.CR1.modify([] (USART1_Type::CR1_DEF & r) -> uint32_t { // pro ilustraci, co by bylo auto
r.B.TE = SET;
//r.B.RE = SET; // příjem je zde zbytečný
//r.B.RXNEIE = SET;
return r.R;
});
USART1.CR2.R = 0;
USART1.CR3.B.OVRDIS = SET;
// Tuhle část už vezmeme přímo z knihovny, jen ty hodiny zjednodušíme na SystemCoreClock
uint32_t apbclock = SystemCoreClock;
uint32_t integerdivider, fractionaldivider;
/* Determine the integer part */
if (USART1.CR1.B.OVER8 != RESET) {
/* Integer part computing in case Oversampling mode is 8 Samples */
integerdivider = ((25u * apbclock) / (2u * (baud)));
} else {
/* Integer part computing in case Oversampling mode is 16 Samples */
integerdivider = ((25u * apbclock) / (4u * (baud)));
}
tmp = (integerdivider / 100u) << 4;
/* Determine the fractional part */
fractionaldivider = integerdivider - (100u * (tmp >> 4));
/* Implement the fractional part in the register */
if (USART1.CR1.B.OVER8 != RESET) {
tmp |= ((((fractionaldivider * 8u ) + 50u) / 100u)) & ((uint8_t)0x07u);
} else {
tmp |= ((((fractionaldivider * 16u) + 50u) / 100u)) & ((uint8_t)0x0Fu);
}
/* Write to USART BRR */
USART1.BRR.R = (uint16_t)tmp;
USART1.CR1.B.UE = SET; // nakonec povolit globálně
}
//! [VirtualMethodBottom]
uint32_t Usart::Down (const char * data, const uint32_t len) {
uint32_t res; // výsledek, musí žít i po ukončení smyčky
for (res=0; res<len; res++) if (!tx_ring.Write(data[res])) break;
USART1.CR1.B.TCIE = SET; // po povolení přerušení okamžitě přeruší
return res;
}
//! [VirtualMethodBottom]
void Usart::SetHalfDuplex (const bool on) const {
USART1.CR1.B.UE = RESET; // zakázat, jinak nelze nastavovat
if (on) USART1.CR3.B.HDSEL = SET; // poloduplex on
else USART1.CR3.B.HDSEL = RESET; // poloduplex off
USART1.CR1.B.UE = SET; // nakonec povolit globálně
}
void Usart::SetRS485 (const bool polarity) const {
USART1.CR1.B.UE = RESET; // zakázat, jinak nelze nastavovat
// Nastavit pin DE (RTS)
GpioClass de (GpioPortA, 12u, GPIO_Mode_AF);
de.setAF (1u);
// Nastavení driveru
USART1.CR3.B.DEM = SET; // povolit DE v USARTu
if (polarity) USART1.CR3.B.DEP = SET;
else USART1.CR3.B.DEP = RESET;
// A nakonec doby vybavení (přesah) - to je hodně užitečné
//! [LambdaExampleUsage]
USART1.CR1.modify([] (auto & r) -> auto {
r.B.DEAT = 1u; // doba vybavení před start bitem - 16 ~= 1 bit, 0..31
r.B.DEDT = 1u; // doba vybavení po stop bitu - 16 ~= 1 bit, 0..31
return r.R;
});
//! [LambdaExampleUsage]
USART1.CR1.B.UE = SET;
}