summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaulo Borges <paulo.borges@openbossa.org>2013-11-04 19:49:28 -0300
committerPaulo Borges <paulo.borges@openbossa.org>2013-11-13 16:50:57 -0300
commit7ace4656ae866ea57008fac5a1b4c3ce1c410d1d (patch)
tree59ce5496373428df912a034a1622ab01543b9155
WIP: First commitmaster
-rw-r--r--.gitignore5
-rw-r--r--examples/Makefile.common130
-rw-r--r--examples/log/log.c182
-rw-r--r--examples/log/log.h59
-rw-r--r--examples/raw-ble-scan/Makefile21
-rw-r--r--examples/raw-ble-scan/main.c234
-rw-r--r--examples/scripts/erase.jlink5
-rw-r--r--examples/scripts/flash.jlink7
-rw-r--r--examples/scripts/softdevice.jlink8
-rw-r--r--examples/segger.py97
10 files changed, 748 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..45079e0
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,5 @@
+build
+*.pyc
+*.log
+*.sublime-project
+*.sublime-workspace
diff --git a/examples/Makefile.common b/examples/Makefile.common
new file mode 100644
index 0000000..bfa66c0
--- /dev/null
+++ b/examples/Makefile.common
@@ -0,0 +1,130 @@
+NRF51_SDK_PATH = /home/borges/workspace/bless/nrf51-sdk
+NRF51_SOFTDEVICE = /home/borges/workspace/bless/nrf51-sdk/s110_nrf51822_6.0.0-1.alpha_softdevice.hex
+JLINK_PATH = /home/borges/workspace/bless/nrf51-sdk/JLink_Linux_V474
+
+
+# Device
+DEVICE_FAMILY = NRF51
+CPU = cortex-m0
+
+ifeq ($(PROJECT_TARGET),)
+ $(error PROJECT_TARGET isn't defined)
+endif
+
+ifeq ($(HEAP_SIZE),)
+ HEAP_SIZE = 2048
+endif
+
+ifeq ($(STACK_SIZE),)
+ STACK_SIZE = 2048
+endif
+
+# Linker script
+ifeq ($(USE_SOFTDEVICE), s110)
+ LINKER_SCRIPT = gcc_nrf51_s110_$(SOC_VARIANT).ld
+ else
+ LINKER_SCRIPT = gcc_nrf51_blank_$(SOC_VARIANT).ld
+endif
+
+# Base paths
+SDK_INCLUDE_PATH = $(NRF51_SDK_PATH)/Nordic/nrf51822/Include
+SDK_SOURCE_PATH = $(NRF51_SDK_PATH)/Nordic/nrf51822/Source
+SDK_TEMPLATE_PATH = $(NRF51_SDK_PATH)/Nordic/nrf51822/Source/templates
+
+# Compiler tools
+CC = arm-none-eabi-gcc
+OBJCOPY = arm-none-eabi-objcopy
+OBJDUMP = arm-none-eabi-objdump
+
+# Include paths
+INCLUDE_PATHS = $(SDK_INCLUDE_PATH) $(SDK_INCLUDE_PATH)/gcc $(SDK_INCLUDE_PATH)/app_common \
+ $(SDK_INCLUDE_PATH)/ble $(SDK_INCLUDE_PATH)/ble/softdevice \
+ $(SDK_INCLUDE_PATH)/ble/ble_services $(PROJECT_INCLUDE_PATHS)
+INCLUDES = $(addprefix -I, $(INCLUDE_PATHS))
+
+# Compiler flags
+CFLAGS = -mcpu=$(CPU) -mthumb -mfloat-abi=soft -Wall -Werror --std=gnu99 -c
+CFLAGS += -D$(DEVICE_FAMILY) -D$(SOC) -D$(BOARD)
+CFLAGS += $(PROJECT_CFLAGS)
+CFLAGS += $(INCLUDES)
+
+ASMFLAGS = $(CFLAGS) -x assembler-with-cpp
+ASMFLAGS += -D__HEAP_SIZE=$(HEAP_SIZE) -D__STACK_SIZE=$(STACK_SIZE)
+
+# Linker flags
+LDFLAGS = -Xlinker -Map=$(BUILD_PATH)/$(PROJECT_TARGET).map -mcpu=$(CPU)
+LDFLAGS += -mthumb -mabi=aapcs --specs=nano.specs
+LDFLAGS += -T$(SDK_TEMPLATE_PATH)/gcc/$(LINKER_SCRIPT) -L$(SDK_TEMPLATE_PATH)/gcc
+LDFLAGS += $(PROJECT_LDFLAGS)
+
+# C sources paths & files
+C_SOURCE_PATHS = $(SDK_SOURCE_PATH) $(SDK_TEMPLATE_PATH) $(SDK_TEMPLATE_PATH)/gcc \
+ $(SDK_SOURCE_PATH)/app_common $(SDK_SOURCE_PATH)/nrf_delay \
+ $(SDK_SOURCE_PATH)/ble $(SDK_SOURCE_PATH)/simple_uart \
+ $(PROJECT_C_SOURCE_PATHS)
+
+C_SOURCE_FILES = system_nrf51.c $(PROJECT_C_SOURCE_FILES)
+
+# ASM sources paths & files
+ASM_SOURCE_PATHS = $(SDK_TEMPLATE_PATH)/gcc
+ASM_SOURCE_PATHS += $(PROJECT_ASM_SOURCE_FILES)
+
+ASM_SOURCE_FILES = gcc_startup_nrf51.s $(PROJECT_ASM_SOURCE_FILES)
+
+# Build path & objects
+BUILD_PATH = build
+
+C_OBJECT_FILES = $(addprefix $(BUILD_PATH)/, $(C_SOURCE_FILES:.c=.o))
+ASM_OBJECT_FILES = $(addprefix $(BUILD_PATH)/, $(ASM_SOURCE_FILES:.s=.o))
+
+vpath %.c $(C_SOURCE_PATHS)
+vpath %.s $(ASM_SOURCE_PATHS)
+
+# Softdevice
+SOFTDEVICE = $(BUILD_PATH)/softdevice_uicr.bin $(BUILD_PATH)/softdevice_main.bin
+
+export JLINK_PATH
+export BUILD_PATH
+export USE_SOFTDEVICE
+export SCRIPTS_PATH
+
+# Rules
+all: $(BUILD_PATH) $(BUILD_PATH)/$(PROJECT_TARGET).bin
+
+$(BUILD_PATH)/$(PROJECT_TARGET).bin: $(BUILD_PATH)/$(PROJECT_TARGET).out
+ $(OBJCOPY) -Obinary $(BUILD_PATH)/$(PROJECT_TARGET).out $(BUILD_PATH)/$(PROJECT_TARGET).bin
+
+$(BUILD_PATH)/$(PROJECT_TARGET).out: $(C_OBJECT_FILES) $(ASM_OBJECT_FILES)
+ $(CC) $(LDFLAGS) $(C_OBJECT_FILES) $(ASM_OBJECT_FILES) -o $@
+ $(OBJDUMP) -h $(BUILD_PATH)/$(PROJECT_TARGET).out
+
+# Build object files from C source files
+$(BUILD_PATH)/%.o: %.c
+ $(CC) $(CFLAGS) -o $@ $<
+
+# Build object files from ASM source files
+$(BUILD_PATH)/%.o: %.s
+ $(CC) $(ASMFLAGS) -o $@ $<
+
+$(BUILD_PATH):
+ -mkdir $@
+
+install upload: all
+ $(PROGRAMMER) flash `pwd`/$(BUILD_PATH)/$(PROJECT_TARGET).bin
+
+erase:
+ $(PROGRAMMER) erase
+
+softdevice: erase $(BUILD_PATH) $(SOFTDEVICE)
+ $(PROGRAMMER) softdevice $(addprefix `pwd`/, $(SOFTDEVICE))
+
+$(BUILD_PATH)/softdevice_uicr.bin: $(NRF51_SOFTDEVICE)
+ $(OBJCOPY) -Iihex -Obinary --only-section .sec3 $< $@
+
+$(BUILD_PATH)/softdevice_main.bin: $(NRF51_SOFTDEVICE)
+ $(OBJCOPY) -Iihex -Obinary --remove-section .sec3 $< $@
+
+clean:
+ rm -rf $(BUILD_PATH) *.log
+
+.PHONY: all install upload erase softdevice clean
diff --git a/examples/log/log.c b/examples/log/log.c
new file mode 100644
index 0000000..e12307e
--- /dev/null
+++ b/examples/log/log.c
@@ -0,0 +1,182 @@
+/**
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2013 Paulo Sérgio Borges de Oliveira Filho
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include "boards.h"
+#include "nrf_error.h"
+#include "nrf_delay.h"
+#include "simple_uart.h"
+#include "ble.h"
+#include "log.h"
+
+#define BUFFER_LEN 128
+
+static char buffer[BUFFER_LEN];
+
+void log_uart_init(void)
+{
+ simple_uart_config(RTS_PIN_NUMBER, TX_PIN_NUMBER,
+ CTS_PIN_NUMBER, RX_PIN_NUMBER,
+ HWFC);
+
+ nrf_delay_ms(1);
+ INIT_LOG();
+}
+
+void log_uart(const char *format, ...)
+{
+ va_list args;
+ va_start(args, format);
+
+ vsnprintf(buffer, BUFFER_LEN, format, args);
+ simple_uart_putstring((const uint8_t *) buffer);
+
+ va_end(args);
+}
+
+const char *nrf_error_to_str(uint32_t error_code)
+{
+ switch (error_code) {
+ case NRF_SUCCESS:
+ return "NRF_SUCCESS";
+ case NRF_ERROR_SVC_HANDLER_MISSING:
+ return "NRF_ERROR_SVC_HANDLER_MISSING";
+ case NRF_ERROR_SOFTDEVICE_NOT_ENABLED:
+ return "NRF_ERROR_SOFTDEVICE_NOT_ENABLED";
+ case NRF_ERROR_INTERNAL:
+ return "NRF_ERROR_INTERNAL";
+ case NRF_ERROR_NO_MEM:
+ return "NRF_ERROR_NO_MEM";
+ case NRF_ERROR_NOT_FOUND:
+ return "NRF_ERROR_NOT_FOUND";
+ case NRF_ERROR_NOT_SUPPORTED:
+ return "NRF_ERROR_NOT_SUPPORTED";
+ case NRF_ERROR_INVALID_PARAM:
+ return "NRF_ERROR_INVALID_PARAM";
+ case NRF_ERROR_INVALID_STATE:
+ return "NRF_ERROR_INVALID_STATE";
+ case NRF_ERROR_INVALID_LENGTH:
+ return "NRF_ERROR_INVALID_LENGTH";
+ case NRF_ERROR_INVALID_FLAGS:
+ return "NRF_ERROR_INVALID_FLAGS";
+ case NRF_ERROR_INVALID_DATA:
+ return "NRF_ERROR_INVALID_DATA";
+ case NRF_ERROR_DATA_SIZE:
+ return "NRF_ERROR_DATA_SIZE";
+ case NRF_ERROR_TIMEOUT:
+ return "NRF_ERROR_TIMEOUT";
+ case NRF_ERROR_NULL:
+ return "NRF_ERROR_NULL";
+ case NRF_ERROR_FORBIDDEN:
+ return "NRF_ERROR_FORBIDDEN";
+ case NRF_ERROR_INVALID_ADDR:
+ return "NRF_ERROR_INVALID_ADDR";
+ case NRF_ERROR_BUSY:
+ return "NRF_ERROR_BUSY";
+ default:
+ return "UNKNOWN_ERROR";
+ }
+}
+
+const char *nrf_evt_to_str(uint16_t evt_id)
+{
+ switch (evt_id) {
+ /* BLE independent events */
+ case BLE_EVT_TX_COMPLETE:
+ return "BLE_EVT_TX_COMPLETE";
+
+ /* BLE GAP events */
+ case BLE_GAP_EVT_CONNECTED:
+ return "BLE_GAP_EVT_CONNECTED";
+ case BLE_GAP_EVT_DISCONNECTED:
+ return "BLE_GAP_EVT_DISCONNECTED";
+ case BLE_GAP_EVT_CONN_PARAM_UPDATE:
+ return "BLE_GAP_EVT_CONN_PARAM_UPDATE";
+ case BLE_GAP_EVT_SEC_PARAMS_REQUEST:
+ return "BLE_GAP_EVT_SEC_PARAMS_REQUEST";
+ case BLE_GAP_EVT_SEC_INFO_REQUEST:
+ return "BLE_GAP_EVT_SEC_INFO_REQUEST";
+ case BLE_GAP_EVT_PASSKEY_DISPLAY:
+ return "BLE_GAP_EVT_PASSKEY_DISPLAY";
+ case BLE_GAP_EVT_AUTH_KEY_REQUEST:
+ return "BLE_GAP_EVT_AUTH_KEY_REQUEST";
+ case BLE_GAP_EVT_AUTH_STATUS:
+ return "BLE_GAP_EVT_AUTH_STATUS";
+ case BLE_GAP_EVT_CONN_SEC_UPDATE:
+ return "BLE_GAP_EVT_CONN_SEC_UPDATE";
+ case BLE_GAP_EVT_TIMEOUT:
+ return "BLE_GAP_EVT_TIMEOUT";
+ case BLE_GAP_EVT_RSSI_CHANGED:
+ return "BLE_GAP_EVT_RSSI_CHANGED";
+
+ /* BLE GATT Client events */
+ case BLE_GATTC_EVT_PRIM_SRVC_DISC_RSP:
+ return "BLE_GATTC_EVT_PRIM_SRVC_DISC_RSP";
+ case BLE_GATTC_EVT_REL_DISC_RSP:
+ return "BLE_GATTC_EVT_REL_DISC_RSP";
+ case BLE_GATTC_EVT_CHAR_DISC_RSP:
+ return "BLE_GATTC_EVT_CHAR_DISC_RSP";
+ case BLE_GATTC_EVT_DESC_DISC_RSP:
+ return "BLE_GATTC_EVT_DESC_DISC_RSP";
+ case BLE_GATTC_EVT_CHAR_VAL_BY_UUID_READ_RSP:
+ return "BLE_GATTC_EVT_CHAR_VAL_BY_UUID_READ_RSP";
+ case BLE_GATTC_EVT_READ_RSP:
+ return "BLE_GATTC_EVT_READ_RSP";
+ case BLE_GATTC_EVT_CHAR_VALS_READ_RSP:
+ return "BLE_GATTC_EVT_CHAR_VALS_READ_RSP";
+ case BLE_GATTC_EVT_WRITE_RSP:
+ return "BLE_GATTC_EVT_WRITE_RSP";
+ case BLE_GATTC_EVT_HVX:
+ return "BLE_GATTC_EVT_HVX";
+ case BLE_GATTC_EVT_TIMEOUT:
+ return "BLE_GATTC_EVT_TIMEOUT";
+
+ /* BLE GATT Server events */
+ case BLE_GATTS_EVT_WRITE:
+ return "BLE_GATTS_EVT_WRITE";
+ case BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST:
+ return "BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST";
+ case BLE_GATTS_EVT_SYS_ATTR_MISSING:
+ return "BLE_GATTS_EVT_SYS_ATTR_MISSING";
+ case BLE_GATTS_EVT_HVC:
+ return "BLE_GATTS_EVT_HVC";
+ case BLE_GATTS_EVT_SC_CONFIRM:
+ return "BLE_GATTS_EVT_SC_CONFIRM";
+ case BLE_GATTS_EVT_TIMEOUT:
+ return "BLE_GATTS_EVT_TIMEOUT";
+
+ /* BLE L2CAP events */
+ case BLE_L2CAP_EVT_RX:
+ return "BLE_L2CAP_EVT_RX";
+
+ /* Unknown */
+ case BLE_EVT_INVALID:
+ return "BLE_EVT_INVALID";
+ default:
+ sprintf(buffer, "#%u", evt_id);
+ return (const char *) buffer;
+ }
+}
diff --git a/examples/log/log.h b/examples/log/log.h
new file mode 100644
index 0000000..065c8c2
--- /dev/null
+++ b/examples/log/log.h
@@ -0,0 +1,59 @@
+/**
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2013 Paulo Sérgio Borges de Oliveira Filho
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef __LOG_H__
+#define __LOG_H__
+
+void log_uart_init(void);
+void log_uart(const char *format, ...);
+const char *nrf_error_to_str(uint32_t error_code);
+const char *nrf_evt_to_str(uint16_t evt_id);
+
+#define INIT_LOG() \
+ do { \
+ log_uart("\r\n"); \
+ } while (0)
+
+#define LOG(level, fmt, arg...) \
+ do { \
+ log_uart(level ":%s:%s() " fmt "\r\n", \
+ __FILE__, __func__, ## arg); \
+ } while (0)
+
+#define DBG(fmt, arg...) \
+ do { \
+ LOG("DEBUG", fmt, ## arg); \
+ } while (0)
+
+#define ERROR(fmt, arg...) \
+ do { \
+ LOG("ERROR", fmt, ## arg); \
+ } while (0)
+
+#define NRF_ERROR(file, line, err) \
+ do { \
+ log_uart("ERROR:%s:%lu %s\r\n", file, line, nrf_error_to_str(err)); \
+ } while (0)
+
+#endif
diff --git a/examples/raw-ble-scan/Makefile b/examples/raw-ble-scan/Makefile
new file mode 100644
index 0000000..07806e9
--- /dev/null
+++ b/examples/raw-ble-scan/Makefile
@@ -0,0 +1,21 @@
+SOC = NRF51822_QFAA_CA
+SOC_VARIANT = xxaa
+BOARD = BOARD_PCA10001
+USE_SOFTDEVICE = blank
+
+PROJECT_TARGET = raw-ble-scan
+
+PROJECT_INCLUDE_PATHS = ../log
+PROJECT_C_SOURCE_PATHS = ../log
+PROJECT_C_SOURCE_FILES = main.c \
+ log.c \
+ nrf_delay.c \
+ simple_uart.c
+
+HEAP_SIZE = 0
+STACK_SIZE = 1024
+
+PROGRAMMER = python ../segger.py
+SCRIPTS_PATH = ../scripts
+
+include ../Makefile.common
diff --git a/examples/raw-ble-scan/main.c b/examples/raw-ble-scan/main.c
new file mode 100644
index 0000000..f2aeef5
--- /dev/null
+++ b/examples/raw-ble-scan/main.c
@@ -0,0 +1,234 @@
+/**
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2013 Paulo Sérgio Borges de Oliveira Filho
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <string.h>
+#include "nrf51.h"
+#include "nrf_delay.h"
+#include "log.h"
+
+#define SET_BIT(n) (1UL << n)
+#define MAX_PDU_SIZE (64UL)
+
+#define ADV_CHANNEL_37 (2UL) /* 2402 MHz */
+#define ADV_CHANNEL_38 (26UL) /* 2426 MHz */
+#define ADV_CHANNEL_39 (80UL) /* 2480 MHz */
+
+#define MS(s) (1000 * s)
+#define RTC_PERIOD (5) /* ms */
+#define RTC_PRESCALER (((32768 * RTC_PERIOD) / 1000) - 1)
+#define SCAN_WINDOW (MS(1) / RTC_PERIOD)
+#define SCAN_INTERVAL (MS(2) / RTC_PERIOD)
+
+#define START_HFCLK() \
+ do { \
+ NRF_CLOCK->EVENTS_HFCLKSTARTED = 0UL; \
+ NRF_CLOCK->TASKS_HFCLKSTART = 1UL; \
+ while (NRF_CLOCK->EVENTS_HFCLKSTARTED == 0UL); \
+ } while(0)
+
+#define START_LFCLK() \
+ do { \
+ NRF_CLOCK->LFCLKSRC = CLOCK_LFCLKSRC_SRC_Xtal \
+ << CLOCK_LFCLKSRC_SRC_Pos; \
+ NRF_CLOCK->EVENTS_LFCLKSTARTED = 0; \
+ NRF_CLOCK->TASKS_LFCLKSTART = 1; \
+ while (NRF_CLOCK->EVENTS_LFCLKSTARTED == 0); \
+ } while (0)
+
+#define START_RTC0() \
+ do { \
+ NRF_RTC0->PRESCALER = RTC_PRESCALER; \
+ NRF_RTC0->TASKS_START = 1UL; \
+ } while (0)
+
+#define DBG_PACKET(channel, pdu) \
+ do { \
+ log_uart("Advertising channel " #channel "\r\n"); \
+ log_uart("CRC: %s\r\n", \
+ (NRF_RADIO->CRCSTATUS == 1) ? "OK" : "FAIL"); \
+ log_uart("PDU Type: 0x%02x\r\n", (pdu[0] >> 4) & 0xF); \
+ log_uart("TxAdd: 0x%02x\r\n", (pdu[0] >> 1) & 0x1); \
+ log_uart("RxAdd: 0x%02x\r\n", pdu[0] & 0x1); \
+ log_uart("Length: 0x%02x\r\n", pdu[1] & 0x3F); \
+ \
+ uint8_t i; \
+ uint8_t f = pdu[1] + 3; \
+ log_uart("Payload: "); \
+ for (i = 3; i < f; i++) { \
+ log_uart("0x%02X ", pdu[i]); \
+ } \
+ log_uart("\r\n"); \
+ } while (0)
+
+#define SCAN_CHANNEL(channel, frequency, window, pdu) \
+ do { \
+ NRF_RADIO->FREQUENCY = frequency; \
+ NRF_RADIO->DATAWHITEIV = channel & 0x3F; \
+ \
+ NRF_RADIO->EVENTS_READY = 0UL; \
+ NRF_RADIO->TASKS_RXEN = 1UL; \
+ while (NRF_RADIO->EVENTS_READY == 0UL); \
+ \
+ NRF_RADIO->EVENTS_END = 0UL; \
+ NRF_RADIO->TASKS_START = 1UL; \
+ while (NRF_RADIO->EVENTS_END == 0UL \
+ && (NRF_RTC0->COUNTER - window < SCAN_WINDOW)); \
+ \
+ NRF_RADIO->EVENTS_DISABLED = 0UL; \
+ NRF_RADIO->TASKS_DISABLE = 1UL; \
+ while (NRF_RADIO->EVENTS_DISABLED == 0UL); \
+ \
+ if (NRF_RADIO->EVENTS_END == 1UL) \
+ DBG_PACKET(channel, pdu); \
+ } while (0)
+
+#define START_TIMERS(t1, t2) do { t1 = t2 = NRF_RTC0->COUNTER; } while (0)
+
+#define WAIT_INTERVAL(interv, tmp) \
+ do { \
+ tmp = SCAN_INTERVAL - RTC_PERIOD * (NRF_RTC0->COUNTER - interv); \
+ if (tmp <= SCAN_INTERVAL) \
+ nrf_delay_ms(tmp); \
+ } while (0)
+
+static uint8_t pdu[MAX_PDU_SIZE];
+static volatile uint32_t window, interval, tmp;
+
+static void __inline setup(void)
+{
+ /* Start UART logging module. */
+ log_uart_init();
+
+ /* Start high frequency clock (16 MHz). */
+ START_HFCLK();
+
+ /* Start low frequency clock (32.768 kHz). */
+ START_LFCLK();
+
+ /* Start Real Timer Counter 0 (RTC0). */
+ START_RTC0();
+
+ /* Start to configure the RADIO.
+ *
+ * We clear PCNF0 and CPNF1 registers to use OR operations in the next
+ * operations.
+ */
+ NRF_RADIO->PCNF0 = 0UL;
+ NRF_RADIO->PCNF1 = 0UL;
+
+ /* Set RADIO mode to Bluetooth Low Energy. */
+ NRF_RADIO->MODE = RADIO_MODE_MODE_Ble_1Mbit << RADIO_MODE_MODE_Pos;
+
+ /* Set transmission power to 0dBm. */
+ NRF_RADIO->TXPOWER = RADIO_TXPOWER_TXPOWER_0dBm
+ << RADIO_TXPOWER_TXPOWER_Pos;
+
+ /* Set access address to 0x8E89BED6. This is the access address to be used
+ * when send packets in advertise channels.
+ *
+ * Since the access address is 4 bytes long and the prefix is 1 byte long,
+ * we first set the base address length to be 3 bytes long.
+ *
+ * Then we split the full access address in:
+ * 1. Prefix0: 0x0000008E (LSB -> Logic address 0)
+ * 2. Base0: 0x89BED600 (3 MSB)
+ *
+ * At last, we enable reception for this address.
+ */
+ NRF_RADIO->PCNF1 |= 3UL << RADIO_PCNF1_BALEN_Pos;
+ NRF_RADIO->BASE0 = 0x89BED600;
+ NRF_RADIO->PREFIX0 = 0x0000008E;
+ NRF_RADIO->RXADDRESSES = 0x00000001;
+
+ /* Enable data whitening. */
+ NRF_RADIO->PCNF1 |= RADIO_PCNF1_WHITEEN_Enabled << RADIO_PCNF1_WHITEEN_Pos;
+
+ /* Set maximum PAYLOAD size. */
+ NRF_RADIO->PCNF1 |= MAX_PDU_SIZE << RADIO_PCNF1_MAXLEN_Pos;
+
+ /* Configure CRC.
+ *
+ * First, we set the length of CRC field to 3 bytes long and ignore the
+ * access address in the CRC calculation.
+ *
+ * Then we set CRC initial value to 0x555555.
+ *
+ * The last step is to set the CRC polynomial to
+ * x^24 + x^10 + x^9 + x^6 + x^4 + x^3 + x + 1.
+ */
+ NRF_RADIO->CRCCNF = RADIO_CRCCNF_LEN_Three << RADIO_CRCCNF_LEN_Pos |
+ RADIO_CRCCNF_SKIP_ADDR_Skip
+ << RADIO_CRCCNF_SKIP_ADDR_Pos;
+ NRF_RADIO->CRCINIT = 0x555555UL;
+ NRF_RADIO->CRCPOLY = SET_BIT(24) | SET_BIT(10) | SET_BIT(9) |
+ SET_BIT(6) | SET_BIT(4) | SET_BIT(3) |
+ SET_BIT(1) | SET_BIT(0);
+
+ /* Configure header size.
+ *
+ * The Advertise has the following format:
+ * PDU Type(4b) | RFU(2b) | TxAdd(1b) | RxAdd(1b) | Length(6b) | RFU(2b)
+ *
+ * And the nRF51822 RADIO packet has the following format
+ * (directly editable fields):
+ * S0 (0/1 bytes) | LENGTH ([0, 8] bits) | S1 ([0, 8] bits)
+ *
+ * We can match those fields with the Link Layer fields:
+ * S0 (1 byte) --> PDU Type(4bits)|RFU(2bits)|TxAdd(1bit)|RxAdd(1bit)
+ * LENGTH (6 bits) --> Length(6bits)
+ * S1 (2 bits) --> S1(2bits)
+ */
+ NRF_RADIO->PCNF0 |= (1 << RADIO_PCNF0_S0LEN_Pos) | /* 1 byte */
+ (6 << RADIO_PCNF0_LFLEN_Pos) | /* 6 bits */
+ (2 << RADIO_PCNF0_S1LEN_Pos); /* 2 bits */
+
+ /* Set the pointer to write the incoming packet. */
+ NRF_RADIO->PACKETPTR = (uint32_t) pdu;
+ memset(pdu, 0, sizeof(pdu));
+}
+
+int main(void)
+{
+ setup();
+
+ while (1) {
+ log_uart("Scanning with wnd: %u ticks, interval: %u ticks\r\n",
+ SCAN_WINDOW, SCAN_INTERVAL);
+
+ /* Advertising channel 37 */
+ START_TIMERS(interval, window);
+ SCAN_CHANNEL(37, ADV_CHANNEL_37, window, pdu);
+ WAIT_INTERVAL(interval, tmp);
+
+ /* Advertising channel 38 */
+ START_TIMERS(interval, window);
+ SCAN_CHANNEL(38, ADV_CHANNEL_38, window, pdu);
+ WAIT_INTERVAL(interval, tmp);
+
+ /* Advertising channel 39 */
+ START_TIMERS(interval, window);
+ SCAN_CHANNEL(39, ADV_CHANNEL_39, window, pdu);
+ WAIT_INTERVAL(interval, tmp);
+ }
+}
diff --git a/examples/scripts/erase.jlink b/examples/scripts/erase.jlink
new file mode 100644
index 0000000..f2b76a7
--- /dev/null
+++ b/examples/scripts/erase.jlink
@@ -0,0 +1,5 @@
+w4 4001e504 2
+w4 4001e50c 1
+w4 4001e514 1
+r
+q
diff --git a/examples/scripts/flash.jlink b/examples/scripts/flash.jlink
new file mode 100644
index 0000000..4aa159c
--- /dev/null
+++ b/examples/scripts/flash.jlink
@@ -0,0 +1,7 @@
+device nrf51822
+speed 1000
+w4 4001e504 1
+loadbin {program} {addr}
+r
+g
+q
diff --git a/examples/scripts/softdevice.jlink b/examples/scripts/softdevice.jlink
new file mode 100644
index 0000000..3a6413f
--- /dev/null
+++ b/examples/scripts/softdevice.jlink
@@ -0,0 +1,8 @@
+device nrf51822
+speed 1000
+w4 4001e504 1
+loadbin {uicr} 0x10001000
+loadbin {main} 0
+r
+g
+q
diff --git a/examples/segger.py b/examples/segger.py
new file mode 100644
index 0000000..bd2c121
--- /dev/null
+++ b/examples/segger.py
@@ -0,0 +1,97 @@
+# coding: utf-8
+
+# The MIT License (MIT)
+#
+# Copyright (c) 2013 Paulo Sérgio Borges de Oliveira Filho
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in all
+# copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+
+import subprocess
+import argparse
+import os.path
+import os
+import sys
+
+###############################################################################
+
+parser = argparse.ArgumentParser(prog="segger")
+subparsers = parser.add_subparsers()
+
+erase = subparsers.add_parser("erase", help="erase the flash")
+erase.set_defaults(command="erase")
+
+flash = subparsers.add_parser("flash", help="program the flash")
+flash.set_defaults(command="flash")
+flash.add_argument("program", help="binary file containing the program")
+
+softdevice = subparsers.add_parser("softdevice", help="program the softdevice")
+softdevice.set_defaults(command="softdevice")
+softdevice.add_argument("uicr")
+softdevice.add_argument("main")
+
+###############################################################################
+
+jlinkexe = "LD_LIBRARY_PATH={path}:$LD_LIBRARY_PATH {path}/JLinkExe {script}"
+
+def exec_jlinkexe(script, path=os.environ["BUILD_PATH"]):
+ try:
+ print subprocess.check_output(jlinkexe.format(
+ path=os.environ["JLINK_PATH"],
+ script=os.path.join(path, script)
+ ), shell=True)
+ except subprocess.CalledProcessError, e:
+ print e.output
+ return 0
+
+def read_script_file(script):
+ return open(os.path.join(os.environ["SCRIPTS_PATH"], script), 'r').read()
+
+def create_tmp_script(name, content):
+ with open(os.path.join(os.environ["BUILD_PATH"], name), 'w') as f:
+ f.write(content)
+
+###############################################################################
+
+def erase():
+ return exec_jlinkexe("erase.jlink", os.environ["SCRIPTS_PATH"])
+
+def flash(program):
+ if os.environ["USE_SOFTDEVICE"] == "s110":
+ addr = hex(0x00014000)
+ else:
+ addr = hex(0)
+
+ script_name = "flash.jlink"
+ content = read_script_file(script_name).format(program=program, addr=addr)
+ create_tmp_script(script_name, content)
+ return exec_jlinkexe(script_name)
+
+def softdevice(uicr, main):
+ script_name = "softdevice.jlink"
+ content = read_script_file(script_name).format(uicr=uicr, main=main)
+ create_tmp_script(script_name, content)
+ return exec_jlinkexe(script_name)
+
+###############################################################################
+
+args = parser.parse_args().__dict__
+command = args.pop("command")
+
+status = globals()[command](**args)
+sys.exit(status)