diff options
author | Paulo Borges <paulo.borges@openbossa.org> | 2013-11-04 19:49:28 -0300 |
---|---|---|
committer | Paulo Borges <paulo.borges@openbossa.org> | 2013-11-13 16:50:57 -0300 |
commit | 7ace4656ae866ea57008fac5a1b4c3ce1c410d1d (patch) | |
tree | 59ce5496373428df912a034a1622ab01543b9155 |
WIP: First commitmaster
-rw-r--r-- | .gitignore | 5 | ||||
-rw-r--r-- | examples/Makefile.common | 130 | ||||
-rw-r--r-- | examples/log/log.c | 182 | ||||
-rw-r--r-- | examples/log/log.h | 59 | ||||
-rw-r--r-- | examples/raw-ble-scan/Makefile | 21 | ||||
-rw-r--r-- | examples/raw-ble-scan/main.c | 234 | ||||
-rw-r--r-- | examples/scripts/erase.jlink | 5 | ||||
-rw-r--r-- | examples/scripts/flash.jlink | 7 | ||||
-rw-r--r-- | examples/scripts/softdevice.jlink | 8 | ||||
-rw-r--r-- | examples/segger.py | 97 |
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) |