Compare commits
2 commits
442fb2ee2a
...
be6759c990
Author | SHA1 | Date | |
---|---|---|---|
|
be6759c990 | ||
|
db1aff0e6c |
25 changed files with 11862 additions and 22 deletions
|
@ -1,8 +1,8 @@
|
||||||
#include "system.h"
|
#include "system.h"
|
||||||
#include "oneway.h"
|
#include "oneway.h"
|
||||||
#include "adcclass.h"
|
#include "adcdma.h"
|
||||||
|
|
||||||
static AdcClass * pInstance = nullptr;
|
static AdcDma * 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 {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
AdcClass::AdcClass() noexcept : pL (buffer), pH (buffer + HALF_LEN), dst (nullptr) {
|
AdcDma::AdcDma() noexcept : pL (buffer), pH (buffer + HALF_LEN), dst (nullptr) {
|
||||||
pInstance = this;
|
pInstance = this;
|
||||||
EnableClock ();
|
EnableClock ();
|
||||||
Timer2Init (1000u);
|
Timer2Init (1000u);
|
||||||
|
@ -101,7 +101,7 @@ AdcClass::AdcClass() noexcept : pL (buffer), pH (buffer + HALF_LEN), dst (nullpt
|
||||||
// start timer
|
// start timer
|
||||||
TIM2.CTLR1.B.CEN = SET;
|
TIM2.CTLR1.B.CEN = SET;
|
||||||
}
|
}
|
||||||
inline void AdcClass::send(const bool b) {
|
inline void AdcDma::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);
|
10
ch32v003/config.h
Normal file
10
ch32v003/config.h
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
#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
|
80
ch32v003/usart.cpp
Normal file
80
ch32v003/usart.cpp
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
#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 {
|
||||||
|
}
|
||||||
|
|
|
@ -1,21 +1,21 @@
|
||||||
#ifndef ADCCLASS_H
|
#ifndef ADCDMA_H
|
||||||
#define ADCCLASS_H
|
#define ADCDMA_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 AdcClass {
|
class AdcDma {
|
||||||
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 AdcClass () noexcept;
|
explicit AdcDma () noexcept;
|
||||||
void attach (OneWay & d) { dst = & d; }
|
void attach (OneWay & d) { dst = & d; }
|
||||||
void send (const bool b);
|
void send (const bool b);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // ADCCLASS_H
|
#endif // ADCDMA_H
|
21
common/usart.h
Normal file
21
common/usart.h
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
#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
|
13
hdo/Makefile
13
hdo/Makefile
|
@ -1,6 +1,9 @@
|
||||||
# ch32v003
|
# ch32v003 | stm32f051
|
||||||
TARGET?= ch32v003
|
TARGET?= ch32v003
|
||||||
|
#TARGET?= stm32f051
|
||||||
TOOL ?= gcc
|
TOOL ?= gcc
|
||||||
|
# do not use for ch32v003
|
||||||
|
#TOOL ?= clang
|
||||||
|
|
||||||
PRJ = example
|
PRJ = example
|
||||||
|
|
||||||
|
@ -16,8 +19,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 adcclass.o hdo.o
|
OBJS = main.o adcdma.o hdo.o
|
||||||
OBJS += usartclass.o print.o
|
OBJS += usart.o print.o
|
||||||
|
|
||||||
include $(TARGET)/$(TOOL).mk
|
include $(TARGET)/$(TOOL).mk
|
||||||
BOBJS = $(addprefix $(BLD),$(OBJS))
|
BOBJS = $(addprefix $(BLD),$(OBJS))
|
||||||
|
@ -44,9 +47,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: $(PRJ).elf
|
flash: $(BLD) $(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
|
.PHONY: all clean flash
|
||||||
|
|
|
@ -37,8 +37,8 @@ void Hdo::pass () {
|
||||||
cout << value << " \r";
|
cout << value << " \r";
|
||||||
value -= trigger;
|
value -= trigger;
|
||||||
|
|
||||||
if (value > 0) led << false; // LED je zapojená proti VCC
|
if (value > 0) led << SW__ON; // LED je zapojená proti VCC
|
||||||
else led << true;
|
else led << SW_OFF;
|
||||||
// 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
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
#ifndef HDO_H
|
#ifndef HDO_H
|
||||||
#define HDO_H
|
#define HDO_H
|
||||||
#include "gpio.h"
|
#include "gpio.h"
|
||||||
#include "usartclass.h"
|
#include "usart.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ě.
|
||||||
|
@ -28,7 +29,7 @@ static constexpr int TBUFLEN = 64;
|
||||||
|
|
||||||
class Hdo : public OneWay {
|
class Hdo : public OneWay {
|
||||||
GpioClass led, relay;
|
GpioClass led, relay;
|
||||||
UsartClass serial;
|
Usart serial;
|
||||||
Print cout;
|
Print cout;
|
||||||
FIFO<int, 8> data;
|
FIFO<int, 8> data;
|
||||||
const int coeff;
|
const int coeff;
|
||||||
|
@ -44,7 +45,7 @@ class Hdo : public OneWay {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit Hdo (const char * command) noexcept : OneWay (),
|
explicit Hdo (const char * command) noexcept : OneWay (),
|
||||||
led (GPIOD, 2), relay (GPIOD, 4), serial (115200u), cout (DEC), data(), coeff (1706), trigger (0x4000),
|
led (LED_CFG), relay (REL_CFG), 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.
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#include "adcclass.h"
|
#include "adcdma.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 AdcClass adc;
|
static AdcDma adc;
|
||||||
static Hdo hdo ("A1B8DP1");
|
static Hdo hdo ("A1B8DP1");
|
||||||
int main () {
|
int main () {
|
||||||
adc.attach(hdo);
|
adc.attach(hdo);
|
||||||
for (;;) {
|
for (;;) {
|
||||||
|
|
1
hdo/stm32f051
Symbolic link
1
hdo/stm32f051
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
../stm32f051/
|
139
stm32f051/CortexM0.h
Normal file
139
stm32f051/CortexM0.h
Normal file
|
@ -0,0 +1,139 @@
|
||||||
|
#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
|
10621
stm32f051/STM32F0x1.h
Normal file
10621
stm32f051/STM32F0x1.h
Normal file
File diff suppressed because it is too large
Load diff
119
stm32f051/adcdma.cpp
Normal file
119
stm32f051/adcdma.cpp
Normal file
|
@ -0,0 +1,119 @@
|
||||||
|
#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);
|
||||||
|
}
|
30
stm32f051/clang.mk
Normal file
30
stm32f051/clang.mk
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
# 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
|
||||||
|
|
10
stm32f051/config.h
Normal file
10
stm32f051/config.h
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
#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
|
21
stm32f051/gcc.mk
Normal file
21
stm32f051/gcc.mk
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
# 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
|
||||||
|
|
||||||
|
|
26
stm32f051/gpio.cpp
Normal file
26
stm32f051/gpio.cpp
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
#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);
|
||||||
|
}
|
||||||
|
|
142
stm32f051/gpio.h
Normal file
142
stm32f051/gpio.h
Normal file
|
@ -0,0 +1,142 @@
|
||||||
|
#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
|
94
stm32f051/script.ld
Normal file
94
stm32f051/script.ld
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
/*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* 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) }
|
||||||
|
}
|
163
stm32f051/startup.c
Normal file
163
stm32f051/startup.c
Normal file
|
@ -0,0 +1,163 @@
|
||||||
|
#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");
|
||||||
|
}
|
232
stm32f051/system.cpp
Normal file
232
stm32f051/system.cpp
Normal file
|
@ -0,0 +1,232 @@
|
||||||
|
#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 */
|
||||||
|
}
|
17
stm32f051/system.h
Normal file
17
stm32f051/system.h
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
#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 */
|
||||||
|
|
110
stm32f051/usart.cpp
Normal file
110
stm32f051/usart.cpp
Normal file
|
@ -0,0 +1,110 @@
|
||||||
|
#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;
|
||||||
|
}
|
Loading…
Reference in a new issue