/** Timer 1 peripheral interrupt handler. */ static void TIMER1_Interrupt(void) { // Update the CCx values NRF_TIMER1->CC[0] = PWM_Channels_Value[0]; NRF_TIMER1->CC[1] = PWM_Channels_Value[1]; NRF_TIMER1->CC[2] = PWM_Channels_Value[2]; if (PWM_Channels_Start[0] == 1) { NRF_TIMER1->EVENTS_COMPARE[0] = 0; nrf_gpiote_task_config(0, Timer1_Compare_Unit_Occupied_by_Pin[0], NRF_GPIOTE_POLARITY_TOGGLE, NRF_GPIOTE_INITIAL_VALUE_LOW); PWM_Channels_Start[0] = 0; } if (PWM_Channels_Start[1] == 1) { NRF_TIMER1->EVENTS_COMPARE[1] = 0; nrf_gpiote_task_config(1, Timer1_Compare_Unit_Occupied_by_Pin[1], NRF_GPIOTE_POLARITY_TOGGLE, NRF_GPIOTE_INITIAL_VALUE_LOW); PWM_Channels_Start[1] = 0; } if (PWM_Channels_Start[2] == 1) { NRF_TIMER1->EVENTS_COMPARE[2] = 0; nrf_gpiote_task_config(2, Timer1_Compare_Unit_Occupied_by_Pin[2], NRF_GPIOTE_POLARITY_TOGGLE, NRF_GPIOTE_INITIAL_VALUE_LOW); PWM_Channels_Start[2] = 0; } NRF_TIMER1->EVENTS_COMPARE[3] = 0; }
bool protocol_send(uint16_t address, uint16_t command, sent_cb_t* cb) { // gpiote0 (toggles gpio) NRF_GPIOTE->POWER = GPIOTE_POWER_POWER_Enabled << GPIOTE_POWER_POWER_Pos; nrf_gpiote_task_config(0, context.led_pin, NRF_GPIOTE_POLARITY_TOGGLE, NRF_GPIOTE_INITIAL_VALUE_LOW); if (context.state != PROTOCOL_STATE_IDLE) { return false; } context.state = PROTOCOL_STATE_PREAMBLE_DONE; context.address = address; context.command = command; context.cb = cb; NRF_POWER->TASKS_CONSTLAT = 1; // PAN 11 "HFCLK: Base current with HFCLK running is too high" NRF_RTC1->TASKS_STOP = 1; NRF_RTC1->TASKS_CLEAR = 1; NRF_RTC1->PRESCALER = ROUNDED_DIV(LFCLK_FREQUENCY, ROUNDED_DIV(1000000, context.protocol->preamble.leader + context.protocol->preamble.pause - RTC_TASK_JITTER )) - 1; NRF_RTC1->CC[0] = 1; NRF_RTC1->TASKS_START = 1; pulse(ROUNDED_DIV(context.protocol->preamble.leader, context.protocol->pulse_width)); return true; }
void setup_example(void) { uint32_t event; nrf_ppi_channel_t ppi_channel; uint32_t err_code; nrf_gpio_cfg_output(BSP_LED_0); err_code = nrf_drv_rtc_init(&rtc, NULL, rtc_evt_handler); APP_ERROR_CHECK(err_code); nrf_drv_rtc_tick_enable(&rtc, false); event = nrf_drv_rtc_event_address_get(&rtc, NRF_RTC_EVENT_TICK); nrf_gpiote_task_config(0, BSP_LED_0, NRF_GPIOTE_POLARITY_TOGGLE, NRF_GPIOTE_INITIAL_VALUE_LOW); err_code = nrf_drv_ppi_init(); APP_ERROR_CHECK(err_code); err_code = nrf_drv_ppi_channel_alloc(&ppi_channel); APP_ERROR_CHECK(err_code); err_code = nrf_drv_ppi_channel_assign(ppi_channel,event,(uint32_t)&NRF_GPIOTE->TASKS_OUT[0]); APP_ERROR_CHECK(err_code); err_code = nrf_drv_ppi_channel_enable(ppi_channel); APP_ERROR_CHECK(err_code); nrf_drv_rtc_enable(&rtc); }
/*---------------------------------------------------------------------------*/ static void buzzer_gpiote_config(void) { /* * Configure GPIOTE_CHANNEL_NUMBERs to toggle the GPIO pins state. * NOTE: Only one GPIOTE task can be coupled to any output pin. */ nrf_gpiote_task_config(GPIOTE_CHANNEL_NUMBER_0, BUZZ1, NRF_GPIOTE_POLARITY_TOGGLE, NRF_GPIOTE_INITIAL_VALUE_LOW); nrf_gpiote_task_config(GPIOTE_CHANNEL_NUMBER_1, BUZZ2, NRF_GPIOTE_POLARITY_TOGGLE, NRF_GPIOTE_INITIAL_VALUE_HIGH); }
static void set_color(void* user_data, uint32_t time) { light_t* light = (light_t*) user_data; int i; PWM_TIMER->TASKS_CLEAR = 1; // setup PWM PWM_TIMER->POWER = 1; PWM_TIMER->PRESCALER = 7; // 256k PWM_TIMER->BITMODE = TIMER_BITMODE_BITMODE_16Bit; PWM_TIMER->CC[3] = 255; PWM_TIMER->MODE = TIMER_MODE_MODE_Timer; PWM_TIMER->SHORTS = TIMER_SHORTS_COMPARE3_CLEAR_Msk; PWM_TIMER->EVENTS_COMPARE[0] = PWM_TIMER->EVENTS_COMPARE[1] = PWM_TIMER->EVENTS_COMPARE[2] = PWM_TIMER->EVENTS_COMPARE[3] = 0; for(i = 0; i < 3; i++) { nrf_gpio_cfg_output(light->pins[i]); PWM_TIMER->CC[i] = light->values[i]; nrf_gpio_cfg_output(light->pins[i]); ppi_enable_channel(i*2, &PWM_TIMER->EVENTS_COMPARE[i], &NRF_GPIOTE->TASKS_OUT[i]); ppi_enable_channel(i*2+1,&PWM_TIMER->EVENTS_COMPARE[3], &NRF_GPIOTE->TASKS_OUT[i]); nrf_gpiote_task_config(i, light->pins[i], GPIOTE_CONFIG_POLARITY_Toggle, NRF_GPIOTE_INITIAL_VALUE_HIGH); } PWM_TIMER->TASKS_START = 1; }
static void gpiote_init(void) { // Configure the GPIOTE Task to toggle the LED state. nrf_gpiote_task_config(GPIOTE_CHAN_FOR_LED_TASK, ADVERTISING_LED_PIN_NO, NRF_GPIOTE_POLARITY_TOGGLE, NRF_GPIOTE_INITIAL_VALUE_HIGH); }
void gpiote_toggle_led_init() { sd_ppi_channel_assign(TOGGLE_LED_GPIOTE_CHANNEL, &(NRF_TIMER2->EVENTS_COMPARE[0]) ,&(NRF_GPIOTE->TASKS_OUT[0])); nrf_gpio_cfg_output(SECONDARY_LED_PIN); nrf_gpio_pin_clear(SECONDARY_LED_PIN); nrf_gpiote_task_config(TOGGLE_LED_GPIOTE_CHANNEL, SECONDARY_LED_PIN, NRF_GPIOTE_POLARITY_TOGGLE, NRF_GPIOTE_INITIAL_VALUE_LOW); sd_ppi_channel_enable_set(PPI_CHEN_CH0_Msk); }
static void spi_slave_gpiote_init(void) { //Configure GPIOTE channel to go low nrf_gpiote_task_config(m_spi_slave_raw_config.gpiote_rdy_ch, m_spi_slave_raw_config.pin_rdy, NRF_GPIOTE_POLARITY_TOGGLE, NRF_GPIOTE_INITIAL_VALUE_HIGH); return; }
void tone(uint8_t ulPin, uint16_t frequency, uint32_t duration) { uint32_t i, prescaler, compare; tone_pin = ulPin; // Find appropriate values for PRESCALER and COMPARE registers for (i = 0; i <= 9; i++) { prescaler = i; compare = VARIANT_MCK / frequency; compare = compare >> (prescaler + 1); compare = compare - 1; if ((compare >= 2) && (compare <= 65535)) break; } // Calculate interrupts count if (duration) { tone_toggle_count = ((frequency * duration) / 1000) * 2; } else { tone_toggle_count = 0xFFFFFFFF; } // Configure ulPin as output digitalWrite(ulPin, LOW); pinMode(ulPin, OUTPUT); // Configure GPIOTE channel "3" to toggle the PWM pin state // Note that we can only connect one GPIOTE task to an output pin nrf_gpiote_task_config(3, ulPin, NRF_GPIOTE_POLARITY_TOGGLE, NRF_GPIOTE_INITIAL_VALUE_LOW); GPIOTE_Channels_Occupied[ulPin] = 3; // Configure PPI channel "6" for toggling pin wavelette_ppi_add(6, &NRF_TIMER2->EVENTS_COMPARE[0], &NRF_GPIOTE->TASKS_OUT[3]); // Configure Timer 2 NRF_TIMER2->TASKS_STOP = 1; NRF_TIMER2->MODE = TIMER_MODE_MODE_Timer; NRF_TIMER2->PRESCALER = prescaler; // Source clock frequency is divided by 2^prescaler NRF_TIMER2->BITMODE = TIMER_BITMODE_BITMODE_16Bit; // Enable Shortcut between CC[0] event and the CLEAR task NRF_TIMER2->SHORTS = (TIMER_SHORTS_COMPARE0_CLEAR_Enabled << TIMER_SHORTS_COMPARE0_CLEAR_Pos); // Clears the timer, sets it to 0 NRF_TIMER2->TASKS_CLEAR = 1; NRF_TIMER2->CC[0] = (uint16_t)(compare); NRF_TIMER2->EVENTS_COMPARE[0] = 0; // Interrupt setup NRF_TIMER2->INTENCLR = 0xFFFFFFFF; NRF_TIMER2->INTENSET = (TIMER_INTENSET_COMPARE0_Enabled << TIMER_INTENSET_COMPARE0_Pos); attachInterrupt(TIMER2_IRQn, TIMER2_Interrupt); // Start clock NRF_TIMER2->TASKS_START = 1; }
/** @brief Function for initializing the GPIO Tasks/Events peripheral. */ static void gpiote_init(void) { // Configure PWM_OUTPUT_PIN_NUMBER as an output. nrf_gpio_cfg_output(PWM_OUTPUT_PIN_NUMBER); // Configure GPIOTE channel 0 to toggle the PWM pin state // @note Only one GPIOTE task can be connected to an output pin. nrf_gpiote_task_config(0, PWM_OUTPUT_PIN_NUMBER, \ NRF_GPIOTE_POLARITY_TOGGLE, NRF_GPIOTE_INITIAL_VALUE_LOW); }
/** @brief Function for initializing the GPIO Tasks and Events peripheral. */ static void gpiote_init(void) { // Configure GPIO_OUTPUT_PIN_NUMBER as an output. nrf_gpio_cfg_output(GPIO_OUTPUT_PIN_NUMBER); // Configure GPIOTE_CHANNEL_NUMBER to toggle the GPIO pin state with input. // @note Only one GPIOTE task can be coupled to an output pin. nrf_gpiote_task_config(GPIOTE_CHANNEL_NUMBER, GPIO_OUTPUT_PIN_NUMBER, \ NRF_GPIOTE_POLARITY_TOGGLE, NRF_GPIOTE_INITIAL_VALUE_LOW); }
//void TIMER1_IRQHandler(void) static void TIMER1_handler( void ) { uint8_t index; // Update the CCx values NRF_TIMER1->CC[0] = PWM_Channels_Value[0]; NRF_TIMER1->CC[1] = PWM_Channels_Value[1]; NRF_TIMER1->CC[2] = PWM_Channels_Value[2]; NRF_TIMER1->CC[3] = 0; if (PWM_Channels_Start[0] == 1) { NRF_TIMER1->EVENTS_COMPARE[0] = 0; nrf_gpiote_task_config(GPIOTE_Channel_for_Analog[0], Timer1_Occupied_Pin[0], NRF_GPIOTE_POLARITY_TOGGLE, NRF_GPIOTE_INITIAL_VALUE_LOW); PWM_Channels_Start[0] = 0; } if (PWM_Channels_Start[1] == 1) { NRF_TIMER1->EVENTS_COMPARE[1] = 0; nrf_gpiote_task_config(GPIOTE_Channel_for_Analog[1], Timer1_Occupied_Pin[1], NRF_GPIOTE_POLARITY_TOGGLE, NRF_GPIOTE_INITIAL_VALUE_LOW); PWM_Channels_Start[1] = 0; } if (PWM_Channels_Start[2] == 1) { NRF_TIMER1->EVENTS_COMPARE[2] = 0; nrf_gpiote_task_config(GPIOTE_Channel_for_Analog[2], Timer1_Occupied_Pin[2], NRF_GPIOTE_POLARITY_TOGGLE, NRF_GPIOTE_INITIAL_VALUE_LOW); PWM_Channels_Start[2] = 0; } //when IRQHandle, make sure all GPIO is LOW. If HIGH,reconfigure it. for(index=0; index<3; index++) { if(Timer1_Occupied_Pin[index] != 255) { if( (NRF_GPIO->IN >> Timer1_Occupied_Pin[index]) & 1UL ) { nrf_gpiote_task_config(GPIOTE_Channel_for_Analog[index], Timer1_Occupied_Pin[index], NRF_GPIOTE_POLARITY_TOGGLE, NRF_GPIOTE_INITIAL_VALUE_LOW); } } } NRF_TIMER1->EVENTS_COMPARE[3] = 0; }
/** Timer 2 peripheral interrupt handler. */ static void TIMER2_Interrupt(void) { // Update the CCx values NRF_TIMER2->CC[0] = PWM_Channels_Value[3]; if (PWM_Channels_Start[3] == 1) { nrf_gpiote_task_config(3, Timer2_Compare_Unit_Occupied_by_Pin[0], NRF_GPIOTE_POLARITY_TOGGLE, NRF_GPIOTE_INITIAL_VALUE_LOW); PWM_Channels_Start[3] = 0; } NRF_TIMER2->EVENTS_COMPARE[3] = 0; }
/** @brief Function for initializing the GPIO Tasks/Events peripheral. */ static void gpiote_init(void) { // Connect GPIO input buffers and configure PWM_OUTPUT_PIN_NUMBER as an output. nrf_gpio_range_cfg_input(BUTTON_START, BUTTON_STOP, BUTTON_PULL); nrf_gpio_cfg_output(PWM_OUTPUT_PIN_NUMBER); nrf_gpio_port_clear(NRF_GPIO_PORT_SELECT_PORT0, 0xFF); // Configure GPIOTE channel 0 to toggle the PWM pin state // @note Only one GPIOTE task can be connected to an output pin. nrf_gpiote_task_config(0, PWM_OUTPUT_PIN_NUMBER, \ NRF_GPIOTE_POLARITY_TOGGLE, NRF_GPIOTE_INITIAL_VALUE_LOW); }
/** @brief Function for initializing the GPIO peripheral. */ static void gpiote_init(void) { NRF_GPIO->OUT = 0x00000000UL; NRF_GPIO->DIRSET = 0x0000FF00UL; NRF_GPIO->DIRCLR = 0x000000FFUL; /* Configuring Button 0 as input */ nrf_gpio_cfg_input(BUTTON_0, BUTTON_PULL); /* Configuring Button 1 as input. */ /*lint -e{845} // A zero has been given as right argument to operator '|'" */ nrf_gpio_cfg_input(BUTTON_1, BUTTON_PULL); /* Configuring Pin PWM_OUTPUT_PIN_NUMBER as output to be used for the PWM waveform. */ nrf_gpio_cfg_output(PWM_OUTPUT_PIN_NUMBER); /* Configure GPIOTE channel 0 to toggle the PWM pin state. */ /* Note that we can only connect one GPIOTE task to one output pin. */ nrf_gpiote_task_config(0, PWM_OUTPUT_PIN_NUMBER, NRF_GPIOTE_POLARITY_TOGGLE, \ NRF_GPIOTE_INITIAL_VALUE_HIGH); }
/** Initializes GPIO Tasks/Events peripheral. */ static void gpiote_init(void) { NRF_GPIO->OUT = 0x00000000UL; NRF_GPIO->DIRSET = 0x0000FF00UL; NRF_GPIO->DIRCLR = 0x000000FFUL; /* Configuring Button 0 as input */ nrf_gpio_cfg_input(BUTTON0, NRF_GPIO_PIN_NOPULL); /* Configuring Button 1 as input */ /*lint -e{845} // A zero has been given as right argument to operator '|'" */ nrf_gpio_cfg_input(BUTTON1, NRF_GPIO_PIN_NOPULL); /* Configuring Pin PWM_OUTPUT_PIN_NUMBER as output to be used for the PWM waveform */ nrf_gpio_cfg_output(PWM_OUTPUT_PIN_NUMBER); *(uint32_t *)0x40000504 = 0xC007FFDF; // Workaround for PAN_028 rev1.1 anomaly 23 - System: Manual setup is required to enable use of peripherals /* Configure GPIOTE channel 0 to toggle the PWM pin state */ /* Note that we can only connect one GPIOTE task to an output pin */ nrf_gpiote_task_config(0, PWM_OUTPUT_PIN_NUMBER, NRF_GPIOTE_POLARITY_TOGGLE, NRF_GPIOTE_INITIAL_VALUE_HIGH); }
/********************************************************************** name : function : **********************************************************************/ void tone(uint32_t pin, uint16_t freq, uint32_t duration) { uint32_t i,prescaler, compare, nrf_pin, err_code = NRF_SUCCESS; uint8_t channel, softdevice_enabled; channel = gpioteChannelFind(); if(channel == UNAVAILABLE_GPIOTE_CHANNEL) { return; } nrf_pin = arduinoToVariantPin(pin); if(nrf_pin < 31) { //save the pin number tone_pin = nrf_pin; // Find appropriate values for PRESCALER and COMPARE registers for (i = 0; i <= 9; i++) { prescaler = i; compare = VARIANT_MCK / freq; compare = compare >> (prescaler+1); compare = compare - 1; if ((compare >= 2) && (compare <= 65535)) break; } //calculate the interrupts count if(duration > 0) { finish_flag = 1; inter_count = ((freq * duration) / 1000) * 2; } else { finish_flag = 0; inter_count = 0xFFFFFFFF; } // //pinMode(pin, OUTPUT); //digitalWrite(pin, LOW); NRF_GPIO->PIN_CNF[nrf_pin] = (GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos) | (GPIO_PIN_CNF_DRIVE_S0S1 << GPIO_PIN_CNF_DRIVE_Pos) | (GPIO_PIN_CNF_PULL_Disabled << GPIO_PIN_CNF_PULL_Pos) | (GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos) | (GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos); NRF_GPIO->OUTCLR = (1 << nrf_pin); //pin_state = 0; //use ppi and gpiote_task tone_channel = channel; gpioteChannelSet(channel); nrf_gpiote_task_config(channel, nrf_pin, NRF_GPIOTE_POLARITY_TOGGLE, NRF_GPIOTE_INITIAL_VALUE_LOW); //configure PPI err_code = sd_softdevice_is_enabled(&softdevice_enabled); APP_ERROR_CHECK(err_code); if (softdevice_enabled == 0) { NRF_PPI->CH[6].EEP = (uint32_t)( &NRF_TIMER2->EVENTS_COMPARE[0] ); NRF_PPI->CH[6].TEP = (uint32_t)( &NRF_GPIOTE->TASKS_OUT[channel]); NRF_PPI->CHEN |= ( 1 << 6); } else { err_code = sd_ppi_channel_assign(6, &NRF_TIMER2->EVENTS_COMPARE[0], &NRF_GPIOTE->TASKS_OUT[channel]); APP_ERROR_CHECK(err_code); err_code = sd_ppi_channel_enable_set(1 << 6); APP_ERROR_CHECK(err_code); } //Configure TIMER2 NRF_TIMER2->TASKS_STOP = 1; NRF_TIMER2->MODE = TIMER_MODE_MODE_Timer; NRF_TIMER2->PRESCALER = prescaler; NRF_TIMER2->BITMODE = TIMER_BITMODE_BITMODE_16Bit; NRF_TIMER2->SHORTS = (TIMER_SHORTS_COMPARE0_CLEAR_Enabled << TIMER_SHORTS_COMPARE0_CLEAR_Pos); NRF_TIMER2->TASKS_CLEAR = 1; NRF_TIMER2->CC[0] = (uint16_t)(compare); NRF_TIMER2->EVENTS_COMPARE[0] = 0; NRF_TIMER2->INTENCLR = 0xFFFFFFFF; NRF_TIMER2->INTENSET = (TIMER_INTENSET_COMPARE0_Enabled << TIMER_INTENSET_COMPARE0_Pos); //open IRQ IntController_linkInterrupt(TIMER2_IRQn, TIMER2_handler); NVIC_EnableIRQ(TIMER2_IRQn); NRF_TIMER2->TASKS_START = 1; }
void analogWrite(uint32_t ulPin, uint32_t ulValue) { if (ulValue == 0) { digitalWrite(ulPin, LOW); return; } if (ulValue == 255) { digitalWrite(ulPin, HIGH); return; } if (Timer1_Compare_Unit_Occupied_by_Pin[0] == ulPin) { update_PWM_value(ulPin, ulValue, 0); } else if (Timer1_Compare_Unit_Occupied_by_Pin[1] == ulPin) { update_PWM_value(ulPin, ulValue, 1); } else if (Timer1_Compare_Unit_Occupied_by_Pin[2] == ulPin) { update_PWM_value(ulPin, ulValue, 2); } else if (Timer2_Compare_Unit_Occupied_by_Pin[0] == ulPin) { update_PWM_value(ulPin, ulValue, 3); } else { if ((Timer1_Compare_Unit_Occupied_by_Pin[0] == 255) && (Timer1_Compare_Unit_Occupied_by_Pin[1] == 255) && (Timer1_Compare_Unit_Occupied_by_Pin[2] == 255)) { // Timer1 is not used: need to initialize it // Configure ulPin as output digitalWrite(ulPin, LOW); pinMode(ulPin, OUTPUT); if (ulValue > 0) { // Configure GPIOTE channel "gpiote_channel" to toggle the PWM pin state // Note that we can only connect one GPIOTE task to an output pin nrf_gpiote_task_config(0, ulPin, NRF_GPIOTE_POLARITY_TOGGLE, NRF_GPIOTE_INITIAL_VALUE_LOW); } GPIOTE_Channels_Occupied[ulPin] = 0; NRF_TIMER1->TASKS_STOP = 1; NRF_TIMER1->MODE = TIMER_MODE_MODE_Timer; //NRF_TIMER1->PRESCALER = 6; // Source clock frequency is divided by 2^6 = 64 NRF_TIMER1->PRESCALER = 0; // Source clock frequency is divided by 2^6 = 64 ///////////////////////////////////////// //NRF_TIMER1->BITMODE = TIMER_BITMODE_BITMODE_08Bit; NRF_TIMER1->BITMODE = TIMER_BITMODE_BITMODE_16Bit; //////////////////////////// // Clears the timer, sets it to 0 NRF_TIMER1->TASKS_CLEAR = 1; NRF_TIMER1->CC[0] = (2^PWM_RESOLUTION - 1); NRF_TIMER1->CC[1] = (2^PWM_RESOLUTION - 1); NRF_TIMER1->CC[2] = (2^PWM_RESOLUTION - 1); NRF_TIMER1->CC[3] = 0; NRF_TIMER1->EVENTS_COMPARE[0] = 0; NRF_TIMER1->EVENTS_COMPARE[1] = 0; NRF_TIMER1->EVENTS_COMPARE[2] = 0; NRF_TIMER1->EVENTS_COMPARE[3] = 0; // Interrupt setup NRF_TIMER1->INTENSET = (TIMER_INTENSET_COMPARE3_Enabled << TIMER_INTENSET_COMPARE3_Pos); attachInterrupt(TIMER1_IRQn, TIMER1_Interrupt); // Start clock NRF_TIMER1->TASKS_START = 1; turn_On_PPI_to_GPIO_for_PWM(ulPin, 0, NRF_TIMER1, 0); PWM_Channels_Value[0] = (2^PWM_RESOLUTION - 1) - mapResolution(ulValue, _writeResolution, PWM_RESOLUTION); Timer1_Compare_Unit_Occupied_by_Pin[0] = ulPin; Pin_Occupied_for_PWM[ulPin] = 1; } else { if (Timer1_Compare_Unit_Occupied_by_Pin[0] == 255) { // Configure ulPin as output digitalWrite(ulPin, LOW); pinMode(ulPin, OUTPUT); if (ulValue > 0) { // Configure GPIOTE channel "gpiote_channel" to toggle the PWM pin state // Note that we can only connect one GPIOTE task to an output pin nrf_gpiote_task_config(0, ulPin, NRF_GPIOTE_POLARITY_TOGGLE, NRF_GPIOTE_INITIAL_VALUE_LOW); } GPIOTE_Channels_Occupied[ulPin] = 0; turn_On_PPI_to_GPIO_for_PWM(ulPin, 0, NRF_TIMER1, 0); PWM_Channels_Value[0] = (2^PWM_RESOLUTION - 1) - mapResolution(ulValue, _writeResolution, PWM_RESOLUTION); Timer1_Compare_Unit_Occupied_by_Pin[0] = ulPin; Pin_Occupied_for_PWM[ulPin] = 1; NRF_TIMER1->EVENTS_COMPARE[0] = 0; } else if (Timer1_Compare_Unit_Occupied_by_Pin[1] == 255) { // Configure ulPin as output digitalWrite(ulPin, LOW); pinMode(ulPin, OUTPUT); if (ulValue > 0) { // Configure GPIOTE channel "gpiote_channel" to toggle the PWM pin state // Note that we can only connect one GPIOTE task to an output pin nrf_gpiote_task_config(1, ulPin, NRF_GPIOTE_POLARITY_TOGGLE, NRF_GPIOTE_INITIAL_VALUE_LOW); } GPIOTE_Channels_Occupied[ulPin] = 1; turn_On_PPI_to_GPIO_for_PWM(ulPin, 1, NRF_TIMER1, 1); PWM_Channels_Value[1] = (2^PWM_RESOLUTION - 1) - mapResolution(ulValue, _writeResolution, PWM_RESOLUTION); Timer1_Compare_Unit_Occupied_by_Pin[1] = ulPin; Pin_Occupied_for_PWM[ulPin] = 1; NRF_TIMER1->EVENTS_COMPARE[1] = 0; } else if (Timer1_Compare_Unit_Occupied_by_Pin[2] == 255) { // Configure ulPin as output digitalWrite(ulPin, LOW); pinMode(ulPin, OUTPUT); if (ulValue > 0) { // Configure GPIOTE channel "gpiote_channel" to toggle the PWM pin state // Note that we can only connect one GPIOTE task to an output pin nrf_gpiote_task_config(2, ulPin, NRF_GPIOTE_POLARITY_TOGGLE, NRF_GPIOTE_INITIAL_VALUE_LOW); } GPIOTE_Channels_Occupied[ulPin] = 2; turn_On_PPI_to_GPIO_for_PWM(ulPin, 2, NRF_TIMER1, 2); PWM_Channels_Value[2] = (2^PWM_RESOLUTION - 1) - mapResolution(ulValue, _writeResolution, PWM_RESOLUTION); Timer1_Compare_Unit_Occupied_by_Pin[2] = ulPin; Pin_Occupied_for_PWM[ulPin] = 1; NRF_TIMER1->EVENTS_COMPARE[2] = 0; } else { // All channels of Timer1 is occupied, need to use Timer2 if (!RFduinoGZLL_used && Timer2_Compare_Unit_Occupied_by_Pin[0] == 255) { // Timer2 is not used: need to initialize it // Configure ulPin as output digitalWrite(ulPin, LOW); pinMode(ulPin, OUTPUT); if (ulValue > 0) { // Configure GPIOTE channel "gpiote_channel" to toggle the PWM pin state // Note that we can only connect one GPIOTE task to an output pin nrf_gpiote_task_config(3, ulPin, NRF_GPIOTE_POLARITY_TOGGLE, NRF_GPIOTE_INITIAL_VALUE_LOW); } GPIOTE_Channels_Occupied[ulPin] = 3; NRF_TIMER2->TASKS_STOP = 1; NRF_TIMER2->MODE = TIMER_MODE_MODE_Timer; //NRF_TIMER2->PRESCALER = 6; // Source clock frequency is divided by 2^6 = 64 NRF_TIMER2->PRESCALER = 0; // Source clock frequency is divided by 2^6 = 64 ///////////////////////////////////////// //NRF_TIMER2->BITMODE = TIMER_BITMODE_BITMODE_08Bit; NRF_TIMER2->BITMODE = TIMER_BITMODE_BITMODE_16Bit; //////////////////////////// // Clears the timer, sets it to 0 NRF_TIMER2->TASKS_CLEAR = 1; NRF_TIMER2->CC[0] = (2^PWM_RESOLUTION - 1); NRF_TIMER2->CC[3] = 0; NRF_TIMER2->EVENTS_COMPARE[0] = 0; NRF_TIMER2->EVENTS_COMPARE[3] = 0; // Interrupt setup NRF_TIMER2->INTENSET = (TIMER_INTENSET_COMPARE3_Enabled << TIMER_INTENSET_COMPARE3_Pos); attachInterrupt(TIMER2_IRQn, TIMER2_Interrupt); // Start clock NRF_TIMER2->TASKS_START = 1; turn_On_PPI_to_GPIO_for_PWM(ulPin, 3, NRF_TIMER2, 0); PWM_Channels_Value[3] = (2^PWM_RESOLUTION - 1) - mapResolution(ulValue, _writeResolution, PWM_RESOLUTION); Timer2_Compare_Unit_Occupied_by_Pin[0] = ulPin; Pin_Occupied_for_PWM[ulPin] = 1; } else { // Using all 4 TASK channels of GPIOTE, it is not possible to add another PWM channel. } } } } /* // Defaults to digital write pinMode(ulPin, OUTPUT); ulValue = mapResolution(ulValue, _writeResolution, 8); if (ulValue < 128) digitalWrite(ulPin, LOW); else digitalWrite(ulPin, HIGH); */ }
int main() { static char address[5]; sd_mbr_command(&startSdCmd); sd_softdevice_vector_table_base_set(BOOTLOADER_ADDRESS); // If the master boot switch has detected short or no click: boot the firmware if (((NRF_POWER->GPREGRET&0x86U) != 0x82U) && ((NRF_POWER->GPREGRET&0x40U) != 0x40U) && (*(uint32_t *)FW_ADDRESS != 0xFFFFFFFFU) ) { start_firmware(); } if (NRF_POWER->GPREGRET&0x40U) { address[4] = 0xb1; memcpy(&address[0], (char*)&NRF_FICR->DEVICEADDR[0], 4); esbSetAddress(address); } NRF_POWER->GPREGRET &= ~(0x60U); // Enable the radio LNA nrf_gpio_cfg_output(RADIO_PAEN_PIN); nrf_gpio_pin_set(RADIO_PAEN_PIN); // Initialize timer module. APP_TIMER_INIT(APP_TIMER_PRESCALER, APP_TIMER_MAX_TIMERS, APP_TIMER_OP_QUEUE_SIZE, false); ble_init(); /* NRF_CLOCK->LFCLKSRC = CLOCK_LFCLKSTAT_SRC_Synth; NRF_CLOCK->TASKS_LFCLKSTART = 1UL; while(!NRF_CLOCK->EVENTS_LFCLKSTARTED); */ systickInit(); buttonInit(buttonIdle); #ifndef DEBUG_TIMESLOT //sd_ppi_channel_assign(0, &(NRF_TIMER1->EVENTS_COMPARE[0]), &(NRF_GPIOTE->TASKS_OUT[0])); //sd_ppi_channel_enable_set(PPI_CHEN_CH0_Msk); //NRF_PPI->CH[0].EEP = &(NRF_TIMER1->EVENTS_COMPARE[0]); //NRF_PPI->CH[0].TEP = &(NRF_GPIOTE->TASKS_OUT[0]); //NRF_PPI->CHENSET = 1; #endif // Start (or continue) to blink the LED at 0.5Hz //NRF_TIMER1->TASKS_STOP = 1; //NRF_TIMER1->MODE = TIMER_MODE_MODE_Timer; //NRF_TIMER1->PRESCALER = 7; //NRF_TIMER1->BITMODE = TIMER_BITMODE_BITMODE_16Bit << TIMER_BITMODE_BITMODE_Pos; //NRF_TIMER1->SHORTS = TIMER_SHORTS_COMPARE0_CLEAR_Msk; // | TIMER_SHORTS_COMPARE1_CLEAR_Msk; //NRF_TIMER1->TASKS_CLEAR = 1; NRF_TIMER1->CC[0] = 1*SEC; //0x1E84 ; NRF_TIMER1->CC[1] = 2*SEC; nrf_gpio_cfg_output(LED_PIN); nrf_gpiote_task_config(0, LED_PIN, NRF_GPIOTE_POLARITY_TOGGLE, NRF_GPIOTE_INITIAL_VALUE_LOW); NRF_TIMER1->TASKS_START = 1; // Enable 500mA USB input and enable battery charging nrf_gpio_cfg_output(PM_EN1); nrf_gpio_pin_set(PM_EN1); nrf_gpio_cfg_output(PM_EN2); nrf_gpio_pin_clear(PM_EN2); nrf_gpio_cfg_output(PM_CHG_EN); nrf_gpio_pin_clear(PM_CHG_EN); // Power STM32, hold reset nrf_gpio_cfg_output(PM_VCCEN_PIN); nrf_gpio_pin_set(PM_VCCEN_PIN); nrf_gpio_cfg_output(STM_NRST_PIN); nrf_gpio_pin_clear(STM_NRST_PIN); // Set flow control and activate pull-down on RX data pin nrf_gpio_cfg_output(UART_TX_PIN); nrf_gpio_pin_set(UART_TX_PIN); nrf_gpio_cfg_output(UART_RTS_PIN); nrf_gpio_pin_set(UART_RTS_PIN); nrf_gpio_cfg_input(UART_RX_PIN, NRF_GPIO_PIN_PULLDOWN); nrf_gpio_pin_set(STM_NRST_PIN); //systickInit(); //syslinkInit(); //buttonInit(); // nrf_gpio_cfg_input(BUTTON_PIN, NRF_GPIO_PIN_PULLUP); mainLoop(); while(1); }
/********************************************************************** name : function : **********************************************************************/ void analogWrite(uint32_t ulPin, uint32_t ulValue) { uint32_t nrf_pin, max_value, err_code = NRF_SUCCESS , crystal_is_running=0; uint8_t gpiote_channel; nrf_pin = Pin_nRF51822_to_Arduino(ulPin); if( nrf_pin < 31) { //if vaule 0 or >255, set LOW or HIGH if(ulValue <= 0) { PPI_Off_FROM_GPIO(nrf_pin); NRF_GPIO->OUTCLR = (1 << nrf_pin); return; } max_value = (uint32_t)( pow(2, analogWriteResolution_bit) - 1 ); if(ulValue >= max_value ) { ulValue = max_value - 1; } //if exist, update the value if (Timer1_Occupied_Pin[0] == nrf_pin) { update_PWM_value(nrf_pin, ulValue, 0); } else if (Timer1_Occupied_Pin[1] == nrf_pin) { update_PWM_value(nrf_pin, ulValue, 1); } else if (Timer1_Occupied_Pin[2] == nrf_pin) { update_PWM_value(nrf_pin, ulValue, 2); } else { if ((Timer1_Occupied_Pin[0] == 255) && (Timer1_Occupied_Pin[1] == 255) && (Timer1_Occupied_Pin[2] == 255)) { // Configure ulPin as output NRF_GPIO->PIN_CNF[nrf_pin] = (GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos) | (GPIO_PIN_CNF_DRIVE_H0H1 << GPIO_PIN_CNF_DRIVE_Pos) | (GPIO_PIN_CNF_PULL_Disabled << GPIO_PIN_CNF_PULL_Pos) | (GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos) | (GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos); NRF_GPIO->OUTCLR = (1 << nrf_pin); //fine a free gpiote channel gpiote_channel = GPIOTE_Channel_Find(); if( gpiote_channel == 255 ) { return; } //configure TIMER1 NRF_TIMER1->TASKS_STOP = 1; NRF_TIMER1->MODE = TIMER_MODE_MODE_Timer; NRF_TIMER1->PRESCALER = 0; // Source clock frequency is divided by 2^6 = 64 //NRF_TIMER1->BITMODE = TIMER_BITMODE_BITMODE_08Bit; NRF_TIMER1->BITMODE = TIMER_BITMODE_BITMODE_16Bit; // Clears the timer, sets it to 0 NRF_TIMER1->TASKS_CLEAR = 1; NRF_TIMER1->CC[0] = ((2^PWM_RESOLUTION) - 1); NRF_TIMER1->CC[1] = ((2^PWM_RESOLUTION) - 1); NRF_TIMER1->CC[2] = ((2^PWM_RESOLUTION) - 1); NRF_TIMER1->CC[3] = 0; NRF_TIMER1->EVENTS_COMPARE[0] = 0; NRF_TIMER1->EVENTS_COMPARE[1] = 0; NRF_TIMER1->EVENTS_COMPARE[2] = 0; NRF_TIMER1->EVENTS_COMPARE[3] = 0; //Interrupt setup NRF_TIMER1->INTENSET = (TIMER_INTENSET_COMPARE3_Enabled << TIMER_INTENSET_COMPARE3_Pos); LinkInterrupt( TIMER1_IRQn, TIMER1_handler ); //can't set low priority, else the GPIO polarity will change //NVIC_SetPriority(TIMER1_IRQn, 3); //NVIC_ClearPendingIRQ(TIMER1_IRQn); NVIC_EnableIRQ(TIMER1_IRQn); NRF_TIMER1->TASKS_START = 1; // PPI for TIMER1 and IO TASK nrf_gpiote_task_config(gpiote_channel, nrf_pin, NRF_GPIOTE_POLARITY_TOGGLE, NRF_GPIOTE_INITIAL_VALUE_LOW); GPIOTE_Channel_Set(gpiote_channel); PPI_ON_TIMER_GPIO(gpiote_channel, NRF_TIMER1, 0); //Save pin , channel and value GPIOTE_Channel_for_Analog[0] = gpiote_channel; PWM_Channels_Value[0] = ((2^PWM_RESOLUTION) - 1) - conversion_Resolution(ulValue, analogWriteResolution_bit, PWM_RESOLUTION); Timer1_Occupied_Pin[0] = nrf_pin; } else { if (Timer1_Occupied_Pin[0] == 255) { NRF_GPIO->PIN_CNF[nrf_pin] = (GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos) | (GPIO_PIN_CNF_DRIVE_H0H1 << GPIO_PIN_CNF_DRIVE_Pos) | (GPIO_PIN_CNF_PULL_Disabled << GPIO_PIN_CNF_PULL_Pos) | (GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos) | (GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos); NRF_GPIO->OUTCLR = (1 << nrf_pin); //fine a free gpiote channel and configure the channel gpiote_channel = GPIOTE_Channel_Find(); if( gpiote_channel == 255 ) { return; } nrf_gpiote_task_config(gpiote_channel, nrf_pin, NRF_GPIOTE_POLARITY_TOGGLE, NRF_GPIOTE_INITIAL_VALUE_LOW); GPIOTE_Channel_Set(gpiote_channel); PPI_ON_TIMER_GPIO(gpiote_channel, NRF_TIMER1, 0); //save the pin and value GPIOTE_Channel_for_Analog[0] = gpiote_channel; PWM_Channels_Value[0] = ((2^PWM_RESOLUTION) - 1) - conversion_Resolution(ulValue, analogWriteResolution_bit, PWM_RESOLUTION); Timer1_Occupied_Pin[0] = nrf_pin; NRF_TIMER1->EVENTS_COMPARE[0] = 0; } else if (Timer1_Occupied_Pin[1] == 255) { NRF_GPIO->PIN_CNF[nrf_pin] = (GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos) | (GPIO_PIN_CNF_DRIVE_H0H1 << GPIO_PIN_CNF_DRIVE_Pos) | (GPIO_PIN_CNF_PULL_Disabled << GPIO_PIN_CNF_PULL_Pos) | (GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos) | (GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos); NRF_GPIO->OUTCLR = (1 << nrf_pin); //find a free gpiote channel gpiote_channel = GPIOTE_Channel_Find(); if( gpiote_channel == 255 ) { return; } nrf_gpiote_task_config(gpiote_channel, nrf_pin, NRF_GPIOTE_POLARITY_TOGGLE, NRF_GPIOTE_INITIAL_VALUE_LOW); GPIOTE_Channel_Set(gpiote_channel); PPI_ON_TIMER_GPIO(gpiote_channel, NRF_TIMER1, 1); //save the pin and value GPIOTE_Channel_for_Analog[1] = gpiote_channel; PWM_Channels_Value[1] = ((2^PWM_RESOLUTION) - 1) - conversion_Resolution(ulValue, analogWriteResolution_bit, PWM_RESOLUTION); Timer1_Occupied_Pin[1] = nrf_pin; NRF_TIMER1->EVENTS_COMPARE[1] = 0; } else if (Timer1_Occupied_Pin[2] == 255) { NRF_GPIO->PIN_CNF[nrf_pin] = (GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos) | (GPIO_PIN_CNF_DRIVE_H0H1 << GPIO_PIN_CNF_DRIVE_Pos) | (GPIO_PIN_CNF_PULL_Disabled << GPIO_PIN_CNF_PULL_Pos) | (GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos) | (GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos); NRF_GPIO->OUTCLR = (1 << nrf_pin); //find a free gpiote channel gpiote_channel = GPIOTE_Channel_Find(); if( gpiote_channel == 255 ) { return; } nrf_gpiote_task_config(gpiote_channel, nrf_pin, NRF_GPIOTE_POLARITY_TOGGLE, NRF_GPIOTE_INITIAL_VALUE_LOW); GPIOTE_Channel_Set(gpiote_channel); PPI_ON_TIMER_GPIO(gpiote_channel, NRF_TIMER1, 2); //save the pin and value GPIOTE_Channel_for_Analog[2] = gpiote_channel; PWM_Channels_Value[2] = ((2^PWM_RESOLUTION) - 1) - conversion_Resolution(ulValue, analogWriteResolution_bit, PWM_RESOLUTION); Timer1_Occupied_Pin[2] = nrf_pin; NRF_TIMER1->EVENTS_COMPARE[2] = 0; } else { //no more } } } } }
void nrf_pwm_set_value(uint32_t pwm_channel, uint32_t pwm_value) { if (pwm_value == PWM_TIMER->CC[pwm_channel]) { // No change necessary return; } if (PWM_TIMER->CC[pwm_channel] == 0) { // This PWM is not running if (pwm_value == 0) { // Corner case: This PWM is not running and new value is 0% duty cycle NRF_GPIO->OUTCLR = (1 << pwm_io_ch[pwm_channel]); PWM_TIMER->CC[pwm_channel] = pwm_value; return; } else if (pwm_value >= pwm_max_value) { // Corner case: This PWM is not running and new value is 100% duty cycle NRF_GPIO->OUTSET = (1 << pwm_io_ch[pwm_channel]); PWM_TIMER->CC[pwm_channel] = pwm_value; return; } ppi_disable_channels((1 << (pwm_channel * 2)) | (1 << (pwm_channel * 2 + 1))); PWM_TIMER->CC[pwm_channel] = pwm_value * 2; if (NRF_GPIO->OUT & (1 << pwm_io_ch[pwm_channel])) { // PWM is currently in 100% duty cycle nrf_gpiote_task_config(pwm_gpiote_channel[pwm_channel], pwm_io_ch[pwm_channel], NRF_GPIOTE_POLARITY_TOGGLE, NRF_GPIOTE_INITIAL_VALUE_HIGH); ppi_configure_channel_group(pwm_ppi_chg, 0); ppi_disable_channel_group(pwm_ppi_chg); ppi_configure_channel_group(pwm_ppi_chg, (1 << (pwm_channel * 2)) | (1 << (pwm_channel * 2 + 1))); ppi_disable_channels(1 << (PWM_MAX_CHANNELS * 2)); ppi_configure_channel(PWM_MAX_CHANNELS * 2, &PWM_TIMER->EVENTS_COMPARE[3], &NRF_PPI->TASKS_CHG[pwm_ppi_chg].EN); ppi_enable_channels(1 << (PWM_MAX_CHANNELS * 2)); } else { // PWM is currently in 0% duty cycle nrf_gpiote_task_config(pwm_gpiote_channel[pwm_channel], pwm_io_ch[pwm_channel], NRF_GPIOTE_POLARITY_TOGGLE, NRF_GPIOTE_INITIAL_VALUE_LOW); ppi_configure_channel_group(pwm_ppi_chg, 0); ppi_disable_channel_group(pwm_ppi_chg); ppi_configure_channel_group(pwm_ppi_chg, (1 << (pwm_channel * 2)) | (1 << (pwm_channel * 2 + 1))); ppi_disable_channels(1 << (PWM_MAX_CHANNELS * 2)); ppi_configure_channel(PWM_MAX_CHANNELS * 2, &PWM_TIMER->EVENTS_COMPARE[pwm_channel], &NRF_PPI->TASKS_CHG[pwm_ppi_chg].EN); ppi_enable_channels(1 << (PWM_MAX_CHANNELS * 2)); } // Disable PPI channels next cycle pwm_freq_int_set(); return; } if (pwm_value == 0) { // Corner case: 0% duty cycle NRF_GPIO->OUTCLR = (1 << pwm_io_ch[pwm_channel]); ppi_configure_channel_group(pwm_ppi_chg, 0); ppi_enable_channel_group(pwm_ppi_chg); ppi_configure_channel_group(pwm_ppi_chg, (1 << (pwm_channel * 2)) | (1 << (pwm_channel * 2 + 1))); ppi_configure_channel(PWM_MAX_CHANNELS * 2, &PWM_TIMER->EVENTS_COMPARE[pwm_channel], &NRF_PPI->TASKS_CHG[pwm_ppi_chg].DIS); ppi_enable_channels(1 << (PWM_MAX_CHANNELS * 2)); // Wait for one PWM clock cycle nrf_delay_us(pwm_period_us); PWM_TIMER->CC[pwm_channel] = 0; ppi_disable_channels(1 << (PWM_MAX_CHANNELS * 2)); ppi_configure_channel_group(pwm_ppi_chg, 0); nrf_gpiote_unconfig(pwm_gpiote_channel[pwm_channel]); } else if (pwm_value >= pwm_max_value) { // Corner case: 100% duty cycle NRF_GPIO->OUTSET = (1 << pwm_io_ch[pwm_channel]); ppi_disable_channels(1 << (PWM_MAX_CHANNELS * 2)); ppi_configure_channel_group(pwm_ppi_chg, 0); ppi_enable_channel_group(pwm_ppi_chg); ppi_configure_channel_group(pwm_ppi_chg, (1 << (pwm_channel * 2)) | (1 << (pwm_channel * 2 + 1))); ppi_configure_channel(PWM_MAX_CHANNELS * 2, &PWM_TIMER->EVENTS_COMPARE[3], &NRF_PPI->TASKS_CHG[pwm_ppi_chg].DIS); ppi_enable_channels(1 << (PWM_MAX_CHANNELS * 2)); // Wait for one PWM clock cycle nrf_delay_us(pwm_period_us); ppi_disable_channels(1 << (PWM_MAX_CHANNELS * 2)); ppi_configure_channel_group(pwm_ppi_chg, 0); PWM_TIMER->CC[pwm_channel] = 0; // 100% duty cycle nrf_gpiote_unconfig(pwm_gpiote_channel[pwm_channel]); return; } else if ((pwm_value * 2) > PWM_TIMER->CC[pwm_channel]) { // New duty cycle is larger than the current one ppi_disable_channels(1 << (PWM_MAX_CHANNELS * 2)); PWM_TIMER->CC[2] = pwm_value * 2; ppi_configure_channel(PWM_MAX_CHANNELS * 2, &PWM_TIMER->EVENTS_COMPARE[2], &PWM_TIMER->TASKS_CAPTURE[pwm_channel]); ppi_enable_channels(1 << (PWM_MAX_CHANNELS * 2)); // Disable PPI channels next cycle pwm_freq_int_set(); } else { // New duty cycle is smaller than the current one ppi_disable_channels((1 << (PWM_MAX_CHANNELS * 2)) | (1 << (PWM_MAX_CHANNELS * 2 + 1)) | (1 << (PWM_MAX_CHANNELS * 2 + 2))); ppi_configure_channel_group(pwm_ppi_chg, 0); ppi_disable_channel_group(pwm_ppi_chg); ppi_configure_channel_group(pwm_ppi_chg, (1 << (PWM_MAX_CHANNELS * 2)) | (1 << (PWM_MAX_CHANNELS * 2 + 1))); ppi_configure_channel(PWM_MAX_CHANNELS * 2, &PWM_TIMER->EVENTS_COMPARE[2], &NRF_GPIOTE->TASKS_OUT[pwm_gpiote_channel[pwm_channel]]); ppi_configure_channel(PWM_MAX_CHANNELS * 2 + 1, &PWM_TIMER->EVENTS_COMPARE[2], &PWM_TIMER->TASKS_CAPTURE[pwm_channel]); ppi_configure_channel(PWM_MAX_CHANNELS * 2 + 2, &PWM_TIMER->EVENTS_COMPARE[3], &NRF_PPI->TASKS_CHG[pwm_ppi_chg].EN); PWM_TIMER->CC[2] = pwm_value * 2; ppi_enable_channels(1 << (PWM_MAX_CHANNELS * 2 + 2)); // Disable PPI channels next cycle pwm_freq_int_set(); } }