diff --git a/pwm/Makefile b/pwm/Makefile index 8941f82..49f9dd8 100644 --- a/pwm/Makefile +++ b/pwm/Makefile @@ -18,7 +18,7 @@ CFLAGS+= -I. -I./$(TARGET) -I/usr/include/newlib DEL = rm -f # zdrojaky -OBJS = main.o pwmclass.o +OBJS = main.o pwmclass.o generator.o sin.o include $(TARGET)/$(TOOL).mk BOBJS = $(addprefix $(BLD),$(OBJS)) @@ -45,9 +45,11 @@ $(BLD)%.o: %.cpp @$(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 *~ + $(DEL) $(BLD)* *.lst *.bin *.elf *.map sin.c *~ .PHONY: all clean diff --git a/pwm/dma_gpio.c b/pwm/dma_gpio.c deleted file mode 100644 index 07fcd23..0000000 --- a/pwm/dma_gpio.c +++ /dev/null @@ -1,150 +0,0 @@ -// DMA GPIO Output Example - this example shows -// how you can output 8 pins all simultaneously -// with a planned bit pattern at 4MSamples/s. -// -// It outputs a pattern of repeating 010101 and -// 00000 alternating "frames". -// -// The interrupt fires once at the beginning and -// once at the end. -// - -#include "ch32v003fun.h" -#include - -volatile uint32_t count; - -#define MBSAMPS 1024 -uint8_t memory_buffer[1024]; - -void DMA1_Channel2_IRQHandler( void ) __attribute__((interrupt)) __attribute__((section(".srodata"))); -void DMA1_Channel2_IRQHandler( void ) -{ - int i; - static int frameno; - volatile int intfr = DMA1->INTFR; - do - { - DMA1->INTFCR = DMA1_IT_GL2; - - // Gets called at the end-of-a frame. - if( intfr & DMA1_IT_TC2 ) - { - uint32_t fv = (frameno&1)?0:0xaa55aa55; - uint32_t * mbb = (uint32_t*)( memory_buffer + MBSAMPS/2 ); - for( i = 0; i < MBSAMPS/8; i++ ) - { - mbb[i] = fv; // Fill in the frame data - } - frameno++; - } - - // Gets called halfway through the frame - if( intfr & DMA1_IT_HT2 ) - { - uint32_t fv = (frameno&1)?0:0xaa55aa55; - uint32_t * mbb = (uint32_t*)( memory_buffer ); - for( i = 0; i < MBSAMPS/8; i++ ) - { - mbb[i] = fv; // Fill in the frame data. - } - } - intfr = DMA1->INTFR; - } while( intfr ); -} - -int main() -{ - int i; - - SystemInit(); - - // Reset all the peripherals we care about. - RCC->APB2PRSTR = 0xffffffff; - RCC->APB2PRSTR = 0; - - // Enable DMA - RCC->AHBPCENR = RCC_AHBPeriph_SRAM | RCC_AHBPeriph_DMA1; - - // Enable GPIO and Timer 1 - RCC->APB2PCENR = RCC_APB2Periph_GPIOD | RCC_APB2Periph_GPIOC | RCC_APB2Periph_TIM1 | RCC_APB2Periph_GPIOA; - - // GPIO D0/D4 Push-Pull (LED) - GPIOD->CFGLR = - (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP)<<(4*1) | // PD1 = SWIO (so we don't go off-bus) - (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP)<<(4*0) | - (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP_AF)<<(4*2) | // PD2 = T1CH1 - (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP)<<(4*4); - - // GPIO C All output. - GPIOC->CFGLR = - (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP)<<(4*0) | - (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP)<<(4*1) | - (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP)<<(4*2) | - (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP)<<(4*3) | - (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP)<<(4*4) | - (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP)<<(4*5) | - (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP)<<(4*6) | - (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP)<<(4*7); - - - // Fill in the plan of what we will be sending out. - for( i = 0; i < sizeof(memory_buffer) / sizeof(memory_buffer[0]); i++ ) - { - memory_buffer[i] = (i&1)?0xaa:0x55; - } - - // DMA2 can be configured to attach to T1CH1 - // The system can only DMA out at ~2.2MSPS. 2MHz is stable. - DMA1_Channel2->CNTR = sizeof(memory_buffer) / sizeof(memory_buffer[0]); - DMA1_Channel2->MADDR = (uint32_t)memory_buffer; - DMA1_Channel2->PADDR = (uint32_t)&GPIOC->OUTDR; - DMA1_Channel2->CFGR = - DMA_CFGR1_DIR | // MEM2PERIPHERAL - DMA_CFGR1_PL | // High priority. - 0 | // 8-bit memory - 0 | // 8-bit peripheral - DMA_CFGR1_MINC | // Increase memory. - DMA_CFGR1_CIRC | // Circular mode. - DMA_CFGR1_HTIE | // Half-trigger - DMA_CFGR1_TCIE | // Whole-trigger - DMA_CFGR1_EN; // Enable - - NVIC_EnableIRQ( DMA1_Channel2_IRQn ); - DMA1_Channel2->CFGR |= DMA_CFGR1_EN; - - // NOTE: You can also hook up DMA1 Channel 3 to T1C2, - // if you want to output to multiple IO ports at - // at the same time. Just be aware you have to offset - // the time they read at by at least 1/8Mth of a second. - - // Setup Timer1. - RCC->APB2PRSTR = RCC_APB2Periph_TIM1; // Reset Timer - RCC->APB2PRSTR = 0; - - // Timer 1 setup. - TIM1->PSC = 0x0000; // Prescaler - TIM1->ATRLR = 11; // Auto Reload - sets period (48MHz / (11+1) = 4MHz) - TIM1->SWEVGR = TIM_UG | TIM_TG; // Reload immediately + Trigger DMA - TIM1->CCER = TIM_CC1E | TIM_CC1P; // Enable CH1 output, positive pol - TIM1->CHCTLR1 = TIM_OC1M_2 | TIM_OC1M_1; // CH1 Mode is output, PWM1 (CC1S = 00, OC1M = 110) - TIM1->CH1CVR = 6; // Set the Capture Compare Register value to 50% initially - TIM1->BDTR = TIM_MOE; // Enable TIM1 outputs - TIM1->CTLR1 = TIM_CEN; // Enable TIM1 - TIM1->DMAINTENR = TIM_UDE | TIM_CC1DE; // Trigger DMA on TC match 1 (DMA Ch2) and TC match 2 (DMA Ch3) - - // Just debug stuff. - printf( "Setup OK\n" ); - - while(1) - { - GPIOD->BSHR = 1 | (1<<4); // Turn on GPIOs - printf( "%lu\n", GPIOD->OUTDR ); - Delay_Ms( 250 ); - GPIOD->BSHR = (1<<16) | (1<<(16+4)); // Turn off GPIODs - printf( "%lu\n", GPIOD->OUTDR ); - Delay_Ms( 250 ); - printf( "Step\n" ); - } -} - diff --git a/pwm/generator.cpp b/pwm/generator.cpp new file mode 100644 index 0000000..ca0003b --- /dev/null +++ b/pwm/generator.cpp @@ -0,0 +1,13 @@ +#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 - +/* C++ interface (jako callback v C) */ class OneWay { public: virtual unsigned Send (uint16_t * const ptr, const unsigned len) = 0; diff --git a/pwm/pwmclass.cpp b/pwm/pwmclass.cpp index 43b510f..3561e2f 100644 --- a/pwm/pwmclass.cpp +++ b/pwm/pwmclass.cpp @@ -1,22 +1,23 @@ #include "system.h" #include "pwmclass.h" +#include "gpio.h" + static PwmClass * pInstance = nullptr; -extern "C" void DMA1_Channel2_IRQHandler( void ) __attribute__((interrupt)); -void DMA1_Channel2_IRQHandler( void ) { +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.HTIF2) pInstance->send(false); - if (state.B.TCIF2) pInstance->send(true); + if (state.B.HTIF5 != RESET) pInstance->send(false); + else if (state.B.TCIF5 != RESET) pInstance->send(true); } /* * initialize TIM1 for PWM */ -static inline void t1pwm_init () noexcept { - // Enable GPIOC, GPIOD and TIM1 +static inline void tim1pwm_init () noexcept { + // Enable GPIOD and TIM1 RCC.APB2PCENR.modify([] (RCC_Type::APB2PCENR_DEF & r) -> auto { - r.B.IOPCEN = SET; r.B.IOPDEN = SET; r.B.TIM1EN = SET; return r.R; @@ -35,12 +36,12 @@ static inline void t1pwm_init () noexcept { // CTLR1: default is up, events generated, edge align // SMCFGR: default clk input is CK_INT // Prescaler - TIM1.PSC.R = 24000u; + TIM1.PSC.R = 0u; // Auto Reload - sets period - TIM1.ATRLR.R = 255u; + TIM1.ATRLR.R = MAXPWM - 1; TIM1.CCER.modify([](TIM1_Type::CCER_DEF & r) -> auto { - // Enable CH1N output, positive pol + // Enable CH1N, CH1 output, positive pol r.B.CC1NE = SET; r.B.CC1E = SET; /* @@ -67,6 +68,7 @@ static inline void t1pwm_init () noexcept { // 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 { @@ -77,8 +79,8 @@ static void dma1ch5_init (void * ptr) { // 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(ptr); - DMA1.PADDR5.R = reinterpret_cast(& TIM1.CH1CVR); + DMA1.MADDR5.R = reinterpret_cast(ptr); + DMA1.PADDR5.R = reinterpret_cast(& TIM1.CH1CVR); DMA1.CFGR5.modify([](DMA1_Type::CFGR5_DEF & r) -> auto { r.B.DIR = SET; // MEM2PERIPHERAL r.B.PL = 2u; // High priority. @@ -95,8 +97,7 @@ static void dma1ch5_init (void * ptr) { } PwmClass::PwmClass() noexcept : pL(buffer), pH(buffer + HALF_LEN), src(nullptr) { - for (unsigned n=0; n +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() +