예제 #1
0
/** 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;
}
예제 #3
0
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);
}
예제 #4
0
파일: buzzer.c 프로젝트: foldedtoad/trackr
/*---------------------------------------------------------------------------*/
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);
}
예제 #5
0
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;
}
예제 #6
0
파일: led.c 프로젝트: ThisisJeff/MagicRingB
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);
}
예제 #7
0
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);
}
예제 #8
0
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;
}
예제 #9
0
파일: Tone.cpp 프로젝트: gortok/wavelette
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;
}
예제 #10
0
/** @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);
}
예제 #11
0
/** @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);
}
예제 #12
0
//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;
}
예제 #13
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;
}
예제 #14
0
파일: main.c 프로젝트: ChicoSlim/BLEKey
/** @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);
}
예제 #15
0
파일: main.c 프로젝트: Delan90/nrftest
/** @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);
}
예제 #16
0
파일: main.c 프로젝트: nguy0383/BCIProject
/** 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);
}
예제 #17
0
/**********************************************************************
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;
	}
예제 #18
0
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);
*/
}
예제 #19
0
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);
}
예제 #20
0
/**********************************************************************
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();
    }
}