add hello
This commit is contained in:
parent
00ed06384b
commit
7b5eae57c9
18 changed files with 621 additions and 0 deletions
1
V203/ch32v203/hello.mk
Normal file
1
V203/ch32v203/hello.mk
Normal file
|
@ -0,0 +1 @@
|
||||||
|
OBJS += pwmclass.o
|
55
V203/hello/Makefile
Normal file
55
V203/hello/Makefile
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
TARGET?= ch32v203
|
||||||
|
#TARGET?= linux
|
||||||
|
|
||||||
|
#TOOL ?= gcc
|
||||||
|
TOOL ?= clang
|
||||||
|
|
||||||
|
PRJ = example
|
||||||
|
|
||||||
|
VPATH = . ./$(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 generator.o morse.o
|
||||||
|
#OBJS +=
|
||||||
|
|
||||||
|
include $(TARGET)/$(TOOL).mk
|
||||||
|
include $(TARGET)/hello.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
V203/hello/ch32v203
Symbolic link
1
V203/hello/ch32v203
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
../ch32v203/
|
1
V203/hello/common
Symbolic link
1
V203/hello/common
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
../common/
|
31
V203/hello/generator.cpp
Normal file
31
V203/hello/generator.cpp
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
#include "generator.h"
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
|
static constexpr unsigned W_TB = 8u;
|
||||||
|
static constexpr double AMPL = 3000.0;
|
||||||
|
static constexpr int ULEN = 1 << W_TB;
|
||||||
|
|
||||||
|
static constexpr uint16_t u16_sin (const int x) {
|
||||||
|
const double a = (double (x) * D_PI) / double (ULEN);
|
||||||
|
const double s = AMPL * (1.0 + 0.96 * sincos (a, true));
|
||||||
|
return i_round (s);
|
||||||
|
}
|
||||||
|
static const TABLE<uint16_t, ULEN> sin_tab (u16_sin);
|
||||||
|
extern void print_sinus_table (const TABLE<uint16_t, ULEN> & tab);
|
||||||
|
|
||||||
|
Generator::Generator (const unsigned f) noexcept : OneWay(),
|
||||||
|
freq (f), base(0u), incr (0u), ms_count (0u) {
|
||||||
|
#ifdef __linux__
|
||||||
|
print_sinus_table(sin_tab);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
uint16_t Generator::step() {
|
||||||
|
const uint16_t v = sin_tab [base >> 24];
|
||||||
|
base += incr;
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
unsigned int Generator::Send(uint16_t * const ptr, const unsigned int len) {
|
||||||
|
for (unsigned n=0u; n<len; n++) ptr [n] = step();
|
||||||
|
if (ms_count) ms_count -= 1u; // průchod zde je za 1 ms přesně
|
||||||
|
return len;
|
||||||
|
}
|
23
V203/hello/generator.h
Normal file
23
V203/hello/generator.h
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
#ifndef GENERATOR_H
|
||||||
|
#define GENERATOR_H
|
||||||
|
#include "oneway.h"
|
||||||
|
/* Něco jako DDS, přesná frekvence není řešena (závisí na TIM1). */
|
||||||
|
class Generator : public OneWay {
|
||||||
|
const unsigned freq;
|
||||||
|
unsigned base, incr;
|
||||||
|
volatile unsigned ms_count;
|
||||||
|
public:
|
||||||
|
explicit Generator (const unsigned f) noexcept;
|
||||||
|
unsigned Send (uint16_t * const ptr, const unsigned len) override;
|
||||||
|
|
||||||
|
void delay (const unsigned ms) {
|
||||||
|
ms_count = ms;
|
||||||
|
while (ms_count);
|
||||||
|
}
|
||||||
|
void on () volatile { incr = freq; }
|
||||||
|
void off () volatile { base = 0u; incr = 0u; }
|
||||||
|
protected:
|
||||||
|
uint16_t step ();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // GENERATOR_H
|
79
V203/hello/linux/alsasound.cpp
Normal file
79
V203/hello/linux/alsasound.cpp
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
#include "pwmclass.h"
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <alsa/asoundlib.h>
|
||||||
|
#include <signal.h>
|
||||||
|
|
||||||
|
struct Sample {
|
||||||
|
short l;
|
||||||
|
short r;
|
||||||
|
}__attribute__((packed));
|
||||||
|
|
||||||
|
static constexpr unsigned BufLen = FULL_LEN;
|
||||||
|
|
||||||
|
static const char *device = "default";
|
||||||
|
static snd_pcm_t *handle;
|
||||||
|
|
||||||
|
static int open_alsa_device (int channels, int srate) {
|
||||||
|
int err;
|
||||||
|
if ((err = snd_pcm_open(&handle, device, SND_PCM_STREAM_PLAYBACK, 0)) < 0) {
|
||||||
|
printf("Playback open error: %s\n", snd_strerror(err));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if ((err = snd_pcm_set_params(handle,
|
||||||
|
SND_PCM_FORMAT_S16_LE,
|
||||||
|
SND_PCM_ACCESS_RW_INTERLEAVED,
|
||||||
|
channels,
|
||||||
|
srate,
|
||||||
|
1,
|
||||||
|
500000)) < 0) { /* 0.5sec */
|
||||||
|
printf("Playback open error: %s\n", snd_strerror(err));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
int alsa_write (const void * buf, int len) {
|
||||||
|
snd_pcm_sframes_t frames;
|
||||||
|
int err = 0;
|
||||||
|
frames = snd_pcm_writei(handle, buf, len);
|
||||||
|
if (frames < 0)
|
||||||
|
frames = snd_pcm_recover(handle, frames, 0);
|
||||||
|
if (frames < 0) {
|
||||||
|
printf("snd_pcm_writei failed: %s\n", snd_strerror(err));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (frames > 0 && frames < (long)sizeof(buf))
|
||||||
|
printf("Short write (expected %i, wrote %li)\n", len, frames);
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
void sig_handler (int signum) {
|
||||||
|
printf(" - Received signal %d\n", signum);
|
||||||
|
::exit (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr int CC = MAXPWM / 2;
|
||||||
|
|
||||||
|
static pthread_t rc;
|
||||||
|
|
||||||
|
void * WriteHandler (void * data) {
|
||||||
|
printf ("Start thread\n");
|
||||||
|
PwmClass * pA = (PwmClass *) data;
|
||||||
|
Sample buf [BufLen];
|
||||||
|
uint16_t * pbuf = pA->getBuff();
|
||||||
|
for (;;) {
|
||||||
|
pA->send (false);
|
||||||
|
pA->send (true);
|
||||||
|
//printf ("pass\n");
|
||||||
|
for (unsigned i=0; i<BufLen; i++) {
|
||||||
|
const short s = (pbuf [i] - CC) * 10;
|
||||||
|
buf[i].l = s; buf[i].r = s;
|
||||||
|
}
|
||||||
|
alsa_write (buf, BufLen);
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
PwmClass::PwmClass() noexcept : pL(buffer), pH(buffer + HALF_LEN), src(nullptr) {
|
||||||
|
signal (SIGINT, sig_handler);
|
||||||
|
open_alsa_device(2, 24000);
|
||||||
|
pthread_create (&rc, NULL, WriteHandler, this);
|
||||||
|
}
|
11
V203/hello/linux/clang.mk
Normal file
11
V203/hello/linux/clang.mk
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
# Use clang / binutils toolchain
|
||||||
|
CC = clang
|
||||||
|
CXX = clang++
|
||||||
|
LD = clang++
|
||||||
|
SIZE = size
|
||||||
|
DUMP = objdump
|
||||||
|
COPY = objcopy
|
||||||
|
CFLAGS+= -Oz
|
||||||
|
|
||||||
|
LFLAGS+= -Wl,--Map=$(@:%.elf=%.map),--gc-sections
|
||||||
|
LDLIBS+= -lc -lpthread -lasound
|
12
V203/hello/linux/gcc.mk
Normal file
12
V203/hello/linux/gcc.mk
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
# Use gcc / binutils toolchain
|
||||||
|
PREFIX =
|
||||||
|
CC = $(PREFIX)gcc
|
||||||
|
CXX = $(PREFIX)g++
|
||||||
|
LD = $(PREFIX)g++
|
||||||
|
SIZE = $(PREFIX)size
|
||||||
|
DUMP = $(PREFIX)objdump
|
||||||
|
COPY = $(PREFIX)objcopy
|
||||||
|
CFLAGS+= -Os
|
||||||
|
|
||||||
|
LFLAGS+= -Wl,--Map=$(@:%.elf=%.map),--gc-sections
|
||||||
|
LDLIBS+= -lc -lpthread -lasound
|
37
V203/hello/linux/gpio.h
Normal file
37
V203/hello/linux/gpio.h
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
#ifndef _GPIO_CLASS_H_
|
||||||
|
#define _GPIO_CLASS_H_
|
||||||
|
#include <stdint.h>
|
||||||
|
enum GPIO_MODE : uint32_t {
|
||||||
|
GPIO_Speed_In = 0u,
|
||||||
|
GPIO_Speed_10MHz = 1u,
|
||||||
|
GPIO_Speed_2MHz = 2u,
|
||||||
|
GPIO_Speed_50MHz = 3u,
|
||||||
|
};
|
||||||
|
enum GPIO_CNF : uint32_t {
|
||||||
|
GPIO_AI_PPO = 0u,
|
||||||
|
GPIO_FI_ODO = 1u << 2,
|
||||||
|
GPIO_UPDI_MPPO = 2u << 2,
|
||||||
|
GPIO_none_MPDO = 3u << 2,
|
||||||
|
};
|
||||||
|
enum GPIOPuPd_TypeDef {
|
||||||
|
GPIO_PuPd_NOPULL = 0x00,
|
||||||
|
GPIO_PuPd_UP = 0x01,
|
||||||
|
GPIO_PuPd_DOWN = 0x02
|
||||||
|
};
|
||||||
|
static constexpr uint32_t GPIOA = 0u;
|
||||||
|
class GpioClass {
|
||||||
|
//const uint32_t pin;
|
||||||
|
public:
|
||||||
|
explicit constexpr GpioClass (const uint32_t _pin, const uint32_t _mode = GPIO_AI_PPO) noexcept
|
||||||
|
{
|
||||||
|
}
|
||||||
|
void operator<< (const bool b) const {
|
||||||
|
}
|
||||||
|
operator bool () const {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
void setPuPd (GPIOPuPd_TypeDef p) {
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // _GPIO_CLASS_H_
|
2
V203/hello/linux/hello.mk
Normal file
2
V203/hello/linux/hello.mk
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
OBJS += alsasound.o print.o
|
||||||
|
|
22
V203/hello/linux/print.cpp
Normal file
22
V203/hello/linux/print.cpp
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
#include <cstdio>
|
||||||
|
#include "utils.h"
|
||||||
|
void print_morse_table (const TABLE<unsigned char, 64> & tab) {
|
||||||
|
int n = 0;
|
||||||
|
printf("static const unsigned char compressed_table [] = {");
|
||||||
|
for (auto & e: tab) {
|
||||||
|
if ((n % 16) == 0) printf("\n");
|
||||||
|
printf("0x%02x,", e);
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
printf("\n};\n");
|
||||||
|
}
|
||||||
|
void print_sinus_table (const TABLE<unsigned short, 256> & tab) {
|
||||||
|
int n = 0;
|
||||||
|
printf("static const uint16_t sin_tab [] = {");
|
||||||
|
for (auto & e: tab) {
|
||||||
|
if ((n % 16) == 0) printf("\n");
|
||||||
|
printf("%5du,", e);
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
printf("\n};\n");
|
||||||
|
}
|
20
V203/hello/main.cpp
Normal file
20
V203/hello/main.cpp
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
/* SIMPLE EXAMPLE: LED blinking */
|
||||||
|
/* Když už mám PWM hotové, tak to může na pinech PA7 a PA8 pípat.
|
||||||
|
* Frekvence je 1kHz - čistý sinus.
|
||||||
|
*
|
||||||
|
* Pro tento čip je možné použít pro překlad clang. Pak je možné
|
||||||
|
* tabulky pro sinus i pro komprimovaný kód morse použít konstantní
|
||||||
|
* výrazy. Nezvětšuje to délku kódu a je z toho vidět, jak se tyto
|
||||||
|
* věci počítají, aniž by bylo nutné použít nějaký externí nástroj.
|
||||||
|
* TARGET linux vypíše obě tabulky na konzoli - funguje i zvuk jako demo.
|
||||||
|
* */
|
||||||
|
#include "morse.h"
|
||||||
|
//////////////////////////////////////
|
||||||
|
static GpioClass led (GPIOA, 0);
|
||||||
|
static Morse morse (led, 100u);
|
||||||
|
int main () {
|
||||||
|
for (;;) {
|
||||||
|
morse << "hello world";
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
91
V203/hello/morse.cpp
Normal file
91
V203/hello/morse.cpp
Normal file
|
@ -0,0 +1,91 @@
|
||||||
|
#include "morse.h"
|
||||||
|
#include "utils.h"
|
||||||
|
// Spočteme číslo (pro 1kHz) jako (1000 << 32) / 24000 (24 kHz je samplerate).
|
||||||
|
static constexpr unsigned F0 = (1000ull << 32) / 24000u;
|
||||||
|
|
||||||
|
static constexpr const char * const morse_code [] = { /* nedefinované znaky nahrazeny mezerou */
|
||||||
|
" ", /* */ " ", /*!*/ ".-..-.", /*\"*/ " ", /*#*/ " ", /*$*/
|
||||||
|
" ", /*%*/ " ", /*&*/ ".----.", /*\'*/ "-.--.", /*(*/ "-.--.-", /*)*/
|
||||||
|
" ", /***/ ".-.-.", /*+*/ "--..--", /*,*/ "-....-", /*-*/ ".-.-.-", /*.*/ "-..-." , /*/*/
|
||||||
|
"-----", /*0*/ ".----", /*1*/ "..---", /*2*/ "...--", /*3*/ "....-", /*4*/
|
||||||
|
".....", /*5*/ "-....", /*6*/ "--...", /*7*/ "---..", /*8*/ "----.", /*9*/
|
||||||
|
"---...", /*:*/ "-.-.-.", /*;*/ " ", /*<*/ "-...-" , /*=*/ " ", /*>*/ "..--..", /*?*/
|
||||||
|
".--.-.", /*@*/
|
||||||
|
".-", /*A*/ "-...", /*B*/ "-.-.", /*C*/ "-..", /*D*/ ".", /*E*/ "..-.", /*F*/
|
||||||
|
"--.", /*G*/ "....", /*H*/ "..", /*I*/ ".---", /*J*/ "-.-", /*K*/ ".-..", /*L*/
|
||||||
|
"--", /*M*/ "-.", /*N*/ "---", /*O*/ ".--.", /*P*/ "--.-", /*Q*/ ".-.", /*R*/
|
||||||
|
"...", /*S*/ "-", /*T*/ "..-", /*U*/ "...-", /*V*/ ".--", /*W*/ "-..-", /*X*/
|
||||||
|
"-.--", /*Y*/ "--..", /*Z*/ " ", " ", " ", " ", "..--.-", /*_*/
|
||||||
|
};
|
||||||
|
static constexpr unsigned slen (const char * const str) {
|
||||||
|
unsigned n = 0;
|
||||||
|
while (str[n]) n++;
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
static constexpr unsigned char compress (const unsigned n) {
|
||||||
|
const char * const ptr = morse_code [n];
|
||||||
|
const unsigned len = slen (ptr);
|
||||||
|
unsigned char mb = 0u;
|
||||||
|
if (ptr [0] == ' ') return mb;
|
||||||
|
mb = (len & 7u) << 5;
|
||||||
|
for (unsigned n=0; n<len; n++) {
|
||||||
|
if (ptr [n] == '-') mb |= (1u << n);
|
||||||
|
}
|
||||||
|
return mb;
|
||||||
|
}
|
||||||
|
static const TABLE<unsigned char, array_size (morse_code)> compressed_table (compress);
|
||||||
|
extern void print_morse_table (const TABLE<unsigned char, array_size(morse_code)> & tab);
|
||||||
|
|
||||||
|
Morse::Morse(const GpioClass & pin, const unsigned int ms) noexcept : unit (ms), led (pin),
|
||||||
|
gen (F0), pwm () {
|
||||||
|
pwm.attach(gen);
|
||||||
|
#ifdef __linux__
|
||||||
|
print_morse_table (compressed_table);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
const Morse & Morse::operator<< (const char * text) {
|
||||||
|
for (unsigned n=0; ; n++) {
|
||||||
|
const char c = text [n];
|
||||||
|
if (c == '\0') break;
|
||||||
|
morse_byte mb;
|
||||||
|
if (c < '\x20') {
|
||||||
|
} else if (c < '`') {
|
||||||
|
const int i = c - '\x20';
|
||||||
|
mb.byte = compressed_table [i];
|
||||||
|
} else if (c == '`') {
|
||||||
|
} else if (c <= 'z') {
|
||||||
|
const int i = c - '\x40';
|
||||||
|
mb.byte = compressed_table [i];
|
||||||
|
} else {
|
||||||
|
}
|
||||||
|
out (mb);
|
||||||
|
}
|
||||||
|
gen.delay (10 * unit);
|
||||||
|
return * this;
|
||||||
|
}
|
||||||
|
/* . => 1 x unit
|
||||||
|
* - => 3 x unit
|
||||||
|
* mezera mezi značkami => 1 x unit
|
||||||
|
* mezera mezi znaky => 3 x unit
|
||||||
|
* mezera mezi slovy => 7 x unit
|
||||||
|
* */
|
||||||
|
void Morse::out (const morse_byte mb) {
|
||||||
|
/* Finta je v tom, že i když se pole mlen a bits překrývají,
|
||||||
|
* nevadí to - maximální délka je 6, takže v nejnižším bitu
|
||||||
|
* mlen může být obsažen 1 bit 6.bitového znaku.
|
||||||
|
* Takhle napsáno to běhá jen na malém indiánu, přepisovat
|
||||||
|
* to do bitových posunů nebudu, i když by to bylo čistší.
|
||||||
|
* */
|
||||||
|
const unsigned len = mb.mlen > 6u ? 6u : mb.mlen;
|
||||||
|
if (!len) { gen.delay (4 * unit); return; }
|
||||||
|
for (unsigned n=0; n<len; n++) {
|
||||||
|
off ();
|
||||||
|
gen.delay (unit);
|
||||||
|
const unsigned v = (1u << n) & mb.bits;
|
||||||
|
const unsigned d = v ? 3u : 1u;
|
||||||
|
on ();
|
||||||
|
gen.delay (d * unit);
|
||||||
|
off ();
|
||||||
|
}
|
||||||
|
gen.delay (3 * unit);
|
||||||
|
}
|
36
V203/hello/morse.h
Normal file
36
V203/hello/morse.h
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
#ifndef MORSE_H
|
||||||
|
#define MORSE_H
|
||||||
|
#include "gpio.h"
|
||||||
|
#include "generator.h"
|
||||||
|
#include "pwmclass.h"
|
||||||
|
union morse_byte {
|
||||||
|
struct {
|
||||||
|
unsigned char bits : 5;
|
||||||
|
unsigned char mlen : 3;
|
||||||
|
};
|
||||||
|
unsigned char byte;
|
||||||
|
explicit constexpr morse_byte () noexcept : byte (0u) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
class Morse {
|
||||||
|
const unsigned unit;
|
||||||
|
const GpioClass & led;
|
||||||
|
Generator gen;
|
||||||
|
PwmClass pwm;
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit Morse (const GpioClass & pin, const unsigned ms = 100u) noexcept;
|
||||||
|
const Morse & operator<< (const char * text);
|
||||||
|
protected:
|
||||||
|
void out (const morse_byte mb);
|
||||||
|
void on () {
|
||||||
|
led << false; // LED je připojena proti VCC, zde se tedy rozsvítí
|
||||||
|
gen.on ();
|
||||||
|
}
|
||||||
|
void off () {
|
||||||
|
led << true;
|
||||||
|
gen.off();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // MORSE_H
|
114
V203/hello/pwmclass.cpp
Normal file
114
V203/hello/pwmclass.cpp
Normal file
|
@ -0,0 +1,114 @@
|
||||||
|
#include "pwmclass.h"
|
||||||
|
#include "gpio.h"
|
||||||
|
#include "system.h"
|
||||||
|
|
||||||
|
static PwmClass * pInstance = nullptr;
|
||||||
|
extern "C" void DMA1_Channel5_IRQHandler( void ) __attribute__((interrupt));
|
||||||
|
void DMA1_Channel5_IRQHandler( void ) {
|
||||||
|
DMA1_Type::INTFR_DEF state (DMA1.INTFR);
|
||||||
|
DMA1.INTFCR.R = state.R; // clear all
|
||||||
|
if (!pInstance) return;
|
||||||
|
if (state.B.HTIF5 != RESET) pInstance->send(false);
|
||||||
|
else if (state.B.TCIF5 != RESET) pInstance->send(true);
|
||||||
|
|
||||||
|
//pInstance->signalize(); // zbytečný efekt
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* initialize TIM1 for PWM
|
||||||
|
*/
|
||||||
|
static inline void tim1pwm_init () noexcept {
|
||||||
|
// Enable GPIOA and TIM1
|
||||||
|
RCC.APB2PCENR.modify([] (RCC_Type::APB2PCENR_DEF & r) -> auto {
|
||||||
|
r.B.IOPAEN = SET;
|
||||||
|
r.B.TIM1EN = SET;
|
||||||
|
r.B.AFIOEN = SET;
|
||||||
|
return r.R;
|
||||||
|
});
|
||||||
|
AFIO.PCFR.modify([](AFIO_Type::PCFR_DEF & r) -> auto {
|
||||||
|
r.B.TIM1RM = 1u;
|
||||||
|
return r.R;
|
||||||
|
});
|
||||||
|
// PA7 is T1CH1N, PA8 is T1CH1, 10MHz Output alt func, push-pull
|
||||||
|
GPIOA.CFGLR.modify([](GPIOA_Type::CFGLR_DEF & r) -> auto {
|
||||||
|
r.B.CNF7 = 2u;
|
||||||
|
r.B.MODE7 = 1u;
|
||||||
|
return r.R;
|
||||||
|
});
|
||||||
|
GPIOA.CFGHR.modify([](GPIOA_Type::CFGHR_DEF & r) -> auto {
|
||||||
|
r.B.CNF8 = 2u;
|
||||||
|
r.B.MODE8 = 1u;
|
||||||
|
return r.R;
|
||||||
|
});
|
||||||
|
// Reset TIM1 to init all regs
|
||||||
|
RCC.APB2PRSTR.B.TIM1RST = SET;
|
||||||
|
RCC.APB2PRSTR.B.TIM1RST = RESET;
|
||||||
|
// CTLR1: default is up, events generated, edge align
|
||||||
|
// SMCFGR: default clk input is CK_INT
|
||||||
|
// Prescaler
|
||||||
|
TIM1.PSC.R = 0u;
|
||||||
|
// Auto Reload - sets period
|
||||||
|
TIM1.ATRLR.R = MAXPWM - 1;
|
||||||
|
|
||||||
|
TIM1.CCER.modify([](TIM1_Type::CCER_DEF & r) -> auto {
|
||||||
|
// Enable CH1N, CH1 output, positive pol
|
||||||
|
r.B.CC1NE = SET;
|
||||||
|
r.B.CC1E = SET;
|
||||||
|
/*
|
||||||
|
r.B.CC1NP = SET; // active Low
|
||||||
|
r.B.CC1P = SET;
|
||||||
|
*/
|
||||||
|
return r.R;
|
||||||
|
});
|
||||||
|
// CH1 Mode is output, PWM1 (CC1S = 00, OC1M = 110)
|
||||||
|
TIM1.CHCTLR1_Output.modify([](TIM1_Type::CHCTLR1_Output_DEF & r) -> auto {
|
||||||
|
r.B.OC1M = 0x6u;
|
||||||
|
return r.R;
|
||||||
|
});
|
||||||
|
// Enable TIM1 outputs
|
||||||
|
TIM1.BDTR.modify([](TIM1_Type::BDTR_DEF & r) -> auto {
|
||||||
|
r.B.MOE = SET;
|
||||||
|
r.B.DTG = 48u; // Dead time 1us
|
||||||
|
return r.R;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Reload immediately + Trigger DMA
|
||||||
|
TIM1.SWEVGR.B.UG = SET;
|
||||||
|
TIM1.DMAINTENR.B.UDE = SET;
|
||||||
|
// Enable TIM1
|
||||||
|
TIM1.CTLR1.B.CEN = SET;
|
||||||
|
}
|
||||||
|
typedef __SIZE_TYPE__ size_t;
|
||||||
|
static inline void dma1ch5_init (void * ptr) noexcept {
|
||||||
|
// Enable DMA
|
||||||
|
RCC.AHBPCENR.modify([](RCC_Type::AHBPCENR_DEF & r) -> auto {
|
||||||
|
r.B.SRAMEN = SET;
|
||||||
|
r.B.DMA1EN = SET;
|
||||||
|
return r.R;
|
||||||
|
});
|
||||||
|
// DMA5 can be configured to attach to T1UP
|
||||||
|
// The system can only DMA out at ~2.2MSPS. 2MHz is stable.
|
||||||
|
DMA1.CNTR5 .R = FULL_LEN;
|
||||||
|
DMA1.MADDR5.R = reinterpret_cast<size_t>(ptr);
|
||||||
|
DMA1.PADDR5.R = reinterpret_cast<size_t>(& TIM1.CH1CVR);
|
||||||
|
NVIC.EnableIRQ (DMA1_Channel5_IRQn);
|
||||||
|
DMA1.CFGR5.modify([](DMA1_Type::CFGR5_DEF & r) -> auto {
|
||||||
|
r.B.DIR = SET; // MEM2PERIPHERAL
|
||||||
|
r.B.PL = 2u; // High priority.
|
||||||
|
r.B.PSIZE = 1u; // 16-bit peripheral
|
||||||
|
r.B.MSIZE = 1u; // 16-bit memory
|
||||||
|
r.B.MINC = SET; // Increase memory.
|
||||||
|
r.B.CIRC = SET; // Circular mode.
|
||||||
|
r.B.HTIE = SET; // Half-trigger
|
||||||
|
r.B.TCIE = SET; // Whole-trigger
|
||||||
|
// Enable DMA1 ch5
|
||||||
|
r.B.EN = SET;
|
||||||
|
return r.R;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
PwmClass::PwmClass() noexcept : pL(buffer), pH(buffer + HALF_LEN), src(nullptr) {
|
||||||
|
pInstance = this;
|
||||||
|
tim1pwm_init ();
|
||||||
|
dma1ch5_init (buffer);
|
||||||
|
}
|
25
V203/hello/pwmclass.h
Normal file
25
V203/hello/pwmclass.h
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
#ifndef PWMCLASS_H
|
||||||
|
#define PWMCLASS_H
|
||||||
|
#include "gpio.h"
|
||||||
|
#include "oneway.h"
|
||||||
|
static constexpr unsigned HALF_LEN = 24u;
|
||||||
|
static constexpr unsigned FULL_LEN = 2u * HALF_LEN;
|
||||||
|
static constexpr unsigned MAXPWM = 6000u;
|
||||||
|
/* Používá TIM1, PWM kanál 1, DMA1 kanál 5, přerušení DMA1_Channel5_IRQHandler */
|
||||||
|
class PwmClass {
|
||||||
|
uint16_t * const pL;
|
||||||
|
uint16_t * const pH;
|
||||||
|
uint16_t buffer [FULL_LEN];
|
||||||
|
OneWay * src;
|
||||||
|
public:
|
||||||
|
explicit PwmClass () noexcept;
|
||||||
|
void attach (OneWay & s) { src = & s; }
|
||||||
|
void send (const bool b) {
|
||||||
|
if (!src) return;
|
||||||
|
if (b) src->Send (pH, HALF_LEN);
|
||||||
|
else src->Send (pL, HALF_LEN);
|
||||||
|
}
|
||||||
|
uint16_t * getBuff () const { return pL; }
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // PWMCLASS_H
|
60
V203/hello/utils.h
Normal file
60
V203/hello/utils.h
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
#ifndef UTILS_H
|
||||||
|
#define UTILS_H
|
||||||
|
|
||||||
|
typedef __SIZE_TYPE__ size_t;
|
||||||
|
template<class T, size_t N>constexpr size_t array_size (T (&) [N]) { return N; }
|
||||||
|
|
||||||
|
template<class T, const int N> class TABLE {
|
||||||
|
T data [N];
|
||||||
|
public:
|
||||||
|
/** @brief Konstruktor.
|
||||||
|
* @param f Ukazatel na constexpr funkci, která pak vytvoří tabulku.
|
||||||
|
* */
|
||||||
|
template<typename F> explicit constexpr TABLE (F f) noexcept {
|
||||||
|
for (int n=0; n<N; n++) data [n] = f (n);
|
||||||
|
}
|
||||||
|
/** operator[] vrátí konstantní odkaz na prvek pole, protože se předpokládá,
|
||||||
|
* že instance této třídy bude jako taková též konstantní
|
||||||
|
*/
|
||||||
|
const T & operator[] (const int index) const {
|
||||||
|
return data [index];
|
||||||
|
}
|
||||||
|
/** @class iterator
|
||||||
|
* @brief range-based for () */
|
||||||
|
class iterator {
|
||||||
|
const T * ptr;
|
||||||
|
public:
|
||||||
|
iterator(const T * _ptr) : ptr (_ptr) {}
|
||||||
|
iterator operator++ () { ++ptr; return * this; }
|
||||||
|
bool operator!= (const iterator & other) const { return ptr != other.ptr; }
|
||||||
|
const T & operator* () const { return * ptr; }
|
||||||
|
};
|
||||||
|
iterator begin () const { return iterator (data ); }
|
||||||
|
iterator end () const { return iterator (data + N); }
|
||||||
|
protected:
|
||||||
|
};
|
||||||
|
|
||||||
|
static constexpr double X_PI = 3.14159265358979323846;
|
||||||
|
static constexpr double D_PI = 2.0 * X_PI;
|
||||||
|
/* cmath nejde použít, tak si to mírně zjednodušíme, ale musí to fungovat */
|
||||||
|
static constexpr double dabs (const double a) { return a < 0.0 ? -a : +a; }
|
||||||
|
static constexpr int i_round (const double a) { return a < 0.0 ? int (a - 0.5) : int (a + 0.5); }
|
||||||
|
/* tahle divná funkce počítá sinus, pokud even=true i kosinus, pokud even=false */
|
||||||
|
static constexpr double sincos (const double x, const bool even) {
|
||||||
|
double result (0.0), element(1.0), divider(0.0);
|
||||||
|
if (even) { element *= x; divider += 1.0; }
|
||||||
|
constexpr double eps = 1.0e-9; // maximální chyba výpočtu
|
||||||
|
const double aa = - (x * x);
|
||||||
|
for (;;) {
|
||||||
|
result += element;
|
||||||
|
if (dabs (element) < eps) break;
|
||||||
|
divider += 1.0;
|
||||||
|
double fact = divider;
|
||||||
|
divider += 1.0;
|
||||||
|
fact *= divider;
|
||||||
|
element *= aa / fact;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // UTILS_H
|
Loading…
Reference in a new issue