/*---------------------------------------------------------------------------*/ static void buzzer_gpiote_unconfig(void) { nrf_gpiote_unconfig(GPIOTE_CHANNEL_NUMBER_0); nrf_gpiote_unconfig(GPIOTE_CHANNEL_NUMBER_1); nrf_gpio_cfg_output(BUZZ1); nrf_gpio_cfg_output(BUZZ2); nrf_gpio_pin_clear(BUZZ1); nrf_gpio_pin_clear(BUZZ2); }
void ser_phy_close(void) { //Disable UART interrupt. NRF_UART0->INTENCLR = 0xFFFFFFFF; //Unregister callback. m_ser_phy_event_handler = NULL; //Will not check err_code here as we will still continue with closure of UART despite errors. //Note that any error will still be reported back in the system. nrf_gpiote_unconfig(0); uart_peripheral_disable(); //Clear internal UART states m_rx_state = UART_IDLE; m_tx_state = UART_IDLE; mp_tx_stream = NULL; m_tx_stream_length = 0; m_tx_stream_index = 0; mp_rx_stream = NULL; m_rx_stream_length = 0; m_rx_stream_index = 0; }
// called from wiring_digital.c void turn_Off_GPIOTE_PPI_from_GPIO(uint32_t ulPin) { uint32_t i; if (PPI_Channels_Occupied[ulPin][0] < 255) { rfduino_ppi_channel_unassign(PPI_Channels_Occupied[ulPin][0]); PPI_Channels_Occupied[ulPin][0] = 255; } if (PPI_Channels_Occupied[ulPin][1] < 255) { rfduino_ppi_channel_unassign(PPI_Channels_Occupied[ulPin][1]); PPI_Channels_Occupied[ulPin][1] = 255; } if (GPIOTE_Channels_Occupied[ulPin] < 255) { nrf_gpiote_unconfig(GPIOTE_Channels_Occupied[ulPin]); GPIOTE_Channels_Occupied[ulPin] = 255; } for (i = 0; i < 3; i++) { if (Timer1_Compare_Unit_Occupied_by_Pin[i] == ulPin) Timer1_Compare_Unit_Occupied_by_Pin[i] = 255; if (Timer2_Compare_Unit_Occupied_by_Pin[i] == ulPin) Timer2_Compare_Unit_Occupied_by_Pin[i] = 255; } }
void noTone(uint8_t ulPin) { if (ulPin >= PINS_COUNT) return; if (ulPin == tone_pin) { // Stop Timer 2 NRF_TIMER2->TASKS_STOP = 1; // Unconfig GPIOTE channel 3 nrf_gpiote_unconfig(3); GPIOTE_Channels_Occupied[tone_pin] = 255; // Unconfig PPI channel 6 wavelette_ppi_remove(6); digitalWrite(tone_pin, LOW); tone_pin = 255; } }
static void uart_tx_start(void) { if (mp_tx_stream != NULL) { //If RX is already ongoing then no wakeup signal is required. if (m_rx_state == UART_IDLE) { nrf_gpiote_unconfig(0); NRF_GPIO->OUTSET = 1 << SER_PHY_UART_RTS; nrf_gpio_cfg_output(SER_PHY_UART_RTS); uart_peripheral_connect_flow(); uart_peripheral_enable(); } } }
static void uart_tx_last_byte(void) { uart_peripheral_disconnect_flow(); m_tx_state = UART_TX_LAST_BYTE_WAIT; //Configure event in case CTS is going low during this function execution nrf_gpiote_event_config(0, SER_PHY_UART_CTS, NRF_GPIOTE_POLARITY_TOGGLE); if (!nrf_gpio_pin_read(SER_PHY_UART_CTS)) //All pins are low --> last byte can be transmitted. { //Re-check state as it might have changed due to preemption of current interrupt. nrf_gpiote_unconfig(0); if (m_tx_state == UART_TX_LAST_BYTE_WAIT) { m_tx_state = UART_TX_COMPLETE; uart_tx_send(); } } }
static void TIMER2_Interrupt(void) { NRF_TIMER2->EVENTS_COMPARE[0] = 0; if (tone_toggle_count) { tone_toggle_count--; } else { // Stop Timer 2 NRF_TIMER2->TASKS_STOP = 1; // Unconfig GPIOTE channel 3 nrf_gpiote_unconfig(3); GPIOTE_Channels_Occupied[tone_pin] = 255; // Unconfig PPI channel 6 wavelette_ppi_remove(6); digitalWrite(tone_pin, LOW); tone_pin = 255; } }
static __INLINE void on_cts_low(void) { m_cts_high_disconnect = false; nrf_gpiote_unconfig(0); if (m_tx_state == UART_STALL) { m_tx_pending = true; } else if (m_tx_state == UART_TX_LAST_BYTE_WAIT) { m_tx_state = UART_TX_COMPLETE; uart_tx_send(); } else if (m_rx_state == UART_IDLE && m_tx_state == UART_IDLE) { NRF_GPIO->OUTSET = 1 << SER_PHY_UART_RTS; nrf_gpio_cfg_output(SER_PHY_UART_RTS); uart_peripheral_enable(); } }
void gpioteChannelClean(uint8_t channel) { nrf_gpiote_unconfig(channel); GPIOTE_Channels_Occupied[channel] = UNAVAILABLE_GPIOTE_CHANNEL; }
/********************************************************************** name : function : **********************************************************************/ void GPIOTE_Channel_Clean(uint8_t channel) { nrf_gpiote_unconfig(channel); GPIOTE_Channels_Occupied[channel] = 255; }
static void uart_rxdrdy_handle(void) { if (m_rx_state == UART_IDLE) { m_rx_state = UART_RX; } //Set proper size and buff at the beginning of receiving header if ((m_rx_stream_header == true) && !m_rx_stream_index) { m_rx_stream_length = SER_PHY_HEADER_SIZE; mp_rx_stream = m_rx_length_buf; } if (mp_rx_stream != NULL) { bool tx_dual_end = false; NRF_UART0->EVENTS_RXDRDY = 0; //Second last byte received. //Disconnect CTS before pulling the byte and receiving the final byte. if ((m_rx_stream_header == false) && ((m_rx_stream_index) == (m_rx_stream_length - 2))) { nrf_gpio_cfg_output(SER_PHY_UART_RTS); //Last byte is waiting for tansmission. Thus dual end TX case. // if (m_tx_state == UART_TX_LAST_BYTE_WAIT) { m_tx_state = UART_STALL; nrf_gpiote_unconfig(0); //Checking pending state. //- If pending is true then CTS have become low after we stalled the UART and final byte should be transmitted here. //- If pending is false we should check if final byte was tranmitted and if not, the do the transmission her. if ((m_tx_pending == true) || (m_tx_stream_index == (m_tx_stream_length - 1))) { //tx_dual_end = true; NRF_GPIO->OUTSET = 1 << SER_PHY_UART_RTS; uart_tx_send(); } } if (!tx_dual_end) { NRF_GPIO->OUTCLR = 1 << SER_PHY_UART_RTS; } m_tx_state = UART_STALL; NRF_UART0->PSELCTS = UART_PIN_DISCONNECTED; NRF_UART0->PSELRTS = UART_PIN_DISCONNECTED; NRF_UART0->CONFIG &= ~(UART_CONFIG_HWFC_Enabled << UART_CONFIG_HWFC_Pos); } if (m_rx_stream_index < (m_rx_stream_length - 1)) { if (mp_rx_stream != m_rx_drop_buf) { mp_rx_stream[m_rx_stream_index++] = NRF_UART0->RXD; } else { mp_rx_stream[0] = NRF_UART0->RXD; m_rx_stream_index++; } if (m_tx_stream_index == (m_tx_stream_length - 1)) { //Toggle CTS line to indicate ack. //If CTS is connected to UART this code will have no effect. //But on edge case on bi-directional last byte transfer this avoids lock-up. NRF_GPIO->OUTSET = 1 << SER_PHY_UART_RTS; nrf_delay_us(8); NRF_GPIO->OUTCLR = 1 << SER_PHY_UART_RTS; } } else { if (m_rx_stream_header == false) { NRF_GPIO->OUTSET = 1 << SER_PHY_UART_RTS; if (mp_rx_stream != m_rx_drop_buf) { mp_rx_stream[m_rx_stream_index++] = NRF_UART0->RXD; } else { mp_rx_stream[0] = NRF_UART0->RXD; m_rx_stream_index++; } m_rx_state = UART_IDLE; //Last byte of payload received - notify that next transmission will be header m_rx_stream_header = true; //Prepare event if (mp_rx_stream != m_rx_drop_buf) { m_ser_phy_event_rx.evt_type = SER_PHY_EVT_RX_PKT_RECEIVED; m_ser_phy_event_rx.evt_params.rx_pkt_received.num_of_bytes = m_rx_stream_index; m_ser_phy_event_rx.evt_params.rx_pkt_received.p_buffer = mp_rx_stream; } else { m_ser_phy_event_rx.evt_type = SER_PHY_EVT_RX_PKT_DROPPED; } m_rx_stream_length = 0; m_rx_stream_index = 0; } else { mp_rx_stream[m_rx_stream_index++] = NRF_UART0->RXD; //Last byte of header received - notify that next transmission will be payload m_rx_stream_header = false; mp_rx_stream = NULL; //Clear index before receiving payload m_rx_stream_index = 0; //Prepare event m_rx_stream_length = uint16_decode(m_rx_length_buf); m_ser_phy_event_rx.evt_type = SER_PHY_EVT_RX_BUF_REQUEST; m_ser_phy_event_rx.evt_params.rx_buf_request.num_of_bytes = m_rx_stream_length; } //Notify upwards m_ser_phy_event_handler(m_ser_phy_event_rx); //UART TX was stalled while receiving final byte. Restart tx. if (m_tx_state == UART_STALL) { if (m_tx_stream_length == m_tx_stream_index) { m_tx_state = UART_IDLE; } else if (m_tx_stream_index == (m_tx_stream_length - 1)) { m_tx_state = UART_TX_LAST_BYTE_WAIT; } else { m_tx_state = UART_TX_SEND; } //Critical region for avoiding timing issues in 'simultaneous RX end and TX start' CRITICAL_REGION_ENTER(); if (m_tx_pending == true) { m_tx_pending = false; uart_tx_start(); if (m_tx_state == UART_TX_SEND) { uart_tx_send(); } else if (m_tx_state == UART_TX_LAST_BYTE_WAIT) { uart_tx_last_byte(); } } CRITICAL_REGION_EXIT(); if (m_tx_state == UART_IDLE) { uart_peripheral_disable(); } } } } else { m_rx_state = UART_RX_PENDING; } }
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(); } }