add thermometer as counter
This commit is contained in:
parent
f11366d182
commit
51d6bea95e
24 changed files with 2415 additions and 0 deletions
44
V203F6P6/thermometer/GsmDecoder.cpp
Normal file
44
V203F6P6/thermometer/GsmDecoder.cpp
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
#include "pwmclass.h"
|
||||||
|
#include "GsmDecoder.h"
|
||||||
|
|
||||||
|
GsmDecoder::GsmDecoder(FIFO<uint32_t, FIFOLEN> & f) noexcept :
|
||||||
|
OneWay<uint16_t>(), fifo(f), enable(GPIOB, 1u), flash(), gsm(), idle(0u) {
|
||||||
|
}
|
||||||
|
static constexpr int INPUT_BIT_RANGE = 16;
|
||||||
|
static constexpr unsigned SIGMA_MASK = (1u << (INPUT_BIT_RANGE + 0)) - 1u;
|
||||||
|
static constexpr unsigned SIGNED_OFFEST = (1u << (INPUT_BIT_RANGE - 1));
|
||||||
|
// Předpokládá se na vstupu signed int o šířce INPUT_BIT_RANGE
|
||||||
|
// přičemž 0 na vstupu odpovídá MAXPWM / 2 na výstupu. Vypadá to divně, ale funguje.
|
||||||
|
static unsigned pwm_sd (const int input) {
|
||||||
|
static unsigned sigma = 0; // podstatné je, že proměnná je statická
|
||||||
|
const unsigned sample = (input + SIGNED_OFFEST) * MAXPWM;
|
||||||
|
sigma &= SIGMA_MASK; // v podstatě se odečte hodnota PWM
|
||||||
|
sigma += sample; // integrace prostým součtem
|
||||||
|
return sigma >> INPUT_BIT_RANGE;
|
||||||
|
}
|
||||||
|
unsigned GsmDecoder::Send(uint16_t * dptr, const unsigned len) {
|
||||||
|
uint32_t source;
|
||||||
|
if (fifo.Read(source)) {
|
||||||
|
enable << true; // zapni budič
|
||||||
|
idle = 0u;
|
||||||
|
gsm_frame tmp;
|
||||||
|
flash.ReadBlock(source, tmp, sizeof(gsm_frame));
|
||||||
|
gsm.decode(tmp, tmpbuf);
|
||||||
|
for (unsigned n=0u, k=0u; k<len; n++) {
|
||||||
|
const int16_t s = tmpbuf[n];
|
||||||
|
dptr [k++] = pwm_sd (s); // vyzkoušená metoda jak vylepšit PWM
|
||||||
|
dptr [k++] = pwm_sd (s); // pokud máme frekvenci PWM větší
|
||||||
|
dptr [k++] = pwm_sd (s); // než vzorkovací frekvence signálu ft = n * fs, n = 3
|
||||||
|
}
|
||||||
|
return GSMLEN;
|
||||||
|
}
|
||||||
|
idle += 1u;
|
||||||
|
if (idle > 3u) { // pro vypnutí budiče je lépe chvilinku počkat
|
||||||
|
idle = 3u;
|
||||||
|
enable << false;
|
||||||
|
}
|
||||||
|
for (unsigned n=0u; n<len; n++) {
|
||||||
|
dptr [n] = MAXPWM >> 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
21
V203F6P6/thermometer/GsmDecoder.h
Normal file
21
V203F6P6/thermometer/GsmDecoder.h
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
#ifndef GSMDECODER_H
|
||||||
|
#define GSMDECODER_H
|
||||||
|
#include "gpio.h"
|
||||||
|
#include "player.h"
|
||||||
|
#include "oneway.h"
|
||||||
|
#include "gsm.h"
|
||||||
|
#include "norflash.h"
|
||||||
|
|
||||||
|
class GsmDecoder : public OneWay<uint16_t> {
|
||||||
|
FIFO<uint32_t, FIFOLEN> & fifo;
|
||||||
|
GpioClass enable;
|
||||||
|
NorFlash flash;
|
||||||
|
GsmStatic gsm;
|
||||||
|
gsm_signal tmpbuf [GSMLEN];
|
||||||
|
unsigned idle;
|
||||||
|
public:
|
||||||
|
explicit GsmDecoder(FIFO<uint32_t, FIFOLEN> & f) noexcept;
|
||||||
|
unsigned Send (uint16_t * ptr, const unsigned len) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // GSMDECODER_H
|
61
V203F6P6/thermometer/Makefile
Normal file
61
V203F6P6/thermometer/Makefile
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
TARGET?= ch32v203
|
||||||
|
|
||||||
|
#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 -I./lib/gsm/inc -DEXTROM=1
|
||||||
|
DEL = rm -f
|
||||||
|
|
||||||
|
# zdrojaky
|
||||||
|
OBJS = main.o pwmclass.o
|
||||||
|
OBJS += GsmDecoder.o wrap.o
|
||||||
|
OBJS += spiblocked.o norflash.o
|
||||||
|
OBJS += extdata.o player.o
|
||||||
|
|
||||||
|
include $(TARGET)/$(TOOL).mk
|
||||||
|
BOBJS = $(addprefix $(BLD),$(OBJS))
|
||||||
|
|
||||||
|
all: $(BLD) $(PRJ).elf
|
||||||
|
# ... atd.
|
||||||
|
-include $(BLD)*.d
|
||||||
|
LDLIBS += -L./lib -lgsm
|
||||||
|
# linker
|
||||||
|
$(PRJ).elf: $(BOBJS) ./lib/libgsm.a
|
||||||
|
-@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)%.o: %.s
|
||||||
|
-@echo [AS $(TOOL),$(TARGET)] $@
|
||||||
|
@$(AS) $(CCPU) $< -o $@
|
||||||
|
$(BLD):
|
||||||
|
mkdir $(BLD)
|
||||||
|
./lib/libgsm.a:
|
||||||
|
cd ./lib/gsm/src && $(MAKE) TARGET=$(TARGET) all
|
||||||
|
flash: $(PRJ).elf
|
||||||
|
minichlink -w $(PRJ).bin flash -b
|
||||||
|
# vycisti
|
||||||
|
clean:
|
||||||
|
$(DEL) $(BLD)* *.lst *.bin *.elf *.map *~
|
||||||
|
.PHONY: all clean flash run
|
1
V203F6P6/thermometer/ch32v203
Symbolic link
1
V203F6P6/thermometer/ch32v203
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
../ch32v203/
|
1
V203F6P6/thermometer/common
Symbolic link
1
V203F6P6/thermometer/common
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
../common/
|
46
V203F6P6/thermometer/extdata.c
Normal file
46
V203F6P6/thermometer/extdata.c
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
/* GENERATED FILE DO NOT EDIT */
|
||||||
|
#ifndef EXTROM
|
||||||
|
#error "Compile with -DEXTROM=1"
|
||||||
|
#endif
|
||||||
|
#include "gsmdata.h"
|
||||||
|
const SayedTexts sayed_texts = {
|
||||||
|
.nula = { 0x0000a2a0u, 22 },
|
||||||
|
.jedna = { 0x00009f60u, 25 },
|
||||||
|
.dva = { 0x00009c80u, 22 },
|
||||||
|
.dve = { 0x00009920u, 26 },
|
||||||
|
.tri = { 0x00009680u, 20 },
|
||||||
|
.ctyri = { 0x00009300u, 27 },
|
||||||
|
.pet = { 0x00009080u, 19 },
|
||||||
|
.sest = { 0x00008d20u, 26 },
|
||||||
|
.sedm = { 0x00008a20u, 23 },
|
||||||
|
.osm = { 0x000087e0u, 17 },
|
||||||
|
.devet = { 0x00008460u, 27 },
|
||||||
|
.deset = { 0x000080e0u, 27 },
|
||||||
|
.jedenact = { 0x00007c00u, 37 },
|
||||||
|
.dvanact = { 0x00007740u, 36 },
|
||||||
|
.trinact = { 0x00007280u, 36 },
|
||||||
|
.ctrnact = { 0x00006da0u, 37 },
|
||||||
|
.patnact = { 0x00006920u, 34 },
|
||||||
|
.sestnact = { 0x00006300u, 47 },
|
||||||
|
.sedmnact = { 0x00005d40u, 44 },
|
||||||
|
.osmnact = { 0x00005840u, 38 },
|
||||||
|
.devatenact = { 0x000052a0u, 43 },
|
||||||
|
.dvacet = { 0x00004ea0u, 31 },
|
||||||
|
.tricet = { 0x00004ae0u, 29 },
|
||||||
|
.ctyricet = { 0x00004640u, 35 },
|
||||||
|
.padesat = { 0x000041c0u, 34 },
|
||||||
|
.sedesat = { 0x00003c80u, 40 },
|
||||||
|
.sedmdesat = { 0x000036a0u, 45 },
|
||||||
|
.osmdesat = { 0x00003180u, 39 },
|
||||||
|
.devadesat = { 0x00002c20u, 41 },
|
||||||
|
.sto = { 0x00002940u, 22 },
|
||||||
|
.dveste = { 0x00002440u, 38 },
|
||||||
|
.sta = { 0x00002180u, 21 },
|
||||||
|
.set = { 0x00001ec0u, 21 },
|
||||||
|
.tisic = { 0x00001ac0u, 31 },
|
||||||
|
.tisice = { 0x000015a0u, 39 },
|
||||||
|
.minus = { 0x000011e0u, 29 },
|
||||||
|
.point = { 0x00000e20u, 29 },
|
||||||
|
.hafo = { 0x00000ac0u, 26 },
|
||||||
|
.units = { 0x00000280u, 64 },
|
||||||
|
};
|
27
V203F6P6/thermometer/extflash/Makefile
Normal file
27
V203F6P6/thermometer/extflash/Makefile
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
PR = test
|
||||||
|
VPATH = .
|
||||||
|
CXX = g++
|
||||||
|
CC = gcc
|
||||||
|
CFLAGS = -Wall -Os -I.. -I../lib/gsm/inc
|
||||||
|
#CFLAGS+= -DDEBUG
|
||||||
|
MFLAGS = -o $(PR)
|
||||||
|
LFLAGS =
|
||||||
|
#arm-none-eabi-
|
||||||
|
|
||||||
|
all: data.elf $(PR)
|
||||||
|
|
||||||
|
OBJECTS = main.o gsmdata.o texts.o
|
||||||
|
|
||||||
|
$(PR): $(OBJECTS)
|
||||||
|
$(CXX) $(MFLAGS) $(OBJECTS) $(LFLAGS)
|
||||||
|
clean:
|
||||||
|
rm -f *.o *~ data.elf data.map data.hex $(PR)
|
||||||
|
%.o: %.cpp
|
||||||
|
$(CXX) -std=c++14 -c $(CFLAGS) -o $@ $<
|
||||||
|
%.o: %.c
|
||||||
|
$(CC) -c $(CFLAGS) -o $@ $<
|
||||||
|
data.elf: gsmdata.c
|
||||||
|
gcc -Wall -Os -I.. -I../lib/gsm/inc -Wl,-Map=data.map,--gc-sections -nostdlib -nostartfiles -o data.elf gsmdata.c -L. -T script.ld
|
||||||
|
objcopy -O binary data.elf data.bin
|
||||||
|
#objcopy -O ihex data.elf data.hex
|
||||||
|
.PHONY: all clean
|
1398
V203F6P6/thermometer/extflash/gsmdata.c
Normal file
1398
V203F6P6/thermometer/extflash/gsmdata.c
Normal file
File diff suppressed because it is too large
Load diff
127
V203F6P6/thermometer/extflash/main.cpp
Normal file
127
V203F6P6/thermometer/extflash/main.cpp
Normal file
|
@ -0,0 +1,127 @@
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "gsmdata.h"
|
||||||
|
#include "texts.h"
|
||||||
|
/* Jedna z možností jak dostat data do externí flash. Sice to poněkud
|
||||||
|
* nabobtná (na začátku je zbytečně celá struktura SayedTexts + padding),
|
||||||
|
* ale funguje to.
|
||||||
|
* 1. zdroják gsmdata.c se přeloží a pomocí linker skriptu se vytvoří elf
|
||||||
|
* 2. z elf se udělá binárka, příp. hex soubor standardním binutils
|
||||||
|
* 3. binárka se tímto přečte a do extdata.c se extrahují potřebné informace.
|
||||||
|
* extdata.c pak obsahuje adresy slov a jejich délky potřebné pro čtení.
|
||||||
|
* Nezávisí to na tom, zda se binárka vytváří na 64. nebo 32. bit stroji. */
|
||||||
|
static void test () {
|
||||||
|
return;
|
||||||
|
// delky sedi
|
||||||
|
printf("l=0x%zX, f=%zd\n", sizeof(sayed_texts), sizeof(gsm_frame));
|
||||||
|
const gsm_frame * p = sayed_texts.nula.frames;
|
||||||
|
const int n = sayed_texts.nula.no_frames;
|
||||||
|
const unsigned char * o = (const unsigned char *) p;
|
||||||
|
for (int i=0; i<n; i++) {
|
||||||
|
const unsigned char * c = p [i];
|
||||||
|
int d = int (c - o);
|
||||||
|
printf("p=%p, d=%d\n", c, d);
|
||||||
|
o = c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
class Reader {
|
||||||
|
unsigned char * file_data;
|
||||||
|
int file_size;
|
||||||
|
public:
|
||||||
|
explicit Reader() : file_data(nullptr), file_size(0) {}
|
||||||
|
~Reader() {
|
||||||
|
if (file_data) delete [] file_data;
|
||||||
|
}
|
||||||
|
int process (const char * filename);
|
||||||
|
protected:
|
||||||
|
void check ();
|
||||||
|
void compare (const size_t ne, const gsm_frame * c, const int f);
|
||||||
|
void generate();
|
||||||
|
};
|
||||||
|
int Reader::process(const char * filename) {
|
||||||
|
struct stat statbuf;
|
||||||
|
int r = ::stat(filename, &statbuf);
|
||||||
|
if (r < 0) return -1;
|
||||||
|
if (file_data) delete [] file_data;
|
||||||
|
file_data = new unsigned char [statbuf.st_size];
|
||||||
|
FILE * in_file = fopen(filename, "r");
|
||||||
|
r = fread (file_data, 1, statbuf.st_size, in_file);
|
||||||
|
file_size = r;
|
||||||
|
printf("readen %d bytes (%g 0x1000 blocks)\n", file_size, double(file_size)/4096.0);
|
||||||
|
if (!in_file) return -1;
|
||||||
|
fclose(in_file);
|
||||||
|
check(); // kontrola - mělo by sedět to co je v data.bin a přeložené gsmdata.c
|
||||||
|
generate(); // generuje C-soubor s adresami a počty rámců
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
void Reader::check() {
|
||||||
|
if (!file_size) return;
|
||||||
|
// file_data[1000] = 0; // když něco změním, opravdu nastane chyba
|
||||||
|
SayedTexts st;
|
||||||
|
memcpy (&st, file_data, sizeof(SayedTexts));
|
||||||
|
const text_p * ebase = (text_p *) & st;
|
||||||
|
const text_p * cbase = (text_p *) & sayed_texts;
|
||||||
|
const size_t count = sizeof(SayedTexts) / sizeof (text_p);
|
||||||
|
printf("count=%zd\n", count);
|
||||||
|
for (unsigned n=0; n<count; n++) {
|
||||||
|
const text_p & ep = ebase [n];
|
||||||
|
const text_p & cp = cbase [n];
|
||||||
|
if (ep.no_frames != cp.no_frames) // struct SayedTexts OK.
|
||||||
|
printf("eframe: %p len=%d, cframe: %p, len=%d\n", ep.frames, ep.no_frames, cp.frames, cp.no_frames);
|
||||||
|
compare (size_t (ep.frames), cp.frames, cp.no_frames);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static bool compare_frame (const unsigned char * a, const unsigned char * b, const int n) {
|
||||||
|
for (int i=0; i<n; i++) {
|
||||||
|
if (a [i] != b [i]) return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
void Reader::compare(const size_t ne, const gsm_frame * c, const int f) {
|
||||||
|
// ofset + adresa pameti
|
||||||
|
const gsm_frame * e = (gsm_frame *) (ne + (size_t) file_data);
|
||||||
|
for (int k=0; k<f; k++) {
|
||||||
|
const unsigned char * a = c [k];
|
||||||
|
const unsigned char * b = e [k];
|
||||||
|
if (!k) { // jen aby bylo neco videt
|
||||||
|
for (int n=0; n<10; n++) printf("%02X:%02X|", a[n], b[n]);
|
||||||
|
printf("...\n");
|
||||||
|
}
|
||||||
|
if (!compare_frame(a, b, sizeof(gsm_frame))) printf ("error:%d\n", k);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Jen toto je podstatné - vytvoření extdata.c
|
||||||
|
static const char * prefix = R"---(/* GENERATED FILE DO NOT EDIT */
|
||||||
|
#ifndef EXTROM
|
||||||
|
#error "Compile with -DEXTROM=1"
|
||||||
|
#endif
|
||||||
|
#include "gsmdata.h"
|
||||||
|
const SayedTexts sayed_texts = {
|
||||||
|
)---";
|
||||||
|
void Reader::generate() {
|
||||||
|
FILE * out = fopen("../extdata.c","w");
|
||||||
|
fprintf(out, "%s", prefix);
|
||||||
|
SayedTexts st;
|
||||||
|
memcpy (&st, file_data, sizeof(SayedTexts));
|
||||||
|
constexpr size_t count = sizeof( SayedTexts) / sizeof (text_p);
|
||||||
|
constexpr size_t txtct = sizeof(eSayedTexts) / sizeof (text_pair);
|
||||||
|
static_assert (count == txtct, "Bad size, regenerate sources");
|
||||||
|
const text_p * ebase = (text_p *) & st; // pole ze struktury (stejných prvků)
|
||||||
|
const text_pair * tbase = (text_pair*) & helper_texts;
|
||||||
|
for (unsigned n=0; n<count; n++) {
|
||||||
|
const text_p & ep = ebase [n];
|
||||||
|
const text_pair & tp = tbase [n];
|
||||||
|
fprintf(out, " .%s = { 0x%08lxu, %d },\n", tp.name, size_t (ep.frames), ep.no_frames);
|
||||||
|
}
|
||||||
|
fprintf(out, "};\n");
|
||||||
|
fclose(out);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// main ()
|
||||||
|
int main (int argc, char *argv[]) {
|
||||||
|
test(); // gsm ramce jsou pakovane, nemel by byt problem.
|
||||||
|
Reader read;
|
||||||
|
return read.process("data.bin");
|
||||||
|
}
|
40
V203F6P6/thermometer/extflash/script.ld
Normal file
40
V203F6P6/thermometer/extflash/script.ld
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
/*OUTPUT_FORMAT (binary) možnosti zjistíme příkazem "objdump -i" (lze i ihex) */
|
||||||
|
|
||||||
|
ENTRY (sayed_texts) /* odtud se začne (start po resetu) */
|
||||||
|
/* popis pamětí */
|
||||||
|
MEMORY {
|
||||||
|
ram (RWX) : ORIGIN = 0x00, LENGTH = 0x40000
|
||||||
|
}
|
||||||
|
/* popis sekcí */
|
||||||
|
SECTIONS {
|
||||||
|
.fixed : { /* výstupní sekce v rom - nazveme např. .fixed */
|
||||||
|
. = ALIGN (8); /* zarovnání příští sekce na 4 byty (celkem zbytečné) */
|
||||||
|
*(.data.rel.ro*)
|
||||||
|
*(.rodata*) /* .rodata* - stejně jako .text*, ale pro const proměnné (data) (-fdata-sections) */
|
||||||
|
. = ALIGN (8);
|
||||||
|
*(.text*) /* gcc pojmenovává sekce s kódem jako .text, pokud je použito -ffunction-sections,
|
||||||
|
pak bude každá funkce v jiné sekci s názvy .text.jmeno_funkce, proto ta * na konci */
|
||||||
|
. = ALIGN (8);
|
||||||
|
*(.data*) /* .data* - stejně jako .text*, ale pro proměnné (data inicializovaná) */
|
||||||
|
. = ALIGN (8);
|
||||||
|
*(.bss*) /* .bss* - stejně jako .text*, ale pro proměnné (data inicializovaná na 0) */
|
||||||
|
*(COMMON*)
|
||||||
|
*(.note.*)
|
||||||
|
. = ALIGN (4096);
|
||||||
|
relocate_end = .; /* konec dat v sekci .relocate - podle toho se např. nějak určí hodnota SP */
|
||||||
|
end = .;
|
||||||
|
} > ram /* tady je řečeno, že to má být v ram */
|
||||||
|
/DISCARD/ : {
|
||||||
|
*(.rela*)
|
||||||
|
*(.dynamic)
|
||||||
|
*(.eh*)
|
||||||
|
*(.debug*)
|
||||||
|
*(.comment*)
|
||||||
|
*(.interp)
|
||||||
|
*(.dynsym)
|
||||||
|
*(.dynstr)
|
||||||
|
*(.hash)
|
||||||
|
*(.gnu.hash)
|
||||||
|
*(.header)
|
||||||
|
} : phdr
|
||||||
|
}
|
47
V203F6P6/thermometer/extflash/texts.c
Normal file
47
V203F6P6/thermometer/extflash/texts.c
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
#include "texts.h"
|
||||||
|
const eSayedTexts helper_texts = {
|
||||||
|
.nula = { "nula", "nula" },
|
||||||
|
.jedna = { "jedna", "jedna" },
|
||||||
|
.dva = { "dva", "dva" },
|
||||||
|
.dve = { "dve", "dvě" },
|
||||||
|
.tri = { "tri", "tři" },
|
||||||
|
.ctyri = { "ctyri", "čtyři" },
|
||||||
|
.pet = { "pet", "pět" },
|
||||||
|
.sest = { "sest", "šest" },
|
||||||
|
.sedm = { "sedm", "sedm" },
|
||||||
|
.osm = { "osm", "osm" },
|
||||||
|
.devet = { "devet", "devět" },
|
||||||
|
|
||||||
|
.deset = { "deset", "deset" },
|
||||||
|
.jedenact = { "jedenact", "jedenáct" },
|
||||||
|
.dvanact = { "dvanact", "dvanáct" },
|
||||||
|
.trinact = { "trinact", "třináct" },
|
||||||
|
.ctrnact = { "ctrnact", "čtrnáct" },
|
||||||
|
.patnact = { "patnact", "patnáct" },
|
||||||
|
.sestnact = { "sestnact", "šestnáct" },
|
||||||
|
.sedmnact = { "sedmnact", "sedmnáct" },
|
||||||
|
.osmnact = { "osmnact", "osmnáct" },
|
||||||
|
.devatenact = { "devatenact", "devatenáct" },
|
||||||
|
|
||||||
|
.dvacet = { "dvacet", "dvacet" },
|
||||||
|
.tricet = { "tricet", "třicet" },
|
||||||
|
.ctyricet = { "ctyricet", "čtyřicet" },
|
||||||
|
.padesat = { "padesat", "padesát" },
|
||||||
|
.sedesat = { "sedesat", "šedesát" },
|
||||||
|
.sedmdesat = { "sedmdesat", "sedmdesát" },
|
||||||
|
.osmdesat = { "osmdesat", "osmdesát" },
|
||||||
|
.devadesat = { "devadesat", "devadesát" },
|
||||||
|
|
||||||
|
.sto = { "sto", "sto" },
|
||||||
|
.dveste = { "dveste", "dvěstě" },
|
||||||
|
.sta = { "sta", "sta" },
|
||||||
|
.set = { "set", "set" },
|
||||||
|
.tisic = { "tisic", "tisíc" },
|
||||||
|
.tisice = { "tisice", "tisíce" },
|
||||||
|
|
||||||
|
.minus = { "minus", "mínus" },
|
||||||
|
.point = { "point", "celých" },
|
||||||
|
.hafo = { "hafo", "hafo" },
|
||||||
|
.units = { "units", "stupňů Celzia" },
|
||||||
|
//.svejk = { "svejk", svejk_t },
|
||||||
|
};
|
26
V203F6P6/thermometer/extflash/texts.h
Normal file
26
V203F6P6/thermometer/extflash/texts.h
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
#ifndef TEXTS_H
|
||||||
|
#define TEXTS_H
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif // __cplusplus
|
||||||
|
typedef struct text_pair_s {
|
||||||
|
const char * name;
|
||||||
|
const char * text;
|
||||||
|
} text_pair;
|
||||||
|
typedef struct eSayedTexts_s {
|
||||||
|
// mandatorní část použitá v playeru :
|
||||||
|
text_pair nula, jedna, dva, dve, tri, ctyri, pet, sest, sedm, osm, devet;
|
||||||
|
text_pair deset, jedenact, dvanact, trinact, ctrnact, patnact;
|
||||||
|
text_pair sestnact, sedmnact, osmnact, devatenact;
|
||||||
|
text_pair dvacet, tricet, ctyricet, padesat, sedesat, sedmdesat, osmdesat, devadesat;
|
||||||
|
text_pair sto, dveste, sta, set, tisic, tisice;
|
||||||
|
|
||||||
|
text_pair minus, point, hafo, units;
|
||||||
|
// uživatelské texty :
|
||||||
|
// text_pair svejk;
|
||||||
|
} eSayedTexts;
|
||||||
|
extern const eSayedTexts helper_texts;
|
||||||
|
#ifdef __cplusplus
|
||||||
|
};
|
||||||
|
#endif // __cplusplus
|
||||||
|
#endif // TEXTS_H
|
62
V203F6P6/thermometer/gsmdata.h
Normal file
62
V203F6P6/thermometer/gsmdata.h
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
/* GENERATED FILE DO NOT EDIT !!! */
|
||||||
|
#ifndef _GSM_DATA_H
|
||||||
|
#define _GSM_DATA_H
|
||||||
|
#include "gsm.h"
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif // __cplusplus
|
||||||
|
typedef struct gsm_data_s {
|
||||||
|
#ifdef EXTROM
|
||||||
|
unsigned long frames;
|
||||||
|
#else
|
||||||
|
const gsm_frame * frames;
|
||||||
|
#endif
|
||||||
|
int no_frames;
|
||||||
|
} text_p;
|
||||||
|
typedef struct SayedTexts_s {
|
||||||
|
text_p nula;
|
||||||
|
text_p jedna;
|
||||||
|
text_p dva;
|
||||||
|
text_p dve;
|
||||||
|
text_p tri;
|
||||||
|
text_p ctyri;
|
||||||
|
text_p pet;
|
||||||
|
text_p sest;
|
||||||
|
text_p sedm;
|
||||||
|
text_p osm;
|
||||||
|
text_p devet;
|
||||||
|
text_p deset;
|
||||||
|
text_p jedenact;
|
||||||
|
text_p dvanact;
|
||||||
|
text_p trinact;
|
||||||
|
text_p ctrnact;
|
||||||
|
text_p patnact;
|
||||||
|
text_p sestnact;
|
||||||
|
text_p sedmnact;
|
||||||
|
text_p osmnact;
|
||||||
|
text_p devatenact;
|
||||||
|
text_p dvacet;
|
||||||
|
text_p tricet;
|
||||||
|
text_p ctyricet;
|
||||||
|
text_p padesat;
|
||||||
|
text_p sedesat;
|
||||||
|
text_p sedmdesat;
|
||||||
|
text_p osmdesat;
|
||||||
|
text_p devadesat;
|
||||||
|
text_p sto;
|
||||||
|
text_p dveste;
|
||||||
|
text_p sta;
|
||||||
|
text_p set;
|
||||||
|
text_p tisic;
|
||||||
|
text_p tisice;
|
||||||
|
text_p minus;
|
||||||
|
text_p point;
|
||||||
|
text_p hafo;
|
||||||
|
text_p units;
|
||||||
|
|
||||||
|
} SayedTexts;
|
||||||
|
extern const SayedTexts sayed_texts;
|
||||||
|
#ifdef __cplusplus
|
||||||
|
};
|
||||||
|
#endif // __cplusplus
|
||||||
|
#endif // _GSM_DATA_H
|
1
V203F6P6/thermometer/lib
Symbolic link
1
V203F6P6/thermometer/lib
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
../../V203/gsm/lib/
|
30
V203F6P6/thermometer/main.cpp
Normal file
30
V203F6P6/thermometer/main.cpp
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
#include "pwmclass.h"
|
||||||
|
#include "fifo.h"
|
||||||
|
#include "player.h"
|
||||||
|
#include "GsmDecoder.h"
|
||||||
|
// #include "adcdma.h"
|
||||||
|
#include "oneway.h"
|
||||||
|
#include "gpio.h"
|
||||||
|
////////////////////////////////////////////////////////
|
||||||
|
/* Demo, které jen počítá od 0 do 1000000. Výstup je PWM
|
||||||
|
* na pinu PA2 24kHz, enable PB1. Odvozeno z teploměru na
|
||||||
|
* https://github.com/Kizarm/TTSCP_Client/tree/main/kecal/stm
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
////////////////////////////////////////////////////////
|
||||||
|
static GpioClass led (GPIOB, 8);
|
||||||
|
static PwmClass pwm;
|
||||||
|
static FIFO<uint32_t, FIFOLEN> fifo;
|
||||||
|
static TextPlayer player (fifo, led);
|
||||||
|
static GsmDecoder decoder(fifo);
|
||||||
|
|
||||||
|
int main () {
|
||||||
|
led << true;
|
||||||
|
unsigned counter = 0u;
|
||||||
|
pwm.attach (decoder);
|
||||||
|
for (;;) {
|
||||||
|
player.say(counter++);
|
||||||
|
pwm.delay ();
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
45
V203F6P6/thermometer/norflash.cpp
Normal file
45
V203F6P6/thermometer/norflash.cpp
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
#include "string.h"
|
||||||
|
#include "norflash.h"
|
||||||
|
|
||||||
|
/// Enumerace povelů pro SPI FLASH.
|
||||||
|
enum FLASH_COMMANDS : uint8_t {
|
||||||
|
/* single byte commands */
|
||||||
|
FLASH_WRDI = 0x04, // nepoužito
|
||||||
|
FLASH_WREN = 0x06,
|
||||||
|
FLASH_RDID = 0x9F,
|
||||||
|
FLASHRSTEN = 0x66, // nepoužito
|
||||||
|
FLASH__RST = 0x99, // nepoužito
|
||||||
|
FLASH__RES = 0xAB, // release from power down, nepoužito
|
||||||
|
FLASH__DPD = 0xB9, // power down, nepoužito
|
||||||
|
// multi - byte
|
||||||
|
FLASH_RDSR1 = 0x05,
|
||||||
|
// dále se mohou povely lišit
|
||||||
|
FLASH_RDSR2 = 0x35, // nepoužito
|
||||||
|
FLASH_4READ = 0x03,
|
||||||
|
FLASH_4PP = 0x02,
|
||||||
|
FLASH_4SE = 0x20,
|
||||||
|
};
|
||||||
|
union FlashCommandHeader {
|
||||||
|
struct {
|
||||||
|
FLASH_COMMANDS cmd : 8;
|
||||||
|
uint32_t adr : 24; // adresa je BIG ENDIEN - vyšší byte vystupuje po SPI dříve (MSB FIRST).
|
||||||
|
}__attribute__((packed));
|
||||||
|
uint8_t bytes [4];
|
||||||
|
}__attribute__((packed));
|
||||||
|
static inline uint32_t be_set_24 (const uint32_t p) {
|
||||||
|
return ((p & 0x000000ff) << 16)
|
||||||
|
| ((p & 0x0000ff00) << 0)
|
||||||
|
| ((p & 0x00ff0000) >> 16);
|
||||||
|
}
|
||||||
|
/* Nic jiného zatím není potřeba, ale šlo by dodělat i zápis včetně mazání bloku.
|
||||||
|
*/
|
||||||
|
unsigned int NorFlash::ReadBlock(const unsigned int addr, uint8_t * data, const unsigned int len) {
|
||||||
|
FlashCommandHeader header;
|
||||||
|
header.cmd = FLASH_4READ;
|
||||||
|
header.adr = be_set_24(addr);
|
||||||
|
spi.ChipSelect(true);
|
||||||
|
for (unsigned n=0u; n<sizeof(header); n++) spi.ReadWriteByte(header.bytes[n]);
|
||||||
|
for (unsigned n=0u; n<len; n++) data [n] = spi.ReadWriteByte(0xff);
|
||||||
|
spi.ChipSelect(false);
|
||||||
|
return len;
|
||||||
|
}
|
13
V203F6P6/thermometer/norflash.h
Normal file
13
V203F6P6/thermometer/norflash.h
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
#ifndef NORFLASH_H
|
||||||
|
#define NORFLASH_H
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "spiblocked.h"
|
||||||
|
|
||||||
|
class NorFlash {
|
||||||
|
SpiBlocked spi;
|
||||||
|
public:
|
||||||
|
explicit NorFlash () noexcept : spi() {}
|
||||||
|
unsigned ReadBlock (const unsigned addr, uint8_t * data, const unsigned len);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // NORFLASH_H
|
153
V203F6P6/thermometer/player.cpp
Normal file
153
V203F6P6/thermometer/player.cpp
Normal file
|
@ -0,0 +1,153 @@
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "player.h"
|
||||||
|
|
||||||
|
/******************************************************************/
|
||||||
|
static constexpr int dmult (const int n) {
|
||||||
|
int r = 1;
|
||||||
|
for (int i=0; i<n; i++) r *= 10;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
static constexpr int strip_zeros (const int n) {
|
||||||
|
if ((n % 10) != 0) return n;
|
||||||
|
return strip_zeros(n / 10);
|
||||||
|
}
|
||||||
|
void TextPlayer::say(const int number) {
|
||||||
|
if (!number) out(m_t.nula);
|
||||||
|
else sre (number);
|
||||||
|
}
|
||||||
|
void TextPlayer::say(const int number, const int dnum) {
|
||||||
|
if (dnum <= 0 or dnum > 3) { out(m_t.hafo); return; } // meze 1..3
|
||||||
|
if (number < 0) {
|
||||||
|
out (m_t.minus); say (-number, dnum); return;
|
||||||
|
}
|
||||||
|
const div_t dt = ::div (number, dmult(dnum));
|
||||||
|
if (dt.quot) sre(dt.quot);
|
||||||
|
else out(m_t.nula);
|
||||||
|
out(m_t.point);
|
||||||
|
mil(dt.rem, dnum);
|
||||||
|
}
|
||||||
|
void TextPlayer::mil(const int number, const int dnum) {
|
||||||
|
if (number == 0) { out(m_t.nula); return; }
|
||||||
|
const int max = dmult(dnum - 1);
|
||||||
|
if (number < max) {
|
||||||
|
out(m_t.nula);
|
||||||
|
mil(number * 10, dnum);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
sre (strip_zeros(number));
|
||||||
|
}
|
||||||
|
|
||||||
|
void TextPlayer::sre(const int number) {
|
||||||
|
if (number < 0) {
|
||||||
|
out (m_t.minus);
|
||||||
|
sre (-number);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (number >= 1000000) {
|
||||||
|
out(m_t.hafo);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (number == 1000) {
|
||||||
|
out(m_t.tisic);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (number > 1000) {
|
||||||
|
const div_t dt = ::div (number, 1000);
|
||||||
|
sre (dt.quot);
|
||||||
|
const int ln = dt.quot % 10;
|
||||||
|
(ln < 2 or ln > 4) ? out(m_t.tisic) : out(m_t.tisice);
|
||||||
|
sre (dt.rem);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (number == 100) {
|
||||||
|
out(m_t.sto);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (number > 100) {
|
||||||
|
const div_t dt = ::div (number, 100);
|
||||||
|
const int ln = dt.quot % 10;
|
||||||
|
//printf ("stovky:%d ", ln);
|
||||||
|
hec (ln);
|
||||||
|
sre (dt.rem);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (number == 20) {
|
||||||
|
out(m_t.dvacet);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (number > 20) {
|
||||||
|
const div_t dt = ::div (number, 10);
|
||||||
|
const int ln = dt.quot % 10;
|
||||||
|
//printf ("desitky:%d ", ln);
|
||||||
|
dek (ln);
|
||||||
|
sre (dt.rem);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (number == 0) return;
|
||||||
|
// jednotky 1 .. 19
|
||||||
|
// printf("jednotky:%d ", number);
|
||||||
|
one (number);
|
||||||
|
}
|
||||||
|
void TextPlayer::hec(const int number) {
|
||||||
|
switch (number) {
|
||||||
|
case 1: out (m_t.sto); break;
|
||||||
|
case 2: out (m_t.dveste); break;
|
||||||
|
case 3:
|
||||||
|
case 4: one(number); out (m_t.sta); break;
|
||||||
|
case 5:
|
||||||
|
case 6:
|
||||||
|
case 7:
|
||||||
|
case 8:
|
||||||
|
case 9: one(number); out (m_t.set); break;
|
||||||
|
default: break;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
void TextPlayer::dek(const int number) {
|
||||||
|
switch (number) {
|
||||||
|
case 2: out (m_t.dvacet); break;
|
||||||
|
case 3: out (m_t.tricet); break;
|
||||||
|
case 4: out (m_t.ctyricet); break;
|
||||||
|
case 5: out (m_t.padesat); break;
|
||||||
|
case 6: out (m_t.sedesat); break;
|
||||||
|
case 7: out (m_t.sedmdesat); break;
|
||||||
|
case 8: out (m_t.osmdesat); break;
|
||||||
|
case 9: out (m_t.devadesat); break;
|
||||||
|
default: break;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
void TextPlayer::one(const int number) {
|
||||||
|
// 1..19
|
||||||
|
switch (number) {
|
||||||
|
case 1: out (m_t.jedna); break;
|
||||||
|
case 2: out (m_t.dva); break;
|
||||||
|
case 3: out (m_t.tri); break;
|
||||||
|
case 4: out (m_t.ctyri); break;
|
||||||
|
case 5: out (m_t.pet); break;
|
||||||
|
case 6: out (m_t.sest); break;
|
||||||
|
case 7: out (m_t.sedm); break;
|
||||||
|
case 8: out (m_t.osm); break;
|
||||||
|
case 9: out (m_t.devet); break;
|
||||||
|
case 10: out (m_t.deset); break;
|
||||||
|
case 11: out (m_t.jedenact); break;
|
||||||
|
case 12: out (m_t.dvanact); break;
|
||||||
|
case 13: out (m_t.trinact); break;
|
||||||
|
case 14: out (m_t.ctrnact); break;
|
||||||
|
case 15: out (m_t.patnact); break;
|
||||||
|
case 16: out (m_t.sestnact); break;
|
||||||
|
case 17: out (m_t.sedmnact); break;
|
||||||
|
case 18: out (m_t.osmnact); break;
|
||||||
|
case 19: out (m_t.devatenact); break;
|
||||||
|
default: break;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
void TextPlayer::out(const text_p & o) {
|
||||||
|
led << true; // led svítí, pokud to mluví
|
||||||
|
const int len = o.no_frames;
|
||||||
|
for (int n=0; n<len; n++) {
|
||||||
|
const uint32_t addr = o.frames + n * sizeof (gsm_frame);
|
||||||
|
while (true) {
|
||||||
|
if (fifo.Write(addr)) break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
led << false;
|
||||||
|
}
|
30
V203F6P6/thermometer/player.h
Normal file
30
V203F6P6/thermometer/player.h
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
#ifndef PLAYER_H
|
||||||
|
#define PLAYER_H
|
||||||
|
#include "gpio.h"
|
||||||
|
#include "gsmdata.h"
|
||||||
|
#include "fifo.h"
|
||||||
|
static constexpr int GSMLEN = 160;
|
||||||
|
static constexpr int FIFOLEN = 8;
|
||||||
|
/* Algoritmus vyslovení čísla v češtině. Sémantika není dokonalá, ale dá tomu rozumět.
|
||||||
|
* */
|
||||||
|
class TextPlayer {
|
||||||
|
GpioClass & led;
|
||||||
|
const SayedTexts & m_t;
|
||||||
|
FIFO<uint32_t, FIFOLEN> & fifo;
|
||||||
|
public:
|
||||||
|
explicit TextPlayer(FIFO<uint32_t, FIFOLEN> & f, GpioClass & io) noexcept :
|
||||||
|
led (io), m_t(sayed_texts), fifo(f) {}
|
||||||
|
void say (const int number); // celé číslo
|
||||||
|
void say (const int number, const int dnum); // celé číslo jako desetinné s dnum míst (1 .. 3)
|
||||||
|
void say (const text_p & o) { out (o); } // přetížení pro uživatelská slova
|
||||||
|
protected:
|
||||||
|
void sre (const int number);
|
||||||
|
void hec (const int number);
|
||||||
|
void dek (const int number);
|
||||||
|
void one (const int number);
|
||||||
|
void mil (const int number, const int dnum);
|
||||||
|
|
||||||
|
void out (const text_p & o);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // PLAYER_H
|
107
V203F6P6/thermometer/pwmclass.cpp
Normal file
107
V203F6P6/thermometer/pwmclass.cpp
Normal file
|
@ -0,0 +1,107 @@
|
||||||
|
#include "pwmclass.h"
|
||||||
|
#include "gpio.h"
|
||||||
|
typedef __SIZE_TYPE__ size_t;
|
||||||
|
extern "C" {
|
||||||
|
[[gnu::interrupt]] extern void DMA1_Channel2_IRQHandler( void );
|
||||||
|
};
|
||||||
|
static PwmClass * pPwmInstance = nullptr;
|
||||||
|
void DMA1_Channel2_IRQHandler( void ) {
|
||||||
|
DMA1_Type::INTFR_DEF state (DMA1.INTFR);
|
||||||
|
if (state.B.GIF2 != RESET) {
|
||||||
|
DMA1.INTFCR.B.CGIF2 = SET;
|
||||||
|
} else return;
|
||||||
|
if (state.B.HTIF2 != RESET) {
|
||||||
|
DMA1.INTFCR.B.CHTIF2 = SET;
|
||||||
|
if (pPwmInstance) pPwmInstance->send(false);
|
||||||
|
}
|
||||||
|
if (state.B.TCIF2 != RESET) {
|
||||||
|
DMA1.INTFCR.B.CTCIF2 = SET;
|
||||||
|
if (pPwmInstance) pPwmInstance->send(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* initialize TIM2 for PWM
|
||||||
|
*/
|
||||||
|
inline void PwmClass::TimInit() noexcept {
|
||||||
|
// Enable GPIOA and TIM1
|
||||||
|
RCC.APB2PCENR.modify([] (RCC_Type::APB2PCENR_DEF & r) -> auto {
|
||||||
|
r.B.IOPAEN = SET;
|
||||||
|
r.B.IOPBEN = SET;
|
||||||
|
//r.B.AFIOEN = SET;
|
||||||
|
return r.R;
|
||||||
|
});
|
||||||
|
RCC.APB1PCENR.B.TIM2EN = SET;
|
||||||
|
// PA2 is TIM2_CH3, 10MHz Output alt func, push-pull
|
||||||
|
GPIOA.CFGLR.modify([](GPIOA_Type::CFGLR_DEF & r) -> auto {
|
||||||
|
r.B.CNF2 = 2u;
|
||||||
|
r.B.MODE2 = 1u;
|
||||||
|
return r.R;
|
||||||
|
});
|
||||||
|
// PB1 is DEN, active H Output 10 MHz, push-pull
|
||||||
|
GPIOB.CFGLR.modify([](GPIOA_Type::CFGLR_DEF & r) -> auto {
|
||||||
|
r.B.CNF1 = 0u;
|
||||||
|
r.B.MODE1 = 1u;
|
||||||
|
return r.R;
|
||||||
|
});
|
||||||
|
GPIOB.BSHR.B.BS1 = SET; // set to H
|
||||||
|
// Reset TIM2 to init all regs
|
||||||
|
RCC.APB1PRSTR.B.TIM2RST = SET;
|
||||||
|
RCC.APB1PRSTR.B.TIM2RST = RESET;
|
||||||
|
// CTLR1: default is up, events generated, edge align
|
||||||
|
// SMCFGR: default clk input is CK_INT
|
||||||
|
// Prescaler
|
||||||
|
TIM2.PSC.R = 0u; // 144 MHz
|
||||||
|
// Auto Reload - sets period
|
||||||
|
TIM2.ATRLR.R = MAXPWM - 1; // 24 kHz
|
||||||
|
|
||||||
|
// CH3 Mode is output, PWM1 (CC3S = 00, OC3M = 110)
|
||||||
|
TIM2.CHCTLR2_Output.modify([](TIM2_Type::CHCTLR2_Output_DEF & r) -> auto {
|
||||||
|
r.B.OC3M = 0x6u;
|
||||||
|
return r.R;
|
||||||
|
});
|
||||||
|
// Enable TIM1 outputs
|
||||||
|
TIM2.CCER.modify([](TIM2_Type::CCER_DEF & r) -> auto {
|
||||||
|
// Enable CH3, CH3 output, positive pol
|
||||||
|
r.B.CC3E = SET;
|
||||||
|
//r.B.CC3P = SET; // negative
|
||||||
|
return r.R;
|
||||||
|
});
|
||||||
|
// Reload immediately + Trigger DMA
|
||||||
|
TIM2.SWEVGR.B.UG = SET;
|
||||||
|
TIM2.DMAINTENR.B.UDE = SET;
|
||||||
|
}
|
||||||
|
inline void PwmClass::DmaInit() noexcept {
|
||||||
|
// Enable DMA
|
||||||
|
RCC.AHBPCENR.modify([](RCC_Type::AHBPCENR_DEF & r) -> auto {
|
||||||
|
r.B.SRAMEN = SET;
|
||||||
|
r.B.DMA1EN = SET;
|
||||||
|
return r.R;
|
||||||
|
});
|
||||||
|
// DMA can be configured to attach to T2UP
|
||||||
|
// The system can only DMA out at ~2.2MSPS. 2MHz is stable.
|
||||||
|
DMA1.CNTR2 .R = FULL_LEN;
|
||||||
|
DMA1.MADDR2.R = reinterpret_cast<size_t>(buffer);
|
||||||
|
DMA1.PADDR2.R = reinterpret_cast<size_t>(& TIM2.CH3CVR);
|
||||||
|
NVIC.EnableIRQ (DMA1_Channel2_IRQn);
|
||||||
|
DMA1.CFGR2.modify([](DMA1_Type::CFGR2_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 CH2
|
||||||
|
r.B.EN = SET;
|
||||||
|
return r.R;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
PwmClass::PwmClass() noexcept : count(0u), pL(buffer), pH(buffer + HALF_LEN), src(nullptr) {
|
||||||
|
pPwmInstance = this;
|
||||||
|
TimInit ();
|
||||||
|
DmaInit ();
|
||||||
|
// Enable TIM2
|
||||||
|
TIM2.CTLR1.B.CEN = SET;
|
||||||
|
}
|
35
V203F6P6/thermometer/pwmclass.h
Normal file
35
V203F6P6/thermometer/pwmclass.h
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
#ifndef PWMCLASS_H
|
||||||
|
#define PWMCLASS_H
|
||||||
|
#include "system.h"
|
||||||
|
#include "oneway.h"
|
||||||
|
static constexpr unsigned MAXPWM = 6000u;
|
||||||
|
/* Používá TIM2, PWM kanál 3, DMA1 kanál 2, přerušení DMA1_Channel2_IRQHandler */
|
||||||
|
class PwmClass {
|
||||||
|
static constexpr unsigned HALF_LEN = 3u * 160u;
|
||||||
|
static constexpr unsigned FULL_LEN = 2u * HALF_LEN;
|
||||||
|
volatile unsigned count;
|
||||||
|
uint16_t * const pL;
|
||||||
|
uint16_t * const pH;
|
||||||
|
uint16_t buffer [FULL_LEN];
|
||||||
|
OneWay<uint16_t> * src;
|
||||||
|
public:
|
||||||
|
explicit PwmClass () noexcept;
|
||||||
|
void attach (OneWay<uint16_t> & s) { src = & s; }
|
||||||
|
void send (const bool b) {
|
||||||
|
if (!src) return;
|
||||||
|
if (b) src->Send (pH, HALF_LEN);
|
||||||
|
else src->Send (pL, HALF_LEN);
|
||||||
|
if (count) count -= 1u;
|
||||||
|
}
|
||||||
|
void delay (const unsigned frames = 50u) {
|
||||||
|
count = frames;
|
||||||
|
while (count) {
|
||||||
|
asm volatile ("nop");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
protected:
|
||||||
|
void DmaInit () noexcept;
|
||||||
|
void TimInit () noexcept;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // PWMCLASS_H
|
66
V203F6P6/thermometer/spiblocked.cpp
Normal file
66
V203F6P6/thermometer/spiblocked.cpp
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
#include "system.h"
|
||||||
|
#include "spiblocked.h"
|
||||||
|
enum SPICLK : uint32_t {
|
||||||
|
FPCLK_2 = 0u, // 72 MHz
|
||||||
|
FPCLK_4, // 36 MHz
|
||||||
|
FPCLK_8, // 18 MHz
|
||||||
|
FPCLK_16, // 9 MHz
|
||||||
|
FPCLK_32, // 4.5 MHz
|
||||||
|
FPCLK_64, // 2.25 MHz
|
||||||
|
FPCLK_128, // 1.125 MHz
|
||||||
|
FPCLK_256, // 0.5625 MHz
|
||||||
|
};
|
||||||
|
static constexpr unsigned FM = 3u; // 50 MHz
|
||||||
|
static void InitPins () noexcept {
|
||||||
|
// PA4 - NSS, PA5 - SCK, PA6 - MISO, PA7 - MOSI
|
||||||
|
GPIOA.CFGLR.modify([](GPIOA_Type::CFGLR_DEF & r) -> uint32_t {
|
||||||
|
r.B.MODE4 = FM;
|
||||||
|
r.B.CNF4 = 0u; // gen push - pull
|
||||||
|
r.B.MODE5 = FM;
|
||||||
|
r.B.CNF5 = 2u; // alt push - pull
|
||||||
|
r.B.MODE6 = 0u; // input mode
|
||||||
|
r.B.CNF6 = 1u; // floating
|
||||||
|
r.B.MODE7 = FM;
|
||||||
|
r.B.CNF7 = 2u; // alt push - pull
|
||||||
|
return r.R;
|
||||||
|
});
|
||||||
|
// AFIO - default
|
||||||
|
GPIOA.BSHR.B.BS4 = SET;
|
||||||
|
}
|
||||||
|
|
||||||
|
SpiBlocked::SpiBlocked() noexcept {
|
||||||
|
RCC.APB2PCENR.modify([](RCC_Type::APB2PCENR_DEF & r) -> uint32_t {
|
||||||
|
r.B.SPI1EN = SET;
|
||||||
|
r.B.IOPAEN = SET;
|
||||||
|
//r.B.AFIOEN = SET;
|
||||||
|
return r.R;
|
||||||
|
});
|
||||||
|
InitPins();
|
||||||
|
RCC.APB2PRSTR.B.SPI1RST = SET;
|
||||||
|
RCC.APB2PRSTR.B.SPI1RST = RESET;
|
||||||
|
SPI1.CTLR1.modify([](SPI1_Type::CTLR1_DEF & r) -> uint32_t {
|
||||||
|
r.B.CPHA = RESET;
|
||||||
|
r.B.CPOL = RESET;
|
||||||
|
r.B.MSTR = SET; // master
|
||||||
|
r.B.DFF = RESET; // 8 bit
|
||||||
|
r.B.SSM = SET; // software
|
||||||
|
r.B.SSI = SET; // !!! netuším proč, ale jinak se nenastaví MSTR a SPE
|
||||||
|
r.B.LSBFIRST = RESET;
|
||||||
|
r.B.BR = FPCLK_64;
|
||||||
|
return r.R;
|
||||||
|
});
|
||||||
|
SPI1.CRCR.R = 7u;
|
||||||
|
SPI1.CTLR1.B.SPE = SET;
|
||||||
|
}
|
||||||
|
uint8_t SpiBlocked::ReadWriteByte(const uint8_t data) {
|
||||||
|
while (SPI1.STATR.B.TXE == RESET);
|
||||||
|
SPI1.DATAR.B.DATAR = data;
|
||||||
|
while (SPI1.STATR.B.RXNE == RESET);
|
||||||
|
return SPI1.DATAR.B.DATAR;
|
||||||
|
}
|
||||||
|
void SpiBlocked::ChipSelect(const bool on) {
|
||||||
|
if (on) GPIOA.BSHR.B.BR4 = SET;
|
||||||
|
else GPIOA.BSHR.B.BS4 = SET;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
12
V203F6P6/thermometer/spiblocked.h
Normal file
12
V203F6P6/thermometer/spiblocked.h
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
#ifndef SPIBLOCKED_H
|
||||||
|
#define SPIBLOCKED_H
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
class SpiBlocked {
|
||||||
|
public:
|
||||||
|
explicit SpiBlocked () noexcept;
|
||||||
|
uint8_t ReadWriteByte (const uint8_t data);
|
||||||
|
void ChipSelect (const bool on);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // SPIBLOCKED_H
|
22
V203F6P6/thermometer/wrap.c
Normal file
22
V203F6P6/thermometer/wrap.c
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
/* Funkce z newlib, použité ve zdrojácích.
|
||||||
|
* Velmi zjednodušeno.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
int quot, rem;
|
||||||
|
} div_t;
|
||||||
|
typedef __SIZE_TYPE__ size_t;
|
||||||
|
div_t div (int numerator, int denominator) {
|
||||||
|
const div_t result = { numerator / denominator, numerator % denominator };
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
void * memset(void * s, int c, size_t n) {
|
||||||
|
char * p = (char*) s;
|
||||||
|
for (unsigned i=0u; i<n; i++) p [i] = c;
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
void * memcpy(void * dest, const void * src, size_t n) {
|
||||||
|
char * d = (char*) dest;
|
||||||
|
const char * s = (const char*) src;
|
||||||
|
for (unsigned i=0u; i<n; i++) d [i] = s [i];
|
||||||
|
return dest;
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue