Compare commits
No commits in common. "910bec6b6c8806b6c8228a7de6d0ff1e8c4d9726" and "fdcc93ce96af5a7cdf8aa352172c098a486f2b76" have entirely different histories.
910bec6b6c
...
fdcc93ce96
9 changed files with 0 additions and 262 deletions
55
pwm/Makefile
55
pwm/Makefile
|
@ -1,55 +0,0 @@
|
||||||
# ch32v003
|
|
||||||
TARGET?= ch32v003
|
|
||||||
TOOL ?= gcc
|
|
||||||
#TOOL ?= clang
|
|
||||||
|
|
||||||
|
|
||||||
PRJ = example
|
|
||||||
|
|
||||||
VPATH = . ./$(TARGET)
|
|
||||||
BLD = ./build/
|
|
||||||
DFLAGS = -d
|
|
||||||
LFLAGS = -g
|
|
||||||
LDLIBS =
|
|
||||||
BFLAGS = --strip-unneeded
|
|
||||||
|
|
||||||
CFLAGS = -MMD -Wall -ggdb -fno-exceptions -ffunction-sections -fdata-sections
|
|
||||||
CFLAGS+= -I. -I./$(TARGET) -I/usr/include/newlib
|
|
||||||
DEL = rm -f
|
|
||||||
|
|
||||||
# zdrojaky
|
|
||||||
OBJS = main.o pwmclass.o generator.o sin.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)
|
|
||||||
sin.c: sin.py
|
|
||||||
./sin.py
|
|
||||||
flash: $(PRJ).elf
|
|
||||||
minichlink -w $(PRJ).bin flash -b
|
|
||||||
# vycisti
|
|
||||||
clean:
|
|
||||||
$(DEL) $(BLD)* *.lst *.bin *.elf *.map sin.c *~
|
|
||||||
.PHONY: all clean
|
|
|
@ -1 +0,0 @@
|
||||||
../ch32v003/
|
|
|
@ -1,13 +0,0 @@
|
||||||
#include "generator.h"
|
|
||||||
|
|
||||||
extern "C" const uint16_t sin_tab[0x100];
|
|
||||||
|
|
||||||
uint16_t Generator::step() {
|
|
||||||
const uint16_t v = sin_tab [base >> 24];
|
|
||||||
base += freq;
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
unsigned int Generator::Send(uint16_t * const ptr, const unsigned int len) {
|
|
||||||
for (unsigned n=0u; n<len; n++) ptr [n] = step();
|
|
||||||
return len;
|
|
||||||
}
|
|
|
@ -1,14 +0,0 @@
|
||||||
#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 {
|
|
||||||
unsigned base, freq;
|
|
||||||
public:
|
|
||||||
explicit Generator (const unsigned f) noexcept : OneWay(), base(0u), freq (f) {};
|
|
||||||
unsigned Send (uint16_t * const ptr, const unsigned len) override;
|
|
||||||
protected:
|
|
||||||
uint16_t step ();
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // GENERATOR_H
|
|
16
pwm/main.cpp
16
pwm/main.cpp
|
@ -1,16 +0,0 @@
|
||||||
#include "pwmclass.h"
|
|
||||||
#include "generator.h"
|
|
||||||
//////////////////////////////////////
|
|
||||||
/* Demonstrace PWM s použitím DMA
|
|
||||||
* Generátor je sinus, data se tvoří
|
|
||||||
* v přerušení. Parametry se musí nastavit
|
|
||||||
* ve zdrojácích, je to jen DEMO.
|
|
||||||
* */
|
|
||||||
//////////////////////////////////////
|
|
||||||
static PwmClass pwm;
|
|
||||||
static Generator gen (1u << 16);
|
|
||||||
int main () {
|
|
||||||
pwm.attach(gen);
|
|
||||||
for (;;);
|
|
||||||
return 0;
|
|
||||||
}
|
|
10
pwm/oneway.h
10
pwm/oneway.h
|
@ -1,10 +0,0 @@
|
||||||
#ifndef ONEWAY_H
|
|
||||||
#define ONEWAY_H
|
|
||||||
#include <stdint.h>
|
|
||||||
/* C++ interface (jako callback v C) */
|
|
||||||
class OneWay {
|
|
||||||
public:
|
|
||||||
virtual unsigned Send (uint16_t * const ptr, const unsigned len) = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // ONEWAY_H
|
|
103
pwm/pwmclass.cpp
103
pwm/pwmclass.cpp
|
@ -1,103 +0,0 @@
|
||||||
#include "system.h"
|
|
||||||
#include "pwmclass.h"
|
|
||||||
#include "gpio.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);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* initialize TIM1 for PWM
|
|
||||||
*/
|
|
||||||
static inline void tim1pwm_init () noexcept {
|
|
||||||
// Enable GPIOD and TIM1
|
|
||||||
RCC.APB2PCENR.modify([] (RCC_Type::APB2PCENR_DEF & r) -> auto {
|
|
||||||
r.B.IOPDEN = SET;
|
|
||||||
r.B.TIM1EN = SET;
|
|
||||||
return r.R;
|
|
||||||
});
|
|
||||||
// PD0 is T1CH1N, PD2 is T1CH1, 10MHz Output alt func, push-pull
|
|
||||||
GPIOD.CFGLR.modify([](GPIOA_Type::CFGLR_DEF & r) -> auto {
|
|
||||||
r.B.CNF0 = 2u;
|
|
||||||
r.B.MODE0 = 1u;
|
|
||||||
r.B.CNF2 = 2u;
|
|
||||||
r.B.MODE2 = 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 void dma1ch5_init (void * ptr) {
|
|
||||||
// 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);
|
|
||||||
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
|
|
||||||
return r.R;
|
|
||||||
});
|
|
||||||
NVIC.EnableIRQ (DMA1_Channel5_IRQn);
|
|
||||||
DMA1.CFGR5.B.EN = SET;
|
|
||||||
}
|
|
||||||
|
|
||||||
PwmClass::PwmClass() noexcept : pL(buffer), pH(buffer + HALF_LEN), src(nullptr) {
|
|
||||||
pInstance = this;
|
|
||||||
tim1pwm_init ();
|
|
||||||
dma1ch5_init (buffer);
|
|
||||||
}
|
|
|
@ -1,23 +0,0 @@
|
||||||
#ifndef PWMCLASS_H
|
|
||||||
#define PWMCLASS_H
|
|
||||||
#include "oneway.h"
|
|
||||||
static constexpr unsigned HALF_LEN = 64u;
|
|
||||||
static constexpr unsigned FULL_LEN = 2u * HALF_LEN;
|
|
||||||
static constexpr unsigned MAXPWM = 2048u;
|
|
||||||
/* 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);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // PWMCLASS_H
|
|
27
pwm/sin.py
27
pwm/sin.py
|
@ -1,27 +0,0 @@
|
||||||
#!/usr/bin/python
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
import math
|
|
||||||
|
|
||||||
header = '''/* Generated file */
|
|
||||||
#include <stdint.h>
|
|
||||||
const uint16_t sin_tab[] = {{{0:s}
|
|
||||||
}};
|
|
||||||
'''
|
|
||||||
|
|
||||||
def generate():
|
|
||||||
s = ''
|
|
||||||
for n in range(0,256):
|
|
||||||
if (n % 16) == 0:
|
|
||||||
s += '\n '
|
|
||||||
a = float(n) * math.pi / 128.0
|
|
||||||
v = int (round (1024.0 * (1.0 + math.sin (a))));
|
|
||||||
s += '{0:+6d},'.format(v)
|
|
||||||
return s
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
s = generate()
|
|
||||||
f = open ('sin.c','w')
|
|
||||||
f.write(header.format(s))
|
|
||||||
f.close()
|
|
||||||
|
|
Loading…
Reference in a new issue