PPM library based on teensy 3 PulsePostion library. uses k64f FTM0 PWM pins.

Dependents:   k64f_ppmtst

PPM library based on teensy 3 PulsePostion library. uses k64f FTM0 PWM pins.

https://www.pjrc.com/teensy/td_libs_PulsePosition.html

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?

UserRevisionLine numberNew 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 }