Test code for Grove Node BLE

Dependencies:   BLE_API nRF51822

Fork of BLE_LoopbackUART by Bluetooth Low Energy

Committer:
yihui
Date:
Thu Nov 27 09:30:36 2014 +0000
Revision:
10:22480ac31879
Parent:
9:05f0b5a3a70a
change to new revision hardware

Who changed what in which revision?

UserRevisionLine numberNew contents of line
yihui 9:05f0b5a3a70a 1 /* mbed Microcontroller Library
yihui 9:05f0b5a3a70a 2 * Copyright (c) 2013 Nordic Semiconductor
yihui 9:05f0b5a3a70a 3 *
yihui 9:05f0b5a3a70a 4 * Licensed under the Apache License, Version 2.0 (the "License");
yihui 9:05f0b5a3a70a 5 * you may not use this file except in compliance with the License.
yihui 9:05f0b5a3a70a 6 * You may obtain a copy of the License at
yihui 9:05f0b5a3a70a 7 *
yihui 9:05f0b5a3a70a 8 * http://www.apache.org/licenses/LICENSE-2.0
yihui 9:05f0b5a3a70a 9 *
yihui 9:05f0b5a3a70a 10 * Unless required by applicable law or agreed to in writing, software
yihui 9:05f0b5a3a70a 11 * distributed under the License is distributed on an "AS IS" BASIS,
yihui 9:05f0b5a3a70a 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
yihui 9:05f0b5a3a70a 13 * See the License for the specific language governing permissions and
yihui 9:05f0b5a3a70a 14 * limitations under the License.
yihui 9:05f0b5a3a70a 15 */
yihui 9:05f0b5a3a70a 16 #include "mbed_assert.h"
yihui 9:05f0b5a3a70a 17 #include "pwmout_api.h"
yihui 9:05f0b5a3a70a 18 #include "cmsis.h"
yihui 9:05f0b5a3a70a 19 #include "pinmap.h"
yihui 9:05f0b5a3a70a 20 #include "mbed_error.h"
yihui 9:05f0b5a3a70a 21
yihui 9:05f0b5a3a70a 22 #define NO_PWMS 3
yihui 9:05f0b5a3a70a 23 #define TIMER_PRECISION 4 //4us ticks
yihui 9:05f0b5a3a70a 24 #define TIMER_PRESCALER 6 //4us ticks = 16Mhz/(2**6)
yihui 9:05f0b5a3a70a 25 static const PinMap PinMap_PWM[] = {
yihui 9:05f0b5a3a70a 26 {p0, PWM_1, 1},
yihui 9:05f0b5a3a70a 27 {p1, PWM_1, 1},
yihui 9:05f0b5a3a70a 28 {p2, PWM_1, 1},
yihui 9:05f0b5a3a70a 29 {p3, PWM_1, 1},
yihui 9:05f0b5a3a70a 30 {p4, PWM_1, 1},
yihui 9:05f0b5a3a70a 31 {p5, PWM_1, 1},
yihui 9:05f0b5a3a70a 32 {p6, PWM_1, 1},
yihui 9:05f0b5a3a70a 33 {p7, PWM_1, 1},
yihui 9:05f0b5a3a70a 34 {p8, PWM_1, 1},
yihui 9:05f0b5a3a70a 35 {p9, PWM_1, 1},
yihui 9:05f0b5a3a70a 36 {p10, PWM_1, 1},
yihui 9:05f0b5a3a70a 37 {p11, PWM_1, 1},
yihui 9:05f0b5a3a70a 38 {p12, PWM_1, 1},
yihui 9:05f0b5a3a70a 39 {p13, PWM_1, 1},
yihui 9:05f0b5a3a70a 40 {p14, PWM_1, 1},
yihui 9:05f0b5a3a70a 41 {p15, PWM_1, 1},
yihui 9:05f0b5a3a70a 42 {p16, PWM_1, 1},
yihui 9:05f0b5a3a70a 43 {p17, PWM_1, 1},
yihui 9:05f0b5a3a70a 44 {p18, PWM_1, 1},
yihui 9:05f0b5a3a70a 45 {p19, PWM_1, 1},
yihui 9:05f0b5a3a70a 46 {p20, PWM_1, 1},
yihui 9:05f0b5a3a70a 47 {p21, PWM_1, 1},
yihui 9:05f0b5a3a70a 48 {p22, PWM_1, 1},
yihui 9:05f0b5a3a70a 49 {p23, PWM_1, 1},
yihui 9:05f0b5a3a70a 50 {p24, PWM_1, 1},
yihui 9:05f0b5a3a70a 51 {p25, PWM_1, 1},
yihui 9:05f0b5a3a70a 52 {p28, PWM_1, 1},
yihui 9:05f0b5a3a70a 53 {p29, PWM_1, 1},
yihui 9:05f0b5a3a70a 54 {p30, PWM_1, 1},
yihui 9:05f0b5a3a70a 55 {NC, NC, 0}
yihui 9:05f0b5a3a70a 56 };
yihui 9:05f0b5a3a70a 57
yihui 9:05f0b5a3a70a 58 static NRF_TIMER_Type *Timers[1] = {
yihui 9:05f0b5a3a70a 59 NRF_TIMER2
yihui 9:05f0b5a3a70a 60 };
yihui 9:05f0b5a3a70a 61
yihui 9:05f0b5a3a70a 62 uint16_t PERIOD = 20000 / TIMER_PRECISION; //20ms
yihui 9:05f0b5a3a70a 63 uint8_t PWM_taken[NO_PWMS] = {0, 0, 0};
yihui 9:05f0b5a3a70a 64 uint16_t PULSE_WIDTH[NO_PWMS] = {1, 1, 1}; //set to 1 instead of 0
yihui 9:05f0b5a3a70a 65 uint16_t ACTUAL_PULSE[NO_PWMS] = {0, 0, 0};
yihui 9:05f0b5a3a70a 66
yihui 9:05f0b5a3a70a 67
yihui 9:05f0b5a3a70a 68 /** @brief Function for handling timer 2 peripheral interrupts.
yihui 9:05f0b5a3a70a 69 */
yihui 9:05f0b5a3a70a 70 #ifdef __cplusplus
yihui 9:05f0b5a3a70a 71 extern "C" {
yihui 9:05f0b5a3a70a 72 #endif
yihui 9:05f0b5a3a70a 73 void TIMER2_IRQHandler(void)
yihui 9:05f0b5a3a70a 74 {
yihui 9:05f0b5a3a70a 75 NRF_TIMER2->EVENTS_COMPARE[3] = 0;
yihui 9:05f0b5a3a70a 76 NRF_TIMER2->CC[3] = PERIOD;
yihui 9:05f0b5a3a70a 77
yihui 9:05f0b5a3a70a 78 if (PWM_taken[0]) {
yihui 9:05f0b5a3a70a 79 NRF_TIMER2->CC[0] = PULSE_WIDTH[0];
yihui 9:05f0b5a3a70a 80 }
yihui 9:05f0b5a3a70a 81 if (PWM_taken[1]) {
yihui 9:05f0b5a3a70a 82 NRF_TIMER2->CC[1] = PULSE_WIDTH[1];
yihui 9:05f0b5a3a70a 83 }
yihui 9:05f0b5a3a70a 84 if (PWM_taken[2]) {
yihui 9:05f0b5a3a70a 85 NRF_TIMER2->CC[2] = PULSE_WIDTH[2];
yihui 9:05f0b5a3a70a 86 }
yihui 9:05f0b5a3a70a 87
yihui 9:05f0b5a3a70a 88 NRF_TIMER2->TASKS_START = 1;
yihui 9:05f0b5a3a70a 89 }
yihui 9:05f0b5a3a70a 90
yihui 9:05f0b5a3a70a 91 #ifdef __cplusplus
yihui 9:05f0b5a3a70a 92 }
yihui 9:05f0b5a3a70a 93 #endif
yihui 9:05f0b5a3a70a 94 /** @brief Function for initializing the Timer peripherals.
yihui 9:05f0b5a3a70a 95 */
yihui 9:05f0b5a3a70a 96 void timer_init(uint8_t pwmChoice)
yihui 9:05f0b5a3a70a 97 {
yihui 9:05f0b5a3a70a 98 NRF_TIMER_Type *timer = Timers[0];
yihui 9:05f0b5a3a70a 99 timer->TASKS_STOP = 0;
yihui 9:05f0b5a3a70a 100
yihui 9:05f0b5a3a70a 101 if (pwmChoice == 0) {
yihui 9:05f0b5a3a70a 102 timer->POWER = 0;
yihui 9:05f0b5a3a70a 103 timer->POWER = 1;
yihui 9:05f0b5a3a70a 104 timer->MODE = TIMER_MODE_MODE_Timer;
yihui 9:05f0b5a3a70a 105 timer->BITMODE = TIMER_BITMODE_BITMODE_16Bit << TIMER_BITMODE_BITMODE_Pos;
yihui 9:05f0b5a3a70a 106 timer->PRESCALER = TIMER_PRESCALER;
yihui 9:05f0b5a3a70a 107 timer->CC[3] = PERIOD;
yihui 9:05f0b5a3a70a 108 }
yihui 9:05f0b5a3a70a 109
yihui 9:05f0b5a3a70a 110 timer->CC[pwmChoice] = PULSE_WIDTH[pwmChoice];
yihui 9:05f0b5a3a70a 111
yihui 9:05f0b5a3a70a 112 //high priority application interrupt
yihui 9:05f0b5a3a70a 113 NVIC_SetPriority(TIMER2_IRQn, 1);
yihui 9:05f0b5a3a70a 114 NVIC_EnableIRQ(TIMER2_IRQn);
yihui 9:05f0b5a3a70a 115
yihui 9:05f0b5a3a70a 116 timer->TASKS_START = 0x01;
yihui 9:05f0b5a3a70a 117 }
yihui 9:05f0b5a3a70a 118
yihui 9:05f0b5a3a70a 119 /** @brief Function for initializing the GPIO Tasks/Events peripheral.
yihui 9:05f0b5a3a70a 120 */
yihui 9:05f0b5a3a70a 121 void gpiote_init(PinName pin, uint8_t channel_number)
yihui 9:05f0b5a3a70a 122 {
yihui 9:05f0b5a3a70a 123 // Connect GPIO input buffers and configure PWM_OUTPUT_PIN_NUMBER as an output.
yihui 9:05f0b5a3a70a 124 NRF_GPIO->PIN_CNF[pin] = (GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos)
yihui 9:05f0b5a3a70a 125 | (GPIO_PIN_CNF_DRIVE_S0S1 << GPIO_PIN_CNF_DRIVE_Pos)
yihui 9:05f0b5a3a70a 126 | (GPIO_PIN_CNF_PULL_Disabled << GPIO_PIN_CNF_PULL_Pos)
yihui 9:05f0b5a3a70a 127 | (GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos)
yihui 9:05f0b5a3a70a 128 | (GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos);
yihui 9:05f0b5a3a70a 129 NRF_GPIO->OUTCLR = (1UL << pin);
yihui 9:05f0b5a3a70a 130 // Configure GPIOTE channel 0 to toggle the PWM pin state
yihui 9:05f0b5a3a70a 131 // @note Only one GPIOTE task can be connected to an output pin.
yihui 9:05f0b5a3a70a 132 /* Configure channel to Pin31, not connected to the pin, and configure as a tasks that will set it to proper level */
yihui 9:05f0b5a3a70a 133 NRF_GPIOTE->CONFIG[channel_number] = (GPIOTE_CONFIG_MODE_Task << GPIOTE_CONFIG_MODE_Pos) |
yihui 9:05f0b5a3a70a 134 (31UL << GPIOTE_CONFIG_PSEL_Pos) |
yihui 9:05f0b5a3a70a 135 (GPIOTE_CONFIG_POLARITY_HiToLo << GPIOTE_CONFIG_POLARITY_Pos);
yihui 9:05f0b5a3a70a 136 /* Three NOPs are required to make sure configuration is written before setting tasks or getting events */
yihui 9:05f0b5a3a70a 137 __NOP();
yihui 9:05f0b5a3a70a 138 __NOP();
yihui 9:05f0b5a3a70a 139 __NOP();
yihui 9:05f0b5a3a70a 140 /* Launch the task to take the GPIOTE channel output to the desired level */
yihui 9:05f0b5a3a70a 141 NRF_GPIOTE->TASKS_OUT[channel_number] = 1;
yihui 9:05f0b5a3a70a 142
yihui 9:05f0b5a3a70a 143 /* Finally configure the channel as the caller expects. If OUTINIT works, the channel is configured properly.
yihui 9:05f0b5a3a70a 144 If it does not, the channel output inheritance sets the proper level. */
yihui 9:05f0b5a3a70a 145 NRF_GPIOTE->CONFIG[channel_number] = (GPIOTE_CONFIG_MODE_Task << GPIOTE_CONFIG_MODE_Pos) |
yihui 9:05f0b5a3a70a 146 ((uint32_t)pin << GPIOTE_CONFIG_PSEL_Pos) |
yihui 9:05f0b5a3a70a 147 ((uint32_t)GPIOTE_CONFIG_POLARITY_Toggle << GPIOTE_CONFIG_POLARITY_Pos) |
yihui 9:05f0b5a3a70a 148 ((uint32_t)GPIOTE_CONFIG_OUTINIT_Low << GPIOTE_CONFIG_OUTINIT_Pos); // ((uint32_t)GPIOTE_CONFIG_OUTINIT_High <<
yihui 9:05f0b5a3a70a 149 // GPIOTE_CONFIG_OUTINIT_Pos);//
yihui 9:05f0b5a3a70a 150
yihui 9:05f0b5a3a70a 151 /* Three NOPs are required to make sure configuration is written before setting tasks or getting events */
yihui 9:05f0b5a3a70a 152 __NOP();
yihui 9:05f0b5a3a70a 153 __NOP();
yihui 9:05f0b5a3a70a 154 __NOP();
yihui 9:05f0b5a3a70a 155 }
yihui 9:05f0b5a3a70a 156
yihui 9:05f0b5a3a70a 157 /** @brief Function for initializing the Programmable Peripheral Interconnect peripheral.
yihui 9:05f0b5a3a70a 158 */
yihui 9:05f0b5a3a70a 159 static void ppi_init(uint8_t pwm)
yihui 9:05f0b5a3a70a 160 {
yihui 9:05f0b5a3a70a 161 //using ppi channels 0-7 (only 0-7 are available)
yihui 9:05f0b5a3a70a 162 uint8_t channel_number = 2 * pwm;
yihui 9:05f0b5a3a70a 163 NRF_TIMER_Type *timer = Timers[0];
yihui 9:05f0b5a3a70a 164
yihui 9:05f0b5a3a70a 165 // Configure PPI channel 0 to toggle ADVERTISING_LED_PIN_NO on every TIMER1 COMPARE[0] match
yihui 9:05f0b5a3a70a 166 NRF_PPI->CH[channel_number].TEP = (uint32_t)&NRF_GPIOTE->TASKS_OUT[pwm];
yihui 9:05f0b5a3a70a 167 NRF_PPI->CH[channel_number + 1].TEP = (uint32_t)&NRF_GPIOTE->TASKS_OUT[pwm];
yihui 9:05f0b5a3a70a 168 NRF_PPI->CH[channel_number].EEP = (uint32_t)&timer->EVENTS_COMPARE[pwm];
yihui 9:05f0b5a3a70a 169 NRF_PPI->CH[channel_number + 1].EEP = (uint32_t)&timer->EVENTS_COMPARE[3];
yihui 9:05f0b5a3a70a 170
yihui 9:05f0b5a3a70a 171 // Enable PPI channels.
yihui 9:05f0b5a3a70a 172 NRF_PPI->CHEN |= (1 << channel_number) |
yihui 9:05f0b5a3a70a 173 (1 << (channel_number + 1));
yihui 9:05f0b5a3a70a 174 }
yihui 9:05f0b5a3a70a 175
yihui 9:05f0b5a3a70a 176 void setModulation(pwmout_t *obj, uint8_t toggle, uint8_t high)
yihui 9:05f0b5a3a70a 177 {
yihui 9:05f0b5a3a70a 178 if (high) {
yihui 9:05f0b5a3a70a 179 NRF_GPIOTE->CONFIG[obj->pwm] |= ((uint32_t)GPIOTE_CONFIG_OUTINIT_High << GPIOTE_CONFIG_OUTINIT_Pos);
yihui 9:05f0b5a3a70a 180 if (toggle) {
yihui 9:05f0b5a3a70a 181 NRF_GPIOTE->CONFIG[obj->pwm] |= (GPIOTE_CONFIG_MODE_Task << GPIOTE_CONFIG_MODE_Pos) |
yihui 9:05f0b5a3a70a 182 ((uint32_t)GPIOTE_CONFIG_POLARITY_Toggle << GPIOTE_CONFIG_POLARITY_Pos);
yihui 9:05f0b5a3a70a 183 } else {
yihui 9:05f0b5a3a70a 184 NRF_GPIOTE->CONFIG[obj->pwm] &= ~((uint32_t)GPIOTE_CONFIG_POLARITY_Toggle << GPIOTE_CONFIG_POLARITY_Pos);
yihui 9:05f0b5a3a70a 185 NRF_GPIOTE->CONFIG[obj->pwm] |= ((uint32_t)GPIOTE_CONFIG_POLARITY_LoToHi << GPIOTE_CONFIG_POLARITY_Pos);
yihui 9:05f0b5a3a70a 186 }
yihui 9:05f0b5a3a70a 187 } else {
yihui 9:05f0b5a3a70a 188 NRF_GPIOTE->CONFIG[obj->pwm] &= ~((uint32_t)GPIOTE_CONFIG_OUTINIT_High << GPIOTE_CONFIG_OUTINIT_Pos);
yihui 9:05f0b5a3a70a 189
yihui 9:05f0b5a3a70a 190 if (toggle) {
yihui 9:05f0b5a3a70a 191 NRF_GPIOTE->CONFIG[obj->pwm] |= (GPIOTE_CONFIG_MODE_Task << GPIOTE_CONFIG_MODE_Pos) |
yihui 9:05f0b5a3a70a 192 ((uint32_t)GPIOTE_CONFIG_POLARITY_Toggle << GPIOTE_CONFIG_POLARITY_Pos);
yihui 9:05f0b5a3a70a 193 } else {
yihui 9:05f0b5a3a70a 194 NRF_GPIOTE->CONFIG[obj->pwm] &= ~((uint32_t)GPIOTE_CONFIG_POLARITY_Toggle << GPIOTE_CONFIG_POLARITY_Pos);
yihui 9:05f0b5a3a70a 195 NRF_GPIOTE->CONFIG[obj->pwm] |= ((uint32_t)GPIOTE_CONFIG_POLARITY_HiToLo << GPIOTE_CONFIG_POLARITY_Pos);
yihui 9:05f0b5a3a70a 196 }
yihui 9:05f0b5a3a70a 197 }
yihui 9:05f0b5a3a70a 198 }
yihui 9:05f0b5a3a70a 199
yihui 9:05f0b5a3a70a 200 void pwmout_init(pwmout_t *obj, PinName pin)
yihui 9:05f0b5a3a70a 201 {
yihui 9:05f0b5a3a70a 202 // determine the channel
yihui 9:05f0b5a3a70a 203 uint8_t pwmOutSuccess = 0;
yihui 9:05f0b5a3a70a 204 PWMName pwm = (PWMName)pinmap_peripheral(pin, PinMap_PWM);
yihui 9:05f0b5a3a70a 205
yihui 9:05f0b5a3a70a 206 MBED_ASSERT(pwm != (PWMName)NC);
yihui 9:05f0b5a3a70a 207
yihui 9:05f0b5a3a70a 208 if (PWM_taken[(uint8_t)pwm]) {
yihui 9:05f0b5a3a70a 209 for (uint8_t i = 1; !pwmOutSuccess && (i<NO_PWMS); i++) {
yihui 9:05f0b5a3a70a 210 if (!PWM_taken[i]) {
yihui 9:05f0b5a3a70a 211 pwm = (PWMName)i;
yihui 9:05f0b5a3a70a 212 PWM_taken[i] = 1;
yihui 9:05f0b5a3a70a 213 pwmOutSuccess = 1;
yihui 9:05f0b5a3a70a 214 }
yihui 9:05f0b5a3a70a 215 }
yihui 9:05f0b5a3a70a 216 } else {
yihui 9:05f0b5a3a70a 217 pwmOutSuccess = 1;
yihui 9:05f0b5a3a70a 218 PWM_taken[(uint8_t)pwm] = 1;
yihui 9:05f0b5a3a70a 219 }
yihui 9:05f0b5a3a70a 220
yihui 9:05f0b5a3a70a 221 if (!pwmOutSuccess) {
yihui 9:05f0b5a3a70a 222 error("PwmOut pin mapping failed. All available PWM channels are in use.");
yihui 9:05f0b5a3a70a 223 }
yihui 9:05f0b5a3a70a 224
yihui 9:05f0b5a3a70a 225 obj->pwm = pwm;
yihui 9:05f0b5a3a70a 226 obj->pin = pin;
yihui 9:05f0b5a3a70a 227
yihui 9:05f0b5a3a70a 228 gpiote_init(pin, (uint8_t)pwm);
yihui 9:05f0b5a3a70a 229 ppi_init((uint8_t)pwm);
yihui 9:05f0b5a3a70a 230
yihui 9:05f0b5a3a70a 231 if (pwm == 0) {
yihui 9:05f0b5a3a70a 232 NRF_POWER->TASKS_CONSTLAT = 1;
yihui 9:05f0b5a3a70a 233 }
yihui 9:05f0b5a3a70a 234
yihui 9:05f0b5a3a70a 235 timer_init((uint8_t)pwm);
yihui 9:05f0b5a3a70a 236
yihui 9:05f0b5a3a70a 237 //default to 20ms: standard for servos, and fine for e.g. brightness control
yihui 9:05f0b5a3a70a 238 pwmout_period_ms(obj, 20);
yihui 9:05f0b5a3a70a 239 pwmout_write (obj, 0);
yihui 9:05f0b5a3a70a 240 }
yihui 9:05f0b5a3a70a 241
yihui 9:05f0b5a3a70a 242 void pwmout_free(pwmout_t *obj)
yihui 9:05f0b5a3a70a 243 {
yihui 9:05f0b5a3a70a 244 MBED_ASSERT(obj->pwm != (PWMName)NC);
yihui 9:05f0b5a3a70a 245 PWM_taken[obj->pwm] = 0;
yihui 9:05f0b5a3a70a 246 pwmout_write(obj, 0);
yihui 9:05f0b5a3a70a 247
yihui 9:05f0b5a3a70a 248 /* Configure channel to Pin31, not connected to the pin, and configure as a tasks that will set it to proper level */
yihui 9:05f0b5a3a70a 249 NRF_GPIOTE->CONFIG[obj->pwm] = (GPIOTE_CONFIG_MODE_Task << GPIOTE_CONFIG_MODE_Pos) |
yihui 9:05f0b5a3a70a 250 (31UL << GPIOTE_CONFIG_PSEL_Pos) |
yihui 9:05f0b5a3a70a 251 (GPIOTE_CONFIG_POLARITY_HiToLo << GPIOTE_CONFIG_POLARITY_Pos);
yihui 9:05f0b5a3a70a 252 }
yihui 9:05f0b5a3a70a 253
yihui 9:05f0b5a3a70a 254 void pwmout_write(pwmout_t *obj, float value)
yihui 9:05f0b5a3a70a 255 {
yihui 9:05f0b5a3a70a 256 uint16_t oldPulseWidth;
yihui 9:05f0b5a3a70a 257
yihui 9:05f0b5a3a70a 258 NRF_TIMER2->EVENTS_COMPARE[3] = 0;
yihui 9:05f0b5a3a70a 259 NRF_TIMER2->TASKS_STOP = 1;
yihui 9:05f0b5a3a70a 260
yihui 9:05f0b5a3a70a 261 if (value < 0.0f) {
yihui 9:05f0b5a3a70a 262 value = 0.0;
yihui 9:05f0b5a3a70a 263 } else if (value > 1.0f) {
yihui 9:05f0b5a3a70a 264 value = 1.0;
yihui 9:05f0b5a3a70a 265 }
yihui 9:05f0b5a3a70a 266
yihui 9:05f0b5a3a70a 267 oldPulseWidth = ACTUAL_PULSE[obj->pwm];
yihui 9:05f0b5a3a70a 268 ACTUAL_PULSE[obj->pwm] = PULSE_WIDTH[obj->pwm] = value * PERIOD;
yihui 9:05f0b5a3a70a 269
yihui 9:05f0b5a3a70a 270 if (PULSE_WIDTH[obj->pwm] == 0) {
yihui 9:05f0b5a3a70a 271 PULSE_WIDTH[obj->pwm] = 1;
yihui 9:05f0b5a3a70a 272 setModulation(obj, 0, 0);
yihui 9:05f0b5a3a70a 273 } else if (PULSE_WIDTH[obj->pwm] == PERIOD) {
yihui 9:05f0b5a3a70a 274 PULSE_WIDTH[obj->pwm] = PERIOD - 1;
yihui 9:05f0b5a3a70a 275 setModulation(obj, 0, 1);
yihui 9:05f0b5a3a70a 276 } else if ((oldPulseWidth == 0) || (oldPulseWidth == PERIOD)) {
yihui 9:05f0b5a3a70a 277 setModulation(obj, 1, oldPulseWidth == PERIOD);
yihui 9:05f0b5a3a70a 278 }
yihui 9:05f0b5a3a70a 279
yihui 9:05f0b5a3a70a 280 NRF_TIMER2->INTENSET = TIMER_INTENSET_COMPARE3_Msk;
yihui 9:05f0b5a3a70a 281 NRF_TIMER2->SHORTS = TIMER_SHORTS_COMPARE3_CLEAR_Msk | TIMER_SHORTS_COMPARE3_STOP_Msk;
yihui 9:05f0b5a3a70a 282 NRF_TIMER2->TASKS_START = 1;
yihui 9:05f0b5a3a70a 283 }
yihui 9:05f0b5a3a70a 284
yihui 9:05f0b5a3a70a 285 float pwmout_read(pwmout_t *obj)
yihui 9:05f0b5a3a70a 286 {
yihui 9:05f0b5a3a70a 287 return ((float)PULSE_WIDTH[obj->pwm] / (float)PERIOD);
yihui 9:05f0b5a3a70a 288 }
yihui 9:05f0b5a3a70a 289
yihui 9:05f0b5a3a70a 290 void pwmout_period(pwmout_t *obj, float seconds)
yihui 9:05f0b5a3a70a 291 {
yihui 9:05f0b5a3a70a 292 pwmout_period_us(obj, seconds * 1000000.0f);
yihui 9:05f0b5a3a70a 293 }
yihui 9:05f0b5a3a70a 294
yihui 9:05f0b5a3a70a 295 void pwmout_period_ms(pwmout_t *obj, int ms)
yihui 9:05f0b5a3a70a 296 {
yihui 9:05f0b5a3a70a 297 pwmout_period_us(obj, ms * 1000);
yihui 9:05f0b5a3a70a 298 }
yihui 9:05f0b5a3a70a 299
yihui 9:05f0b5a3a70a 300 // Set the PWM period, keeping the duty cycle the same.
yihui 9:05f0b5a3a70a 301 void pwmout_period_us(pwmout_t *obj, int us)
yihui 9:05f0b5a3a70a 302 {
yihui 9:05f0b5a3a70a 303 uint32_t periodInTicks = us / TIMER_PRECISION;
yihui 9:05f0b5a3a70a 304
yihui 9:05f0b5a3a70a 305 NRF_TIMER2->EVENTS_COMPARE[3] = 0;
yihui 9:05f0b5a3a70a 306 NRF_TIMER2->TASKS_STOP = 1;
yihui 9:05f0b5a3a70a 307
yihui 9:05f0b5a3a70a 308 if (periodInTicks>((1 << 16) - 1)) {
yihui 9:05f0b5a3a70a 309 PERIOD = (1 << 16) - 1; //131ms
yihui 9:05f0b5a3a70a 310 } else if (periodInTicks<5) {
yihui 9:05f0b5a3a70a 311 PERIOD = 5;
yihui 9:05f0b5a3a70a 312 } else {
yihui 9:05f0b5a3a70a 313 PERIOD = periodInTicks;
yihui 9:05f0b5a3a70a 314 }
yihui 9:05f0b5a3a70a 315 NRF_TIMER2->INTENSET = TIMER_INTENSET_COMPARE3_Msk;
yihui 9:05f0b5a3a70a 316 NRF_TIMER2->SHORTS = TIMER_SHORTS_COMPARE3_CLEAR_Msk | TIMER_SHORTS_COMPARE3_STOP_Msk;
yihui 9:05f0b5a3a70a 317 NRF_TIMER2->TASKS_START = 1;
yihui 9:05f0b5a3a70a 318 }
yihui 9:05f0b5a3a70a 319
yihui 9:05f0b5a3a70a 320 void pwmout_pulsewidth(pwmout_t *obj, float seconds)
yihui 9:05f0b5a3a70a 321 {
yihui 9:05f0b5a3a70a 322 pwmout_pulsewidth_us(obj, seconds * 1000000.0f);
yihui 9:05f0b5a3a70a 323 }
yihui 9:05f0b5a3a70a 324
yihui 9:05f0b5a3a70a 325 void pwmout_pulsewidth_ms(pwmout_t *obj, int ms)
yihui 9:05f0b5a3a70a 326 {
yihui 9:05f0b5a3a70a 327 pwmout_pulsewidth_us(obj, ms * 1000);
yihui 9:05f0b5a3a70a 328 }
yihui 9:05f0b5a3a70a 329
yihui 9:05f0b5a3a70a 330 void pwmout_pulsewidth_us(pwmout_t *obj, int us)
yihui 9:05f0b5a3a70a 331 {
yihui 9:05f0b5a3a70a 332 uint32_t pulseInTicks = us / TIMER_PRECISION;
yihui 9:05f0b5a3a70a 333 uint16_t oldPulseWidth = ACTUAL_PULSE[obj->pwm];
yihui 9:05f0b5a3a70a 334
yihui 9:05f0b5a3a70a 335 NRF_TIMER2->EVENTS_COMPARE[3] = 0;
yihui 9:05f0b5a3a70a 336 NRF_TIMER2->TASKS_STOP = 1;
yihui 9:05f0b5a3a70a 337
yihui 9:05f0b5a3a70a 338 ACTUAL_PULSE[obj->pwm] = PULSE_WIDTH[obj->pwm] = pulseInTicks;
yihui 9:05f0b5a3a70a 339
yihui 9:05f0b5a3a70a 340 if (PULSE_WIDTH[obj->pwm] == 0) {
yihui 9:05f0b5a3a70a 341 PULSE_WIDTH[obj->pwm] = 1;
yihui 9:05f0b5a3a70a 342 setModulation(obj, 0, 0);
yihui 9:05f0b5a3a70a 343 } else if (PULSE_WIDTH[obj->pwm] == PERIOD) {
yihui 9:05f0b5a3a70a 344 PULSE_WIDTH[obj->pwm] = PERIOD - 1;
yihui 9:05f0b5a3a70a 345 setModulation(obj, 0, 1);
yihui 9:05f0b5a3a70a 346 } else if ((oldPulseWidth == 0) || (oldPulseWidth == PERIOD)) {
yihui 9:05f0b5a3a70a 347 setModulation(obj, 1, oldPulseWidth == PERIOD);
yihui 9:05f0b5a3a70a 348 }
yihui 9:05f0b5a3a70a 349 NRF_TIMER2->INTENSET = TIMER_INTENSET_COMPARE3_Msk;
yihui 9:05f0b5a3a70a 350 NRF_TIMER2->SHORTS = TIMER_SHORTS_COMPARE3_CLEAR_Msk | TIMER_SHORTS_COMPARE3_STOP_Msk;
yihui 9:05f0b5a3a70a 351 NRF_TIMER2->TASKS_START = 1;
yihui 9:05f0b5a3a70a 352 }