summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorClaudio Takahasi <claudio.takahasi@gmail.com>2013-12-23 14:31:13 -0300
committerClaudio Takahasi <claudio.takahasi@gmail.com>2013-12-23 14:48:27 -0300
commit943fe20f4245d8699403c9860089fa9c410b5e5f (patch)
tree704c77d479622106e157bcd148338c827eb5b90f
parentc723c128c40c4ae5ee44512abdbd80b9b516d26b (diff)
nrf51822: Add local copy of platform files
-rw-r--r--platform/nrf51822/Makefile.am16
-rw-r--r--platform/nrf51822/app_fifo.c73
-rw-r--r--platform/nrf51822/app_gpiote.c302
-rw-r--r--platform/nrf51822/app_uart.c644
-rw-r--r--platform/nrf51822/nrf_delay.c25
-rw-r--r--platform/nrf51822/simple_uart.c108
6 files changed, 1165 insertions, 3 deletions
diff --git a/platform/nrf51822/Makefile.am b/platform/nrf51822/Makefile.am
index 9904bdb..1c6a594 100644
--- a/platform/nrf51822/Makefile.am
+++ b/platform/nrf51822/Makefile.am
@@ -1,9 +1,19 @@
noinst_LIBRARIES = libnrf.a
-AM_CPPFLAGS =-I$(SDK_DIR)/Nordic/nrf51822/Include
-AM_CPPFLAGS += -I$(SDK_DIR)/Nordic/nrf51822/Include/gcc
+AM_CPPFLAGS = -I$(SDK_DIR)/Nordic/nrf51822/Include \
+ -I$(SDK_DIR)/Nordic/nrf51822/Include/gcc \
+ -I$(SDK_DIR)/Nordic/nrf51822/Include/app_common \
+ -I$(SDK_DIR)/Nordic/nrf51422/Include/ant/softdevice \
+ -I$(top_builddir)/stack
+
ASMFLAGS = -D__HEAP_SIZE=0 -D__STACK_SIZE=1024
-libnrf_a_SOURCES = system_nrf51.c gcc_startup_nrf51.s
+libnrf_a_SOURCES = system_nrf51.c \
+ gcc_startup_nrf51.s \
+ log.c \
+ nrf_delay.c \
+ app_uart.c \
+ app_gpiote.c \
+ app_fifo.c
MAINTAINERCLEANFILES = Makefile.in
diff --git a/platform/nrf51822/app_fifo.c b/platform/nrf51822/app_fifo.c
new file mode 100644
index 0000000..3cc1df2
--- /dev/null
+++ b/platform/nrf51822/app_fifo.c
@@ -0,0 +1,73 @@
+/* Copyright (c) 2013 Nordic Semiconductor. All Rights Reserved.
+ *
+ * The information contained herein is property of Nordic Semiconductor ASA.
+ * Terms and conditions of usage are described in detail in NORDIC
+ * SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT.
+ *
+ * Licensees are granted free, non-transferable use of the information. NO
+ * WARRANTY of ANY KIND is provided. This heading must NOT be removed from
+ * the file.
+ *
+ */
+
+#include "app_fifo.h"
+#include "app_util.h"
+
+
+#define FIFO_LENGTH (p_fifo->write_pos - p_fifo->read_pos) /**< Macro for calculating the FIFO length. */
+
+
+uint32_t app_fifo_init(app_fifo_t * p_fifo, uint8_t * p_buf, uint16_t buf_size)
+{
+ // Check buffer for null pointer
+ if (p_buf == NULL)
+ {
+ return NRF_ERROR_NULL;
+ }
+
+ // Check that the buffer size is a power of two
+ if (!IS_POWER_OF_TWO(buf_size))
+ {
+ return NRF_ERROR_INVALID_LENGTH;
+ }
+
+ p_fifo->p_buf = p_buf;
+ p_fifo->buf_size_mask = buf_size - 1;
+ p_fifo->read_pos = 0;
+ p_fifo->write_pos = 0;
+
+ return NRF_SUCCESS;
+}
+
+
+uint32_t app_fifo_put(app_fifo_t * p_fifo, uint8_t byte)
+{
+ if (FIFO_LENGTH <= p_fifo->buf_size_mask)
+ {
+ p_fifo->p_buf[p_fifo->write_pos & p_fifo->buf_size_mask] = byte;
+ p_fifo->write_pos++;
+ return NRF_SUCCESS;
+ }
+
+ return NRF_ERROR_NO_MEM;
+}
+
+
+uint32_t app_fifo_get(app_fifo_t * p_fifo, uint8_t * p_byte)
+{
+ if (FIFO_LENGTH != 0)
+ {
+ *p_byte = p_fifo->p_buf[p_fifo->read_pos & p_fifo->buf_size_mask];
+ p_fifo->read_pos++;
+ return NRF_SUCCESS;
+ }
+
+ return NRF_ERROR_NOT_FOUND;
+
+}
+
+uint32_t app_fifo_flush(app_fifo_t * p_fifo)
+{
+ p_fifo->read_pos = p_fifo->write_pos;
+ return NRF_SUCCESS;
+}
diff --git a/platform/nrf51822/app_gpiote.c b/platform/nrf51822/app_gpiote.c
new file mode 100644
index 0000000..a6188de
--- /dev/null
+++ b/platform/nrf51822/app_gpiote.c
@@ -0,0 +1,302 @@
+/* Copyright (c) 2012 Nordic Semiconductor. All Rights Reserved.
+ *
+ * The information contained herein is property of Nordic Semiconductor ASA.
+ * Terms and conditions of usage are described in detail in NORDIC
+ * SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT.
+ *
+ * Licensees are granted free, non-transferable use of the information. NO
+ * WARRANTY of ANY KIND is provided. This heading must NOT be removed from
+ * the file.
+ *
+ */
+
+#include "app_gpiote.h"
+#include <stdlib.h>
+#include <string.h>
+#include "app_util.h"
+#include "nrf_error.h"
+#include "nrf_gpio.h"
+
+
+/**@brief GPIOTE user type. */
+typedef struct
+{
+ uint32_t pins_mask; /**< Mask defining which pins user wants to monitor. */
+ uint32_t pins_low_to_high_mask; /**< Mask defining which pins will generate events to this user when toggling low->high. */
+ uint32_t pins_high_to_low_mask; /**< Mask defining which pins will generate events to this user when toggling high->low. */
+ uint32_t sense_high_pins; /**< Mask defining which pins are configured to generate GPIOTE interrupt on transition to high level. */
+ app_gpiote_event_handler_t event_handler; /**< Pointer to function to be executed when an event occurs. */
+} gpiote_user_t;
+
+STATIC_ASSERT(sizeof(gpiote_user_t) <= GPIOTE_USER_NODE_SIZE);
+STATIC_ASSERT(sizeof(gpiote_user_t) % 4 == 0);
+
+static uint32_t m_enabled_users_mask; /**< Mask for tracking which users are enabled. */
+static uint8_t m_user_array_size; /**< Size of user array. */
+static uint8_t m_user_count; /**< Number of registered users. */
+static gpiote_user_t * mp_users = NULL; /**< Array of GPIOTE users. */
+
+
+/**@brief Toggle sense level for specified pins.
+ *
+ * @param[in] p_user Pointer to user structure.
+ * @param[in] pins Bitmask specifying for which pins the sense level is to be toggled.
+ */
+static void sense_level_toggle(gpiote_user_t * p_user, uint32_t pins)
+{
+ uint32_t pin_no;
+
+ for (pin_no = 0; pin_no < NO_OF_PINS; pin_no++)
+ {
+ uint32_t pin_mask = (1 << pin_no);
+
+ if ((pins & pin_mask) != 0)
+ {
+ uint32_t sense;
+
+ // Invert sensing.
+ if ((p_user->sense_high_pins & pin_mask) == 0)
+ {
+ sense = GPIO_PIN_CNF_SENSE_High << GPIO_PIN_CNF_SENSE_Pos;
+ p_user->sense_high_pins |= pin_mask;
+ }
+ else
+ {
+ sense = GPIO_PIN_CNF_SENSE_Low << GPIO_PIN_CNF_SENSE_Pos;
+ p_user->sense_high_pins &= ~pin_mask;
+ }
+
+ NRF_GPIO->PIN_CNF[pin_no] &= ~GPIO_PIN_CNF_SENSE_Msk;
+ NRF_GPIO->PIN_CNF[pin_no] |= sense;
+ }
+ }
+}
+
+
+/**@brief GPIOTE interrupt handler.
+ */
+static void GPIOTE_IRQHandler(void)
+{
+ uint8_t i;
+ uint32_t pins_state = NRF_GPIO->IN;
+
+ // Clear event.
+ NRF_GPIOTE->EVENTS_PORT = 0;
+
+ // Check all users.
+ for (i = 0; i < m_user_count; i++)
+ {
+ gpiote_user_t * p_user = &mp_users[i];
+
+ // Check if user is enabled.
+ if (((1 << i) & m_enabled_users_mask) != 0)
+ {
+ uint32_t transition_pins;
+ uint32_t event_low_to_high;
+ uint32_t event_high_to_low;
+
+ // Find set of pins on which there has been a transition.
+ transition_pins = (pins_state ^ ~p_user->sense_high_pins) & p_user->pins_mask;
+
+ // Toggle SENSE level for all pins that have changed state.
+ sense_level_toggle(p_user, transition_pins);
+
+ // Call user event handler if an event has occurred.
+ event_high_to_low = (~pins_state & p_user->pins_high_to_low_mask) & transition_pins;
+ event_low_to_high = (pins_state & p_user->pins_low_to_high_mask) & transition_pins;
+
+ if ((event_low_to_high | event_high_to_low) != 0)
+ {
+ p_user->event_handler(event_low_to_high, event_high_to_low);
+ }
+ }
+ }
+}
+
+
+/**@brief Disable sensing for all pins for specified user.
+ *
+ * @param[in] user_id User id.
+ */
+static void pins_sense_disable(app_gpiote_user_id_t user_id)
+{
+ uint32_t pin_no;
+
+ for (pin_no = 0; pin_no < 32; pin_no++)
+ {
+ if ((mp_users[user_id].pins_mask & (1 << pin_no)) != 0)
+ {
+ NRF_GPIO->PIN_CNF[pin_no] &= ~GPIO_PIN_CNF_SENSE_Msk;
+ NRF_GPIO->PIN_CNF[pin_no] |= GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos;
+ }
+ }
+}
+
+
+uint32_t app_gpiote_init(uint8_t max_users, void * p_buffer)
+{
+ if (p_buffer == NULL)
+ {
+ return NRF_ERROR_INVALID_PARAM;
+ }
+
+ // Check that buffer is correctly aligned.
+ if (!is_word_aligned(p_buffer))
+ {
+ return NRF_ERROR_INVALID_PARAM;
+ }
+
+ // Initialize file globals.
+ mp_users = (gpiote_user_t *)p_buffer;
+ m_user_array_size = max_users;
+ m_user_count = 0;
+ m_enabled_users_mask = 0;
+
+ memset(mp_users, 0, m_user_array_size * sizeof(gpiote_user_t));
+
+ // Initialize GPIOTE interrupt (will not be enabled until app_gpiote_user_enable() is called).
+ NRF_GPIOTE->INTENCLR = 0xFFFFFFFF;
+
+ NVIC_ClearPendingIRQ(GPIOTE_IRQn);
+ NVIC_SetPriority(GPIOTE_IRQn, APP_IRQ_PRIORITY_HIGH);
+ NVIC_EnableIRQ(GPIOTE_IRQn);
+
+ return NRF_SUCCESS;
+}
+
+
+uint32_t app_gpiote_user_register(app_gpiote_user_id_t * p_user_id,
+ uint32_t pins_low_to_high_mask,
+ uint32_t pins_high_to_low_mask,
+ app_gpiote_event_handler_t event_handler)
+{
+ // Check state and parameters.
+ if (mp_users == NULL)
+ {
+ return NRF_ERROR_INVALID_STATE;
+ }
+ if (event_handler == NULL)
+ {
+ return NRF_ERROR_INVALID_PARAM;
+ }
+ if (m_user_count >= m_user_array_size)
+ {
+ return NRF_ERROR_NO_MEM;
+ }
+
+ // Allocate new user.
+ mp_users[m_user_count].pins_mask = pins_low_to_high_mask | pins_high_to_low_mask;
+ mp_users[m_user_count].pins_low_to_high_mask = pins_low_to_high_mask;
+ mp_users[m_user_count].pins_high_to_low_mask = pins_high_to_low_mask;
+ mp_users[m_user_count].event_handler = event_handler;
+
+ *p_user_id = m_user_count++;
+
+ // Make sure SENSE is disabled for all pins.
+ pins_sense_disable(*p_user_id);
+
+ return NRF_SUCCESS;
+}
+
+
+uint32_t app_gpiote_user_enable(app_gpiote_user_id_t user_id)
+{
+ uint32_t pin_no;
+ uint32_t pins_state;
+
+ // Check state and parameters.
+ if (mp_users == NULL)
+ {
+ return NRF_ERROR_INVALID_STATE;
+ }
+ if (user_id >= m_user_count)
+ {
+ return NRF_ERROR_INVALID_PARAM;
+ }
+
+ // Clear any pending event.
+ NRF_GPIOTE->EVENTS_PORT = 0;
+ pins_state = NRF_GPIO->IN;
+
+ // Enable user.
+ if (m_enabled_users_mask == 0)
+ {
+ NRF_GPIOTE->INTENSET = GPIOTE_INTENSET_PORT_Msk;
+ }
+ m_enabled_users_mask |= (1 << user_id);
+
+ // Enable sensing for all pins for specified user.
+ mp_users[user_id].sense_high_pins = 0;
+ for (pin_no = 0; pin_no < 32; pin_no++)
+ {
+ uint32_t pin_mask = (1 << pin_no);
+
+ if ((mp_users[user_id].pins_mask & pin_mask) != 0)
+ {
+ uint32_t sense;
+
+ if ((pins_state & pin_mask) != 0)
+ {
+ sense = GPIO_PIN_CNF_SENSE_Low << GPIO_PIN_CNF_SENSE_Pos;
+ }
+ else
+ {
+ sense = GPIO_PIN_CNF_SENSE_High << GPIO_PIN_CNF_SENSE_Pos;
+ mp_users[user_id].sense_high_pins |= pin_mask;
+ }
+
+ NRF_GPIO->PIN_CNF[pin_no] &= ~GPIO_PIN_CNF_SENSE_Msk;
+ NRF_GPIO->PIN_CNF[pin_no] |= sense;
+ }
+ }
+
+ return NRF_SUCCESS;
+}
+
+
+uint32_t app_gpiote_user_disable(app_gpiote_user_id_t user_id)
+{
+ // Check state and parameters.
+ if (mp_users == NULL)
+ {
+ return NRF_ERROR_INVALID_STATE;
+ }
+ if (user_id >= m_user_count)
+ {
+ return NRF_ERROR_INVALID_PARAM;
+ }
+
+ // Disable sensing for all pins for specified user.
+ pins_sense_disable(user_id);
+
+ // Disable user.
+ m_enabled_users_mask &= ~(1UL << user_id);
+ if (m_enabled_users_mask == 0)
+ {
+ NRF_GPIOTE->INTENCLR = GPIOTE_INTENSET_PORT_Msk;
+ }
+
+ return NRF_SUCCESS;
+}
+
+
+uint32_t app_gpiote_pins_state_get(app_gpiote_user_id_t user_id, uint32_t * p_pins)
+{
+ gpiote_user_t * p_user;
+
+ // Check state and parameters.
+ if (mp_users == NULL)
+ {
+ return NRF_ERROR_INVALID_STATE;
+ }
+ if (user_id >= m_user_count)
+ {
+ return NRF_ERROR_INVALID_PARAM;
+ }
+
+ // Get pins.
+ p_user = &mp_users[user_id];
+ *p_pins = NRF_GPIO->IN & p_user->pins_mask;
+
+ return NRF_SUCCESS;
+}
diff --git a/platform/nrf51822/app_uart.c b/platform/nrf51822/app_uart.c
new file mode 100644
index 0000000..a40ae96
--- /dev/null
+++ b/platform/nrf51822/app_uart.c
@@ -0,0 +1,644 @@
+/* Copyright (c) 2013 Nordic Semiconductor. All Rights Reserved.
+ *
+ * The information contained herein is property of Nordic Semiconductor ASA.
+ * Terms and conditions of usage are described in detail in NORDIC
+ * SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT.
+ *
+ * Licensees are granted free, non-transferable use of the information. NO
+ * WARRANTY of ANY KIND is provided. This heading must NOT be removed from
+ * the file.
+ *
+ */
+
+#include "app_uart.h"
+#include "app_fifo.h"
+#include "nrf.h"
+#include "nrf_gpio.h"
+#include "app_error.h"
+#include "app_util.h"
+#include "app_gpiote.h"
+
+#define FIFO_LENGTH(F) (F.write_pos - F.read_pos) /**< Macro to calculate length of a FIFO. */
+#define UART_INSTANCE_GPIOTE_BASE 0x00FF /**< Define the base for UART instance ID when flow control is used. The userid from GPIOTE will be used with padded 0xFF at LSB for easy converting the instance id to GPIOTE id. */
+#define UART_INSTANCE_ID_INVALID 0x0000 /**< Value 0x0000 is used to indicate an invalid instance id. When 0 is provided as instance id upon initialization, the module will provide a valid id to the caller. */
+
+/** @brief States for the app_uart state machine. */
+typedef enum
+{
+ UART_OFF, /**< app_uart state OFF, indicating CTS is low. */
+ UART_READY, /**< app_uart state ON, indicating CTS is high. */
+ UART_ON, /**< app_uart state TX, indicating UART is ongoing transmitting data. */
+ UART_WAIT_CLOSE, /**< app_uart state WAIT CLOSE, indicating that CTS is low, but a byte is currently being transmitted on the line. */
+} app_uart_states_t;
+
+/** @brief State transition events for the app_uart state machine. */
+typedef enum
+{
+ ON_CTS_HIGH, /**< Event: CTS gone high. */
+ ON_CTS_LOW, /**< Event: CTS gone low. */
+ ON_UART_PUT, /**< Event: Application wants to transmit data. */
+ ON_TX_READY, /**< Event: Data has been transmitted on the uart and line is available. */
+ ON_UART_CLOSE, /**< Event: The UART module are being stopped. */
+} app_uart_state_events_t;
+
+static bool m_use_fifo;
+static app_fifo_t m_rx_fifo; /**< RX FIFO buffer for storing data received on the UART until the application fetches them using app_uart_get(). */
+static app_fifo_t m_tx_fifo; /**< TX FIFO buffer for storing data to be transmitted on the UART when TXD is ready. Data is put to the buffer on using app_uart_put(). */
+static uint8_t m_tx_byte; /**< TX Byte placeholder when no FIFO is used. */
+
+static uint8_t m_instance_counter = 1; /**< Instance counter for each caller using the UART module. The GPIOTE user id is mapped directly for callers using HW Flow Control. */
+static app_gpiote_user_id_t m_gpiote_uid; /**< GPIOTE id for currently active caller to the UART module. */
+static uint32_t m_pin_cts_mask; /**< CTS pin mask for UART module. */
+static app_uart_event_handler_t m_event_handler; /**< Event handler function. */
+static volatile app_uart_states_t m_current_state = UART_OFF; /**< State of the state machine. */
+
+/*@brief Action to disable the UART when entering the UART_OFF state.
+ */
+static void action_uart_deactivate(void)
+{
+ m_current_state = UART_OFF;
+ NRF_UART0->TASKS_STOPTX = 1;
+ NRF_UART0->TASKS_STOPRX = 1;
+ NRF_UART0->ENABLE = (UART_ENABLE_ENABLE_Disabled << UART_ENABLE_ENABLE_Pos);
+}
+
+
+static void action_tx_stop()
+{
+ app_uart_evt_t app_uart_event;
+ // No more bytes in FIFO, terminate transmission.
+ NRF_UART0->TASKS_STOPTX = 1;
+ m_current_state = UART_READY;
+ // Last byte from FIFO transmitted, notify the application.
+ // Notify that new data is available if this was first byte put in the buffer.
+ app_uart_event.evt_type = APP_UART_TX_EMPTY;
+ m_event_handler(&app_uart_event);
+}
+
+
+/*@brief Action to send next byte in the TX buffer. Called when (re-)entering the UART_ON state.
+ * If no more data is available in the TX buffer, the state machine will enter UART_READY state.
+ */
+static void action_tx_send()
+{
+ if (m_current_state != UART_ON)
+ {
+ // Start the UART.
+ NRF_UART0->TASKS_STARTTX = 1;
+ }
+
+ if (m_use_fifo && (app_fifo_get(&m_tx_fifo, &m_tx_byte) != NRF_SUCCESS))
+ {
+ action_tx_stop();
+ return;
+ }
+
+ NRF_UART0->INTENCLR = (UART_INTENSET_TXDRDY_Set << UART_INTENSET_TXDRDY_Pos);
+ NRF_UART0->TXD = m_tx_byte;
+ m_current_state = UART_ON;
+ NRF_UART0->INTENSET = (UART_INTENSET_TXDRDY_Set << UART_INTENSET_TXDRDY_Pos);
+}
+
+
+static void action_tx_ready()
+{
+ // Get next byte from FIFO.
+ if (m_use_fifo && (FIFO_LENGTH(m_tx_fifo) != 0))
+ {
+ action_tx_send();
+ }
+ else
+ {
+ action_tx_stop();
+ }
+}
+
+
+/**@brief Handling of the ON_CTS_HIGH event.
+ */
+static void on_cts_high(void)
+{
+ switch (m_current_state)
+ {
+ case UART_READY:
+ action_uart_deactivate();
+ break;
+
+ case UART_ON:
+ m_current_state = UART_WAIT_CLOSE;
+ break;
+
+ default:
+ // Nothing to do.
+ break;
+ }
+}
+
+
+/**@brief Handling of the ON_CTS_LOW event.
+ */
+static void on_cts_low(void)
+{
+ switch (m_current_state)
+ {
+ case UART_OFF:
+ NRF_UART0->ENABLE = (UART_ENABLE_ENABLE_Enabled << UART_ENABLE_ENABLE_Pos);
+ NRF_UART0->TASKS_STARTRX = 1;
+
+ if (FIFO_LENGTH(m_tx_fifo) != 0)
+ {
+ action_tx_send();
+ }
+ else
+ {
+ m_current_state = UART_READY;
+ }
+ break;
+
+ case UART_WAIT_CLOSE:
+ m_current_state = UART_ON;
+ break;
+
+ default:
+ // Nothing to do.
+ break;
+ }
+}
+
+
+/**@brief Handling of the ON_TX_READY event.
+ */
+static void on_tx_ready(void)
+{
+ switch (m_current_state)
+ {
+ case UART_WAIT_CLOSE:
+ action_uart_deactivate();
+ break;
+
+ case UART_ON:
+ case UART_READY:
+ action_tx_ready();
+ break;
+
+ default:
+ // Nothing to do.
+ break;
+ }
+}
+
+
+/**@brief Handling of the ON_UART_PUT event when application has put data in the TX buffer.
+ */
+static void on_uart_put(void)
+{
+ if (m_current_state == UART_READY)
+ {
+ action_tx_send();
+ }
+}
+
+
+/**@brief Handling of the ON_UART_CLOSE event when application is closing the UART module.
+ */
+static void on_uart_close(void)
+{
+ action_uart_deactivate();
+}
+
+
+/**@brief State machine main event handler.
+ *
+ * @param[in] event Event that has occurred.
+ */
+static void on_uart_event(app_uart_state_events_t event)
+{
+ switch (event)
+ {
+ case ON_CTS_HIGH:
+ on_cts_high();
+ break;
+
+ case ON_CTS_LOW:
+ on_cts_low();
+ break;
+
+ case ON_TX_READY:
+ on_tx_ready();
+ break;
+
+ case ON_UART_PUT:
+ on_uart_put();
+ break;
+
+ case ON_UART_CLOSE:
+ on_uart_close();
+ break;
+
+ default:
+ // All valid events are handled above.
+ break;
+ }
+}
+
+
+/**@brief GPIOTE event handler.
+ *
+ * @param[in] event_pins_low_to_high Mask telling which pin(s) generated an event from low->high.
+ * @param[in] event_pins_high_to_low Mask telling which pin(s) generated an event from high->low.
+ */
+static void gpiote_uart_event_handler(uint32_t event_pins_low_to_high,
+ uint32_t event_pins_high_to_low)
+{
+ if ((event_pins_high_to_low & event_pins_low_to_high & m_pin_cts_mask) != 0)
+ {
+ // We have an indication from GPIOTE that the CTS pin has toggled high->low and low->high.
+ // If this occurs, we must read the active pins in the GPIOTE module ourself.
+ uint32_t active_pins;
+ uint32_t err_code;
+
+ err_code = app_gpiote_pins_state_get(m_gpiote_uid, &active_pins);
+ if (err_code != NRF_SUCCESS)
+ {
+ // Pin reading was not possible, even though an event from GPIOTE was received that the
+ // CTS pin toggled. If pin double toggled but status cannot be fetched we silently
+ // return and keep the current UART status as-is.
+ return;
+ }
+ event_pins_low_to_high &= active_pins;
+ event_pins_high_to_low &= ~active_pins;
+ }
+
+ if ((event_pins_high_to_low & m_pin_cts_mask) != 0)
+ {
+ on_uart_event(ON_CTS_LOW);
+ }
+ else if ((event_pins_low_to_high & m_pin_cts_mask) != 0)
+ {
+ on_uart_event(ON_CTS_HIGH);
+ }
+ else
+ {
+ // Do nothing, as the CTS pin didn't toggle.
+ }
+}
+
+
+/**@brief UART Interrupt handler.
+ *
+ * @details UART interrupt handler to process TX Ready when TXD is available, RX Ready when a byte
+ * is received, or in case of error when receiving a byte.
+ */
+static void UART0_IRQHandler(void)
+{
+ // Handle reception
+ if (NRF_UART0->EVENTS_RXDRDY != 0)
+ {
+ uint32_t err_code;
+
+ // Clear UART RX event flag
+ NRF_UART0->EVENTS_RXDRDY = 0;
+
+ if (m_use_fifo)
+ {
+ // Write received byte to FIFO
+ err_code = app_fifo_put(&m_rx_fifo, (uint8_t)NRF_UART0->RXD);
+ if (err_code != NRF_SUCCESS)
+ {
+ app_uart_evt_t app_uart_event;
+ app_uart_event.evt_type = APP_UART_FIFO_ERROR;
+ app_uart_event.data.error_code = err_code;
+ m_event_handler(&app_uart_event);
+ }
+ // Notify that new data is available if this was first byte put in the buffer.
+ else if (FIFO_LENGTH(m_rx_fifo) == 1)
+ {
+ app_uart_evt_t app_uart_event;
+ app_uart_event.evt_type = APP_UART_DATA_READY;
+ m_event_handler(&app_uart_event);
+ }
+ else
+ {
+ // Do nothing, only send event if first byte was added or overflow in FIFO occurred.
+ }
+ }
+ else
+ {
+ app_uart_evt_t app_uart_event;
+ app_uart_event.evt_type = APP_UART_DATA;
+ app_uart_event.data.value = (uint8_t) NRF_UART0->RXD;
+ m_event_handler(&app_uart_event);
+ }
+ }
+
+ // Handle transmission.
+ if (NRF_UART0->EVENTS_TXDRDY != 0)
+ {
+ // Clear UART TX event flag.
+ NRF_UART0->EVENTS_TXDRDY = 0;
+ on_uart_event(ON_TX_READY);
+ }
+
+ // Handle errors.
+ if (NRF_UART0->EVENTS_ERROR != 0)
+ {
+ uint32_t error_source;
+ app_uart_evt_t app_uart_event;
+
+ // Clear UART ERROR event flag.
+ NRF_UART0->EVENTS_ERROR = 0;
+
+ // Clear error source.
+ error_source = NRF_UART0->ERRORSRC;
+ NRF_UART0->ERRORSRC = error_source;
+
+ app_uart_event.evt_type = APP_UART_COMMUNICATION_ERROR;
+ app_uart_event.data.error_communication = error_source;
+
+ m_event_handler(&app_uart_event);
+ }
+}
+
+
+/**@brief Initialization of UART when flow control is disabled.
+ */
+static void uart_no_flow_control_init(void)
+{
+ NRF_UART0->ENABLE = (UART_ENABLE_ENABLE_Enabled << UART_ENABLE_ENABLE_Pos);
+ NRF_UART0->EVENTS_RXDRDY = 0;
+ NRF_UART0->EVENTS_TXDRDY = 0;
+
+ NRF_UART0->CONFIG &= ~(UART_CONFIG_HWFC_Enabled << UART_CONFIG_HWFC_Pos);
+
+ NRF_UART0->PSELRTS = UART_PIN_DISCONNECTED;
+ NRF_UART0->PSELCTS = UART_PIN_DISCONNECTED;
+
+ NRF_UART0->TASKS_STARTTX = 1;
+ NRF_UART0->TASKS_STARTRX = 1;
+}
+
+
+/**@brief Initialization of UART when standard flow control is enabled.
+ */
+static void uart_standard_flow_control_init(const app_uart_comm_params_t * p_comm_params)
+{
+ NRF_UART0->ENABLE = (UART_ENABLE_ENABLE_Enabled << UART_ENABLE_ENABLE_Pos);
+ NRF_UART0->EVENTS_RXDRDY = 0;
+ NRF_UART0->EVENTS_TXDRDY = 0;
+
+ NRF_UART0->CONFIG |= (UART_CONFIG_HWFC_Enabled << UART_CONFIG_HWFC_Pos);
+
+ NRF_UART0->PSELCTS = p_comm_params->cts_pin_no;
+ NRF_UART0->PSELRTS = p_comm_params->rts_pin_no;
+
+ NRF_UART0->TASKS_STARTTX = 1;
+ NRF_UART0->TASKS_STARTRX = 1;
+}
+
+
+uint32_t app_uart_init(const app_uart_comm_params_t * p_comm_params,
+ app_uart_buffers_t * p_buffers,
+ app_uart_event_handler_t event_handler,
+ app_irq_priority_t irq_priority,
+ uint16_t * p_app_uart_uid)
+{
+ uint32_t err_code;
+ uint32_t gpiote_high_pins;
+ uint32_t gpiote_pin_low_high_mask = 0;
+ uint32_t gpiote_pin_high_low_mask = 0;
+
+ m_current_state = UART_OFF;
+ m_event_handler = event_handler;
+
+ if (p_buffers == NULL)
+ {
+ m_use_fifo = false;
+ m_rx_fifo.p_buf = NULL;
+ m_tx_fifo.p_buf = NULL;
+ }
+ else
+ {
+ m_use_fifo = true;
+ // Configure buffer RX buffer.
+ err_code = app_fifo_init(&m_rx_fifo, p_buffers->rx_buf, p_buffers->rx_buf_size);
+ if (err_code != NRF_SUCCESS)
+ {
+ // Propagate error code.
+ return err_code;
+ }
+
+ // Configure buffer TX buffer.
+ err_code = app_fifo_init(&m_tx_fifo, p_buffers->tx_buf, p_buffers->tx_buf_size);
+ if (err_code != NRF_SUCCESS)
+ {
+ // Propagate error code.
+ return err_code;
+ }
+ }
+
+ // Configure RX and TX pins.
+ nrf_gpio_cfg_output(p_comm_params->tx_pin_no);
+ nrf_gpio_cfg_input(p_comm_params->rx_pin_no, NRF_GPIO_PIN_NOPULL);
+
+ NRF_UART0->PSELTXD = p_comm_params->tx_pin_no;
+ NRF_UART0->PSELRXD = p_comm_params->rx_pin_no;
+
+ // Configure baud rate and parity.
+ NRF_UART0->BAUDRATE = (p_comm_params->baud_rate << UART_BAUDRATE_BAUDRATE_Pos);
+ if (p_comm_params->use_parity)
+ {
+ NRF_UART0->CONFIG = (UART_CONFIG_PARITY_Included << UART_CONFIG_PARITY_Pos);
+ }
+ else
+ {
+ NRF_UART0->CONFIG = (UART_CONFIG_PARITY_Excluded << UART_CONFIG_PARITY_Pos);
+ }
+
+ if (p_comm_params->flow_control == APP_UART_FLOW_CONTROL_LOW_POWER)
+ {
+ // Configure hardware flow control.
+ nrf_gpio_cfg_output(p_comm_params->rts_pin_no);
+ NRF_GPIO->OUT = 1 << p_comm_params->rts_pin_no;
+
+ NRF_UART0->PSELCTS = UART_PIN_DISCONNECTED;
+ NRF_UART0->PSELRTS = p_comm_params->rts_pin_no;
+ NRF_UART0->CONFIG |= (UART_CONFIG_HWFC_Enabled << UART_CONFIG_HWFC_Pos);
+
+ // Setup the gpiote to handle pin events on cts-pin.
+ // For the UART we want to detect both low->high and high->low transitions in order to
+ // know when to activate/de-activate the TX/RX in the UART.
+ // Configure pin.
+ m_pin_cts_mask = (1 << p_comm_params->cts_pin_no);
+ GPIO_PIN_CONFIG(p_comm_params->cts_pin_no,
+ GPIO_PIN_CNF_DIR_Input,
+ GPIO_PIN_CNF_INPUT_Connect,
+ GPIO_PIN_CNF_PULL_Disabled,
+ GPIO_PIN_CNF_DRIVE_S0S1,
+ GPIO_PIN_CNF_SENSE_Low);
+
+ gpiote_pin_low_high_mask = (1 << p_comm_params->cts_pin_no);
+ gpiote_pin_high_low_mask = (1 << p_comm_params->cts_pin_no);
+
+ if (*p_app_uart_uid == UART_INSTANCE_ID_INVALID)
+ {
+ err_code = app_gpiote_user_register(&m_gpiote_uid,
+ gpiote_pin_low_high_mask,
+ gpiote_pin_high_low_mask,
+ gpiote_uart_event_handler);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+ *p_app_uart_uid = (m_gpiote_uid << 8) | UART_INSTANCE_GPIOTE_BASE;
+ }
+ else if (*p_app_uart_uid < UART_INSTANCE_GPIOTE_BASE)
+ {
+ return NRF_ERROR_INVALID_PARAM;
+ }
+ else
+ {
+ m_gpiote_uid = ((*p_app_uart_uid) >> 8) & UART_INSTANCE_GPIOTE_BASE;
+ }
+
+ err_code = app_gpiote_pins_state_get(m_gpiote_uid, &gpiote_high_pins);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ err_code = app_gpiote_user_enable(m_gpiote_uid);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ // UART CTS pin is active when low.
+ if ((gpiote_high_pins & (1 << p_comm_params->cts_pin_no)) == 0)
+ {
+ on_uart_event(ON_CTS_LOW);
+ }
+ else
+ {
+ on_uart_event(ON_CTS_HIGH);
+ }
+ }
+ else if (p_comm_params->flow_control == APP_UART_FLOW_CONTROL_ENABLED)
+ {
+ if (*p_app_uart_uid == UART_INSTANCE_ID_INVALID)
+ {
+ *p_app_uart_uid = m_instance_counter++;
+ }
+
+ uart_standard_flow_control_init(p_comm_params);
+ m_current_state = UART_READY;
+ }
+ else
+ {
+ if (*p_app_uart_uid == UART_INSTANCE_ID_INVALID)
+ {
+ *p_app_uart_uid = m_instance_counter++;
+ }
+
+ uart_no_flow_control_init();
+ m_current_state = UART_READY;
+ }
+
+ // Enable UART interrupt
+ NRF_UART0->INTENCLR = 0xffffffffUL;
+ NRF_UART0->INTENSET = (UART_INTENSET_RXDRDY_Set << UART_INTENSET_RXDRDY_Pos) |
+ (UART_INTENSET_TXDRDY_Set << UART_INTENSET_TXDRDY_Pos) |
+ (UART_INTENSET_ERROR_Set << UART_INTENSET_ERROR_Pos);
+
+ NVIC_ClearPendingIRQ(UART0_IRQn);
+ NVIC_SetPriority(UART0_IRQn, irq_priority);
+ NVIC_EnableIRQ(UART0_IRQn);
+
+ return NRF_SUCCESS;
+}
+
+
+uint32_t app_uart_get(uint8_t * p_byte)
+{
+ if (m_use_fifo)
+ {
+ return app_fifo_get(&m_rx_fifo, p_byte);
+ }
+ return NRF_ERROR_NOT_FOUND;
+}
+
+
+uint32_t app_uart_put(uint8_t byte)
+{
+ uint32_t err_code = NRF_SUCCESS;
+ if (m_use_fifo)
+ {
+ err_code = app_fifo_put(&m_tx_fifo, byte);
+ }
+ else
+ {
+ if (m_current_state == UART_READY)
+ {
+ m_tx_byte = byte;
+ }
+ else
+ {
+ return NRF_ERROR_NO_MEM;
+ }
+ }
+
+ on_uart_event(ON_UART_PUT);
+
+ return err_code;
+}
+
+
+uint32_t app_uart_flush(void)
+{
+ uint32_t err_code;
+
+ err_code = app_fifo_flush(&m_rx_fifo);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ err_code = app_fifo_flush(&m_tx_fifo);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ return NRF_SUCCESS;
+}
+
+
+uint32_t app_uart_get_connection_state(app_uart_connection_state_t * p_conn_state)
+{
+ *p_conn_state = ((m_current_state == UART_OFF) ? APP_UART_DISCONNECTED : APP_UART_CONNECTED);
+
+ return NRF_SUCCESS;
+}
+
+
+uint32_t app_uart_close(uint16_t app_uart_uid)
+{
+ uint16_t gpiote_uid;
+
+ if (app_uart_uid < UART_INSTANCE_GPIOTE_BASE)
+ {
+ on_uart_event(ON_UART_CLOSE);
+ return NRF_SUCCESS;
+ }
+
+ gpiote_uid = (app_uart_uid >> 8) & UART_INSTANCE_GPIOTE_BASE;
+
+ if (gpiote_uid != m_gpiote_uid)
+ {
+ return NRF_ERROR_INVALID_PARAM;
+ }
+
+ on_uart_event(ON_UART_CLOSE);
+
+ return app_gpiote_user_disable(m_gpiote_uid);
+}
+
diff --git a/platform/nrf51822/nrf_delay.c b/platform/nrf51822/nrf_delay.c
new file mode 100644
index 0000000..d48489e
--- /dev/null
+++ b/platform/nrf51822/nrf_delay.c
@@ -0,0 +1,25 @@
+/* Copyright (c) 2012 Nordic Semiconductor. All Rights Reserved.
+ *
+ * The information contained herein is property of Nordic Semiconductor ASA.
+ * Terms and conditions of usage are described in detail in NORDIC
+ * SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT.
+ *
+ * Licensees are granted free, non-transferable use of the information. NO
+ * WARRANTY of ANY KIND is provided. This heading must NOT be removed from
+ * the file.
+ *
+ */
+
+#include "compiler_abstraction.h"
+#include "nrf.h"
+#include "nrf_delay.h"
+
+/*lint --e{438} "Variable not used" */
+void nrf_delay_ms(uint32_t volatile number_of_ms)
+{
+ while(number_of_ms != 0)
+ {
+ number_of_ms--;
+ nrf_delay_us(999);
+ }
+}
diff --git a/platform/nrf51822/simple_uart.c b/platform/nrf51822/simple_uart.c
new file mode 100644
index 0000000..04d3c64
--- /dev/null
+++ b/platform/nrf51822/simple_uart.c
@@ -0,0 +1,108 @@
+/* Copyright (c) 2009 Nordic Semiconductor. All Rights Reserved.
+ *
+ * The information contained herein is property of Nordic Semiconductor ASA.
+ * Terms and conditions of usage are described in detail in NORDIC
+ * SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT.
+ *
+ * Licensees are granted free, non-transferable use of the information. NO
+ * WARRANTY of ANY KIND is provided. This heading must NOT be removed from
+ * the file.
+ *
+ */
+
+#include <stdint.h>
+
+#include "nrf.h"
+#include "simple_uart.h"
+#include "nrf_delay.h"
+#include "nrf_gpio.h"
+
+uint8_t simple_uart_get(void)
+{
+ while (NRF_UART0->EVENTS_RXDRDY != 1)
+ {
+ // Wait for RXD data to be received
+ }
+
+ NRF_UART0->EVENTS_RXDRDY = 0;
+ return (uint8_t)NRF_UART0->RXD;
+}
+
+bool simple_uart_get_with_timeout(int32_t timeout_ms, uint8_t *rx_data)
+{
+ bool ret = true;
+
+ while (NRF_UART0->EVENTS_RXDRDY != 1)
+ {
+ if (timeout_ms-- >= 0)
+ {
+ // wait in 1ms chunk before checking for status
+ nrf_delay_us(1000);
+ }
+ else
+ {
+ ret = false;
+ break;
+ }
+ } // Wait for RXD data to be received
+
+ if (timeout_ms >= 0)
+ {
+ // clear the event and set rx_data with received byte
+ NRF_UART0->EVENTS_RXDRDY = 0;
+ *rx_data = (uint8_t)NRF_UART0->RXD;
+ }
+
+ return ret;
+}
+
+void simple_uart_put(uint8_t cr)
+{
+ NRF_UART0->TXD = (uint8_t)cr;
+
+ while (NRF_UART0->EVENTS_TXDRDY!=1)
+ {
+ // Wait for TXD data to be sent
+ }
+
+ NRF_UART0->EVENTS_TXDRDY=0;
+}
+
+void simple_uart_putstring(const uint8_t *str)
+{
+ uint_fast8_t i = 0;
+ uint8_t ch = str[i++];
+ while (ch != '\0')
+ {
+ simple_uart_put(ch);
+ ch = str[i++];
+ }
+}
+
+void simple_uart_config( uint8_t rts_pin_number,
+ uint8_t txd_pin_number,
+ uint8_t cts_pin_number,
+ uint8_t rxd_pin_number,
+ bool hwfc)
+{
+ nrf_gpio_cfg_output(txd_pin_number);
+ nrf_gpio_cfg_input(rxd_pin_number, NRF_GPIO_PIN_NOPULL);
+
+ NRF_UART0->PSELTXD = txd_pin_number;
+ NRF_UART0->PSELRXD = rxd_pin_number;
+
+ if (hwfc)
+ {
+ nrf_gpio_cfg_output(rts_pin_number);
+ nrf_gpio_cfg_input(cts_pin_number, NRF_GPIO_PIN_NOPULL);
+ NRF_UART0->PSELCTS = cts_pin_number;
+ NRF_UART0->PSELRTS = rts_pin_number;
+ NRF_UART0->CONFIG = (UART_CONFIG_HWFC_Enabled << UART_CONFIG_HWFC_Pos);
+ }
+
+ NRF_UART0->BAUDRATE = (UART_BAUDRATE_BAUDRATE_Baud38400 << UART_BAUDRATE_BAUDRATE_Pos);
+ NRF_UART0->ENABLE = (UART_ENABLE_ENABLE_Enabled << UART_ENABLE_ENABLE_Pos);
+ NRF_UART0->TASKS_STARTTX = 1;
+ NRF_UART0->TASKS_STARTRX = 1;
+ NRF_UART0->EVENTS_RXDRDY = 0;
+}