Advertisement
Guest User

Untitled

a guest
Jun 1st, 2014
64
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 6.16 KB | None | 0 0
  1. /*
  2.  * Copyright (c) 2014 ELL-i co-op.
  3.  *
  4.  * This is part of ELL-i software.
  5.  *
  6.  * ELL-i software is free software: you can redistribute it and/or modify
  7.  * it under the terms of the GNU General Public License as published by
  8.  * the Free Software Foundation, either version 3 of the License, or
  9.  * (at your option) any later version.
  10.  *
  11.  * ELL-i software is distributed in the hope that it will be useful,
  12.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  * GNU General Public License for more details.
  15.  *
  16.  * You should have received a copy of the GNU General Public License
  17.  * along with ELL-i software.  If not, see <http://www.gnu.org/licenses/>.
  18.  */
  19.  
  20. #include <Arduino.h>
  21.  
  22. #define DMALEN 120
  23. uint16_t dmabuf[DMALEN];
  24.  
  25. const int8_t sine[] = {
  26. 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
  27. };
  28. const int8_t *const cosine = sine+0x40;
  29.  
  30. uint32_t oph=0, ofq=1773279735;
  31. int32_t lpfr=0,lpfi=0;
  32. int8_t att=0;
  33. uint32_t clipn=0, clipn2=0, clipc=0;
  34.  
  35. void rxbuf(uint16_t *buf) {
  36.     /*
  37.     OK, this dsp code sucks, it's just enough to
  38.     show that the concept works.
  39.     The 8-bit sine table probably produces some spurs
  40.     (accumulator truncation noise, quantization noise).
  41.     The integrate-and-dump resampler aliases.
  42.     The AM demodulator should include a square root
  43.     to get magnitude instead of magnitude^2.
  44.     The bit shifting AGC makes huge 12 dB steps in output power
  45.     and is controlled by the number of sampled clipped.
  46.     */
  47.     register int32_t sumr=0, sumi=0;
  48.     int32_t sor,soi;
  49.     uint32_t p;
  50.     //ofq += 10000; // could sweep the frequency
  51.     // quadrature mix and resample by DMALEN/2
  52.     for(uint16_t *bp=buf; bp<buf+DMALEN/2; bp++) {
  53.         int32_t b = (int32_t)(*bp)-0x800;
  54.         oph += ofq;
  55.         sumr += b*cosine[oph>>24];
  56.         sumi += b*sine[oph>>24];
  57.     }
  58.     // IIR lowpass filter
  59.     lpfr = lpfr+((sumr-lpfr)>>4);
  60.     sor = lpfr>>att;
  61.     lpfi = lpfi+((sumi-lpfi)>>4);
  62.     soi = lpfi>>att;
  63.     // demodulate AM
  64.     p = (sor*sor) + (soi*soi);
  65.     p >>= 16;
  66.     // clip
  67.     if(p > 0xFFF) {
  68.         p = 0xFFF;
  69.         clipn++;
  70.     }
  71.     // set the DAC output register
  72.     DAC->DHR12R1 = p;
  73.     // gain control
  74.     if(p > 0x400) clipn2++;
  75.     clipc++;
  76.     if(clipc >= 0x1000) {
  77.         if(clipn > 0x200 && att<21) att++;
  78.         else if(clipn2 < 0x100 && att>0) att--;
  79.         clipc = clipn = clipn2 = 0;
  80.     }
  81. }
  82.  
  83. void setup() {
  84.     /* I'm not going to explain everything here.
  85.        The datasheet is quite good, just read it carefully and see
  86.        what all these registers can do.
  87.        PA0 adc in, PA4 adc out */
  88.     pinMode(2,OUTPUT); pinMode(3,OUTPUT);
  89.     digitalWrite(2,0); digitalWrite(3,1);
  90.    
  91.     FLASH->ACR |= FLASH_ACR_PRFTBE;
  92.    
  93.     // enable clocks
  94.     RCC->AHBENR |= RCC_AHBENR_GPIOAEN | RCC_AHBENR_DMA1EN;
  95.     RCC->APB1ENR |= RCC_APB1ENR_DACEN;
  96.     RCC->APB2ENR |= RCC_APB2ENR_ADC1EN;
  97.  
  98.     GPIOA->MODER |=
  99.      GPIO_MODER_MODER0_0 | GPIO_MODER_MODER0_1 |
  100.      GPIO_MODER_MODER4_0 | GPIO_MODER_MODER4_1; // analog mode
  101.     GPIOA->PUPDR &= ~(GPIO_PUPDR_PUPDR0 | GPIO_PUPDR_PUPDR4);
  102.    
  103.     // set DAC to be triggered from software and enable it
  104.     DAC->CR = DAC_CR_TEN1 | DAC_CR_EN1 |
  105.      DAC_CR_TSEL1_2 | DAC_CR_TSEL1_1 | DAC_CR_TSEL1_0;
  106.    
  107.     ADC1->CR = 0; // make sure ADC is disabled
  108.     ADC1->CFGR1 = ADC_CFGR1_DMACFG | ADC_CFGR1_DMAEN | ADC_CFGR1_CONT;
  109.     ADC1->CFGR2 = ADC_CFGR2_JITOFFDIV2;
  110.    
  111.     /* use the sampling time to fine-tune sample rate such that
  112.        we have enough time to process everything */
  113.     ADC1->SMPR = 2;
  114.    
  115.     ADC1->CHSELR = ADC_CHSELR_CHSEL0;
  116.     ADC->CCR = ADC_CCR_VREFEN;
  117.     ADC1->CR = ADC_CR_ADEN; // finally enable it
  118.    
  119.     DMA1_Channel1->CCR = 0; // make sure DMA is disabled
  120.     DMA1->IFCR |= DMA_IFCR_CHTIF1|DMA_IFCR_CTCIF1;
  121.     DMA1_Channel1->CNDTR = DMALEN;
  122.     DMA1_Channel1->CPAR = (uint32_t)&ADC1->DR;
  123.     DMA1_Channel1->CMAR = (uint32_t)&dmabuf;
  124.     DMA1_Channel1->CCR =
  125.      DMA_CCR_PL_1 | DMA_CCR_MSIZE_0 | DMA_CCR_PSIZE_0 |
  126.      DMA_CCR_MINC | DMA_CCR_CIRC | DMA_CCR_EN; // finally enable it
  127.      
  128.     /* First trigger the ADC from software.
  129.        It will retrigger itself after each conversion when
  130.        ADC_CFGR1_CONT is set. */
  131.     ADC1->CR |= ADC_CR_ADSTART;
  132. }
  133.  
  134. void loop() {
  135.     for(;;) {
  136.         /* wait until half of the DMA buffer is full
  137.            TODO: use interrupts instead of polling */
  138.         while(!(DMA1->ISR & DMA_ISR_HTIF1));
  139.         /* Trigger the DAC here instead of the end of rxbuf function
  140.            to make the trigger time a bit more constant. There may
  141.            still be jitter of a few cycles because of the polling. */
  142.         DAC->SWTRIGR = DAC_SWTRIGR_SWTRIG1;
  143.        
  144.         DMA1->IFCR |= DMA_IFCR_CHTIF1; // clear the half transfer flag
  145.         // use output 2 to see how much time is spent in rxbuf
  146.         digitalWrite(2,1);
  147.         // process the first half of the buffer
  148.         rxbuf(dmabuf);
  149.         digitalWrite(2,0);
  150.  
  151.         /* wait until second half of the DMA buffer is completed
  152.            (DMA transfer completed) */
  153.         while(!(DMA1->ISR & DMA_ISR_TCIF1));
  154.         DAC->SWTRIGR = DAC_SWTRIGR_SWTRIG1;
  155.         DMA1->IFCR |= DMA_IFCR_CTCIF1;
  156.         digitalWrite(2,1);
  157.         // process the second half
  158.         rxbuf(dmabuf + DMALEN/2);
  159.         digitalWrite(2,0);
  160.        
  161.         /* DMA now wraps back in the beginning of the buffer because
  162.            DMA_CCR_CIRC is set */
  163.     }
  164. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement