Advertisement
Guest User

maple mini ppm-decode.cpp

a guest
Dec 28th, 2011
332
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. // File: ppm-decode.cpp
  2. // Original code from http://pastebin.com/NQtbVCFh
  3. // Posted on the leaflabs.com forum by Dweller:
  4. // http://forums.leaflabs.com/topic.php?id=1170
  5. ///**********************************************************************
  6. // Various Maple tests.. including timer capture to memory via dma =)
  7. // */
  8. #include "main.h"
  9. #include "wirish.h"
  10. #include "usb.h"
  11. #include "timer.h"
  12. #include "dma.h"
  13. #include "utils.h"
  14.  
  15. //number of captures to do by dma
  16. #define TIMERS 9
  17.  
  18. // timer prescale
  19. #define TIMER_PRESCALE 26
  20.  
  21. // TIMER_PRESCALE*(1/72 MHz) =
  22. #define TICK_PERIOD ( TIMER_PRESCALE*0.0000138888889f )
  23.  
  24. HardwareTimer timer4 = HardwareTimer(4);
  25. volatile int dma_data_captured=0;            //set to 1 when dma complete.
  26. volatile uint16 data[TIMERS];   //place to put the data via dma
  27. uint16 delta=0;
  28. uint16 ppm_timeout=0;
  29. int do_print=1;
  30.  
  31. //dump routine to show content of captured data.
  32. void printData(){
  33.     float duty;
  34.     for(int i=0; i<TIMERS; i++){
  35.  
  36.         if(ppm_timeout==1){
  37.             if(do_print==1)
  38.             {
  39.                 SerialUSB.println("PPM timeout!");
  40.                 do_print=0;
  41.             }
  42.             return;
  43.         }
  44.  
  45.         if(i>0) delta = data[i]-data[i-1];
  46.         else delta = data[i] - data[TIMERS-1];
  47.  
  48.         duty=(delta)*TICK_PERIOD;
  49.  
  50.         SerialUSB.print(delta);
  51.         SerialUSB.print(":(");
  52.         SerialUSB.print(duty);
  53.         SerialUSB.print(")");
  54.         if ((i+1)%9==0) SerialUSB.print("\r");
  55.         else SerialUSB.print("\t");
  56.     }
  57.     SerialUSB.println();
  58. }
  59.  
  60. //invoked as configured by the DMA mode flags.
  61. void dma_isr()
  62. {
  63.     dma_irq_cause cause = dma_get_irq_cause(DMA1, DMA_CH1);
  64.         //using serialusb to print messages here is nice, but
  65.         //it takes so long, we may never exit this isr invocation
  66.         //before the next one comes in.. (dma is fast.. m'kay)
  67.  
  68.     timer4.setCount(0);  // clear counter
  69.     if(ppm_timeout) ppm_timeout=0;
  70.     if(!do_print) do_print=1;
  71.     switch(cause)
  72.     {
  73.         case DMA_TRANSFER_COMPLETE:
  74.             // Transfer completed
  75.                         //SerialUSB.println("DMA Complete");
  76.                         dma_data_captured=1;
  77.             break;
  78.         case DMA_TRANSFER_HALF_COMPLETE:
  79.             // Transfer is half complete
  80.                         SerialUSB.println("DMA Half Complete");
  81.             break;
  82.         case DMA_TRANSFER_ERROR:
  83.             // An error occurred during transfer
  84.                         SerialUSB.println("DMA Error");
  85.                         dma_data_captured=1;
  86.             break;
  87.         default:
  88.             // Something went horribly wrong.
  89.             // Should never happen.
  90.                         SerialUSB.println("DMA WTF");
  91.                         dma_data_captured=1;
  92.             break;
  93.     }
  94.  
  95. }
  96.  
  97. void ppm_timeout_isr()
  98. {
  99.     // This failure mode indicates we lost comm with
  100.     // the transmitter
  101.  
  102.     //TODO: re-initialize the timer and wait for ppm signal
  103.     //re-initializing should ensure that the ppm signal
  104.     // is captured on the sync pulse.
  105.     ppm_timeout=1;
  106.     dma_data_captured=0;
  107. }
  108.  
  109. void init_timer_input_capture_dma()
  110. {
  111.  
  112.     timer_dev *t = TIMER4;
  113.  
  114.     timer4.pause();
  115.     timer4.setPrescaleFactor(TIMER_PRESCALE);
  116.     timer4.setOverflow(65535);
  117.     timer4.setCount(0);
  118.  
  119.     // use channel 2 to detect when we stop receiving
  120.     // a ppm signal from the encoder.
  121.     timer4.setMode(TIMER_CH2, TIMER_OUTPUT_COMPARE);
  122.     timer4.setCompare(TIMER_CH2, 65535);
  123.     timer4.attachCompare2Interrupt(ppm_timeout_isr);
  124.  
  125.  
  126.     timer4.refresh();
  127.  
  128.     timer_reg_map r = t->regs;
  129.  
  130.     //using timer4, channel1, maps to pin d16 (maple mini) //d6 (maple?)
  131.     //according to maple master pin map.
  132.     pinMode(PPM_PIN, INPUT);
  133.  
  134.     //capture compare regs TIMx_CCRx used to hold val after a transition on corresponding ICx
  135.  
  136.     //when cap occurs, flag CCXIF (TIMx_SR register) is set,
  137.     //and interrupt, or dma req can be sent if they are enabled.
  138.  
  139.     //if cap occurs while flag is already high CCxOF (overcapture) flag is set..
  140.  
  141.     //CCIX can be cleared by writing 0, or by reading the capped data from TIMx_CCRx
  142.     //CCxOF is cleared by writing 0 to it.
  143.  
  144.     //Clear the CC1E bit to disable capture from the counter as we set it up.
  145.     //CC1S bits aren't writeable when CC1E is set.
  146.     //CC1E is bit 0 of CCER (page 401)
  147.     bitClear(r.gen->CCER,0);
  148.  
  149.  
  150.     //Capture/Compare 1 Selection
  151.     //  set CC1S bits to 01 in the capture compare mode register 1.
  152.     //  01 selects TI1 as the input to use. (page 399 stm32 reference)
  153.     //  (assuming here that TI1 is D16, according to maple master pin map)
  154.     //CC1S bits are bits 1,0
  155.     bitClear(r.gen->CCMR1, 1);
  156.     bitSet(r.gen->CCMR1, 0);
  157.  
  158.  
  159.     //Input Capture 1 Filter.
  160.     //  need to set IC1F bits according to a table saying how long
  161.     //  we should wait for a signal to be 'stable' to validate a transition
  162.     //  on the input.
  163.     //  (page 401 stm32 reference)
  164.     //IC1F bits are bits 7,6,5,4
  165.     bitClear(r.gen->CCMR1, 7);
  166.     bitClear(r.gen->CCMR1, 6);
  167.     bitSet(r.gen->CCMR1, 5);
  168.     bitSet(r.gen->CCMR1, 4);
  169.  
  170.     //sort out the input capture prescaler IC1PSC..
  171.     //00 no prescaler.. capture is done at every edge detected
  172.     bitClear(r.gen->CCMR1, 3);
  173.     bitClear(r.gen->CCMR1, 2);
  174.  
  175.     //select the edge for the transition on TI1 channel using CC1P in CCER
  176.     //CC1P is bit 1 of CCER (page 401)
  177.     // 0 = rising (non-inverted. capture is done on a rising edge of IC1)
  178.     // 1 = falling (inverted. capture is done on a falling edge of IC1)
  179.     bitClear(r.gen->CCER,1);
  180.  
  181.     //set the CC1E bit to enable capture from the counter.
  182.     //CC1E is bit 0 of CCER (page 401)
  183.     bitSet(r.gen->CCER,0);
  184.  
  185.     //enable dma for this timer..
  186.     //sets the Capture/Compare 1 DMA request enable bit on the DMA/interrupt enable register.
  187.     //bit 9 is CC1DE as defined on page 393.
  188.     bitSet(r.gen->DIER,9);
  189.  
  190.     dma_init(DMA1);
  191.     dma_setup_transfer( DMA1,    //dma device, dma1 here because that's the only one we have
  192.                         DMA_CH1, //dma channel, channel1, because it looks after tim4_ch1 (timer4, channel1)
  193.                         &(r.gen->CCR1), //peripheral address
  194.                         DMA_SIZE_16BITS, //peripheral size
  195.                         data, //memory address
  196.                         DMA_SIZE_16BITS, //memory transfer size
  197.                         (0
  198.                          //| DMA_FROM_MEM  //set if going from memory, don't set if going to memory.
  199.                          | DMA_MINC_MODE //auto inc where the data does in memory (uses size_16bits to know how much)
  200.                          | DMA_TRNS_ERR  //tell me if it's fubar
  201.                          //| DMA_HALF_TRNS //tell me half way (actually, don't as I spend so long there, I dont see 'complete')
  202.                          | DMA_TRNS_CMPLT //tell me at the end
  203.                          | DMA_CIRC_MODE // circular mode... capture "num_transfers" (below) and repeat
  204.                          )
  205.                         );
  206.  
  207.     dma_attach_interrupt(DMA1, DMA_CH1, dma_isr); //hook up an isr for the dma chan to tell us if things happen.
  208.     dma_set_num_transfers(DMA1, DMA_CH1, TIMERS); //only allow it to transfer TIMERS number of times.
  209.     dma_enable(DMA1, DMA_CH1);                    //enable it..
  210.  
  211.  
  212. }
  213.  
  214. void ppm_decode_interrupt_dma()
  215. {
  216.  
  217.     SerialUSB.print("Starting timer.. rising edge of D");
  218.     SerialUSB.print(PPM_PIN);
  219.     disable_usarts();
  220.  
  221.     //start the timer counting.
  222.     timer4.resume();
  223.     //the timer is now counting up, and any rising edges on D16
  224.     //will trigger a DMA request to clone the timercapture to the array
  225.  
  226.     //If we weren't using DMA, we could busy wait on the CC1IF bit in SR
  227.     //
  228.     //when the timer captures, the CC1IF bit will be set on the timer SR register.
  229.     //CC1IF bit is bit 1 (page 332)
  230.     //while(!bitRead(r.gen->SR, 1)){
  231.     //}
  232.     //SerialUSB.println("Timer triggered : ");
  233.     //SerialUSB.println(r.gen->CCR1);
  234.  
  235.     //SerialUSB.println("Waiting for dma_data_captured flag from dma...");
  236.     //busy wait on the dma_data_captured flag
  237.     //we could do real work here if wanted..
  238.     while(!dma_data_captured && !SerialUSB.available());
  239.  
  240.     while(!SerialUSB.available() && do_print==1)
  241.     {
  242.       //dump the data
  243.       printData();
  244.       delay(100);
  245.     }
  246.  
  247.     //turn off the timer & tidy up before we leave this cmd.
  248.     timer4.pause();
  249.  
  250.     //      dma_disable(DMA1, DMA_CH2);
  251.     //      dma_detach_interrupt(DMA1, DMA_CH2);
  252.     dma_data_captured=0;
  253.  
  254. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement