Advertisement
Guest User

Maple Timer Input Capture via DMA

a guest
Nov 12th, 2011
496
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 11.65 KB | None | 0 0
  1. /**********************************************************************
  2.  Various Maple tests.. including timer capture to memory via dma =)
  3.  */
  4.  
  5. #include "usb.h"
  6. #include "timer.h"
  7. #include "dma.h"
  8.  
  9. //quick method to return if there's anyone on the other end of the serialusb link yet.
  10. boolean isConnected(){
  11.   return (SerialUSB.isConnected() && (SerialUSB.getDTR() || SerialUSB.getRTS()));
  12. }
  13.  
  14. void setup(){
  15.   SerialUSB.begin();
  16.   while(!isConnected()); //wait till console attaches.
  17.   SerialUSB.println("Hello!");
  18. }
  19.  
  20. /**********************************************************************
  21.  timer tests.. seeing if the timer clock really does run at 72mhz..
  22.  */
  23.  
  24. volatile int overflowCount=0;
  25. void countOverflows(){
  26.   overflowCount++;
  27. }
  28.  
  29. int PRESCALE=128;
  30. int WAIT=50;
  31. int results[16];
  32. int overflow[16];
  33. void testHardwareTimer(HardwareTimer t){
  34.   t.attachInterrupt(1,countOverflows);
  35.   for(int i=0; i<16; i++){
  36.     t.setCount(0);
  37.     overflowCount=0;
  38.     t.resume();
  39.     delay(WAIT);
  40.     t.pause();
  41.     results[i]=t.getCount();
  42.     overflow[i]=overflowCount;
  43.   }
  44.   t.detachInterrupt(1);
  45. }
  46. void printResults(){  
  47.   SerialUSB.print("Timing results: ");
  48.   for(int i=0; i<16; i++){
  49.     SerialUSB.print(results[i]);
  50.     SerialUSB.print(" ");
  51.   }
  52.   SerialUSB.println();
  53.   SerialUSB.print("Overflows: ");
  54.   for(int i=0; i<16; i++){
  55.     SerialUSB.print(overflow[i]);
  56.     SerialUSB.print(" ");
  57.   }
  58.   SerialUSB.println();
  59.   SerialUSB.print("Each count worth approx (ns): ");
  60.   for(int i=0; i<16; i++){
  61.     SerialUSB.print( waitToNanos(overflow[i], results[i]) );
  62.     SerialUSB.print(" ");
  63.   }
  64.   SerialUSB.println();
  65. }
  66. double expectedTimePeriod(){
  67.   //in nanos.. so 72mhz = 72000khz = 72000000hz  1/72000000hz = tick in seconds
  68.   // 1/72000 = tick in ms, 1/72 = tick in us (1/72) * 1000 = tick in ns
  69.   //tick in ns * prescale == time we're supposed to see
  70.   return ((double)1.0 / ((double)72.0)) * (double)1000.0 * (double)PRESCALE;
  71. }
  72. double waitToNanos( int overflows, int count ){
  73.   //wait is in millis, *1000 for micros, *1000 for nanos
  74.   double time = (((double)WAIT * (double)1000.0 * (double)1000.0) ) ;
  75.   time = time / ((double)count + ((double)65535*(double)overflows));
  76.   return time;
  77. }
  78.  
  79. int readInt(char terminator){
  80.   char current;
  81.   int output=0;
  82.   while(SerialUSB.available() && (current=SerialUSB.read())!=terminator){
  83.     if(current>='0' && current<='9'){
  84.       output=output*10;
  85.       output+=(current-'0');
  86.     }else{
  87.       output=-1;
  88.       break;
  89.     }
  90.   }
  91.   return output;
  92. }
  93.  
  94. HardwareTimer timer2 = HardwareTimer(2);
  95. HardwareTimer timer1 = HardwareTimer(1);
  96. void timingTest(){
  97.       SerialUSB.println("Starting Timing test");
  98.       SerialUSB.print(" Prescale: ");
  99.       SerialUSB.println(PRESCALE);
  100.       SerialUSB.print(" Wait Period (ms): ");
  101.       SerialUSB.println(WAIT);
  102.       SerialUSB.print(" Expected value for each tick :");
  103.       SerialUSB.println(expectedTimePeriod());
  104.       timer1.pause();
  105.       timer2.pause();
  106.  
  107.       timer2.setMode(TIMER_CH1, TIMER_OUTPUT_COMPARE);
  108.       timer2.setPrescaleFactor(PRESCALE);
  109.       timer2.setOverflow(65535);
  110.       timer2.setCompare(1,65535);
  111.       timer2.setCount(0);
  112.       timer2.refresh();
  113.  
  114.       timer1.setMode(TIMER_CH1, TIMER_OUTPUT_COMPARE);
  115.       timer1.setPrescaleFactor(PRESCALE);
  116.       timer1.setOverflow(65535);
  117.       timer1.setCompare(1,65535);
  118.       timer1.setCount(0);
  119.       timer1.refresh();
  120.  
  121.       testHardwareTimer(timer1);
  122.       printResults();
  123.  
  124.       testHardwareTimer(timer2);
  125.       printResults();        
  126. }
  127.  
  128. /******************************************************************************
  129.  DMA from Timer Capture to array test..
  130.  */
  131.  
  132. //number of captures to do..
  133. #define TIMERS 512
  134. volatile int exit=0;            //set to 1 when dma complete.
  135. volatile uint16 data[TIMERS];   //place to put the data via dma
  136.  
  137. //dump routine to show content of captured data.
  138. void printData(){
  139.   SerialUSB.print("DATA: ");
  140.   for(int i=0; i<TIMERS; i++){
  141.     SerialUSB.print(data[i]);
  142.     SerialUSB.print(" ");
  143.   }
  144.   SerialUSB.println();
  145. }
  146.  
  147. //invoked as configured by the DMA mode flags.
  148. void dma_isr()
  149. {
  150.     dma_irq_cause cause = dma_get_irq_cause(DMA1, DMA_CH2);
  151.         //using serialusb to print messages here is nice, but
  152.         //it takes so long, we may never exit this isr invocation
  153.         //before the next one comes in.. (dma is fast.. m'kay)
  154.     switch(cause)
  155.     {
  156.         case DMA_TRANSFER_COMPLETE:
  157.             // Transfer completed
  158.                         SerialUSB.println("DMA Complete");
  159.                         exit=1;
  160.             break;
  161.         case DMA_TRANSFER_HALF_COMPLETE:
  162.             // Transfer is half complete
  163.                         SerialUSB.println("DMA Half Complete");                  
  164.             break;
  165.         case DMA_TRANSFER_ERROR:
  166.             // An error occurred during transfer
  167.                         SerialUSB.println("DMA Error");
  168.                         exit=1;
  169.             break;
  170.         default:
  171.             // Something went horribly wrong.
  172.             // Should never happen.
  173.                         SerialUSB.println("DMA WTF");
  174.                         exit=1;
  175.             break;
  176.     }
  177.  
  178. }
  179.  
  180.  
  181. void loop(){
  182.  
  183.   //simple main loop, listens for a char, and uses it as a command
  184.   //to select what task to perform
  185.   //
  186.   // a   echo test
  187.   // b   echo test
  188.   // c   serialusb disable/enable test
  189.   // d   time the timer test, default params
  190.   // e   time the timer test, user supplied args
  191.   // f   DMA timer capture of pulse widths from D6 straight to memory
  192.  
  193.   while(!SerialUSB.available());
  194.   char cmd = SerialUSB.read();
  195.   switch(cmd)
  196.   {
  197.   case 'a':
  198.     {
  199.       SerialUSB.println("Hello");
  200.       break;
  201.     }
  202.   case 'b':
  203.     {
  204.       SerialUSB.println("There");
  205.       break;
  206.     }
  207.  
  208.   case 'c':
  209.     {
  210.       SerialUSB.println("Going away for a while");
  211.       SerialUSB.end();
  212.       usbPowerOff();
  213.       delay(5000);
  214.       usbPowerOn();
  215.       SerialUSB.begin();
  216.       delay(5000);
  217.       while(!isConnected());
  218.       SerialUSB.println("Welcome back");
  219.       break;
  220.     }
  221.   case 'd':
  222.     {
  223.        WAIT=50;
  224.        PRESCALE=128;
  225.        timingTest();
  226.        break;
  227.     }
  228.     case 'e':
  229.     {
  230.       int arg1=0;
  231.       int arg2=0;
  232.      
  233.       if(!SerialUSB.available())
  234.         goto usage;
  235.       if(SerialUSB.read()!=' ')
  236.         goto usage;
  237.        
  238.       arg1 = readInt(' ');
  239.       arg2 = readInt(' ');
  240.      
  241.       if(arg1==-1 || arg2==-1)
  242.         goto usage;
  243.      
  244.       SerialUSB.print("Setting prescale to: ");
  245.       SerialUSB.println(arg1);
  246.       SerialUSB.print("Setting wait to: ");
  247.       SerialUSB.println(arg2);
  248.      
  249.       WAIT=arg2;
  250.       PRESCALE=arg1;
  251.       timingTest();
  252.        
  253.       goto done;
  254. usage:
  255.       SerialUSB.println("Usage: e <prescale> <wait>");
  256.       SerialUSB.println(" eg. e 128 200   for a prescale of 128 and wait of 200");
  257. done:
  258.       break;
  259.     }
  260.     case 'f':{      
  261.       timer_dev *t = TIMER1;
  262.      
  263.       timer1.pause();
  264.       timer1.setPrescaleFactor(128);
  265.       timer1.setOverflow(65535);
  266.       timer1.setCount(0);
  267.       timer1.refresh();
  268.      
  269.       timer_reg_map r = t->regs;
  270.      
  271.       //using timer1, channel1, maps to pin d6
  272.       //according to maple master pin map.
  273.       pinMode(6,INPUT_PULLUP);
  274.      
  275.       //capture compare regs TIMx_CCRx used to hold val after a transition on corresponding ICx
  276.      
  277.       //when cap occurs, flag CCXIF (TIMx_SR register) is set,
  278.       //and interrupt, or dma req can be sent if they are enabled.
  279.      
  280.       //if cap occurs while flag is already high CCxOF (overcapture) flag is set..
  281.      
  282.       //CCIX can be cleared by writing 0, or by reading the capped data from TIMx_CCRx
  283.       //CCxOF is cleared by writing 0 to it.
  284.      
  285.       //Capture/Compare 1 Selection
  286.       //  set CC1S bits to 01 in the capture compare mode register.
  287.       //  01 selects TI1 as the input to use. (page 336 stm32 reference)
  288.       //  (assuming here that TI1 is D6, according to maple master pin map)
  289.       //CC1S bits are bits 0,1
  290.       bitSet(r.adv->CCMR1, 0);
  291.       bitClear(r.adv->CCMR1, 1);
  292.  
  293.      
  294.       //Input Capture 1 Filter.
  295.       //  need to set IC1F bits according to a table saying how long
  296.       //  we should wait for a signal to be 'stable' to validate a transition
  297.       //  on the input.
  298.       //  (page 336 stm32 reference)
  299.       //IC1F bits are bits 7,6,5,4    
  300.       bitClear(r.adv->CCMR1, 7);                        
  301.       bitClear(r.adv->CCMR1, 6);  
  302.       bitSet(r.adv->CCMR1, 5);  
  303.       bitSet(r.adv->CCMR1, 4);  
  304.      
  305.       //sort out the input capture prescaler..
  306.       //00 no prescaler.. capture is done as soon as edge is detected
  307.       bitClear(r.adv->CCMR1, 3);                        
  308.       bitClear(r.adv->CCMR1, 2);  
  309.  
  310.       //select the edge for the transition on TI1 channel using CC1P in CCER
  311.       //CC1P is bit 1 of CCER (page 339)
  312.       // 0 = falling
  313.       // 1 = rising
  314.       bitClear(r.adv->CCER,1);
  315.      
  316.       //set the CC1E bit to enable capture from the counter.
  317.       //CCE1 is bit 0 of CCER (page 339)
  318.       bitSet(r.adv->CCER,0);
  319.  
  320.       //enable dma for this timer..
  321.       //sets the Capture/Compare 1 DMA request enable bit on the DMA/interrupt enable register.
  322.       //bit 9 is CC1DE as defined on page 329.
  323.       bitSet(r.adv->DIER,9);      
  324.      
  325.       dma_init(DMA1);
  326.       dma_setup_transfer( DMA1,    //dma device, dma1 here because that's the only one we have
  327.                           DMA_CH2, //dma channel, channel2, because it looks after tim1_ch1 (timer1, channel1)
  328.                           &(r.adv->CCR1), //peripheral address
  329.                           DMA_SIZE_16BITS, //peripheral size
  330.                           data, //memory address
  331.                           DMA_SIZE_16BITS, //memory transfer size
  332.                           (0
  333.                            //| DMA_FROM_MEM  //set if going from memory, don't set if going to memory.
  334.                            | DMA_MINC_MODE //auto inc where the data does in memory (uses size_16bits to know how much)
  335.                            | DMA_TRNS_ERR  //tell me if it's fubar
  336.                            //| DMA_HALF_TRNS //tell me half way (actually, don't as I spend so long there, I dont see 'complete')                          
  337.                            | DMA_TRNS_CMPLT //tell me at the end
  338.                            )  
  339.                           );
  340.                                                    
  341.       dma_attach_interrupt(DMA1, DMA_CH2, dma_isr); //hook up an isr for the dma chan to tell us if things happen.
  342.       dma_set_num_transfers(DMA1, DMA_CH2, TIMERS); //only allow it to transfer TIMERS number of times.    
  343.       dma_enable(DMA1, DMA_CH2);                    //enable it..
  344.      
  345.       SerialUSB.println("Starting timer.. falling edge of D6 (hopefully)");
  346.       //start the timer counting.
  347.       timer1.resume();
  348.       //the timer is now counting up, and any falling edges on D6
  349.       //will trigger a DMA request to clone the timercapture to the array
  350.      
  351.       //If we weren't using DMA, we could busy wait on the CC1IF bit in SR
  352.       //
  353.       //when the timer captures, the CC1IF bit will be set on the timer SR register.
  354.       //CC1IF bit is bit 1 (page 332)
  355.       //while(!bitRead(r.adv->SR, 1)){
  356.       //}
  357.       //SerialUSB.println("Timer triggered : ");
  358.       //SerialUSB.println(r.adv->CCR1);      
  359.      
  360.       SerialUSB.println("Waiting for exit flag from dma...");  
  361.       //busy wait on the exit flag
  362.       //we could do real work here if wanted..
  363.       while(!exit);
  364.       //dump the data
  365.       printData();
  366.      
  367.      
  368.       //turn off the timer & tidy up before we leave this cmd.
  369.       timer1.pause();
  370.       dma_disable(DMA1, DMA_CH2);
  371.       dma_detach_interrupt(DMA1, DMA_CH2);
  372.  
  373.       break;
  374.     }
  375.   }
  376. }
  377.  
  378.  
  379.  
  380.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement