View difference between Paste ID: dUjysqwt and NQtbVCFh
SHOW: | | - or go back to the newest paste.
1-
/**********************************************************************
1+
// File: ppm-decode.cpp
2-
 Various Maple tests.. including timer capture to memory via dma =)
2+
// Original code from http://pastebin.com/NQtbVCFh
3-
 */
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-
//quick method to return if there's anyone on the other end of the serialusb link yet.
9+
#include "wirish.h"
10-
boolean isConnected(){
10+
11-
  return (SerialUSB.isConnected() && (SerialUSB.getDTR() || SerialUSB.getRTS()));
11+
12
#include "dma.h"
13
#include "utils.h"
14-
void setup(){
14+
15-
  SerialUSB.begin();
15+
//number of captures to do by dma
16-
  while(!isConnected()); //wait till console attaches.
16+
#define TIMERS 9
17-
  SerialUSB.println("Hello!");
17+
18
// timer prescale
19
#define TIMER_PRESCALE 26
20-
/**********************************************************************
20+
21-
 timer tests.. seeing if the timer clock really does run at 72mhz..
21+
// TIMER_PRESCALE*(1/72 MHz) =
22-
 */
22+
#define TICK_PERIOD ( TIMER_PRESCALE*0.0000138888889f )
23
24-
volatile int overflowCount=0;
24+
HardwareTimer timer4 = HardwareTimer(4);
25-
void countOverflows(){
25+
volatile int dma_data_captured=0;            //set to 1 when dma complete.
26-
  overflowCount++;
26+
27
uint16 delta=0;
28
uint16 ppm_timeout=0;
29-
int PRESCALE=128;
29+
int do_print=1;
30-
int WAIT=50;
30+
31-
int results[16];
31+
32-
int overflow[16];
32+
33-
void testHardwareTimer(HardwareTimer t){
33+
	float duty;
34-
  t.attachInterrupt(1,countOverflows);
34+
	for(int i=0; i<TIMERS; i++){
35-
  for(int i=0; i<16; i++){
35+
36-
    t.setCount(0);
36+
		if(ppm_timeout==1){
37-
    overflowCount=0;
37+
			if(do_print==1)
38-
    t.resume();
38+
			{
39-
    delay(WAIT);
39+
				SerialUSB.println("PPM timeout!");
40-
    t.pause();
40+
				do_print=0;
41-
    results[i]=t.getCount();
41+
			}
42-
    overflow[i]=overflowCount;
42+
			return;
43-
  }
43+
		}
44-
  t.detachInterrupt(1);
44+
45
		if(i>0) delta = data[i]-data[i-1];
46-
void printResults(){  
46+
		else delta = data[i] - data[TIMERS-1];
47-
  SerialUSB.print("Timing results: ");
47+
48-
  for(int i=0; i<16; i++){
48+
		duty=(delta)*TICK_PERIOD;
49-
    SerialUSB.print(results[i]);
49+
50-
    SerialUSB.print(" ");
50+
		SerialUSB.print(delta);
51-
  }
51+
		SerialUSB.print(":(");
52-
  SerialUSB.println();
52+
		SerialUSB.print(duty);
53-
  SerialUSB.print("Overflows: ");
53+
		SerialUSB.print(")");
54-
  for(int i=0; i<16; i++){
54+
		if ((i+1)%9==0)	SerialUSB.print("\r");
55-
    SerialUSB.print(overflow[i]);
55+
		else SerialUSB.print("\t");
56-
    SerialUSB.print(" ");
56+
57-
  }
57+
	SerialUSB.println();
58-
  SerialUSB.println();
58+
59-
  SerialUSB.print("Each count worth approx (ns): ");
59+
60-
  for(int i=0; i<16; i++){
60+
61-
    SerialUSB.print( waitToNanos(overflow[i], results[i]) );
61+
62-
    SerialUSB.print(" ");
62+
63-
  }
63+
	dma_irq_cause cause = dma_get_irq_cause(DMA1, DMA_CH1);
64-
  SerialUSB.println();
64+
        //using serialusb to print messages here is nice, but
65
        //it takes so long, we may never exit this isr invocation
66-
double expectedTimePeriod(){
66+
67-
  //in nanos.. so 72mhz = 72000khz = 72000000hz  1/72000000hz = tick in seconds
67+
68-
  // 1/72000 = tick in ms, 1/72 = tick in us (1/72) * 1000 = tick in ns
68+
	timer4.setCount(0);  // clear counter
69-
  //tick in ns * prescale == time we're supposed to see
69+
	if(ppm_timeout) ppm_timeout=0;
70-
  return ((double)1.0 / ((double)72.0)) * (double)1000.0 * (double)PRESCALE;
70+
	if(!do_print) do_print=1;
71
	switch(cause)
72-
double waitToNanos( int overflows, int count ){
72+
73-
  //wait is in millis, *1000 for micros, *1000 for nanos
73+
74-
  double time = (((double)WAIT * (double)1000.0 * (double)1000.0) ) ;
74+
75-
  time = time / ((double)count + ((double)65535*(double)overflows));
75+
                        //SerialUSB.println("DMA Complete");
76-
  return time;
76+
                        dma_data_captured=1;
77
			break;
78
		case DMA_TRANSFER_HALF_COMPLETE:
79-
int readInt(char terminator){
79+
80-
  char current;
80+
                        SerialUSB.println("DMA Half Complete");
81-
  int output=0;
81+
82-
  while(SerialUSB.available() && (current=SerialUSB.read())!=terminator){
82+
83-
    if(current>='0' && current<='9'){
83+
84-
      output=output*10;
84+
85-
      output+=(current-'0');
85+
                        dma_data_captured=1;
86-
    }else{
86+
87-
      output=-1;
87+
88-
      break;
88+
89-
    }
89+
90-
  }
90+
91-
  return output;
91+
                        dma_data_captured=1;
92
			break;
93
	}
94-
HardwareTimer timer2 = HardwareTimer(2);
94+
95-
HardwareTimer timer1 = HardwareTimer(1);
95+
96-
void timingTest(){
96+
97-
      SerialUSB.println("Starting Timing test");
97+
void ppm_timeout_isr()
98-
      SerialUSB.print(" Prescale: ");
98+
99-
      SerialUSB.println(PRESCALE);
99+
	// This failure mode indicates we lost comm with
100-
      SerialUSB.print(" Wait Period (ms): ");
100+
	// the transmitter
101-
      SerialUSB.println(WAIT);
101+
102-
      SerialUSB.print(" Expected value for each tick :");
102+
	//TODO: re-initialize the timer and wait for ppm signal
103-
      SerialUSB.println(expectedTimePeriod());
103+
	//re-initializing should ensure that the ppm signal
104-
      timer1.pause();
104+
	// is captured on the sync pulse.
105-
      timer2.pause();
105+
	ppm_timeout=1;
106
	dma_data_captured=0;
107-
      timer2.setMode(TIMER_CH1, TIMER_OUTPUT_COMPARE);
107+
108-
      timer2.setPrescaleFactor(PRESCALE);
108+
109-
      timer2.setOverflow(65535);
109+
void init_timer_input_capture_dma()
110-
      timer2.setCompare(1,65535);
110+
111-
      timer2.setCount(0);
111+
112-
      timer2.refresh();
112+
    timer_dev *t = TIMER4;
113
114-
      timer1.setMode(TIMER_CH1, TIMER_OUTPUT_COMPARE);
114+
    timer4.pause();
115-
      timer1.setPrescaleFactor(PRESCALE);
115+
    timer4.setPrescaleFactor(TIMER_PRESCALE);
116-
      timer1.setOverflow(65535);
116+
    timer4.setOverflow(65535);
117-
      timer1.setCompare(1,65535);
117+
    timer4.setCount(0);
118-
      timer1.setCount(0);
118+
119-
      timer1.refresh();
119+
    // use channel 2 to detect when we stop receiving
120
    // a ppm signal from the encoder.
121-
      testHardwareTimer(timer1);
121+
    timer4.setMode(TIMER_CH2, TIMER_OUTPUT_COMPARE);
122-
      printResults();
122+
    timer4.setCompare(TIMER_CH2, 65535);
123
    timer4.attachCompare2Interrupt(ppm_timeout_isr);
124-
      testHardwareTimer(timer2);
124+
125-
      printResults();         
125+
126
    timer4.refresh();
127
128-
/******************************************************************************
128+
    timer_reg_map r = t->regs;
129-
 DMA from Timer Capture to array test..
129+
130-
 */
130+
    //using timer4, channel1, maps to pin d16 (maple mini) //d6 (maple?)
131
    //according to maple master pin map.
132-
//number of captures to do..
132+
    pinMode(PPM_PIN, INPUT);
133-
#define TIMERS 512 
133+
134-
volatile int exit=0;            //set to 1 when dma complete.
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-
  SerialUSB.print("DATA: ");
139+
    //if cap occurs while flag is already high CCxOF (overcapture) flag is set..
140-
  for(int i=0; i<TIMERS; i++){
140+
141-
    SerialUSB.print(data[i]);
141+
    //CCIX can be cleared by writing 0, or by reading the capped data from TIMx_CCRx
142-
    SerialUSB.print(" ");
142+
    //CCxOF is cleared by writing 0 to it.
143-
  }
143+
144-
  SerialUSB.println();
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-
	dma_irq_cause cause = dma_get_irq_cause(DMA1, DMA_CH2);
150+
    //Capture/Compare 1 Selection
151-
        //using serialusb to print messages here is nice, but 
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-
                        SerialUSB.println("DMA Complete");
158+
159-
                        exit=1;
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-
                        SerialUSB.println("DMA Half Complete");                  
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-
                        exit=1;
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-
                        exit=1;
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-
void loop(){
181+
    //set the CC1E bit to enable capture from the counter.
182-
  
182+
    //CC1E is bit 0 of CCER (page 401)
183-
  //simple main loop, listens for a char, and uses it as a command
183+
    bitSet(r.gen->CCER,0);
184-
  //to select what task to perform
184+
185-
  //
185+
    //enable dma for this timer..
186-
  // a   echo test
186+
    //sets the Capture/Compare 1 DMA request enable bit on the DMA/interrupt enable register.
187-
  // b   echo test
187+
    //bit 9 is CC1DE as defined on page 393.
188-
  // c   serialusb disable/enable test
188+
    bitSet(r.gen->DIER,9);
189-
  // d   time the timer test, default params
189+
190-
  // e   time the timer test, user supplied args
190+
    dma_init(DMA1);
191-
  // f   DMA timer capture of pulse widths from D6 straight to memory
191+
    dma_setup_transfer( DMA1,    //dma device, dma1 here because that's the only one we have
192-
  
192+
                        DMA_CH1, //dma channel, channel1, because it looks after tim4_ch1 (timer4, channel1)
193-
  while(!SerialUSB.available());
193+
                        &(r.gen->CCR1), //peripheral address
194-
  char cmd = SerialUSB.read();
194+
                        DMA_SIZE_16BITS, //peripheral size
195-
  switch(cmd)
195+
                        data, //memory address
196-
  {
196+
                        DMA_SIZE_16BITS, //memory transfer size
197-
  case 'a':
197+
                        (0
198-
    { 
198+
                         //| DMA_FROM_MEM  //set if going from memory, don't set if going to memory.
199-
      SerialUSB.println("Hello"); 
199+
                         | DMA_MINC_MODE //auto inc where the data does in memory (uses size_16bits to know how much)
200-
      break;
200+
                         | DMA_TRNS_ERR  //tell me if it's fubar
201-
    }
201+
                         //| DMA_HALF_TRNS //tell me half way (actually, don't as I spend so long there, I dont see 'complete')
202-
  case 'b':
202+
                         | DMA_TRNS_CMPLT //tell me at the end
203-
    {
203+
                         | DMA_CIRC_MODE // circular mode... capture "num_transfers" (below) and repeat
204-
      SerialUSB.println("There"); 
204+
                         )
205-
      break;
205+
                        );
206-
    }
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-
  case 'c':
208+
    dma_set_num_transfers(DMA1, DMA_CH1, TIMERS); //only allow it to transfer TIMERS number of times.
209-
    {
209+
    dma_enable(DMA1, DMA_CH1);                    //enable it..
210-
      SerialUSB.println("Going away for a while");
210+
211-
      SerialUSB.end();
211+
212-
      usbPowerOff();
212+
213-
      delay(5000);
213+
214-
      usbPowerOn();
214+
void ppm_decode_interrupt_dma()
215-
      SerialUSB.begin();
215+
216-
      delay(5000);
216+
217-
      while(!isConnected());
217+
	SerialUSB.print("Starting timer.. rising edge of D");
218-
      SerialUSB.println("Welcome back");
218+
    SerialUSB.print(PPM_PIN);
219-
      break;
219+
    disable_usarts();
220-
    }
220+
221-
  case 'd':
221+
	//start the timer counting.
222-
    {
222+
	timer4.resume();
223-
       WAIT=50;
223+
	//the timer is now counting up, and any rising edges on D16
224-
       PRESCALE=128;
224+
	//will trigger a DMA request to clone the timercapture to the array
225-
       timingTest();
225+
226-
       break;
226+
	//If we weren't using DMA, we could busy wait on the CC1IF bit in SR
227-
    }
227+
	//
228-
    case 'e':
228+
	//when the timer captures, the CC1IF bit will be set on the timer SR register.
229-
    {
229+
	//CC1IF bit is bit 1 (page 332)
230-
      int arg1=0;
230+
	//while(!bitRead(r.gen->SR, 1)){
231-
      int arg2=0;
231+
	//}
232-
      
232+
	//SerialUSB.println("Timer triggered : ");
233-
      if(!SerialUSB.available())
233+
	//SerialUSB.println(r.gen->CCR1);
234-
        goto usage;
234+
235-
      if(SerialUSB.read()!=' ')
235+
	//SerialUSB.println("Waiting for dma_data_captured flag from dma...");
236-
        goto usage;
236+
	//busy wait on the dma_data_captured flag
237-
        
237+
	//we could do real work here if wanted..
238-
      arg1 = readInt(' ');
238+
	while(!dma_data_captured && !SerialUSB.available());
239-
      arg2 = readInt(' ');
239+
240-
      
240+
	while(!SerialUSB.available() && do_print==1)
241-
      if(arg1==-1 || arg2==-1)
241+
242-
        goto usage;
242+
	  //dump the data
243-
      
243+
	  printData();
244-
      SerialUSB.print("Setting prescale to: ");
244+
	  delay(100);
245-
      SerialUSB.println(arg1);
245+
246-
      SerialUSB.print("Setting wait to: ");
246+
247-
      SerialUSB.println(arg2);
247+
	//turn off the timer & tidy up before we leave this cmd.
248-
      
248+
	timer4.pause();
249-
      WAIT=arg2;
249+
250-
      PRESCALE=arg1;
250+
	//      dma_disable(DMA1, DMA_CH2);
251-
      timingTest();
251+
	//      dma_detach_interrupt(DMA1, DMA_CH2);
252-
        
252+
	dma_data_captured=0;
253-
      goto done;
253+
254-
usage:
254+
}