Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

boards/nrf52xxxdk: make reset pin work #10072

Merged
merged 2 commits into from
Oct 12, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
11 changes: 11 additions & 0 deletions boards/nrf52840dk/doc.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,15 @@
@defgroup boards_nrf52840dk nRF52840 DK
@ingroup boards
@brief Support for the nRF52840 DK


### RESET pin configuration

On many (all?) nrf52840dk boards, the reset pin is not configured out-of-the box.
This means, that simply nothing happens if the RESET pin is pressed. To change
this, RIOT provides a little tool in `dist/tools/nrf52_resetpin_cfg`.

Simply compile, flash, and run that tool on your board, and the reset pin should
work for the time being.

*/
9 changes: 9 additions & 0 deletions boards/nrf52dk/doc.txt
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,15 @@ board](https://github.com/d00616/temp/raw/master/nrf52-minidev.jpg)

**Caution**: NFC is not usable with this board.

### RESET pin configuration

On many (all?) nrf52dk boards, the reset pin is not configured out-of-the box.
This means, that simply nothing happens if the RESET pin is pressed. To change
this, RIOT provides a little tool in `dist/tools/nrf52_resetpin_cfg`.

Simply compile, flash, and run that tool on your board, and the reset pin should
work for the time being.

## Current measurement:

There are two pins for current measurement on board. Don't connect these pins
Expand Down
24 changes: 24 additions & 0 deletions dist/tools/nrf52_resetpin_cfg/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# name of your application
APPLICATION = nrf52_resetpin_cfg

# configure RIOT basics
BOARD ?= nrf52dk
RIOTBASE ?= $(CURDIR)/../../..

# the RESET_PIN environment variable allows for manually specifying the reset
# pin that is programmed. Below this Makefile already contains the specific pins
# for some known platforms
ifeq (nrf52dk,$(BOARD))
RESET_PIN ?= 21
endif
ifeq (nrf52840dk,$(BOARD))
RESET_PIN ?= 18
endif
ifeq (,$(RESET_PIN))
$(error Please specify the target reset pin using the RESET_PIN env variable)
else
CFLAGS += -DRESET_PIN=$(RESET_PIN)
endif


include $(RIOTBASE)/Makefile.include
18 changes: 18 additions & 0 deletions dist/tools/nrf52_resetpin_cfg/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
Program the reset pin for nRF52x CPUs
=====================================

Simply compile, flash, and run this tool on your nRF52x-based board. It will
program the given `RESET_PIN` into the NRF_UICR->PSELRESET registers, hence
allowing for hardware resets using a button connected to that pin.


Context
=======
For nRF52x CPUs, the reset pin is programmable. The reset pin configuration is
store in two persistent registers, that are programmed in the same way as the
CPUs flash memory.

In most cases, these values should be readily programmed when you get your
board, and thus do not need to be touched. However, we have seen however a
number of nrf52xxxdk boards, where this was not the case and the on-board reset
button did have no effect. Running this tool on those boards solves the issue.
131 changes: 131 additions & 0 deletions dist/tools/nrf52_resetpin_cfg/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
/*
* Copyright (C) 2018 Freie Universität Berlin
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/

/**
* @ingroup tools
* @{
*
* @file
* @brief Tool for programming the reset pin on nRF52x-based boards
*
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
*
* @}
*/

#include <stdio.h>
#include <string.h>

#include "cpu.h"
#include "periph/pm.h"

/* guard against bad usage: only allow building for nRF52x CPUs */
#ifndef CPU_NRF52
#error This tool is only usable for nRF52x-based platforms
#endif

#ifndef RESET_PIN
#error RESET_PIN not specified
#endif

#define PORT_BIT (0x00000020)
#define PORT_POS (5U)
#define PIN_MASK (0x0000001f)

#define RESET_VAL (0xffffffff)

#define REG_NUM (sizeof(NRF_UICR_Type) / 4)

/* allocate a copy of the registers in RAM */
static NRF_UICR_Type _buf;

static void _print_pin(uint32_t p)
{
printf("P%i.%2i", (int)((p & PORT_BIT) >> PORT_POS), (int)(p & PIN_MASK));
}

static void _copy(volatile uint32_t *dst, volatile uint32_t *src, unsigned num)
{
for (unsigned i = 0; i < num; i++) {
*dst++ = *src++;
}
}

static void _save_uicr(void)
{
memcpy(&_buf, (void *)NRF_UICR, sizeof(NRF_UICR_Type));
}

static void _restore_uicr(void)
{
NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Wen;
while (NRF_NVMC->READY == NVMC_READY_READY_Busy) {}

/* we copy the values back selectively, skipping the PSELRESET fields */
_copy(NRF_UICR->NRFFW, _buf.NRFFW, 15);
_copy(NRF_UICR->NRFHW, _buf.NRFHW, 12);
_copy(NRF_UICR->CUSTOMER, _buf.CUSTOMER, 32);
NRF_UICR->APPROTECT = _buf.APPROTECT;
NRF_UICR->NFCPINS = _buf.NFCPINS;
#ifdef CPU_MODEL_NRF52840XXAA
NRF_UICR->EXTSUPPLY = _buf.EXTSUPPLY;
NRF_UICR->REGOUT0 = _buf.REGOUT0;
#endif

/* we can leave the NVMC in write enable mode when leaving... */
}

int main(void)
{
uint32_t target = (uint32_t)RESET_PIN;

if ((NRF_UICR->PSELRESET[0] == target) &&
(NRF_UICR->PSELRESET[1] == target)) {
puts("\nAll good!");
_print_pin(target);
puts(" programmed as reset pin\n");
puts("Now press the reset button to confirm its function!");
}
else {
puts("\nReset pin is not programmed properly");
printf("Will now program it to ");
_print_pin(target);
puts("\n\nPress any key (meaning send any char) to continue");
getchar();

puts("Progamming the pin now...");
if ((NRF_UICR->PSELRESET[0] != RESET_VAL) ||
(NRF_UICR->PSELRESET[1] != RESET_VAL)) {
/* we can only erase all UICR registers at once, so we need to save
* and restore there values for clearing the PSELRESET registers */
puts("save uicr");
_save_uicr();
NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Een;
while (NRF_NVMC->READY == NVMC_READY_READY_Busy) {}
NRF_NVMC->ERASEUICR = 1;
while (NRF_NVMC->READY == NVMC_READY_READY_Busy) {}
puts("restore");
_restore_uicr();
}

puts("promming new value to PSELRESET");
NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Wen;
while (NRF_NVMC->READY == NVMC_READY_READY_Busy) {}
NRF_UICR->PSELRESET[0] = target;
NRF_UICR->PSELRESET[1] = target;
while (NRF_NVMC->READY == NVMC_READY_READY_Busy) {}
NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Ren;

/* verify result */
puts("The changes will only take effect after reboot.\n"
"Doing a reboot now...\n");
pm_reboot();
}

return 0;
}