diff --git a/examples/adc_dma_opamp/Makefile b/examples/adc_dma_opamp/Makefile index acbb935a099a3cc0df772edda761e88cf6f7aeed..7c4d8f1ba2aad23a3c593486ba15b183ec542028 100644 --- a/examples/adc_dma_opamp/Makefile +++ b/examples/adc_dma_opamp/Makefile @@ -1,5 +1,7 @@ TARGET:=adc_dma_opamp +CFLAGS+=-DSTDOUT_UART + include ../../ch32v003fun/ch32v003fun.mk all : flash diff --git a/examples/adc_dma_opamp/adc.h b/examples/adc_dma_opamp/adc.h deleted file mode 100644 index 87201e6edfa5a7c1ea27d4fa1e5bb2a5e520fc46..0000000000000000000000000000000000000000 --- a/examples/adc_dma_opamp/adc.h +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Single-File-Header for using ADC with DMA - * 04-13-2023 E. Brombaugh - */ - -#ifndef _ADC_H -#define _ADC_H - -#include <stdint.h> - -#define ADC_NUMCHLS 4 -volatile uint16_t adc_buffer[ADC_NUMCHLS]; - -/* - * initialize adc for DMA - */ -void adc_init( void ) -{ - // ADCCLK = 24 MHz => RCC_ADCPRE = 0: divide by 2 - RCC->CFGR0 &= ~(0x1F<<11); - - // Enable GPIOD and ADC - RCC->APB2PCENR |= RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD | - RCC_APB2Periph_ADC1; - - // PD4 is analog input chl 7 - GPIOD->CFGLR &= ~(0xf<<(4*4)); // CNF = 00: Analog, MODE = 00: Input - - // PD3 is analog input chl 4 - GPIOD->CFGLR &= ~(0xf<<(4*3)); // CNF = 00: Analog, MODE = 00: Input - - // PD2 is analog input chl 3 - GPIOD->CFGLR &= ~(0xf<<(4*2)); // CNF = 00: Analog, MODE = 00: Input - - // PC4 is analog input chl 2 - GPIOC->CFGLR &= ~(0xf<<(4*4)); // CNF = 00: Analog, MODE = 00: Input - - // Reset the ADC to init all regs - RCC->APB2PRSTR |= RCC_APB2Periph_ADC1; - RCC->APB2PRSTR &= ~RCC_APB2Periph_ADC1; - - // Set up four conversions on chl 7, 4, 3, 2 - ADC1->RSQR1 = (ADC_NUMCHLS-1) << 20; // four chls in the sequence - ADC1->RSQR2 = 0; - ADC1->RSQR3 = (7<<(5*0)) | (4<<(5*1)) | (3<<(5*2)) | (2<<(5*3)); - - // set sampling time for chl 7, 4, 3, 2 - // 0:7 => 3/9/15/30/43/57/73/241 cycles - ADC1->SAMPTR2 = (7<<(3*7)) | (7<<(3*4)) | (7<<(3*3)) | (7<<(3*2)); - - // turn on ADC - ADC1->CTLR2 |= ADC_ADON; - - // Reset calibration - ADC1->CTLR2 |= ADC_RSTCAL; - while(ADC1->CTLR2 & ADC_RSTCAL); - - // Calibrate - ADC1->CTLR2 |= ADC_CAL; - while(ADC1->CTLR2 & ADC_CAL); - - // Turn on DMA - RCC->AHBPCENR |= RCC_AHBPeriph_DMA1; - - //DMA1_Channel1 is for ADC - DMA1_Channel1->PADDR = (uint32_t)&ADC1->RDATAR; - DMA1_Channel1->MADDR = (uint32_t)adc_buffer; - DMA1_Channel1->CNTR = ADC_NUMCHLS; - DMA1_Channel1->CFGR = - DMA_M2M_Disable | - DMA_Priority_VeryHigh | - DMA_MemoryDataSize_HalfWord | - DMA_PeripheralDataSize_HalfWord | - DMA_MemoryInc_Enable | - DMA_Mode_Circular | - DMA_DIR_PeripheralSRC; - - // Turn on DMA channel 1 - DMA1_Channel1->CFGR |= DMA_CFGR1_EN; - - // enable scanning - ADC1->CTLR1 |= ADC_SCAN; - - // Enable continuous conversion and DMA - ADC1->CTLR2 |= ADC_CONT | ADC_DMA | ADC_EXTSEL; - - // start conversion - ADC1->CTLR2 |= ADC_SWSTART; -} - -#endif diff --git a/examples/adc_dma_opamp/adc_dma_opamp.c b/examples/adc_dma_opamp/adc_dma_opamp.c index cb3d6a3b50b87dd3922f669080f090ba4e21dd4f..e56bc2a836d46cb12a02812baebab4dde36e435c 100644 --- a/examples/adc_dma_opamp/adc_dma_opamp.c +++ b/examples/adc_dma_opamp/adc_dma_opamp.c @@ -9,9 +9,105 @@ #include "ch32v003fun.h" #include <stdio.h> -#include "adc.h" -#include "opamp.h" +#define ADC_NUMCHLS 4 +volatile uint16_t adc_buffer[ADC_NUMCHLS]; + +/* + * initialize adc for DMA + */ +void adc_init( void ) +{ + // ADCCLK = 24 MHz => RCC_ADCPRE = 0: divide by 2 + RCC->CFGR0 &= ~(0x1F<<11); + + // Enable GPIOD and ADC + RCC->APB2PCENR |= RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD | + RCC_APB2Periph_ADC1; + + // PD4 is analog input chl 7 + GPIOD->CFGLR &= ~(0xf<<(4*4)); // CNF = 00: Analog, MODE = 00: Input + + // PD3 is analog input chl 4 + GPIOD->CFGLR &= ~(0xf<<(4*3)); // CNF = 00: Analog, MODE = 00: Input + + // PD2 is analog input chl 3 + GPIOD->CFGLR &= ~(0xf<<(4*2)); // CNF = 00: Analog, MODE = 00: Input + + // PC4 is analog input chl 2 + GPIOC->CFGLR &= ~(0xf<<(4*4)); // CNF = 00: Analog, MODE = 00: Input + + // Reset the ADC to init all regs + RCC->APB2PRSTR |= RCC_APB2Periph_ADC1; + RCC->APB2PRSTR &= ~RCC_APB2Periph_ADC1; + + // Set up four conversions on chl 7, 4, 3, 2 + ADC1->RSQR1 = (ADC_NUMCHLS-1) << 20; // four chls in the sequence + ADC1->RSQR2 = 0; + ADC1->RSQR3 = (7<<(5*0)) | (4<<(5*1)) | (3<<(5*2)) | (2<<(5*3)); + + // set sampling time for chl 7, 4, 3, 2 + // 0:7 => 3/9/15/30/43/57/73/241 cycles + ADC1->SAMPTR2 = (7<<(3*7)) | (7<<(3*4)) | (7<<(3*3)) | (7<<(3*2)); + + // turn on ADC + ADC1->CTLR2 |= ADC_ADON; + + // Reset calibration + ADC1->CTLR2 |= ADC_RSTCAL; + while(ADC1->CTLR2 & ADC_RSTCAL); + + // Calibrate + ADC1->CTLR2 |= ADC_CAL; + while(ADC1->CTLR2 & ADC_CAL); + + // Turn on DMA + RCC->AHBPCENR |= RCC_AHBPeriph_DMA1; + + //DMA1_Channel1 is for ADC + DMA1_Channel1->PADDR = (uint32_t)&ADC1->RDATAR; + DMA1_Channel1->MADDR = (uint32_t)adc_buffer; + DMA1_Channel1->CNTR = ADC_NUMCHLS; + DMA1_Channel1->CFGR = + DMA_M2M_Disable | + DMA_Priority_VeryHigh | + DMA_MemoryDataSize_HalfWord | + DMA_PeripheralDataSize_HalfWord | + DMA_MemoryInc_Enable | + DMA_Mode_Circular | + DMA_DIR_PeripheralSRC; + + // Turn on DMA channel 1 + DMA1_Channel1->CFGR |= DMA_CFGR1_EN; + + // enable scanning + ADC1->CTLR1 |= ADC_SCAN; + + // Enable continuous conversion and DMA + ADC1->CTLR2 |= ADC_CONT | ADC_DMA | ADC_EXTSEL; + + // start conversion + ADC1->CTLR2 |= ADC_SWSTART; +} + +/* + * turn on op-amp, select input pins + */ +void opamp_init( void ) +{ + // turn on the op-amp + EXTEN->EXTEN_CTR |= EXTEN_OPA_EN; + + // select op-amp pos pin: 0 = PA2, 1 = PD7 + //EXTEN->EXTEN_CTR |= EXTEN_OPA_PSEL; + + // select op-amp neg pin: 0 = PA1, 1 = PD0 + //EXTEN->EXTEN_CTR |= EXTEN_OPA_NSEL; +} + +/* + * entry + */ int main() { SystemInit48HSI(); @@ -26,25 +122,15 @@ int main() adc_init(); printf("done.\n\r"); -#if 0 - printf("MADDR = 0x%08X, Buffer = 0x%08X\n\r", - DMA1_Channel1->CNTR, adc_buffer); - while(1) - { - //printf("STATR = 0x%08X, RDATAR = 0x%04X, CNTR = 0x%04X\n\r", - //ADC1->STATR, ADC1->RDATAR, DMA1_Channel1->CNTR); - } -#endif - // init op-amp printf("initializing op-amp...\n\r"); opamp_init(); printf("done.\n\r"); - // Enable GPIOs + // Enable GPIO for blinky diag RCC->APB2PCENR |= RCC_APB2Periph_GPIOC; - // GPIO C1 Push-Pull + // GPIO C1 Push-Pull for blinky diag GPIOC->CFGLR &= ~(0xf<<(4*1)); GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP)<<(4*1); diff --git a/examples/adc_dma_opamp/opamp.h b/examples/adc_dma_opamp/opamp.h deleted file mode 100644 index 20b0786fe7108e23a7c82383fe596f74f456db19..0000000000000000000000000000000000000000 --- a/examples/adc_dma_opamp/opamp.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Single-File-Header for using op-amp - * 04-13-2023 E. Brombaugh - */ - -#ifndef _OPAMP_H -#define _OPAMP_H - -#include <stdint.h> - -/* - * initialize adc for polling - */ -void opamp_init( void ) -{ - // turn on the op-amp - EXTEN->EXTEN_CTR |= EXTEN_OPA_EN; - - // select op-amp pos pin: 0 = PA2, 1 = PD7 - //EXTEN->EXTEN_CTR |= EXTEN_OPA_PSEL; - - // select op-amp neg pin: 0 = PA1, 1 = PD0 - //EXTEN->EXTEN_CTR |= EXTEN_OPA_NSEL; -} -#endif - diff --git a/examples/adc_polled/Makefile b/examples/adc_polled/Makefile index 0a4ea74980b737226422795be13e88cdb8f62611..11afe2ea9535ca5cdd34755e263a2653f54fdc83 100644 --- a/examples/adc_polled/Makefile +++ b/examples/adc_polled/Makefile @@ -1,5 +1,7 @@ TARGET:=adc_polled +CFLAGS+=-DSTDOUT_UART + include ../../ch32v003fun/ch32v003fun.mk all : flash diff --git a/examples/adc_polled/adc.h b/examples/adc_polled/adc.h deleted file mode 100644 index b9777ec29ea01c15ce6048a7fc3f9bbcbcdd750b..0000000000000000000000000000000000000000 --- a/examples/adc_polled/adc.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Single-File-Header for using ADC with polling - * 03-27-2023 E. Brombaugh - */ - -#ifndef _ADC_H -#define _ADC_H - -#include <stdint.h> - -/* - * initialize adc for polling - */ -void adc_init( void ) -{ - // ADCCLK = 24 MHz => RCC_ADCPRE = 0: divide by 2 - RCC->CFGR0 &= ~(0x1F<<11); - - // Enable GPIOD and ADC - RCC->APB2PCENR |= RCC_APB2Periph_GPIOD | RCC_APB2Periph_ADC1; - - // PD4 is analog input chl 7 - GPIOD->CFGLR &= ~(0xf<<(4*4)); // CNF = 00: Analog, MODE = 00: Input - - // Reset the ADC to init all regs - RCC->APB2PRSTR |= RCC_APB2Periph_ADC1; - RCC->APB2PRSTR &= ~RCC_APB2Periph_ADC1; - - // Set up single conversion on chl 7 - ADC1->RSQR1 = 0; - ADC1->RSQR2 = 0; - ADC1->RSQR3 = 7; // 0-9 for 8 ext inputs and two internals - - // set sampling time for chl 7 - ADC1->SAMPTR2 &= ~(ADC_SMP0<<(3*7)); - ADC1->SAMPTR2 |= 7<<(3*7); // 0:7 => 3/9/15/30/43/57/73/241 cycles - - // turn on ADC and set rule group to sw trig - ADC1->CTLR2 |= ADC_ADON | ADC_EXTSEL; - - // Reset calibration - ADC1->CTLR2 |= ADC_RSTCAL; - while(ADC1->CTLR2 & ADC_RSTCAL); - - // Calibrate - ADC1->CTLR2 |= ADC_CAL; - while(ADC1->CTLR2 & ADC_CAL); - - // should be ready for SW conversion now -} - -/* - * start conversion, wait and return result - */ -uint16_t adc_get( void ) -{ - // start sw conversion (auto clears) - ADC1->CTLR2 |= ADC_SWSTART; - - // wait for conversion complete - while(!(ADC1->STATR & ADC_EOC)); - - // get result - return ADC1->RDATAR; -} - -#endif diff --git a/examples/adc_polled/adc_polled.c b/examples/adc_polled/adc_polled.c index 56283d10853a3cfeba6cb98ace926d1682160901..65ed99c9c261c7d7328f5e0e24c83b09bdf4faa9 100644 --- a/examples/adc_polled/adc_polled.c +++ b/examples/adc_polled/adc_polled.c @@ -9,8 +9,66 @@ #include "ch32v003fun.h" #include <stdio.h> -#include "adc.h" +/* + * initialize adc for polling + */ +void adc_init( void ) +{ + // ADCCLK = 24 MHz => RCC_ADCPRE = 0: divide by 2 + RCC->CFGR0 &= ~(0x1F<<11); + + // Enable GPIOD and ADC + RCC->APB2PCENR |= RCC_APB2Periph_GPIOD | RCC_APB2Periph_ADC1; + + // PD4 is analog input chl 7 + GPIOD->CFGLR &= ~(0xf<<(4*4)); // CNF = 00: Analog, MODE = 00: Input + + // Reset the ADC to init all regs + RCC->APB2PRSTR |= RCC_APB2Periph_ADC1; + RCC->APB2PRSTR &= ~RCC_APB2Periph_ADC1; + + // Set up single conversion on chl 7 + ADC1->RSQR1 = 0; + ADC1->RSQR2 = 0; + ADC1->RSQR3 = 7; // 0-9 for 8 ext inputs and two internals + + // set sampling time for chl 7 + ADC1->SAMPTR2 &= ~(ADC_SMP0<<(3*7)); + ADC1->SAMPTR2 |= 7<<(3*7); // 0:7 => 3/9/15/30/43/57/73/241 cycles + + // turn on ADC and set rule group to sw trig + ADC1->CTLR2 |= ADC_ADON | ADC_EXTSEL; + + // Reset calibration + ADC1->CTLR2 |= ADC_RSTCAL; + while(ADC1->CTLR2 & ADC_RSTCAL); + + // Calibrate + ADC1->CTLR2 |= ADC_CAL; + while(ADC1->CTLR2 & ADC_CAL); + + // should be ready for SW conversion now +} + +/* + * start conversion, wait and return result + */ +uint16_t adc_get( void ) +{ + // start sw conversion (auto clears) + ADC1->CTLR2 |= ADC_SWSTART; + + // wait for conversion complete + while(!(ADC1->STATR & ADC_EOC)); + + // get result + return ADC1->RDATAR; +} + +/* + * entry + */ int main() { uint32_t count = 0; diff --git a/examples/i2c_oled/Makefile b/examples/i2c_oled/Makefile index 2da3d040f9198403a7e306626b2d171c0c9373a7..e2e933a29f60c3cc30163258029f222918fd6224 100644 --- a/examples/i2c_oled/Makefile +++ b/examples/i2c_oled/Makefile @@ -1,5 +1,7 @@ TARGET:=i2c_oled +CFLAGS+=-DSTDOUT_UART + include ../../ch32v003fun/ch32v003fun.mk all : flash diff --git a/examples/i2c_oled/i2c.h b/examples/i2c_oled/i2c.h index 92cfbdd58ec091024723f96c417a4a96860c0af7..335aafa969ffee617a09d8346f9ebc895f7ffb37 100644 --- a/examples/i2c_oled/i2c.h +++ b/examples/i2c_oled/i2c.h @@ -89,13 +89,13 @@ void i2c_init(void) RCC->APB2PCENR |= RCC_APB2Periph_GPIOC; RCC->APB1PCENR |= RCC_APB1Periph_I2C1; - // PC1/PC2 are SDA/SCL, 50MHz Output PP CNF = 11: Mux OD, MODE = 11: Out 50MHz - GPIOC->CFGLR &= ~(GPIO_CFGLR_MODE1 | GPIO_CFGLR_CNF1 | - GPIO_CFGLR_MODE1 | GPIO_CFGLR_CNF1); - GPIOC->CFGLR |= GPIO_CFGLR_CNF1_1 | GPIO_CFGLR_CNF1_0 | - GPIO_CFGLR_MODE1_1 | GPIO_CFGLR_MODE1_0 | - GPIO_CFGLR_CNF2_1 | GPIO_CFGLR_CNF2_0 | - GPIO_CFGLR_MODE2_1 | GPIO_CFGLR_MODE2_0; + // PC1 is SDA, 10MHz Output, alt func, open-drain + GPIOC->CFGLR &= ~(0xf<<(4*1)); + GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_OD_AF)<<(4*1); + + // PC2 is SCL, 10MHz Output, alt func, open-drain + GPIOC->CFGLR &= ~(0xf<<(4*2)); + GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_OD_AF)<<(4*2); #ifdef IRQ_DIAG // GPIO diags on PC3/PC4 diff --git a/examples/spi_dac/Makefile b/examples/spi_dac/Makefile index 109146ea58aa15694cb0213829b9ccb8cf43ddf9..98e7abf89391863e9082a989e53c584224db3ee5 100644 --- a/examples/spi_dac/Makefile +++ b/examples/spi_dac/Makefile @@ -1,5 +1,7 @@ TARGET:=spi_dac +CFLAGS+=-DSTDOUT_UART + include ../../ch32v003fun/ch32v003fun.mk all : flash diff --git a/examples/spi_dac/spi_dac.c b/examples/spi_dac/spi_dac.c index cab61e6c82b4548f9d0ed090abf40f23b0e41a4a..aaed51fc769d463ec64a9e4d4eb949362b86a6d8 100644 --- a/examples/spi_dac/spi_dac.c +++ b/examples/spi_dac/spi_dac.c @@ -9,8 +9,187 @@ #include "ch32v003fun.h" #include <stdio.h> -#include "spidac.h" +// this table contains a 512-sample 16-bit sine waveform +#include "Sine16bit.h" + +// uncomment this to enable GPIO diag +#define DAC_DIAG + +// Length of the DAC DMA buffer +#define DACBUFSZ 32 + +uint16_t dac_buffer[DACBUFSZ]; +uint32_t osc_phs[2], osc_frq[2]; + +/* + * initialize SPI and DMA + */ +void spidac_init( void ) +{ + // init two oscillators + osc_phs[0] = 0; + osc_phs[1] = 0; + osc_frq[0] = 0x01000000; + osc_frq[1] = 0x00400000; + + // Enable DMA + Peripherals + RCC->AHBPCENR |= RCC_AHBPeriph_DMA1; + RCC->APB2PCENR |= RCC_APB2Periph_GPIOC | RCC_APB2Periph_SPI1; + +#ifdef DAC_DIAG + // GPIO D0 10MHz Push-Pull for diags + RCC->APB2PCENR |= RCC_APB2Periph_GPIOD; + GPIOD->CFGLR &= ~(0xf<<(4*0)); + GPIOD->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP)<<(4*0); +#endif + + // MOSI on PC6, 10MHz Output, alt func, push-pull + GPIOC->CFGLR &= ~(0xf<<(4*6)); + GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP_AF)<<(4*6); + + // SCK on PC5, 10MHz Output, alt func, push-pull + GPIOC->CFGLR &= ~(0xf<<(4*5)); + GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP_AF)<<(4*5); + + // Configure SPI + SPI1->CTLR1 = + SPI_NSS_Soft | SPI_CPHA_1Edge | SPI_CPOL_Low | SPI_DataSize_16b | + SPI_Mode_Master | SPI_Direction_1Line_Tx | + SPI_BaudRatePrescaler_16; + + // enable SPI port + SPI1->CTLR1 |= CTLR1_SPE_Set; + + // TIM1 generates DMA Req and external signal + // Enable TIM1 + RCC->APB2PCENR |= RCC_APB2Periph_TIM1; + + // PC4 is T1CH4, 10MHz Output, alt func, push-pull + GPIOC->CFGLR &= ~(0xf<<(4*4)); + GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP_AF)<<(4*4); + + // Reset TIM1 to init all regs + RCC->APB2PRSTR |= RCC_APB2Periph_TIM1; + RCC->APB2PRSTR &= ~RCC_APB2Periph_TIM1; + + // CTLR1: default is up, events generated, edge align + // CTLR1: up/down, events on both edges + TIM1->CTLR1 = TIM_CMS; + // SMCFGR: default clk input is CK_INT + + // Prescaler + TIM1->PSC = 0x0000; + + // Auto Reload - sets period to ~47kHz + TIM1->ATRLR = 499; + + // Reload immediately + TIM1->SWEVGR |= TIM_UG; + + // Enable CH4 output, positive pol + TIM1->CCER |= TIM_CC4E;// | TIM_CC4P; + + // CH2 Mode is output, PWM1 (CC1S = 00, OC1M = 110) + TIM1->CHCTLR2 |= TIM_OC4M_2 | TIM_OC4M_1; + + // Set the Capture Compare Register value to 50% initially + TIM1->CH4CVR = 256; + + // Enable TIM1 outputs + TIM1->BDTR |= TIM_MOE; + + // Enable CH4 DMA Req + TIM1->DMAINTENR |= TIM_CC4DE; + + // Enable TIM1 + TIM1->CTLR1 |= TIM_CEN; + + //DMA1_Channel4 is for TIM1CH4 + DMA1_Channel4->PADDR = (uint32_t)&SPI1->DATAR; + DMA1_Channel4->MADDR = (uint32_t)dac_buffer; + DMA1_Channel4->CNTR = DACBUFSZ; + DMA1_Channel4->CFGR = + DMA_M2M_Disable | + DMA_Priority_VeryHigh | + DMA_MemoryDataSize_HalfWord | + DMA_PeripheralDataSize_HalfWord | + DMA_MemoryInc_Enable | + DMA_Mode_Circular | + DMA_DIR_PeripheralDST | + DMA_IT_TC | DMA_IT_HT; + + NVIC_EnableIRQ( DMA1_Channel4_IRQn ); + DMA1_Channel4->CFGR |= DMA_CFGR1_EN; +} + +/* + * DAC buffer updates - called at IRQ time + */ +void dac_update(uint16_t *buffer) +{ + int i; + + // fill the buffer with stereo data + for(i=0;i<DACBUFSZ/2;i+=2) + { + // right chl + *buffer++ = Sine16bit[osc_phs[0]>>24]; + osc_phs[0] += osc_frq[0]; + + // left chl + //*buffer++ = Sine16bit[osc_phs[1]>>24]; + *buffer++ = osc_phs[1]>>16; + osc_phs[1] += osc_frq[1]; + } +} + +/* + * TIM1CH4 DMA IRQ Handler + */ +void DMA1_Channel4_IRQHandler( void ) __attribute__((interrupt)); +void DMA1_Channel4_IRQHandler( void ) +{ +#ifdef DAC_DIAG + GPIOD->BSHR = 1; +#endif + + // why is this needed? Can't just direct compare the reg in tests below + volatile uint16_t intfr = DMA1->INTFR; + + if( intfr & DMA1_IT_TC4 ) + { + // Transfer complete - update 2nd half + dac_update(dac_buffer+DACBUFSZ/2); + + // clear TC IRQ + DMA1->INTFCR = DMA1_IT_TC4; + + GPIOC->BSHR = (1<<1); // NSS 1 + } + + if( intfr & DMA1_IT_HT4 ) + { + // Half transfer - update first half + dac_update(dac_buffer); + + // clear HT IRQ + DMA1->INTFCR = DMA1_IT_HT4; + + GPIOC->BSHR = (1<<(1+16)); // NSS 0 + } + + // clear the Global IRQ + DMA1->INTFCR = DMA1_IT_GL4; + +#ifdef DAC_DIAG + GPIOD->BSHR = 1<<16; +#endif +} + +/* + * entry + */ int main() { SystemInit48HSI(); diff --git a/examples/spi_dac/spidac.h b/examples/spi_dac/spidac.h deleted file mode 100644 index e8242b9321abaada92d2d6c7bcd513cc15de2c26..0000000000000000000000000000000000000000 --- a/examples/spi_dac/spidac.h +++ /dev/null @@ -1,203 +0,0 @@ -/* - * Single-File-Header for SPI with circular DMA for audio output - * 04-10-2023 E. Brombaugh - */ - -#ifndef _SPIDAC_H -#define _SPIDAC_H - -#include <stdint.h> -#include "Sine16bit.h" - -// uncomment this to enable GPIO diag -#define DAC_DIAG - -// uncomment this to fill the buffer with static test data -//#define DAC_STATIC - -// uncomment this for timer-generated DMA -#define DAC_TIMDMA - -#define DACBUFSZ 32 - -uint16_t dac_buffer[DACBUFSZ]; -uint32_t osc_phs[2], osc_frq[2]; - -/* - * initialize SPI and DMA - */ -void spidac_init( void ) -{ -#ifdef DAC_STATIC - // fill output buffer with diag data - uint16_t data = 0xffff; - for(int i=0;i<DACBUFSZ;i++) - { - /* just a full-scale ramp for now */ - dac_buffer[i] = data; - data >>= 1; - } -#else - // init two oscillators - osc_phs[0] = 0; - osc_phs[1] = 0; - osc_frq[0] = 0x01000000; - osc_frq[1] = 0x00400000; -#endif - - // Enable DMA + Peripherals - RCC->AHBPCENR |= RCC_AHBPeriph_DMA1; - RCC->APB2PCENR |= RCC_APB2Periph_GPIOC | RCC_APB2Periph_SPI1; - -#ifdef DAC_DIAG - // GPIO D0 Push-Pull for diags - RCC->APB2PCENR |= RCC_APB2Periph_GPIOD; - GPIOD->CFGLR &= ~(0xf<<(4*0)); - GPIOD->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP)<<(4*0); -#endif - - // MOSI on PC6 - GPIOC->CFGLR &= ~(0xf<<(4*6)); - GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP_AF)<<(4*6); - // SCK on PC5 - GPIOC->CFGLR &= ~(0xf<<(4*5)); - GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP_AF)<<(4*5); - // NSS on PC1 is GPIO - GPIOC->CFGLR &= ~(0xf<<(4*1)); - GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP)<<(4*1); - - // Configure SPI - SPI1->CTLR1 = - SPI_NSS_Soft | SPI_CPHA_1Edge | SPI_CPOL_Low | SPI_DataSize_16b | - SPI_Mode_Master | SPI_Direction_1Line_Tx | - SPI_BaudRatePrescaler_16; - - // enable SPI port - SPI1->CTLR1 |= CTLR1_SPE_Set; - - // TIM1 generates DMA Req and external signal - // Enable TIM1 - RCC->APB2PCENR |= RCC_APB2Periph_TIM1; - - // PC4 is T1CH4, 50MHz Output PP CNF = 10: Mux PP, MODE = 11: Out 50MHz - GPIOC->CFGLR &= ~(GPIO_CFGLR_MODE4 | GPIO_CFGLR_CNF4); - GPIOC->CFGLR |= GPIO_CFGLR_CNF4_1 | GPIO_CFGLR_MODE4_0 | GPIO_CFGLR_MODE4_1; - - // Reset TIM1 to init all regs - RCC->APB2PRSTR |= RCC_APB2Periph_TIM1; - RCC->APB2PRSTR &= ~RCC_APB2Periph_TIM1; - - // CTLR1: default is up, events generated, edge align - // CTLR1: up/down, events on both edges - TIM1->CTLR1 = TIM_CMS; - // SMCFGR: default clk input is CK_INT - - // Prescaler - TIM1->PSC = 0x0000; - - // Auto Reload - sets period to ~47kHz - TIM1->ATRLR = 499; - - // Reload immediately - TIM1->SWEVGR |= TIM_UG; - - // Enable CH4 output, positive pol - TIM1->CCER |= TIM_CC4E;// | TIM_CC4P; - - // CH2 Mode is output, PWM1 (CC1S = 00, OC1M = 110) - TIM1->CHCTLR2 |= TIM_OC4M_2 | TIM_OC4M_1; - - // Set the Capture Compare Register value to 50% initially - TIM1->CH4CVR = 256; - - // Enable TIM1 outputs - TIM1->BDTR |= TIM_MOE; - - // Enable CH4 DMA Req - TIM1->DMAINTENR |= TIM_CC4DE; - - // Enable TIM1 - TIM1->CTLR1 |= TIM_CEN; - - //DMA1_Channel4 is for TIM1CH4 - DMA1_Channel4->PADDR = (uint32_t)&SPI1->DATAR; - DMA1_Channel4->MADDR = (uint32_t)dac_buffer; - DMA1_Channel4->CNTR = DACBUFSZ; - DMA1_Channel4->CFGR = - DMA_M2M_Disable | - DMA_Priority_VeryHigh | - DMA_MemoryDataSize_HalfWord | - DMA_PeripheralDataSize_HalfWord | - DMA_MemoryInc_Enable | - DMA_Mode_Circular | - DMA_DIR_PeripheralDST | - DMA_IT_TC | DMA_IT_HT; - - NVIC_EnableIRQ( DMA1_Channel4_IRQn ); - DMA1_Channel4->CFGR |= DMA_CFGR1_EN; -} - -/* - * DAC buffer updates - called at IRQ time - */ -void dac_update(uint16_t *buffer) -{ - int i; - - // fill the buffer with stereo data - for(i=0;i<DACBUFSZ/2;i+=2) - { - // right chl - *buffer++ = Sine16bit[osc_phs[0]>>24]; - osc_phs[0] += osc_frq[0]; - - // left chl - //*buffer++ = Sine16bit[osc_phs[1]>>24]; - *buffer++ = osc_phs[1]>>16; - osc_phs[1] += osc_frq[1]; - } -} - -/* - * TIM1CH4 DMA IRQ Handler - */ -void DMA1_Channel4_IRQHandler( void ) __attribute__((interrupt)); -void DMA1_Channel4_IRQHandler( void ) -{ -#ifdef DAC_DIAG - GPIOD->BSHR = 1; -#endif - - // why is this needed? Can't just direct compare the reg in tests below - volatile uint16_t intfr = DMA1->INTFR; - - if( intfr & DMA1_IT_TC4 ) - { - // Transfer complete - update 2nd half - dac_update(dac_buffer+DACBUFSZ/2); - - // clear TC IRQ - DMA1->INTFCR = DMA1_IT_TC4; - - GPIOC->BSHR = (1<<1); // NSS 1 - } - - if( intfr & DMA1_IT_HT4 ) - { - // Half transfer - update first half - dac_update(dac_buffer); - - // clear HT IRQ - DMA1->INTFCR = DMA1_IT_HT4; - - GPIOC->BSHR = (1<<(1+16)); // NSS 0 - } - - // clear the Global IRQ - DMA1->INTFCR = DMA1_IT_GL4; - -#ifdef DAC_DIAG - GPIOD->BSHR = 1<<16; -#endif -} -#endif diff --git a/examples/systick_irq/Makefile b/examples/systick_irq/Makefile index c9c13def5aa9978795a523d8d019e17d54c3f4e3..e72ba9807b0ce6f59d5e2bf6d9e69ca7472d7108 100644 --- a/examples/systick_irq/Makefile +++ b/examples/systick_irq/Makefile @@ -1,5 +1,7 @@ TARGET:=systick_irq +CFLAGS+=-DSTDOUT_UART + include ../../ch32v003fun/ch32v003fun.mk all : flash diff --git a/examples/systick_irq/systick.h b/examples/systick_irq/systick.h deleted file mode 100644 index 53bde7c828e74e77d60ffc8c59b5b7680ee3774f..0000000000000000000000000000000000000000 --- a/examples/systick_irq/systick.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Single-File-Header for using SysTick with millisecond interrupts - * 03-25-2023 E. Brombaugh - */ - -#ifndef _SYSTICK_H -#define _SYSTICK_H - -#include <stdint.h> - -/* some bit definitions for systick regs */ -#define SYSTICK_SR_CNTIF (1<<0) -#define SYSTICK_CTLR_STE (1<<0) -#define SYSTICK_CTLR_STIE (1<<1) -#define SYSTICK_CTLR_STCLK (1<<2) -#define SYSTICK_CTLR_STRE (1<<3) -#define SYSTICK_CTLR_SWIE (1<<31) - -volatile uint32_t systick_cnt; - -/* - * Start up the SysTick IRQ - */ -void systick_init(void) -{ - /* enable the SysTick IRQ */ - NVIC_EnableIRQ(SysTicK_IRQn); - - /* Clear any existing IRQ */ - SysTick->SR &= ~SYSTICK_SR_CNTIF; - - /* Set the tick interval to 1ms for normal op */ - SysTick->CMP = (SYSTEM_CORE_CLOCK/1000)-1; - - /* Start at zero */ - SysTick->CNT = 0; - systick_cnt = 0; - - /* Enable SysTick counter, IRQ, HCLK/1, auto reload */ - SysTick->CTLR = SYSTICK_CTLR_STE | SYSTICK_CTLR_STIE | - SYSTICK_CTLR_STCLK | SYSTICK_CTLR_STRE; -} - -#if 1 -/* - * SysTick ISR just counts ticks - * note - the __attribute__((interrupt)) syntax is crucial! - */ -void SysTick_Handler(void) __attribute__((interrupt)); -void SysTick_Handler(void) -{ - /* clear IRQ */ - SysTick->SR &= 0; - - /* update counter */ - systick_cnt++; -} -#endif - -/* - * Millisecond delay routine - */ -void systick_delay_ms(uint32_t milliseconds) -{ - /* compute end time */ - uint32_t etime = systick_cnt + milliseconds; - - /* wait for current time == end time */ - while(systick_cnt != etime); -} - -#endif diff --git a/examples/systick_irq/systick_irq.c b/examples/systick_irq/systick_irq.c index ebc0165e190a3aa6f209b216f529e9bc40986e48..0ec6631adb0e58d553a3bfe8f97afb0bb7b59091 100644 --- a/examples/systick_irq/systick_irq.c +++ b/examples/systick_irq/systick_irq.c @@ -9,8 +9,69 @@ #include "ch32v003fun.h" #include <stdio.h> -#include "systick.h" +/* some bit definitions for systick regs */ +#define SYSTICK_SR_CNTIF (1<<0) +#define SYSTICK_CTLR_STE (1<<0) +#define SYSTICK_CTLR_STIE (1<<1) +#define SYSTICK_CTLR_STCLK (1<<2) +#define SYSTICK_CTLR_STRE (1<<3) +#define SYSTICK_CTLR_SWIE (1<<31) + +volatile uint32_t systick_cnt; + +/* + * Start up the SysTick IRQ + */ +void systick_init(void) +{ + /* enable the SysTick IRQ */ + NVIC_EnableIRQ(SysTicK_IRQn); + + /* Clear any existing IRQ */ + SysTick->SR &= ~SYSTICK_SR_CNTIF; + + /* Set the tick interval to 1ms for normal op */ + SysTick->CMP = (SYSTEM_CORE_CLOCK/1000)-1; + + /* Start at zero */ + SysTick->CNT = 0; + systick_cnt = 0; + + /* Enable SysTick counter, IRQ, HCLK/1, auto reload */ + SysTick->CTLR = SYSTICK_CTLR_STE | SYSTICK_CTLR_STIE | + SYSTICK_CTLR_STCLK | SYSTICK_CTLR_STRE; +} + +/* + * SysTick ISR just counts ticks + * note - the __attribute__((interrupt)) syntax is crucial! + */ +void SysTick_Handler(void) __attribute__((interrupt)); +void SysTick_Handler(void) +{ + /* clear IRQ */ + SysTick->SR &= 0; + + /* update counter */ + systick_cnt++; +} + +/* + * Millisecond delay routine + */ +void systick_delay_ms(uint32_t milliseconds) +{ + /* compute end time */ + uint32_t etime = systick_cnt + milliseconds; + + /* wait for current time == end time */ + while(systick_cnt != etime); +} + +/* + * entry + */ int main() { uint32_t count = 0; @@ -21,8 +82,6 @@ int main() SetupUART( UART_BRR ); printf("\r\r\n\nsystick_irq example\n\r"); - printf("SysTick_Handler = 0x%08X\n\r", SysTick_Handler); - // init systick @ 1ms rate printf("initializing systick..."); systick_init(); diff --git a/examples/tim1_pwm/t1pwm.h b/examples/tim1_pwm/t1pwm.h deleted file mode 100644 index 261659d35a2cf5c3d40e2619bb3a9ab762f952d8..0000000000000000000000000000000000000000 --- a/examples/tim1_pwm/t1pwm.h +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Single-File-Header for using Advanced Control Timer (TIM1) for PWM generation - * 03-28-2023 E. Brombaugh - */ - -#ifndef _T1PWM_H -#define _T1PWM_H - -#include <stdint.h> - -/* - * initialize act - */ -void t1pwm_init( void ) -{ - // Enable GPIOC, GPIOD and TIM1 - RCC->APB2PCENR |= RCC_APB2Periph_GPIOD | RCC_APB2Periph_GPIOC | - RCC_APB2Periph_TIM1; - - // PD0 is T1CH1N, 50MHz Output PP CNF = 10: Mux PP, MODE = 11: Out 50MHz - GPIOD->CFGLR &= ~(GPIO_CFGLR_MODE0 | GPIO_CFGLR_CNF0); - GPIOD->CFGLR |= GPIO_CFGLR_CNF0_1 | GPIO_CFGLR_MODE0_0 | GPIO_CFGLR_MODE0_1; - - // PC4 is T1CH4, 50MHz Output PP CNF = 10: Mux PP, MODE = 11: Out 50MHz - GPIOC->CFGLR &= ~(GPIO_CFGLR_MODE4 | GPIO_CFGLR_CNF4); - GPIOC->CFGLR |= GPIO_CFGLR_CNF4_1 | GPIO_CFGLR_MODE4_0 | GPIO_CFGLR_MODE4_1; - - // Reset TIM1 to init all regs - RCC->APB2PRSTR |= RCC_APB2Periph_TIM1; - RCC->APB2PRSTR &= ~RCC_APB2Periph_TIM1; - - // CTLR1: default is up, events generated, edge align - // SMCFGR: default clk input is CK_INT - - // Prescaler - TIM1->PSC = 0x0000; - - // Auto Reload - sets period - TIM1->ATRLR = 255; - - // Reload immediately - TIM1->SWEVGR |= TIM_UG; - - // Enable CH1N output, positive pol - TIM1->CCER |= TIM_CC1NE | TIM_CC1NP; - - // Enable CH4 output, positive pol - TIM1->CCER |= TIM_CC4E | TIM_CC4P; - - // CH1 Mode is output, PWM1 (CC1S = 00, OC1M = 110) - TIM1->CHCTLR1 |= TIM_OC1M_2 | TIM_OC1M_1; - - // CH2 Mode is output, PWM1 (CC1S = 00, OC1M = 110) - TIM1->CHCTLR2 |= TIM_OC4M_2 | TIM_OC4M_1; - - // Set the Capture Compare Register value to 50% initially - TIM1->CH1CVR = 128; - TIM1->CH4CVR = 128; - - // Enable TIM1 outputs - TIM1->BDTR |= TIM_MOE; - - // Enable TIM1 - TIM1->CTLR1 |= TIM_CEN; -} - -/* - * set timer channel PW - */ -void t1pwm_setpw(uint8_t chl, uint16_t width) -{ - switch(chl&3) - { - case 0: TIM1->CH1CVR = width; break; - case 1: TIM1->CH2CVR = width; break; - case 2: TIM1->CH3CVR = width; break; - case 3: TIM1->CH4CVR = width; break; - } -} - -/* - * force output - */ -void t1pwm_force(uint8_t chl, uint8_t val) -{ - uint16_t temp; - - chl &= 3; - - if(chl < 2) - { - temp = TIM1->CHCTLR1; - temp &= ~(TIM_OC1M<<(8*chl)); - temp |= (TIM_OC1M_2 | (val?TIM_OC1M_0:0))<<(8*chl); - TIM1->CHCTLR1 = temp; - } - else - { - chl &= 1; - temp = TIM1->CHCTLR2; - temp &= ~(TIM_OC1M<<(8*chl)); - temp |= (TIM_OC1M_2 | (val?TIM_OC1M_0:0))<<(8*chl); - TIM1->CHCTLR2 = temp; - } -} - -#endif diff --git a/examples/tim1_pwm/tim1_pwm.c b/examples/tim1_pwm/tim1_pwm.c index 84d77bdd9cb0a9446874f8ecd68b1b0febcf2628..1ead833489df1901e18f63e7f28f4009783527e7 100644 --- a/examples/tim1_pwm/tim1_pwm.c +++ b/examples/tim1_pwm/tim1_pwm.c @@ -9,8 +9,106 @@ #include "ch32v003fun.h" #include <stdio.h> -#include "t1pwm.h" +/* + * initialize TIM1 for PWM + */ +void t1pwm_init( void ) +{ + // Enable GPIOC, GPIOD and TIM1 + RCC->APB2PCENR |= RCC_APB2Periph_GPIOD | RCC_APB2Periph_GPIOC | + RCC_APB2Periph_TIM1; + + // PD0 is T1CH1N, 10MHz Output alt func, push-pull + GPIOD->CFGLR &= ~(0xf<<(4*0)); + GPIOD->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP_AF)<<(4*0); + + // PC4 is T1CH4, 10MHz Output alt func, push-pull + GPIOC->CFGLR &= ~(0xf<<(4*4)); + GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP_AF)<<(4*4); + + // Reset TIM1 to init all regs + RCC->APB2PRSTR |= RCC_APB2Periph_TIM1; + RCC->APB2PRSTR &= ~RCC_APB2Periph_TIM1; + + // CTLR1: default is up, events generated, edge align + // SMCFGR: default clk input is CK_INT + + // Prescaler + TIM1->PSC = 0x0000; + + // Auto Reload - sets period + TIM1->ATRLR = 255; + + // Reload immediately + TIM1->SWEVGR |= TIM_UG; + + // Enable CH1N output, positive pol + TIM1->CCER |= TIM_CC1NE | TIM_CC1NP; + + // Enable CH4 output, positive pol + TIM1->CCER |= TIM_CC4E | TIM_CC4P; + + // CH1 Mode is output, PWM1 (CC1S = 00, OC1M = 110) + TIM1->CHCTLR1 |= TIM_OC1M_2 | TIM_OC1M_1; + + // CH2 Mode is output, PWM1 (CC1S = 00, OC1M = 110) + TIM1->CHCTLR2 |= TIM_OC4M_2 | TIM_OC4M_1; + + // Set the Capture Compare Register value to 50% initially + TIM1->CH1CVR = 128; + TIM1->CH4CVR = 128; + + // Enable TIM1 outputs + TIM1->BDTR |= TIM_MOE; + + // Enable TIM1 + TIM1->CTLR1 |= TIM_CEN; +} + +/* + * set timer channel PW + */ +void t1pwm_setpw(uint8_t chl, uint16_t width) +{ + switch(chl&3) + { + case 0: TIM1->CH1CVR = width; break; + case 1: TIM1->CH2CVR = width; break; + case 2: TIM1->CH3CVR = width; break; + case 3: TIM1->CH4CVR = width; break; + } +} + +/* + * force output (used for testing / debug) + */ +void t1pwm_force(uint8_t chl, uint8_t val) +{ + uint16_t temp; + + chl &= 3; + + if(chl < 2) + { + temp = TIM1->CHCTLR1; + temp &= ~(TIM_OC1M<<(8*chl)); + temp |= (TIM_OC1M_2 | (val?TIM_OC1M_0:0))<<(8*chl); + TIM1->CHCTLR1 = temp; + } + else + { + chl &= 1; + temp = TIM1->CHCTLR2; + temp &= ~(TIM_OC1M<<(8*chl)); + temp |= (TIM_OC1M_2 | (val?TIM_OC1M_0:0))<<(8*chl); + TIM1->CHCTLR2 = temp; + } +} + +/* + * entry + */ int main() { uint32_t count = 0;