Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*
- * Copyright (c) 2014 ELL-i co-op.
- *
- * This is part of ELL-i software.
- *
- * ELL-i software is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * ELL-i software is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with ELL-i software. If not, see <http://www.gnu.org/licenses/>.
- */
- #include <Arduino.h>
- #define DMALEN 120
- uint16_t dmabuf[DMALEN];
- const int8_t sine[] = {
- 0,3,6,9,12,16,19,22,25,28,31,34,37,40,43,46,49,51,54,57,60,63,65,68,71,73,76,78,81,83,85,88,90,92,94,96,98,100,102,104,106,107,109,111,112,113,115,116,117,118,120,121,122,122,123,124,125,125,126,126,126,127,127,127,127,127,127,127,126,126,126,125,125,124,123,122,122,121,120,118,117,116,115,113,112,111,109,107,106,104,102,100,98,96,94,92,90,88,85,83,81,78,76,73,71,68,65,63,60,57,54,51,49,46,43,40,37,34,31,28,25,22,19,16,12,9,6,3,0,-3,-6,-9,-12,-16,-19,-22,-25,-28,-31,-34,-37,-40,-43,-46,-49,-51,-54,-57,-60,-63,-65,-68,-71,-73,-76,-78,-81,-83,-85,-88,-90,-92,-94,-96,-98,-100,-102,-104,-106,-107,-109,-111,-112,-113,-115,-116,-117,-118,-120,-121,-122,-122,-123,-124,-125,-125,-126,-126,-126,-127,-127,-127,-127,-127,-127,-127,-126,-126,-126,-125,-125,-124,-123,-122,-122,-121,-120,-118,-117,-116,-115,-113,-112,-111,-109,-107,-106,-104,-102,-100,-98,-96,-94,-92,-90,-88,-85,-83,-81,-78,-76,-73,-71,-68,-65,-63,-60,-57,-54,-51,-49,-46,-43,-40,-37,-34,-31,-28,-25,-22,-19,-16,-12,-9,-6,-3,0,3,6,9,12,16,19,22,25,28,31,34,37,40,43,46,49,51,54,57,60,63,65,68,71,73,76,78,81,83,85,88,90,92,94,96,98,100,102,104,106,107,109,111,112,113,115,116,117,118,120,121,122,122,123,124,125,125,126,126,126,127,127,127
- };
- const int8_t *const cosine = sine+0x40;
- uint32_t oph=0, ofq=1773279735;
- int32_t lpfr=0,lpfi=0;
- int8_t att=0;
- uint32_t clipn=0, clipn2=0, clipc=0;
- void rxbuf(uint16_t *buf) {
- /*
- OK, this dsp code sucks, it's just enough to
- show that the concept works.
- The 8-bit sine table probably produces some spurs
- (accumulator truncation noise, quantization noise).
- The integrate-and-dump resampler aliases.
- The AM demodulator should include a square root
- to get magnitude instead of magnitude^2.
- The bit shifting AGC makes huge 12 dB steps in output power
- and is controlled by the number of sampled clipped.
- */
- register int32_t sumr=0, sumi=0;
- int32_t sor,soi;
- uint32_t p;
- //ofq += 10000; // could sweep the frequency
- // quadrature mix and resample by DMALEN/2
- for(uint16_t *bp=buf; bp<buf+DMALEN/2; bp++) {
- int32_t b = (int32_t)(*bp)-0x800;
- oph += ofq;
- sumr += b*cosine[oph>>24];
- sumi += b*sine[oph>>24];
- }
- // IIR lowpass filter
- lpfr = lpfr+((sumr-lpfr)>>4);
- sor = lpfr>>att;
- lpfi = lpfi+((sumi-lpfi)>>4);
- soi = lpfi>>att;
- // demodulate AM
- p = (sor*sor) + (soi*soi);
- p >>= 16;
- // clip
- if(p > 0xFFF) {
- p = 0xFFF;
- clipn++;
- }
- // set the DAC output register
- DAC->DHR12R1 = p;
- // gain control
- if(p > 0x400) clipn2++;
- clipc++;
- if(clipc >= 0x1000) {
- if(clipn > 0x200 && att<21) att++;
- else if(clipn2 < 0x100 && att>0) att--;
- clipc = clipn = clipn2 = 0;
- }
- }
- void setup() {
- /* I'm not going to explain everything here.
- The datasheet is quite good, just read it carefully and see
- what all these registers can do.
- PA0 adc in, PA4 adc out */
- pinMode(2,OUTPUT); pinMode(3,OUTPUT);
- digitalWrite(2,0); digitalWrite(3,1);
- FLASH->ACR |= FLASH_ACR_PRFTBE;
- // enable clocks
- RCC->AHBENR |= RCC_AHBENR_GPIOAEN | RCC_AHBENR_DMA1EN;
- RCC->APB1ENR |= RCC_APB1ENR_DACEN;
- RCC->APB2ENR |= RCC_APB2ENR_ADC1EN;
- GPIOA->MODER |=
- GPIO_MODER_MODER0_0 | GPIO_MODER_MODER0_1 |
- GPIO_MODER_MODER4_0 | GPIO_MODER_MODER4_1; // analog mode
- GPIOA->PUPDR &= ~(GPIO_PUPDR_PUPDR0 | GPIO_PUPDR_PUPDR4);
- // set DAC to be triggered from software and enable it
- DAC->CR = DAC_CR_TEN1 | DAC_CR_EN1 |
- DAC_CR_TSEL1_2 | DAC_CR_TSEL1_1 | DAC_CR_TSEL1_0;
- ADC1->CR = 0; // make sure ADC is disabled
- ADC1->CFGR1 = ADC_CFGR1_DMACFG | ADC_CFGR1_DMAEN | ADC_CFGR1_CONT;
- ADC1->CFGR2 = ADC_CFGR2_JITOFFDIV2;
- /* use the sampling time to fine-tune sample rate such that
- we have enough time to process everything */
- ADC1->SMPR = 2;
- ADC1->CHSELR = ADC_CHSELR_CHSEL0;
- ADC->CCR = ADC_CCR_VREFEN;
- ADC1->CR = ADC_CR_ADEN; // finally enable it
- DMA1_Channel1->CCR = 0; // make sure DMA is disabled
- DMA1->IFCR |= DMA_IFCR_CHTIF1|DMA_IFCR_CTCIF1;
- DMA1_Channel1->CNDTR = DMALEN;
- DMA1_Channel1->CPAR = (uint32_t)&ADC1->DR;
- DMA1_Channel1->CMAR = (uint32_t)&dmabuf;
- DMA1_Channel1->CCR =
- DMA_CCR_PL_1 | DMA_CCR_MSIZE_0 | DMA_CCR_PSIZE_0 |
- DMA_CCR_MINC | DMA_CCR_CIRC | DMA_CCR_EN; // finally enable it
- /* First trigger the ADC from software.
- It will retrigger itself after each conversion when
- ADC_CFGR1_CONT is set. */
- ADC1->CR |= ADC_CR_ADSTART;
- }
- void loop() {
- for(;;) {
- /* wait until half of the DMA buffer is full
- TODO: use interrupts instead of polling */
- while(!(DMA1->ISR & DMA_ISR_HTIF1));
- /* Trigger the DAC here instead of the end of rxbuf function
- to make the trigger time a bit more constant. There may
- still be jitter of a few cycles because of the polling. */
- DAC->SWTRIGR = DAC_SWTRIGR_SWTRIG1;
- DMA1->IFCR |= DMA_IFCR_CHTIF1; // clear the half transfer flag
- // use output 2 to see how much time is spent in rxbuf
- digitalWrite(2,1);
- // process the first half of the buffer
- rxbuf(dmabuf);
- digitalWrite(2,0);
- /* wait until second half of the DMA buffer is completed
- (DMA transfer completed) */
- while(!(DMA1->ISR & DMA_ISR_TCIF1));
- DAC->SWTRIGR = DAC_SWTRIGR_SWTRIG1;
- DMA1->IFCR |= DMA_IFCR_CTCIF1;
- digitalWrite(2,1);
- // process the second half
- rxbuf(dmabuf + DMALEN/2);
- digitalWrite(2,0);
- /* DMA now wraps back in the beginning of the buffer because
- DMA_CCR_CIRC is set */
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement