mbed library sources. Supersedes mbed-src.

Dependents:   Nucleo_Hello_Encoder BLE_iBeaconScan AM1805_DEMO DISCO-F429ZI_ExportTemplate1 ... more

Committer:
AnnaBridge
Date:
Wed Feb 20 22:31:08 2019 +0000
Revision:
189:f392fc9709a3
Parent:
151:5eaa88a5bcc7
mbed library release version 165

Who changed what in which revision?

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