From a9351ebff7a2842866bb06a100606512f0ff0432 Mon Sep 17 00:00:00 2001 From: Kizarm Date: Mon, 4 Mar 2024 22:23:14 +0100 Subject: [PATCH] hdo base --- ch32v003/system.cpp | 30 ++++++++++-- hdo/Makefile | 52 +++++++++++++++++++++ hdo/adcclass.cpp | 108 ++++++++++++++++++++++++++++++++++++++++++++ hdo/adcclass.h | 21 +++++++++ hdo/ch32v003 | 1 + hdo/common | 1 + hdo/main.cpp | 56 +++++++++++++++++++++++ 7 files changed, 266 insertions(+), 3 deletions(-) create mode 100644 hdo/Makefile create mode 100644 hdo/adcclass.cpp create mode 100644 hdo/adcclass.h create mode 120000 hdo/ch32v003 create mode 120000 hdo/common create mode 100644 hdo/main.cpp diff --git a/ch32v003/system.cpp b/ch32v003/system.cpp index 7e3669f..b8ea9ae 100644 --- a/ch32v003/system.cpp +++ b/ch32v003/system.cpp @@ -5,9 +5,31 @@ enum CLKSRC : uint32_t { CLK_HSE, CLK_PLL, }; - +// HSE i HSI mají frekvenci 24 MHz 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 { r.B.HSITRIM = 0x10u; r.B.HSION = SET; @@ -16,9 +38,11 @@ void SystemInit(void) { r.B.PLLON = SET; return r.R; }); +#endif // USE_HSE FLASH.ACTLR.B.LATENCY = SET; RCC.INTR.R = 0x009F0000u; // clear interrupts while (RCC.CTLR.B.PLLRDY == RESET); - RCC.CFGR0.B.SW = CLK_PLL; + // USE PLL - zdvojení frekvence, tj. 48 MHz + RCC.CFGR0.B.SW = CLK_PLL ; while (RCC.CFGR0.B.SWS != CLK_PLL); } diff --git a/hdo/Makefile b/hdo/Makefile new file mode 100644 index 0000000..ca6778c --- /dev/null +++ b/hdo/Makefile @@ -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 diff --git a/hdo/adcclass.cpp b/hdo/adcclass.cpp new file mode 100644 index 0000000..0868fd8 --- /dev/null +++ b/hdo/adcclass.cpp @@ -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 (& ADC1.RDATAR); + // Configure the memory address + DMA1.MADDR1.R = reinterpret_cast (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); +} diff --git a/hdo/adcclass.h b/hdo/adcclass.h new file mode 100644 index 0000000..a49481e --- /dev/null +++ b/hdo/adcclass.h @@ -0,0 +1,21 @@ +#ifndef ADCCLASS_H +#define ADCCLASS_H +#include + +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 diff --git a/hdo/ch32v003 b/hdo/ch32v003 new file mode 120000 index 0000000..0bcf9a1 --- /dev/null +++ b/hdo/ch32v003 @@ -0,0 +1 @@ +../ch32v003/ \ No newline at end of file diff --git a/hdo/common b/hdo/common new file mode 120000 index 0000000..8332399 --- /dev/null +++ b/hdo/common @@ -0,0 +1 @@ +../common/ \ No newline at end of file diff --git a/hdo/main.cpp b/hdo/main.cpp new file mode 100644 index 0000000..faca227 --- /dev/null +++ b/hdo/main.cpp @@ -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 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>= 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; +}