Compare commits
No commits in common. "153ccf570b542c6b5d06a369d9d6399e36b97308" and "a8fb67d6104e0c84c36dea936fd6af1f298a4ba8" have entirely different histories.
153ccf570b
...
a8fb67d610
11 changed files with 0 additions and 503 deletions
|
@ -8958,7 +8958,6 @@ struct USART1_Type { /*!< Universal synchronous asynchronous receiver tran
|
||||||
} B;
|
} B;
|
||||||
__IO uint32_t R;
|
__IO uint32_t R;
|
||||||
explicit STATR_DEF () noexcept { R = 0x000000c0u; }
|
explicit STATR_DEF () noexcept { R = 0x000000c0u; }
|
||||||
explicit STATR_DEF (volatile STATR_DEF & o) noexcept { R = o.R; };
|
|
||||||
template<typename F> void setbit (F f) volatile {
|
template<typename F> void setbit (F f) volatile {
|
||||||
STATR_DEF r;
|
STATR_DEF r;
|
||||||
R = f (r);
|
R = f (r);
|
||||||
|
|
|
@ -1,85 +0,0 @@
|
||||||
#include "system.h"
|
|
||||||
#include "usart.h"
|
|
||||||
static Usart * pInstance = nullptr;
|
|
||||||
static constexpr unsigned HCLK = SYSTEM_CORE_CLOCK;
|
|
||||||
|
|
||||||
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.IOPAEN = SET;
|
|
||||||
//r.B.AFIOEN = SET;
|
|
||||||
return r.R;
|
|
||||||
});
|
|
||||||
// 2. GPIO Alternate Config - default TX/PA9, RX/PA10
|
|
||||||
GPIOA.CFGHR.modify([](GPIOA_Type::CFGHR_DEF & r) -> auto {
|
|
||||||
r.B.MODE9 = 1u;
|
|
||||||
r.B.CNF9 = 2u; // or 3u for open drain
|
|
||||||
r.B.MODE10 = 0u;
|
|
||||||
r.B.CNF10 = 1u; // floating input
|
|
||||||
return r.R;
|
|
||||||
});
|
|
||||||
RCC.APB2PRSTR.B.USART1RST = SET;
|
|
||||||
RCC.APB2PRSTR.B.USART1RST = RESET;
|
|
||||||
// 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.modify ([](USART1_Type::CTLR2_DEF & r) -> auto {
|
|
||||||
r.B.STOP = 0u;
|
|
||||||
return r.R;
|
|
||||||
});
|
|
||||||
const uint32_t tmp = HCLK / _baud;
|
|
||||||
USART1.BRR.R = tmp;
|
|
||||||
// NVIC
|
|
||||||
NVIC.EnableIRQ (USART1_IRQn);
|
|
||||||
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,85 +0,0 @@
|
||||||
#include "print.h"
|
|
||||||
|
|
||||||
#define sleep()
|
|
||||||
|
|
||||||
static const char * hexStr = "0123456789ABCDEF";
|
|
||||||
static const uint16_t numLen[] = {1, 32, 1, 11, 8, 0};
|
|
||||||
|
|
||||||
Print::Print (PrintBases b) : BaseLayer () {
|
|
||||||
base = b;
|
|
||||||
}
|
|
||||||
// Výstup blokujeme podle toho, co se vrací ze spodní vrstvy
|
|
||||||
uint32_t Print::BlockDown (const char * buf, uint32_t len) {
|
|
||||||
uint32_t n, ofs = 0, req = len;
|
|
||||||
for (;;) {
|
|
||||||
// spodní vrstva může vrátit i nulu, pokud je FIFO plné
|
|
||||||
n = BaseLayer::Down (buf + ofs, req);
|
|
||||||
ofs += n; // Posuneme ukazatel
|
|
||||||
req -= n; // Zmenšíme další požadavek
|
|
||||||
if (!req) break;
|
|
||||||
sleep(); // A klidně můžeme spát
|
|
||||||
}
|
|
||||||
return ofs;
|
|
||||||
}
|
|
||||||
|
|
||||||
Print& Print::operator<< (const char * str) {
|
|
||||||
uint32_t i = 0;
|
|
||||||
while (str[i++]); // strlen
|
|
||||||
BlockDown (str, --i);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
Print& Print::operator<< (const int num) {
|
|
||||||
uint32_t i = BUFLEN;
|
|
||||||
|
|
||||||
if (base == DEC) {
|
|
||||||
unsigned int u;
|
|
||||||
if (num < 0) u = -num;
|
|
||||||
else u = num;
|
|
||||||
do {
|
|
||||||
// Knihovní div() je nevhodné - dělí 2x.
|
|
||||||
// Přímočaré a funkční řešení
|
|
||||||
uint32_t rem;
|
|
||||||
rem = u % (unsigned) DEC; // 1.dělení
|
|
||||||
u = u / (unsigned) DEC; // 2.dělení
|
|
||||||
buf [--i] = hexStr [rem];
|
|
||||||
} while (u);
|
|
||||||
if (num < 0) buf [--i] = '-';
|
|
||||||
} else {
|
|
||||||
uint32_t m = (1U << (uint32_t) base) - 1U;
|
|
||||||
uint32_t l = (uint32_t) numLen [(int) base];
|
|
||||||
uint32_t u = (uint32_t) num;
|
|
||||||
for (unsigned n=0; n<l; n++) {
|
|
||||||
buf [--i] = hexStr [u & m];
|
|
||||||
u >>= (unsigned) base;
|
|
||||||
}
|
|
||||||
if (base == BIN) buf [--i] = 'b';
|
|
||||||
if (base == HEX) buf [--i] = 'x';
|
|
||||||
buf [--i] = '0';
|
|
||||||
}
|
|
||||||
BlockDown (buf+i, BUFLEN-i);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
Print& Print::operator<< (const PrintBases num) {
|
|
||||||
base = num;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
void Print::out (const void * p, uint32_t l) {
|
|
||||||
const unsigned char* q = (const unsigned char*) p;
|
|
||||||
unsigned char uc;
|
|
||||||
uint32_t k, n = 0;
|
|
||||||
for (uint32_t i=0; i<l; i++) {
|
|
||||||
uc = q[i];
|
|
||||||
buf[n++] = '<';
|
|
||||||
k = uc >> 4;
|
|
||||||
buf[n++] = hexStr [k];
|
|
||||||
k = uc & 0x0f;
|
|
||||||
buf[n++] = hexStr [k];
|
|
||||||
buf[n++] = '>';
|
|
||||||
}
|
|
||||||
buf[n++] = '\r';
|
|
||||||
buf[n++] = '\n';
|
|
||||||
BlockDown (buf, n);
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,73 +0,0 @@
|
||||||
#ifndef PRINT_H
|
|
||||||
#define PRINT_H
|
|
||||||
|
|
||||||
#include "baselayer.h"
|
|
||||||
|
|
||||||
#define EOL "\r\n"
|
|
||||||
#define BUFLEN 64
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @file
|
|
||||||
* @brief Něco jako ostream.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
/// Základy pro zobrazení čísla.
|
|
||||||
enum PrintBases {
|
|
||||||
BIN=1, OCT=3, DEC=10, HEX=4
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @class Print
|
|
||||||
* @brief Třída pro výpisy do Down().
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* V main pak přibude jen definice instance této třídy
|
|
||||||
* @code
|
|
||||||
static Print print;
|
|
||||||
* @endcode
|
|
||||||
* a ukázka, jak se s tím pracuje:
|
|
||||||
* @snippet main.cpp Main print example
|
|
||||||
* Nic na tom není - operátor << má přetížení pro string, číslo a volbu formátu čísla (enum PrintBases).
|
|
||||||
* Výstup je pak do bufferu a aby nám to "neutíkalo", tedy aby se vypsalo vše,
|
|
||||||
* zavedeme blokování, vycházející z toho, že spodní třída vrátí jen počet bytů,
|
|
||||||
* které skutečně odeslala. Při čekání spí, takže nepoužívat v přerušení.
|
|
||||||
* @snippet src/print.cpp Block example
|
|
||||||
* Toto blokování pak není použito ve vrchních třídách stacku,
|
|
||||||
* blokovaná metoda je BlockDown(). Pokud bychom použili přímo Down(), blokování by pak
|
|
||||||
* používaly všechny vrstvy nad tím. A protože mohou Down() používat v přerušení, byl by problém.
|
|
||||||
*
|
|
||||||
* Metody pro výpisy jsou sice dost zjednodušené, ale zase to nezabere
|
|
||||||
* moc místa - pro ladění se to použít dá. Délka vypisovaného stringu není omezena
|
|
||||||
* délkou použitého buferu.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
class Print : public BaseLayer {
|
|
||||||
public:
|
|
||||||
/// Konstruktor @param b Default decimální výpisy.
|
|
||||||
Print (PrintBases b = DEC);
|
|
||||||
/// Blokování výstupu
|
|
||||||
/// @param buf Ukazatel na data
|
|
||||||
/// @param len Délka přenášených dat
|
|
||||||
/// @return Počet přenesených bytů (rovno len)
|
|
||||||
uint32_t BlockDown (const char * buf, uint32_t len);
|
|
||||||
/// Výstup řetězce bytů
|
|
||||||
/// @param str Ukazatel na řetězec
|
|
||||||
/// @return Odkaz na tuto třídu kvůli řetězení.
|
|
||||||
Print & operator << (const char * str);
|
|
||||||
/// Výstup celého čísla podle base
|
|
||||||
/// @param num Číslo
|
|
||||||
/// @return Odkaz na tuto třídu kvůli řetězení.
|
|
||||||
Print & operator << (const int num);
|
|
||||||
/// Změna základu pro výstup čísla
|
|
||||||
/// @param num enum PrintBases
|
|
||||||
/// @return Odkaz na tuto třídu kvůli řetězení.
|
|
||||||
Print & operator << (const PrintBases num);
|
|
||||||
void out (const void* p, uint32_t l);
|
|
||||||
private:
|
|
||||||
PrintBases base; //!< Základ pro výstup čísla.
|
|
||||||
char buf[BUFLEN]; //!< Buffer pro výstup čísla.
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // PRINT_H
|
|
|
@ -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
|
|
|
@ -1,53 +0,0 @@
|
||||||
TARGET?= ch32v203
|
|
||||||
|
|
||||||
#TOOL ?= gcc
|
|
||||||
TOOL ?= clang
|
|
||||||
|
|
||||||
PRJ = example
|
|
||||||
|
|
||||||
VPATH = . ./common ./$(TARGET)
|
|
||||||
BLD = ./build/
|
|
||||||
DFLAGS = -d
|
|
||||||
LFLAGS = -g
|
|
||||||
LDLIBS =
|
|
||||||
BFLAGS = --strip-unneeded
|
|
||||||
|
|
||||||
CFLAGS = -MMD -Wall -Wno-parentheses -ggdb -fno-exceptions -ffunction-sections -fdata-sections
|
|
||||||
CFLAGS+= -I. -I./$(TARGET) -I./common
|
|
||||||
DEL = rm -f
|
|
||||||
|
|
||||||
# zdrojaky
|
|
||||||
OBJS = main.o usart.o print.o adcdma.o
|
|
||||||
#OBJS +=
|
|
||||||
|
|
||||||
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) -std=gnu99 -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 *~
|
|
||||||
.PHONY: all clean flash run
|
|
|
@ -1,114 +0,0 @@
|
||||||
#include "system.h"
|
|
||||||
#include "oneway.h"
|
|
||||||
#include "adcdma.h"
|
|
||||||
|
|
||||||
static AdcDma * 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 + GPIOA
|
|
||||||
RCC.APB2PCENR.modify([](RCC_Type::APB2PCENR_DEF & r) -> auto {
|
|
||||||
r.B.ADC1EN = SET;
|
|
||||||
r.B.IOPAEN = SET;
|
|
||||||
return r.R;
|
|
||||||
});
|
|
||||||
RCC.APB1PCENR.B.TIM3EN = SET; // Enable TIM3
|
|
||||||
RCC.CFGR0.B.ADCPRE = 3u; // 11: PCLK2 divided by 8 // max 14 MHz (18) ?
|
|
||||||
// PIN PA2 / A2
|
|
||||||
GPIOA.CFGLR.modify([](GPIOA_Type::CFGLR_DEF & r) -> auto {
|
|
||||||
r.B.MODE2 = 0u;
|
|
||||||
r.B.CNF2 = 0u;
|
|
||||||
return r.R;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
static inline void TimerInit (uint32_t us) noexcept {
|
|
||||||
TIM3.PSC.R = 143u; // 1 MHz Fs
|
|
||||||
TIM3.ATRLR.R = us - 1u;
|
|
||||||
// TRGO update for ADC
|
|
||||||
TIM3.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__CHANNEL.B.SQ1__CHSEL = 2u; // CH2
|
|
||||||
ADC1.SAMPTR2_CHARGE2.B.SMP2_TKCG2 = 7u;
|
|
||||||
/*
|
|
||||||
ADC1.RSQR3__CHANNEL.B.SQ1__CHSEL = 16u; // teplota
|
|
||||||
ADC1.SAMPTR1_CHARGE1.B.SMP16_TKCG16 = 7u;
|
|
||||||
*/
|
|
||||||
ADC1.RSQR1.B.L = 0u; // 1 regular conversion
|
|
||||||
ADC1.CTLR1.B.SCAN = SET;
|
|
||||||
|
|
||||||
ADC1.CTLR2.B.ADON = SET;
|
|
||||||
//ADC1.CTLR2.B.TSVREFE = 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_DR_ACT_DCG);
|
|
||||||
// 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 = 4u; // TRGO event of timer 3
|
|
||||||
r.B.SWSTART = SET;
|
|
||||||
return r.R;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
AdcDma::AdcDma() noexcept : pL (buffer), pH (buffer + HALF_LEN), dst (nullptr) {
|
|
||||||
pInstance = this;
|
|
||||||
EnableClock ();
|
|
||||||
TimerInit (1000u);
|
|
||||||
NVIC.EnableIRQ (DMA1_Channel1_IRQn);
|
|
||||||
AdcCalibrate();
|
|
||||||
Dma1Ch1Init (buffer);
|
|
||||||
AdcPostInit ();
|
|
||||||
// start timer
|
|
||||||
TIM3.CTLR1.B.CEN = SET;
|
|
||||||
}
|
|
||||||
inline void AdcDma::send(const bool b) {
|
|
||||||
if (!dst) return;
|
|
||||||
if (b) dst->Send (pH, HALF_LEN);
|
|
||||||
else dst->Send (pL, HALF_LEN);
|
|
||||||
}
|
|
|
@ -1,21 +0,0 @@
|
||||||
#ifndef ADCDMA_H
|
|
||||||
#define ADCDMA_H
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
class OneWay;
|
|
||||||
static constexpr unsigned HALF_LEN = 120u;
|
|
||||||
static constexpr unsigned FULL_LEN = HALF_LEN * 2u;
|
|
||||||
|
|
||||||
class AdcDma {
|
|
||||||
uint16_t * pL;
|
|
||||||
uint16_t * pH;
|
|
||||||
uint16_t buffer [FULL_LEN];
|
|
||||||
OneWay * dst;
|
|
||||||
public:
|
|
||||||
explicit AdcDma () noexcept;
|
|
||||||
void attach (OneWay & d) { dst = & d; }
|
|
||||||
void send (const bool b);
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // ADCDMA_H
|
|
|
@ -1 +0,0 @@
|
||||||
../ch32v203/
|
|
|
@ -1 +0,0 @@
|
||||||
../common/
|
|
|
@ -1,48 +0,0 @@
|
||||||
#include "usart.h"
|
|
||||||
#include "print.h"
|
|
||||||
#include "adcdma.h"
|
|
||||||
#include "oneway.h"
|
|
||||||
#include "fifo.h"
|
|
||||||
////////////////////////////////////////////////////////
|
|
||||||
/* Voltmetr měří na pinu PA2 napětí a vypisuje v mV.
|
|
||||||
* Frekvence vzorkování je 1kHz, průměruje se to a
|
|
||||||
* zobrazuje jednou za 120 ms (9600 Bd). */
|
|
||||||
////////////////////////////////////////////////////////
|
|
||||||
class Meassure : public OneWay {
|
|
||||||
FIFO<unsigned, 8u> fifo;
|
|
||||||
unsigned avg;
|
|
||||||
public:
|
|
||||||
explicit Meassure () noexcept : OneWay(), fifo(), avg(0u) {}
|
|
||||||
unsigned int Send (uint16_t * const ptr, const unsigned int len) override;
|
|
||||||
void out ();
|
|
||||||
};
|
|
||||||
////////////////////////////////////////////////////////
|
|
||||||
static Usart serial (9600u);
|
|
||||||
static Print cout (DEC);
|
|
||||||
static AdcDma adc;
|
|
||||||
static Meassure meas;
|
|
||||||
////////////////////////////////////////////////////////
|
|
||||||
int main () {
|
|
||||||
cout += serial;
|
|
||||||
adc.attach (meas);
|
|
||||||
for (;;) {
|
|
||||||
meas.out();
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
////////////////////////////////////////////////////////
|
|
||||||
static constexpr unsigned BK = 3316u << 4; // Mělo by to být přesně 3300.
|
|
||||||
unsigned int Meassure::Send(uint16_t * const ptr, const unsigned int len) {
|
|
||||||
for (unsigned n=0; n<len; n++) {
|
|
||||||
const unsigned mv = (BK * ptr [n]) >> 16;
|
|
||||||
avg = (avg * 15 + mv) >> 4; // klouzavý průměr s postupným zapomínáním
|
|
||||||
}
|
|
||||||
fifo.Write (avg);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
void Meassure::out() {
|
|
||||||
unsigned t;
|
|
||||||
if (fifo.Read (t)) {
|
|
||||||
cout << t << " mV\r\n";
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in a new issue