hdo base
This commit is contained in:
parent
40cc0ee799
commit
a9351ebff7
7 changed files with 266 additions and 3 deletions
|
@ -5,9 +5,31 @@ enum CLKSRC : uint32_t {
|
||||||
CLK_HSE,
|
CLK_HSE,
|
||||||
CLK_PLL,
|
CLK_PLL,
|
||||||
};
|
};
|
||||||
|
// HSE i HSI mají frekvenci 24 MHz
|
||||||
void SystemInit(void) {
|
void SystemInit(void) {
|
||||||
RCC.CFGR0.R = 0u; // prescaler OFF
|
RCC.CFGR0.R = 0u; // prescaler OFF
|
||||||
|
#if USE_HSE
|
||||||
|
RCC.CTLR.modify([](RCC_Type::CTLR_DEF & r) -> auto {
|
||||||
|
r.B.HSITRIM = 0x10u;
|
||||||
|
r.B.HSION = SET;
|
||||||
|
r.B.HSEON = SET;
|
||||||
|
r.B.HSEBYP = RESET; // krystal
|
||||||
|
r.B.CSSON = SET;
|
||||||
|
r.B.PLLON = RESET;
|
||||||
|
return r.R;
|
||||||
|
});
|
||||||
|
while (RCC.CTLR.B.HSERDY == RESET);
|
||||||
|
RCC.CFGR0.modify([](RCC_Type::CFGR0_DEF & r) -> auto {
|
||||||
|
r.B.SW = CLK_HSE;
|
||||||
|
r.B.PLLSRC = SET; // write only when PLL is off
|
||||||
|
return r.R;
|
||||||
|
});
|
||||||
|
RCC.CTLR.modify([](RCC_Type::CTLR_DEF & r) -> auto {
|
||||||
|
//r.B.HSION = RESET; // je možné vypnout, ale není to dobrý nápad, pak je nutný unbrick
|
||||||
|
r.B.PLLON = SET;
|
||||||
|
return r.R;
|
||||||
|
});
|
||||||
|
#else // HSI
|
||||||
RCC.CTLR.modify([](RCC_Type::CTLR_DEF & r) -> auto {
|
RCC.CTLR.modify([](RCC_Type::CTLR_DEF & r) -> auto {
|
||||||
r.B.HSITRIM = 0x10u;
|
r.B.HSITRIM = 0x10u;
|
||||||
r.B.HSION = SET;
|
r.B.HSION = SET;
|
||||||
|
@ -16,9 +38,11 @@ void SystemInit(void) {
|
||||||
r.B.PLLON = SET;
|
r.B.PLLON = SET;
|
||||||
return r.R;
|
return r.R;
|
||||||
});
|
});
|
||||||
|
#endif // USE_HSE
|
||||||
FLASH.ACTLR.B.LATENCY = SET;
|
FLASH.ACTLR.B.LATENCY = SET;
|
||||||
RCC.INTR.R = 0x009F0000u; // clear interrupts
|
RCC.INTR.R = 0x009F0000u; // clear interrupts
|
||||||
while (RCC.CTLR.B.PLLRDY == RESET);
|
while (RCC.CTLR.B.PLLRDY == RESET);
|
||||||
|
// USE PLL - zdvojení frekvence, tj. 48 MHz
|
||||||
RCC.CFGR0.B.SW = CLK_PLL ;
|
RCC.CFGR0.B.SW = CLK_PLL ;
|
||||||
while (RCC.CFGR0.B.SWS != CLK_PLL);
|
while (RCC.CFGR0.B.SWS != CLK_PLL);
|
||||||
}
|
}
|
||||||
|
|
52
hdo/Makefile
Normal file
52
hdo/Makefile
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
# ch32v003
|
||||||
|
TARGET?= ch32v003
|
||||||
|
TOOL ?= gcc
|
||||||
|
|
||||||
|
PRJ = example
|
||||||
|
|
||||||
|
VPATH = . ./$(TARGET) ./common
|
||||||
|
BLD = ./build/
|
||||||
|
DFLAGS = -d
|
||||||
|
LFLAGS = -g
|
||||||
|
LDLIBS =
|
||||||
|
BFLAGS = --strip-unneeded
|
||||||
|
|
||||||
|
CFLAGS = -MMD -Wall -ggdb -fno-exceptions -ffunction-sections -fdata-sections
|
||||||
|
CFLAGS+= -I. -I./common -I./$(TARGET) -I/usr/include/newlib -DUSE_HSE=1
|
||||||
|
DEL = rm -f
|
||||||
|
|
||||||
|
# zdrojaky
|
||||||
|
OBJS = main.o adcclass.o
|
||||||
|
OBJS += usartclass.o print.o
|
||||||
|
|
||||||
|
include $(TARGET)/$(TOOL).mk
|
||||||
|
BOBJS = $(addprefix $(BLD),$(OBJS))
|
||||||
|
|
||||||
|
all: $(BLD) $(PRJ).elf
|
||||||
|
# ... atd.
|
||||||
|
-include $(BLD)*.d
|
||||||
|
# linker
|
||||||
|
$(PRJ).elf: $(BOBJS)
|
||||||
|
-@echo [LD $(TOOL),$(TARGET)] $@
|
||||||
|
@$(LD) $(LFLAGS) -o $(PRJ).elf $(BOBJS) $(LDLIBS)
|
||||||
|
-@echo "size:"
|
||||||
|
@$(SIZE) $(PRJ).elf
|
||||||
|
-@echo "listing:"
|
||||||
|
$(DUMP) $(DFLAGS) $(PRJ).elf > $(PRJ).lst
|
||||||
|
-@echo "OK."
|
||||||
|
$(COPY) $(BFLAGS) -O binary $(PRJ).elf $(PRJ).bin
|
||||||
|
# preloz co je potreba
|
||||||
|
$(BLD)%.o: %.c
|
||||||
|
-@echo [CC $(TOOL),$(TARGET)] $@
|
||||||
|
@$(CC) -c $(CFLAGS) $< -o $@
|
||||||
|
$(BLD)%.o: %.cpp
|
||||||
|
-@echo [CX $(TOOL),$(TARGET)] $@
|
||||||
|
@$(CXX) -std=c++17 -fno-rtti -c $(CFLAGS) $< -o $@
|
||||||
|
$(BLD):
|
||||||
|
mkdir $(BLD)
|
||||||
|
flash: $(PRJ).elf
|
||||||
|
minichlink -w $(PRJ).bin flash -b
|
||||||
|
# vycisti
|
||||||
|
clean:
|
||||||
|
$(DEL) $(BLD)* *.lst *.bin *.elf *.map sin.c *~
|
||||||
|
.PHONY: all clean
|
108
hdo/adcclass.cpp
Normal file
108
hdo/adcclass.cpp
Normal file
|
@ -0,0 +1,108 @@
|
||||||
|
#include "system.h"
|
||||||
|
#include "oneway.h"
|
||||||
|
#include "adcclass.h"
|
||||||
|
|
||||||
|
static AdcClass * pInstance = nullptr;
|
||||||
|
|
||||||
|
extern "C" void DMA1_Channel1_IRQHandler( void ) __attribute__((interrupt));
|
||||||
|
void DMA1_Channel1_IRQHandler( void ) {
|
||||||
|
DMA1_Type::INTFR_DEF state (DMA1.INTFR);
|
||||||
|
DMA1.INTFCR.R = state.R; // clear all
|
||||||
|
if (!pInstance) return;
|
||||||
|
if (state.B.HTIF1 != RESET) pInstance->send (false);
|
||||||
|
else if (state.B.TCIF1 != RESET) pInstance->send (true);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void EnableClock (void) noexcept {
|
||||||
|
// Enable DMA
|
||||||
|
RCC.AHBPCENR.modify([](RCC_Type::AHBPCENR_DEF & r) -> auto {
|
||||||
|
r.B.SRAMEN = SET;
|
||||||
|
r.B.DMA1EN = SET;
|
||||||
|
return r.R;
|
||||||
|
});
|
||||||
|
// Enable ADC + GPIOC
|
||||||
|
RCC.APB2PCENR.modify([](RCC_Type::APB2PCENR_DEF & r) -> auto {
|
||||||
|
r.B.ADC1EN = SET;
|
||||||
|
r.B.IOPCEN = SET;
|
||||||
|
return r.R;
|
||||||
|
});
|
||||||
|
RCC.APB1PCENR.B.TIM2EN = SET; // Enable TIM2
|
||||||
|
RCC.CFGR0.B.ADCPRE = 0u; // 000xx: AHBCLK divided by 2 as ADC clock (24 MHz max).
|
||||||
|
// PIN PC4 / A2
|
||||||
|
GPIOC.CFGLR.modify([](GPIOA_Type::CFGLR_DEF & r) -> auto {
|
||||||
|
r.B.MODE4 = 0u;
|
||||||
|
r.B.CNF4 = 0u;
|
||||||
|
return r.R;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
static inline void Timer2Init (uint32_t us) noexcept {
|
||||||
|
TIM2.PSC.R = 47u; // 1 MHz Fs
|
||||||
|
TIM2.ATRLR.R = us - 1u;
|
||||||
|
// TRGO update for ADC
|
||||||
|
TIM2.CTLR2.B.MMS = 2u;
|
||||||
|
}
|
||||||
|
static inline void AdcCalibrate (void) noexcept {
|
||||||
|
// RESET
|
||||||
|
RCC.APB2PRSTR.B.ADC1RST = SET;
|
||||||
|
RCC.APB2PRSTR.B.ADC1RST = RESET;
|
||||||
|
// set channels
|
||||||
|
ADC1.RSQR3.B.SQ1 = 2u; // CH2
|
||||||
|
ADC1.RSQR1.B.L = 0u; // 1 regular conversion
|
||||||
|
ADC1.SAMPTR2_CHARGE2.B.SMP2_TKCG2 = 7u;
|
||||||
|
ADC1.CTLR1.B.SCAN = SET;
|
||||||
|
|
||||||
|
ADC1.CTLR2.B.ADON = SET;
|
||||||
|
ADC1.CTLR2.B.RSTCAL = SET; // Launch the calibration by setting RSTCAL
|
||||||
|
while (ADC1.CTLR2.B.RSTCAL != RESET); // Wait until RSTCAL=0
|
||||||
|
ADC1.CTLR2.B.CAL = SET; // Launch the calibration by setting CAL
|
||||||
|
while (ADC1.CTLR2.B.CAL != RESET); // Wait until CAL=0
|
||||||
|
}
|
||||||
|
typedef __SIZE_TYPE__ size_t;
|
||||||
|
static inline void Dma1Ch1Init (void * ptr) noexcept {
|
||||||
|
// Configure the peripheral data register address
|
||||||
|
DMA1.PADDR1.R = reinterpret_cast<size_t> (& ADC1.RDATAR);
|
||||||
|
// Configure the memory address
|
||||||
|
DMA1.MADDR1.R = reinterpret_cast<size_t> (ptr);
|
||||||
|
// Configure the number of DMA tranfer to be performs on DMA channel 1
|
||||||
|
DMA1.CNTR1 .R = FULL_LEN;
|
||||||
|
// Configure increment, size, interrupts and circular mode
|
||||||
|
DMA1.CFGR1.modify([] (DMA1_Type::CFGR1_DEF & r) -> auto {
|
||||||
|
r.B.PL = 3u; // highest priority
|
||||||
|
r.B.MEM2MEM = RESET; // periferal -> memory
|
||||||
|
r.B.MINC = SET; // memory increment
|
||||||
|
r.B.MSIZE = 1u; // 16-bit
|
||||||
|
r.B.PSIZE = 1u; // 16-bit
|
||||||
|
r.B.HTIE = SET; // INT Enable HALF
|
||||||
|
r.B.TCIE = SET; // INT Enable FULL
|
||||||
|
r.B.CIRC = SET; // Circular MODE
|
||||||
|
// Enable DMA Channel 1
|
||||||
|
r.B.EN = SET;
|
||||||
|
return r.R;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
static inline void AdcPostInit (void) noexcept {
|
||||||
|
ADC1.CTLR2.modify([](ADC1_Type::CTLR2_DEF & r) -> auto {
|
||||||
|
r.B.DMA = SET;
|
||||||
|
r.B.EXTTRIG = SET;
|
||||||
|
r.B.EXTSEL = 3u; // TRGO event of timer 2
|
||||||
|
r.B.SWSTART = SET;
|
||||||
|
return r.R;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
AdcClass::AdcClass() noexcept : pL (buffer), pH (buffer + HALF_LEN), dst (nullptr) {
|
||||||
|
pInstance = this;
|
||||||
|
EnableClock ();
|
||||||
|
Timer2Init (1000u);
|
||||||
|
NVIC.EnableIRQ (DMA1_Channel1_IRQn);
|
||||||
|
AdcCalibrate();
|
||||||
|
Dma1Ch1Init (buffer);
|
||||||
|
AdcPostInit ();
|
||||||
|
// start timer
|
||||||
|
TIM2.CTLR1.B.CEN = SET;
|
||||||
|
}
|
||||||
|
inline void AdcClass::send(const bool b) {
|
||||||
|
if (!dst) return;
|
||||||
|
if (b) dst->Send (pH, HALF_LEN);
|
||||||
|
else dst->Send (pL, HALF_LEN);
|
||||||
|
}
|
21
hdo/adcclass.h
Normal file
21
hdo/adcclass.h
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
#ifndef ADCCLASS_H
|
||||||
|
#define ADCCLASS_H
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
class OneWay;
|
||||||
|
static constexpr unsigned HALF_LEN = 120u;
|
||||||
|
static constexpr unsigned FULL_LEN = HALF_LEN * 2u;
|
||||||
|
|
||||||
|
class AdcClass {
|
||||||
|
uint16_t * pL;
|
||||||
|
uint16_t * pH;
|
||||||
|
uint16_t buffer [FULL_LEN];
|
||||||
|
OneWay * dst;
|
||||||
|
public:
|
||||||
|
explicit AdcClass () noexcept;
|
||||||
|
void attach (OneWay & d) { dst = & d; }
|
||||||
|
void send (const bool b);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // ADCCLASS_H
|
1
hdo/ch32v003
Symbolic link
1
hdo/ch32v003
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
../ch32v003/
|
1
hdo/common
Symbolic link
1
hdo/common
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
../common/
|
56
hdo/main.cpp
Normal file
56
hdo/main.cpp
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
#include "gpio.h"
|
||||||
|
#include "usartclass.h"
|
||||||
|
#include "print.h"
|
||||||
|
#include "adcclass.h"
|
||||||
|
#include "oneway.h"
|
||||||
|
static constexpr int ISHIFT = 12;
|
||||||
|
//////////////////////////////////////
|
||||||
|
class Process : public OneWay {
|
||||||
|
GpioClass led;
|
||||||
|
UsartClass serial;
|
||||||
|
Print cout;
|
||||||
|
FIFO<int, 8> data;
|
||||||
|
const int coeff, trigger;
|
||||||
|
public:
|
||||||
|
explicit Process () noexcept : OneWay (),
|
||||||
|
led (GPIOD, 4), serial (115200u), cout (DEC), data(), coeff (1706), trigger (0x1000) {
|
||||||
|
|
||||||
|
cout += serial;
|
||||||
|
}
|
||||||
|
unsigned Send (uint16_t * const ptr, const unsigned len) override {
|
||||||
|
int q2 = 0, q1 = 0;
|
||||||
|
for (unsigned n=0; n<len; n++) {
|
||||||
|
// Vlastní Goertzelův algoritmus.
|
||||||
|
int q0 = coeff * q1;
|
||||||
|
// pokud byl coeff zvětšen, je třeba to tu zase zmenšit
|
||||||
|
q0 >>= ISHIFT; // zmenšení pro int
|
||||||
|
q0 += ((int) ptr [n]) - q2; // vlastní výpočet
|
||||||
|
q2 = q1; // posuv o vzorek
|
||||||
|
q1 = q0; // (rekurze)
|
||||||
|
}
|
||||||
|
int rv = q1 * q2;
|
||||||
|
rv *= -coeff;
|
||||||
|
rv >>= ISHIFT; // tady nutno zmenšit tak, jak bylo zvětšeno v calc_coeff()
|
||||||
|
rv += q1 * q1 + q2 * q2; // výkon by byl sqrt (rv), není nutné počítat, napětí stačí
|
||||||
|
data.Write (rv); // dáme do FIFO, vybíráme v main()
|
||||||
|
q1 = 0; q2 = 0;
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
void pass () {
|
||||||
|
int avg;
|
||||||
|
if (!data.Read (avg)) return;
|
||||||
|
cout << avg << EOL;
|
||||||
|
if (avg > trigger) led << true;
|
||||||
|
else led << false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
//////////////////////////////////////
|
||||||
|
static AdcClass adc;
|
||||||
|
static Process out;
|
||||||
|
int main () {
|
||||||
|
adc.attach(out);
|
||||||
|
for (;;) {
|
||||||
|
out.pass();
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
Reference in a new issue