PPM library based on teensy 3 PulsePostion library. uses k64f FTM0 PWM pins.
PPM library based on teensy 3 PulsePostion library. uses k64f FTM0 PWM pins.
https://www.pjrc.com/teensy/td_libs_PulsePosition.html
PulsePosition.cpp@1:cb791d277230, 2016-04-21 (annotated)
- Committer:
- manitou
- Date:
- Thu Apr 21 17:04:15 2016 +0000
- Revision:
- 1:cb791d277230
- Parent:
- 0:3b67d4bc53ca
fix alt selection for pin mux
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
manitou | 0:3b67d4bc53ca | 1 | /* PulsePosition Library for Teensy 3.1 |
manitou | 0:3b67d4bc53ca | 2 | * High resolution input and output of PPM encoded signals |
manitou | 0:3b67d4bc53ca | 3 | * http://www.pjrc.com/teensy/td_libs_PulsePosition.html |
manitou | 0:3b67d4bc53ca | 4 | * Copyright (c) 2014, Paul Stoffregen, paul@pjrc.com |
manitou | 0:3b67d4bc53ca | 5 | * |
manitou | 0:3b67d4bc53ca | 6 | * Development of this library was funded by PJRC.COM, LLC by sales of Teensy |
manitou | 0:3b67d4bc53ca | 7 | * boards. Please support PJRC's efforts to develop open source software by |
manitou | 0:3b67d4bc53ca | 8 | * purchasing Teensy or other PJRC products. |
manitou | 0:3b67d4bc53ca | 9 | * |
manitou | 0:3b67d4bc53ca | 10 | * Permission is hereby granted, free of charge, to any person obtaining a copy |
manitou | 0:3b67d4bc53ca | 11 | * of this software and associated documentation files (the "Software"), to deal |
manitou | 0:3b67d4bc53ca | 12 | * in the Software without restriction, including without limitation the rights |
manitou | 0:3b67d4bc53ca | 13 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
manitou | 0:3b67d4bc53ca | 14 | * copies of the Software, and to permit persons to whom the Software is |
manitou | 0:3b67d4bc53ca | 15 | * furnished to do so, subject to the following conditions: |
manitou | 0:3b67d4bc53ca | 16 | * |
manitou | 0:3b67d4bc53ca | 17 | * The above copyright notice, development funding notice, and this permission |
manitou | 0:3b67d4bc53ca | 18 | * notice shall be included in all copies or substantial portions of the Software. |
manitou | 0:3b67d4bc53ca | 19 | * |
manitou | 0:3b67d4bc53ca | 20 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
manitou | 0:3b67d4bc53ca | 21 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
manitou | 0:3b67d4bc53ca | 22 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
manitou | 0:3b67d4bc53ca | 23 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
manitou | 0:3b67d4bc53ca | 24 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
manitou | 0:3b67d4bc53ca | 25 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
manitou | 0:3b67d4bc53ca | 26 | * THE SOFTWARE. |
manitou | 0:3b67d4bc53ca | 27 | */ |
manitou | 0:3b67d4bc53ca | 28 | |
manitou | 0:3b67d4bc53ca | 29 | |
manitou | 0:3b67d4bc53ca | 30 | #include "mbed.h" |
manitou | 1:cb791d277230 | 31 | #include "PeripheralPins.h" |
manitou | 0:3b67d4bc53ca | 32 | #include "PulsePosition.h" |
manitou | 0:3b67d4bc53ca | 33 | |
manitou | 0:3b67d4bc53ca | 34 | #define F_BUS 60000000 |
manitou | 0:3b67d4bc53ca | 35 | // Timing parameters, in microseconds. |
manitou | 0:3b67d4bc53ca | 36 | |
manitou | 0:3b67d4bc53ca | 37 | |
manitou | 0:3b67d4bc53ca | 38 | // The shortest time allowed between any 2 rising edges. This should be at |
manitou | 0:3b67d4bc53ca | 39 | // least double TX_PULSE_WIDTH. |
manitou | 0:3b67d4bc53ca | 40 | #define TX_MINIMUM_SIGNAL 300.0 |
manitou | 0:3b67d4bc53ca | 41 | |
manitou | 0:3b67d4bc53ca | 42 | // The longest time allowed between any 2 rising edges for a normal signal. |
manitou | 0:3b67d4bc53ca | 43 | #define TX_MAXIMUM_SIGNAL 2500.0 |
manitou | 0:3b67d4bc53ca | 44 | |
manitou | 0:3b67d4bc53ca | 45 | // The default signal to send if nothing has been written. |
manitou | 0:3b67d4bc53ca | 46 | #define TX_DEFAULT_SIGNAL 1500.0 |
manitou | 0:3b67d4bc53ca | 47 | |
manitou | 0:3b67d4bc53ca | 48 | // When transmitting with a single pin, the minimum space signal that marks |
manitou | 0:3b67d4bc53ca | 49 | // the end of a frame. Single wire receivers recognize the end of a frame |
manitou | 0:3b67d4bc53ca | 50 | // by looking for a gap longer than the maximum data size. When viewing the |
manitou | 0:3b67d4bc53ca | 51 | // waveform on an oscilloscope, set the trigger "holdoff" time to slightly |
manitou | 0:3b67d4bc53ca | 52 | // less than TX_MINIMUM_SPACE, for the most reliable display. This parameter |
manitou | 0:3b67d4bc53ca | 53 | // is not used when transmitting with 2 pins. |
manitou | 0:3b67d4bc53ca | 54 | #define TX_MINIMUM_SPACE 5000.0 |
manitou | 0:3b67d4bc53ca | 55 | |
manitou | 0:3b67d4bc53ca | 56 | // The minimum total frame size. Some servo motors or other devices may not |
manitou | 0:3b67d4bc53ca | 57 | // work with pulses the repeat more often than 50 Hz. To allow transmission |
manitou | 0:3b67d4bc53ca | 58 | // as fast as possible, set this to the same as TX_MINIMUM_SIGNAL. |
manitou | 0:3b67d4bc53ca | 59 | #define TX_MINIMUM_FRAME 20000.0 |
manitou | 0:3b67d4bc53ca | 60 | |
manitou | 0:3b67d4bc53ca | 61 | // The length of all transmitted pulses. This must be longer than the worst |
manitou | 0:3b67d4bc53ca | 62 | // case interrupt latency, which depends on how long any other library may |
manitou | 0:3b67d4bc53ca | 63 | // disable interrupts. This must also be no more than half TX_MINIMUM_SIGNAL. |
manitou | 0:3b67d4bc53ca | 64 | // Most libraries disable interrupts for no more than a few microseconds. |
manitou | 0:3b67d4bc53ca | 65 | // The OneWire library is a notable exception, so this may need to be lengthened |
manitou | 0:3b67d4bc53ca | 66 | // if a library that imposes unusual interrupt latency is in use. |
manitou | 0:3b67d4bc53ca | 67 | #define TX_PULSE_WIDTH 100.0 |
manitou | 0:3b67d4bc53ca | 68 | |
manitou | 0:3b67d4bc53ca | 69 | // When receiving, any time between rising edges longer than this will be |
manitou | 0:3b67d4bc53ca | 70 | // treated as the end-of-frame marker. |
manitou | 0:3b67d4bc53ca | 71 | #define RX_MINIMUM_SPACE 3500.0 |
manitou | 0:3b67d4bc53ca | 72 | |
manitou | 0:3b67d4bc53ca | 73 | |
manitou | 0:3b67d4bc53ca | 74 | // convert from microseconds to I/O clock ticks |
manitou | 0:3b67d4bc53ca | 75 | |
manitou | 0:3b67d4bc53ca | 76 | #define CLOCKS_PER_MICROSECOND ((double)F_BUS / 1000000.0) |
manitou | 0:3b67d4bc53ca | 77 | |
manitou | 0:3b67d4bc53ca | 78 | #define TX_MINIMUM_SIGNAL_CLOCKS (uint32_t)(TX_MINIMUM_SIGNAL * CLOCKS_PER_MICROSECOND) |
manitou | 0:3b67d4bc53ca | 79 | #define TX_MAXIMUM_SIGNAL_CLOCKS (uint32_t)(TX_MAXIMUM_SIGNAL * CLOCKS_PER_MICROSECOND) |
manitou | 0:3b67d4bc53ca | 80 | #define TX_DEFAULT_SIGNAL_CLOCKS (uint32_t)(TX_DEFAULT_SIGNAL * CLOCKS_PER_MICROSECOND) |
manitou | 0:3b67d4bc53ca | 81 | #define TX_MINIMUM_SPACE_CLOCKS (uint32_t)(TX_MINIMUM_SPACE * CLOCKS_PER_MICROSECOND) |
manitou | 0:3b67d4bc53ca | 82 | #define TX_MINIMUM_FRAME_CLOCKS (uint32_t)(TX_MINIMUM_FRAME * CLOCKS_PER_MICROSECOND) |
manitou | 0:3b67d4bc53ca | 83 | #define TX_PULSE_WIDTH_CLOCKS (uint32_t)(TX_PULSE_WIDTH * CLOCKS_PER_MICROSECOND) |
manitou | 0:3b67d4bc53ca | 84 | #define RX_MINIMUM_SPACE_CLOCKS (uint32_t)(RX_MINIMUM_SPACE * CLOCKS_PER_MICROSECOND) |
manitou | 0:3b67d4bc53ca | 85 | |
manitou | 0:3b67d4bc53ca | 86 | |
manitou | 0:3b67d4bc53ca | 87 | #define FTM0_SC_VALUE (FTM_SC_TOIE_MASK | FTM_SC_CLKS(1) | FTM_SC_PS(0)) |
manitou | 0:3b67d4bc53ca | 88 | |
manitou | 0:3b67d4bc53ca | 89 | #define CSC_CHANGE(reg, val) ((reg)->csc = (val)) |
manitou | 0:3b67d4bc53ca | 90 | #define CSC_INTACK(reg, val) ((reg)->csc = (val)) |
manitou | 0:3b67d4bc53ca | 91 | #define CSC_CHANGE_INTACK(reg, val) ((reg)->csc = (val)) |
manitou | 0:3b67d4bc53ca | 92 | #define FRAME_PIN_SET() *framePinReg = 1 |
manitou | 0:3b67d4bc53ca | 93 | #define FRAME_PIN_CLEAR() *framePinReg = 0 |
manitou | 0:3b67d4bc53ca | 94 | |
manitou | 0:3b67d4bc53ca | 95 | |
manitou | 0:3b67d4bc53ca | 96 | uint8_t PulsePositionOutput::channelmask = 0; |
manitou | 0:3b67d4bc53ca | 97 | PulsePositionOutput * PulsePositionOutput::list[8]; |
manitou | 0:3b67d4bc53ca | 98 | |
manitou | 0:3b67d4bc53ca | 99 | PulsePositionOutput::PulsePositionOutput(void) |
manitou | 0:3b67d4bc53ca | 100 | { |
manitou | 0:3b67d4bc53ca | 101 | pulse_width[0] = TX_MINIMUM_FRAME_CLOCKS; |
manitou | 0:3b67d4bc53ca | 102 | for (int i=1; i <= PULSEPOSITION_MAXCHANNELS; i++) { |
manitou | 0:3b67d4bc53ca | 103 | pulse_width[i] = TX_DEFAULT_SIGNAL_CLOCKS; |
manitou | 0:3b67d4bc53ca | 104 | } |
manitou | 0:3b67d4bc53ca | 105 | cscSet = 0b01011100; |
manitou | 0:3b67d4bc53ca | 106 | cscClear = 0b01011000; |
manitou | 0:3b67d4bc53ca | 107 | } |
manitou | 0:3b67d4bc53ca | 108 | |
manitou | 0:3b67d4bc53ca | 109 | PulsePositionOutput::PulsePositionOutput(int polarity) |
manitou | 0:3b67d4bc53ca | 110 | { |
manitou | 0:3b67d4bc53ca | 111 | pulse_width[0] = TX_MINIMUM_FRAME_CLOCKS; |
manitou | 0:3b67d4bc53ca | 112 | for (int i=1; i <= PULSEPOSITION_MAXCHANNELS; i++) { |
manitou | 0:3b67d4bc53ca | 113 | pulse_width[i] = TX_DEFAULT_SIGNAL_CLOCKS; |
manitou | 0:3b67d4bc53ca | 114 | } |
manitou | 0:3b67d4bc53ca | 115 | if (polarity == FALLING) { |
manitou | 0:3b67d4bc53ca | 116 | cscSet = 0b01011000; |
manitou | 0:3b67d4bc53ca | 117 | cscClear = 0b01011100; |
manitou | 0:3b67d4bc53ca | 118 | } else { |
manitou | 0:3b67d4bc53ca | 119 | cscSet = 0b01011100; |
manitou | 0:3b67d4bc53ca | 120 | cscClear = 0b01011000; |
manitou | 0:3b67d4bc53ca | 121 | } |
manitou | 0:3b67d4bc53ca | 122 | } |
manitou | 0:3b67d4bc53ca | 123 | |
manitou | 0:3b67d4bc53ca | 124 | bool PulsePositionOutput::begin(PinName txPin) |
manitou | 0:3b67d4bc53ca | 125 | { |
manitou | 0:3b67d4bc53ca | 126 | return begin(txPin, (PinName)255); // thd ? |
manitou | 0:3b67d4bc53ca | 127 | } |
manitou | 0:3b67d4bc53ca | 128 | |
manitou | 0:3b67d4bc53ca | 129 | bool PulsePositionOutput::begin(PinName txPin, PinName framePin) |
manitou | 0:3b67d4bc53ca | 130 | { |
manitou | 0:3b67d4bc53ca | 131 | uint32_t channel; |
manitou | 0:3b67d4bc53ca | 132 | volatile void *reg; |
manitou | 0:3b67d4bc53ca | 133 | |
manitou | 0:3b67d4bc53ca | 134 | SIM_SCGC6 |= (1 << SIM_SCGC6_FTM0_SHIFT); // enable FMT0 |
manitou | 0:3b67d4bc53ca | 135 | if (FTM0_MOD != 0xFFFF || (FTM0_SC & 0x7F) != FTM0_SC_VALUE) { |
manitou | 0:3b67d4bc53ca | 136 | FTM0_SC = 0; |
manitou | 0:3b67d4bc53ca | 137 | FTM0_CNT = 0; |
manitou | 0:3b67d4bc53ca | 138 | FTM0_MOD = 0xFFFF; |
manitou | 0:3b67d4bc53ca | 139 | FTM0_SC = FTM0_SC_VALUE; |
manitou | 0:3b67d4bc53ca | 140 | FTM0_MODE = 0; |
manitou | 0:3b67d4bc53ca | 141 | } |
manitou | 0:3b67d4bc53ca | 142 | |
manitou | 0:3b67d4bc53ca | 143 | switch (txPin) { |
manitou | 0:3b67d4bc53ca | 144 | case PTC3: channel = 2; reg = &FTM0_C2SC; break; |
manitou | 0:3b67d4bc53ca | 145 | case PTC4: channel = 3; reg = &FTM0_C3SC; break; |
manitou | 0:3b67d4bc53ca | 146 | case PTA0: channel = 5; reg = &FTM0_C5SC; break; |
manitou | 0:3b67d4bc53ca | 147 | case PTC2: channel = 1; reg = &FTM0_C1SC; break; |
manitou | 0:3b67d4bc53ca | 148 | case PTA1: channel = 6; reg = &FTM0_C6SC; break; |
manitou | 0:3b67d4bc53ca | 149 | case PTA2: channel = 7; reg = &FTM0_C7SC; break; |
manitou | 0:3b67d4bc53ca | 150 | default: |
manitou | 0:3b67d4bc53ca | 151 | return false; |
manitou | 0:3b67d4bc53ca | 152 | } |
manitou | 0:3b67d4bc53ca | 153 | if (framePin != (PinName)255) framePinReg = new DigitalOut(framePin); |
manitou | 0:3b67d4bc53ca | 154 | else framePinReg = NULL; |
manitou | 0:3b67d4bc53ca | 155 | state = 0; |
manitou | 0:3b67d4bc53ca | 156 | current_channel = 0; |
manitou | 0:3b67d4bc53ca | 157 | total_channels = 0; |
manitou | 0:3b67d4bc53ca | 158 | ftm = (struct ftm_channel_struct *)reg; |
manitou | 0:3b67d4bc53ca | 159 | ftm->cv = 200; |
manitou | 0:3b67d4bc53ca | 160 | CSC_CHANGE(ftm, cscSet); // set on compare match & interrupt |
manitou | 0:3b67d4bc53ca | 161 | list[channel] = this; |
manitou | 0:3b67d4bc53ca | 162 | channelmask |= (1<<channel); |
manitou | 0:3b67d4bc53ca | 163 | SIM_SCGC5 |= (1 << SIM_SCGC5_PORTC_SHIFT); // power PORTC |
manitou | 0:3b67d4bc53ca | 164 | uint32_t port = txPin >> GPIO_PORT_SHIFT; |
manitou | 0:3b67d4bc53ca | 165 | uint32_t pin = (txPin & 0x1F) ; |
manitou | 1:cb791d277230 | 166 | uint32_t alt= pinmap_function(txPin, PinMap_PWM); |
manitou | 0:3b67d4bc53ca | 167 | ((PORT_Type *)(PORTA_BASE + 0x1000 * port))->PCR[pin] = PORT_PCR_MUX(alt) | PORT_PCR_DSE_MASK | PORT_PCR_SRE_MASK; |
manitou | 0:3b67d4bc53ca | 168 | NVIC_SetPriority(FTM0_IRQn, 32); |
manitou | 0:3b67d4bc53ca | 169 | NVIC_EnableIRQ(FTM0_IRQn); |
manitou | 0:3b67d4bc53ca | 170 | return true; |
manitou | 0:3b67d4bc53ca | 171 | } |
manitou | 0:3b67d4bc53ca | 172 | |
manitou | 0:3b67d4bc53ca | 173 | bool PulsePositionOutput::write(uint8_t channel, float microseconds) |
manitou | 0:3b67d4bc53ca | 174 | { |
manitou | 0:3b67d4bc53ca | 175 | uint32_t i, sum, space, clocks, num_channels; |
manitou | 0:3b67d4bc53ca | 176 | |
manitou | 0:3b67d4bc53ca | 177 | if (channel < 1 || channel > PULSEPOSITION_MAXCHANNELS) return false; |
manitou | 0:3b67d4bc53ca | 178 | if (microseconds < TX_MINIMUM_SIGNAL || microseconds > TX_MAXIMUM_SIGNAL) return false; |
manitou | 0:3b67d4bc53ca | 179 | clocks = microseconds * CLOCKS_PER_MICROSECOND; |
manitou | 0:3b67d4bc53ca | 180 | num_channels = total_channels; |
manitou | 0:3b67d4bc53ca | 181 | if (channel > num_channels) num_channels = channel; |
manitou | 0:3b67d4bc53ca | 182 | sum = clocks; |
manitou | 0:3b67d4bc53ca | 183 | for (i=1; i < channel; i++) sum += pulse_width[i]; |
manitou | 0:3b67d4bc53ca | 184 | for (i=channel+1; i <= num_channels; i++) sum += pulse_width[i]; |
manitou | 0:3b67d4bc53ca | 185 | if (sum < TX_MINIMUM_FRAME_CLOCKS - TX_MINIMUM_SPACE_CLOCKS) { |
manitou | 0:3b67d4bc53ca | 186 | space = TX_MINIMUM_FRAME_CLOCKS - sum; |
manitou | 0:3b67d4bc53ca | 187 | } else { |
manitou | 0:3b67d4bc53ca | 188 | if (framePinReg) { |
manitou | 0:3b67d4bc53ca | 189 | space = TX_PULSE_WIDTH_CLOCKS; |
manitou | 0:3b67d4bc53ca | 190 | } else { |
manitou | 0:3b67d4bc53ca | 191 | space = TX_MINIMUM_SPACE_CLOCKS; |
manitou | 0:3b67d4bc53ca | 192 | } |
manitou | 0:3b67d4bc53ca | 193 | } |
manitou | 0:3b67d4bc53ca | 194 | __disable_irq(); |
manitou | 0:3b67d4bc53ca | 195 | pulse_width[0] = space; |
manitou | 0:3b67d4bc53ca | 196 | pulse_width[channel] = clocks; |
manitou | 0:3b67d4bc53ca | 197 | total_channels = num_channels; |
manitou | 0:3b67d4bc53ca | 198 | __enable_irq(); |
manitou | 0:3b67d4bc53ca | 199 | return true; |
manitou | 0:3b67d4bc53ca | 200 | } |
manitou | 0:3b67d4bc53ca | 201 | |
manitou | 0:3b67d4bc53ca | 202 | void PulsePositionOutput::isr(void) |
manitou | 0:3b67d4bc53ca | 203 | { |
manitou | 0:3b67d4bc53ca | 204 | // printf("out isr %d %d\n",state,ftm->cv); |
manitou | 0:3b67d4bc53ca | 205 | FTM0_MODE = 0; |
manitou | 0:3b67d4bc53ca | 206 | if (state == 0) { |
manitou | 0:3b67d4bc53ca | 207 | // pin was just set high, schedule it to go low |
manitou | 0:3b67d4bc53ca | 208 | ftm->cv += TX_PULSE_WIDTH_CLOCKS; |
manitou | 0:3b67d4bc53ca | 209 | CSC_CHANGE_INTACK(ftm, cscClear); // clear on compare match & interrupt |
manitou | 0:3b67d4bc53ca | 210 | state = 1; |
manitou | 0:3b67d4bc53ca | 211 | } else { |
manitou | 0:3b67d4bc53ca | 212 | // pin just went low |
manitou | 0:3b67d4bc53ca | 213 | uint32_t width, channel; |
manitou | 0:3b67d4bc53ca | 214 | if (state == 1) { |
manitou | 0:3b67d4bc53ca | 215 | channel = current_channel; |
manitou | 0:3b67d4bc53ca | 216 | if (channel == 0) { |
manitou | 0:3b67d4bc53ca | 217 | total_channels_buffer = total_channels; |
manitou | 0:3b67d4bc53ca | 218 | for (uint32_t i=0; i <= total_channels_buffer; i++) { |
manitou | 0:3b67d4bc53ca | 219 | pulse_buffer[i] = pulse_width[i]; |
manitou | 0:3b67d4bc53ca | 220 | } |
manitou | 0:3b67d4bc53ca | 221 | } |
manitou | 0:3b67d4bc53ca | 222 | width = pulse_buffer[channel] - TX_PULSE_WIDTH_CLOCKS; |
manitou | 0:3b67d4bc53ca | 223 | if (++channel > total_channels_buffer) { |
manitou | 0:3b67d4bc53ca | 224 | channel = 0; |
manitou | 0:3b67d4bc53ca | 225 | } |
manitou | 0:3b67d4bc53ca | 226 | if (framePinReg) { |
manitou | 0:3b67d4bc53ca | 227 | //if (channel == 0) { |
manitou | 0:3b67d4bc53ca | 228 | if (channel == 1) { |
manitou | 0:3b67d4bc53ca | 229 | FRAME_PIN_SET(); |
manitou | 0:3b67d4bc53ca | 230 | } else { |
manitou | 0:3b67d4bc53ca | 231 | FRAME_PIN_CLEAR(); |
manitou | 0:3b67d4bc53ca | 232 | } |
manitou | 0:3b67d4bc53ca | 233 | } |
manitou | 0:3b67d4bc53ca | 234 | current_channel = channel; |
manitou | 0:3b67d4bc53ca | 235 | } else { |
manitou | 0:3b67d4bc53ca | 236 | width = pulse_remaining; |
manitou | 0:3b67d4bc53ca | 237 | } |
manitou | 0:3b67d4bc53ca | 238 | if (width <= 60000) { |
manitou | 0:3b67d4bc53ca | 239 | ftm->cv += width; |
manitou | 0:3b67d4bc53ca | 240 | CSC_CHANGE_INTACK(ftm, cscSet); // set on compare match & interrupt |
manitou | 0:3b67d4bc53ca | 241 | state = 0; |
manitou | 0:3b67d4bc53ca | 242 | } else { |
manitou | 0:3b67d4bc53ca | 243 | ftm->cv += 58000; |
manitou | 0:3b67d4bc53ca | 244 | CSC_INTACK(ftm, cscClear); // clear on compare match & interrupt |
manitou | 0:3b67d4bc53ca | 245 | pulse_remaining = width - 58000; |
manitou | 0:3b67d4bc53ca | 246 | state = 2; |
manitou | 0:3b67d4bc53ca | 247 | } |
manitou | 0:3b67d4bc53ca | 248 | } |
manitou | 0:3b67d4bc53ca | 249 | } |
manitou | 0:3b67d4bc53ca | 250 | |
manitou | 0:3b67d4bc53ca | 251 | |
manitou | 0:3b67d4bc53ca | 252 | |
manitou | 0:3b67d4bc53ca | 253 | void ftm0_isr(void) { |
manitou | 0:3b67d4bc53ca | 254 | if (FTM0_SC & 0x80) { |
manitou | 0:3b67d4bc53ca | 255 | FTM0_SC = FTM0_SC_VALUE; |
manitou | 0:3b67d4bc53ca | 256 | PulsePositionInput::overflow_count++; |
manitou | 0:3b67d4bc53ca | 257 | PulsePositionInput::overflow_inc = true; |
manitou | 0:3b67d4bc53ca | 258 | } |
manitou | 0:3b67d4bc53ca | 259 | // TODO: this could be efficient by reading FTM0_STATUS |
manitou | 0:3b67d4bc53ca | 260 | uint8_t maskin = PulsePositionInput::channelmask; |
manitou | 0:3b67d4bc53ca | 261 | if ((maskin & 0x01) && (FTM0_C0SC & 0x80)) PulsePositionInput::list[0]->isr(); |
manitou | 0:3b67d4bc53ca | 262 | if ((maskin & 0x02) && (FTM0_C1SC & 0x80)) PulsePositionInput::list[1]->isr(); |
manitou | 0:3b67d4bc53ca | 263 | if ((maskin & 0x04) && (FTM0_C2SC & 0x80)) PulsePositionInput::list[2]->isr(); |
manitou | 0:3b67d4bc53ca | 264 | if ((maskin & 0x08) && (FTM0_C3SC & 0x80)) PulsePositionInput::list[3]->isr(); |
manitou | 0:3b67d4bc53ca | 265 | if ((maskin & 0x10) && (FTM0_C4SC & 0x80)) PulsePositionInput::list[4]->isr(); |
manitou | 0:3b67d4bc53ca | 266 | if ((maskin & 0x20) && (FTM0_C5SC & 0x80)) PulsePositionInput::list[5]->isr(); |
manitou | 0:3b67d4bc53ca | 267 | if ((maskin & 0x40) && (FTM0_C6SC & 0x80)) PulsePositionInput::list[6]->isr(); |
manitou | 0:3b67d4bc53ca | 268 | if ((maskin & 0x80) && (FTM0_C7SC & 0x80)) PulsePositionInput::list[7]->isr(); |
manitou | 0:3b67d4bc53ca | 269 | |
manitou | 0:3b67d4bc53ca | 270 | uint8_t maskout = PulsePositionOutput::channelmask; |
manitou | 0:3b67d4bc53ca | 271 | if ((maskout & 0x01) && (FTM0_C0SC & 0x80)) PulsePositionOutput::list[0]->isr(); |
manitou | 0:3b67d4bc53ca | 272 | if ((maskout & 0x02) && (FTM0_C1SC & 0x80)) PulsePositionOutput::list[1]->isr(); |
manitou | 0:3b67d4bc53ca | 273 | if ((maskout & 0x04) && (FTM0_C2SC & 0x80)) PulsePositionOutput::list[2]->isr(); |
manitou | 0:3b67d4bc53ca | 274 | if ((maskout & 0x08) && (FTM0_C3SC & 0x80)) PulsePositionOutput::list[3]->isr(); |
manitou | 0:3b67d4bc53ca | 275 | if ((maskout & 0x10) && (FTM0_C4SC & 0x80)) PulsePositionOutput::list[4]->isr(); |
manitou | 0:3b67d4bc53ca | 276 | if ((maskout & 0x20) && (FTM0_C5SC & 0x80)) PulsePositionOutput::list[5]->isr(); |
manitou | 0:3b67d4bc53ca | 277 | if ((maskout & 0x40) && (FTM0_C6SC & 0x80)) PulsePositionOutput::list[6]->isr(); |
manitou | 0:3b67d4bc53ca | 278 | if ((maskout & 0x80) && (FTM0_C7SC & 0x80)) PulsePositionOutput::list[7]->isr(); |
manitou | 0:3b67d4bc53ca | 279 | PulsePositionInput::overflow_inc = false; |
manitou | 0:3b67d4bc53ca | 280 | |
manitou | 0:3b67d4bc53ca | 281 | } |
manitou | 0:3b67d4bc53ca | 282 | uint32_t ticks; |
manitou | 0:3b67d4bc53ca | 283 | extern "C" void FTM0_IRQHandler() { |
manitou | 0:3b67d4bc53ca | 284 | ticks++; |
manitou | 0:3b67d4bc53ca | 285 | ftm0_isr(); |
manitou | 0:3b67d4bc53ca | 286 | } |
manitou | 0:3b67d4bc53ca | 287 | // some explanation regarding this C to C++ trickery can be found here: |
manitou | 0:3b67d4bc53ca | 288 | // http://forum.pjrc.com/threads/25278-Low-Power-with-Event-based-software-architecture-brainstorm?p=43496&viewfull=1#post43496 |
manitou | 0:3b67d4bc53ca | 289 | |
manitou | 0:3b67d4bc53ca | 290 | uint16_t PulsePositionInput::overflow_count = 0; |
manitou | 0:3b67d4bc53ca | 291 | bool PulsePositionInput::overflow_inc = false; |
manitou | 0:3b67d4bc53ca | 292 | uint8_t PulsePositionInput::channelmask = 0; |
manitou | 0:3b67d4bc53ca | 293 | PulsePositionInput * PulsePositionInput::list[8]; |
manitou | 0:3b67d4bc53ca | 294 | |
manitou | 0:3b67d4bc53ca | 295 | PulsePositionInput::PulsePositionInput(void) |
manitou | 0:3b67d4bc53ca | 296 | { |
manitou | 0:3b67d4bc53ca | 297 | cscEdge = 0b01000100; |
manitou | 0:3b67d4bc53ca | 298 | } |
manitou | 0:3b67d4bc53ca | 299 | |
manitou | 0:3b67d4bc53ca | 300 | PulsePositionInput::PulsePositionInput(int polarity) |
manitou | 0:3b67d4bc53ca | 301 | { |
manitou | 0:3b67d4bc53ca | 302 | cscEdge = (polarity == FALLING) ? 0b01001000 : 0b01000100; |
manitou | 0:3b67d4bc53ca | 303 | } |
manitou | 0:3b67d4bc53ca | 304 | |
manitou | 0:3b67d4bc53ca | 305 | |
manitou | 0:3b67d4bc53ca | 306 | bool PulsePositionInput::begin(PinName pin) |
manitou | 0:3b67d4bc53ca | 307 | { |
manitou | 0:3b67d4bc53ca | 308 | uint32_t channel; |
manitou | 0:3b67d4bc53ca | 309 | volatile void *reg; |
manitou | 0:3b67d4bc53ca | 310 | |
manitou | 0:3b67d4bc53ca | 311 | SIM_SCGC6 |= (1 << SIM_SCGC6_FTM0_SHIFT); // enable FTM0 |
manitou | 0:3b67d4bc53ca | 312 | if (FTM0_MOD != 0xFFFF || (FTM0_SC & 0x7F) != FTM0_SC_VALUE) { |
manitou | 0:3b67d4bc53ca | 313 | FTM0_SC = 0; |
manitou | 0:3b67d4bc53ca | 314 | FTM0_CNT = 0; |
manitou | 0:3b67d4bc53ca | 315 | FTM0_MOD = 0xFFFF; |
manitou | 0:3b67d4bc53ca | 316 | FTM0_SC = FTM0_SC_VALUE; |
manitou | 0:3b67d4bc53ca | 317 | FTM0_MODE = 0; |
manitou | 0:3b67d4bc53ca | 318 | } |
manitou | 0:3b67d4bc53ca | 319 | switch (pin) { |
manitou | 0:3b67d4bc53ca | 320 | case PTC3: channel = 2; reg = &FTM0_C2SC; break; |
manitou | 0:3b67d4bc53ca | 321 | case PTC4: channel = 3; reg = &FTM0_C3SC; break; |
manitou | 0:3b67d4bc53ca | 322 | case PTA0: channel = 5; reg = &FTM0_C5SC; break; |
manitou | 0:3b67d4bc53ca | 323 | case PTC2: channel = 1; reg = &FTM0_C1SC; break; |
manitou | 0:3b67d4bc53ca | 324 | case PTA1: channel = 6; reg = &FTM0_C6SC; break; |
manitou | 0:3b67d4bc53ca | 325 | case PTA2: channel = 7; reg = &FTM0_C7SC; break; |
manitou | 0:3b67d4bc53ca | 326 | default: |
manitou | 0:3b67d4bc53ca | 327 | return false; |
manitou | 0:3b67d4bc53ca | 328 | } |
manitou | 0:3b67d4bc53ca | 329 | prev = 0; |
manitou | 0:3b67d4bc53ca | 330 | write_index = 255; |
manitou | 0:3b67d4bc53ca | 331 | available_flag = false; |
manitou | 0:3b67d4bc53ca | 332 | ftm = (struct ftm_channel_struct *)reg; |
manitou | 0:3b67d4bc53ca | 333 | list[channel] = this; |
manitou | 0:3b67d4bc53ca | 334 | channelmask |= (1<<channel); |
manitou | 0:3b67d4bc53ca | 335 | SIM_SCGC5 |= (1 << SIM_SCGC5_PORTC_SHIFT); // power PORTC |
manitou | 0:3b67d4bc53ca | 336 | uint32_t port = pin >> GPIO_PORT_SHIFT; |
manitou | 0:3b67d4bc53ca | 337 | uint32_t ppin = (pin & 0x1F) ; |
manitou | 1:cb791d277230 | 338 | uint32_t alt= pinmap_function(pin, PinMap_PWM); |
manitou | 0:3b67d4bc53ca | 339 | ((PORT_Type *)(PORTA_BASE + 0x1000 * port))->PCR[ppin] = PORT_PCR_MUX(alt); |
manitou | 0:3b67d4bc53ca | 340 | CSC_CHANGE(ftm, cscEdge); // input capture & interrupt on rising edge |
manitou | 0:3b67d4bc53ca | 341 | NVIC_SetPriority(FTM0_IRQn, 32); |
manitou | 0:3b67d4bc53ca | 342 | NVIC_EnableIRQ(FTM0_IRQn); |
manitou | 0:3b67d4bc53ca | 343 | return true; |
manitou | 0:3b67d4bc53ca | 344 | } |
manitou | 0:3b67d4bc53ca | 345 | |
manitou | 0:3b67d4bc53ca | 346 | void PulsePositionInput::isr(void) |
manitou | 0:3b67d4bc53ca | 347 | { |
manitou | 0:3b67d4bc53ca | 348 | uint32_t val, count; |
manitou | 0:3b67d4bc53ca | 349 | |
manitou | 0:3b67d4bc53ca | 350 | val = ftm->cv; |
manitou | 0:3b67d4bc53ca | 351 | CSC_INTACK(ftm, cscEdge); // input capture & interrupt on rising edge |
manitou | 0:3b67d4bc53ca | 352 | count = overflow_count; |
manitou | 0:3b67d4bc53ca | 353 | if (val > 0xE000 && overflow_inc) count--; |
manitou | 0:3b67d4bc53ca | 354 | val |= (count << 16); |
manitou | 0:3b67d4bc53ca | 355 | count = val - prev; |
manitou | 0:3b67d4bc53ca | 356 | prev = val; |
manitou | 0:3b67d4bc53ca | 357 | //Serial.print(val, HEX); |
manitou | 0:3b67d4bc53ca | 358 | //Serial.print(" "); |
manitou | 0:3b67d4bc53ca | 359 | //Serial.println(count); |
manitou | 0:3b67d4bc53ca | 360 | if (count >= RX_MINIMUM_SPACE_CLOCKS) { |
manitou | 0:3b67d4bc53ca | 361 | if (write_index < 255) { |
manitou | 0:3b67d4bc53ca | 362 | for (int i=0; i < write_index; i++) { |
manitou | 0:3b67d4bc53ca | 363 | pulse_buffer[i] = pulse_width[i]; |
manitou | 0:3b67d4bc53ca | 364 | } |
manitou | 0:3b67d4bc53ca | 365 | total_channels = write_index; |
manitou | 0:3b67d4bc53ca | 366 | available_flag = true; |
manitou | 0:3b67d4bc53ca | 367 | } |
manitou | 0:3b67d4bc53ca | 368 | write_index = 0; |
manitou | 0:3b67d4bc53ca | 369 | } else { |
manitou | 0:3b67d4bc53ca | 370 | if (write_index < PULSEPOSITION_MAXCHANNELS) { |
manitou | 0:3b67d4bc53ca | 371 | pulse_width[write_index++] = count; |
manitou | 0:3b67d4bc53ca | 372 | } |
manitou | 0:3b67d4bc53ca | 373 | } |
manitou | 0:3b67d4bc53ca | 374 | } |
manitou | 0:3b67d4bc53ca | 375 | |
manitou | 0:3b67d4bc53ca | 376 | int PulsePositionInput::available(void) |
manitou | 0:3b67d4bc53ca | 377 | { |
manitou | 0:3b67d4bc53ca | 378 | uint32_t total; |
manitou | 0:3b67d4bc53ca | 379 | bool flag; |
manitou | 0:3b67d4bc53ca | 380 | |
manitou | 0:3b67d4bc53ca | 381 | __disable_irq(); |
manitou | 0:3b67d4bc53ca | 382 | flag = available_flag; |
manitou | 0:3b67d4bc53ca | 383 | total = total_channels; |
manitou | 0:3b67d4bc53ca | 384 | __enable_irq(); |
manitou | 0:3b67d4bc53ca | 385 | if (flag) return total; |
manitou | 0:3b67d4bc53ca | 386 | return -1; |
manitou | 0:3b67d4bc53ca | 387 | } |
manitou | 0:3b67d4bc53ca | 388 | |
manitou | 0:3b67d4bc53ca | 389 | float PulsePositionInput::read(uint8_t channel) |
manitou | 0:3b67d4bc53ca | 390 | { |
manitou | 0:3b67d4bc53ca | 391 | uint32_t total, index, value=0; |
manitou | 0:3b67d4bc53ca | 392 | |
manitou | 0:3b67d4bc53ca | 393 | if (channel == 0) return 0.0; |
manitou | 0:3b67d4bc53ca | 394 | index = channel - 1; |
manitou | 0:3b67d4bc53ca | 395 | __disable_irq(); |
manitou | 0:3b67d4bc53ca | 396 | total = total_channels; |
manitou | 0:3b67d4bc53ca | 397 | if (index < total) value = pulse_buffer[index]; |
manitou | 0:3b67d4bc53ca | 398 | if (channel >= total) available_flag = false; |
manitou | 0:3b67d4bc53ca | 399 | __enable_irq(); |
manitou | 0:3b67d4bc53ca | 400 | return (float)value / (float)CLOCKS_PER_MICROSECOND; |
manitou | 0:3b67d4bc53ca | 401 | } |