Skip to content

Commit 554f82f

Browse files
authored
Merge pull request adafruit#1286 from klardotsh/topic-nrf52840-mdk
Add support for MakerDiary nRF52840 MDK board
2 parents 74e0142 + 4a40919 commit 554f82f

File tree

9 files changed

+302
-9
lines changed

9 files changed

+302
-9
lines changed

.travis.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ git:
2121
# that SDK is shortest and add it there. In the case of major re-organizations,
2222
# just try to make the builds "about equal in run time"
2323
env:
24-
- TRAVIS_TESTS="unix docs translations" TRAVIS_BOARDS="feather_huzzah circuitplayground_express pca10056 pca10059 feather_nrf52832 feather_nrf52840_express" TRAVIS_SDK=arm:nrf:esp8266
24+
- TRAVIS_TESTS="unix docs translations" TRAVIS_BOARDS="feather_huzzah circuitplayground_express pca10056 pca10059 feather_nrf52832 feather_nrf52840_express makerdiary_nrf52840_mdk" TRAVIS_SDK=arm:nrf:esp8266
2525
- TRAVIS_BOARDS="metro_m0_express metro_m4_express pirkey_m0 trellis_m4_express trinket_m0" TRAVIS_SDK=arm
2626
- TRAVIS_BOARDS="feather_radiofruit_zigbee gemma_m0 hallowing_m0_express itsybitsy_m0_express itsybitsy_m4_express meowmeow" TRAVIS_SDK=arm
2727
- TRAVIS_BOARDS="feather_m0_express_crickit feather_m0_rfm69 feather_m0_rfm9x feather_m4_express arduino_zero" TRAVIS_SDK=arm

ports/nrf/Makefile

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -300,16 +300,16 @@ sd: $(BUILD)/$(OUTPUT_FILENAME).hex
300300
else ifeq ($(FLASHER), pyocd)
301301

302302
flash: $(BUILD)/$(OUTPUT_FILENAME).hex
303-
pyocd-flashtool -t $(MCU_SUB_VARIANT) $< --sector_erase
304-
pyocd-tool -t $(MCU_SUB_VARIANT) erase $(BOOT_SETTING_ADDR)
305-
pyocd-tool -t $(MCU_SUB_VARIANT) write32 $(BOOT_SETTING_ADDR) 0x00000001
306-
pyocd-tool -t $(MCU_SUB_VARIANT) reset
303+
pyocd-flashtool -t $(MCU_VARIANT) $< --sector_erase
304+
#pyocd-tool -t $(MCU_VARIANT) erase $(BOOT_SETTING_ADDR)
305+
pyocd-tool -t $(MCU_VARIANT) write32 $(BOOT_SETTING_ADDR) 0x00000001
306+
pyocd-tool -t $(MCU_VARIANT) reset
307307

308308
sd: $(BUILD)/$(OUTPUT_FILENAME).hex
309-
pyocd-flashtool -t $(MCU_SUB_VARIANT) --chip_erase
310-
pyocd-flashtool -t $(MCU_SUB_VARIANT) $(SOFTDEV_HEX)
311-
pyocd-flashtool -t $(MCU_SUB_VARIANT) $< --sector_erase
312-
pyocd-tool -t $(MCU_SUB_VARIANT) reset $(BOOT_SETTING_ADDR)
309+
pyocd-flashtool -t $(MCU_VARIANT) --chip_erase
310+
pyocd-flashtool -t $(MCU_VARIANT) $(SOFTDEV_HEX)
311+
pyocd-flashtool -t $(MCU_VARIANT) $< --sector_erase
312+
pyocd-tool -t $(MCU_VARIANT) reset $(BOOT_SETTING_ADDR)
313313

314314
endif
315315

ports/nrf/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ the following links:
3939
* Adafruit [Feather nRF52](boards/feather_nrf52832/README.md): 512KB Flash, 64KB SRAM
4040
* Adafruit [Feather nRF52840](boards/feather_nrf52840_express/README.md): 1MB Flash, 256KB SRAM
4141
* Nordic PCA10056 see [Feather nRF52840](boards/pca10056/README.md)
42+
* MakerDiary NRF52840 MDK see [its README](boards/makerdiary_nrf52840_mdk/README.md)
4243

4344
For all other board targets, see the generic notes below.
4445

@@ -80,6 +81,7 @@ pca10040 | s132 | Peripheral and Scanner | [S
8081
pca10056 | s140 | Peripheral and Scanner | [Segger](#segger-targets)
8182
feather_nrf52832 | s132 | Peripheral and Scanner | [UART DFU](#dfu-targets)
8283
feather_nrf52840_express | s140 | Peripheral and Scanner | UF2 bootloader
84+
makerdiary_nrf52840_mdk | s140 | Peripheral and Scanner | pyocd or ARM mbed DAPLink
8385

8486
## Segger Targets
8587

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
# MakerDiary NRF52840 MDK
2+
3+
Refer to https://github.com/makerdiary/nrf52840-mdk or
4+
https://wiki.makerdiary.com/nrf52840-mdk/ for more details about the device.
5+
6+
Notably, CircuitPython does not currently support QSPI external flash on NRF
7+
devices, so neither does this port - the 64Mb flash device is not used for
8+
anything. Also, don't confuse this with the 64MiB drive that shows up on your
9+
computer - it's actually part of the MSC driver provided by the DAPLink
10+
debugger, and is inaccessible at all from Python land (this drive is where you
11+
can copy `firmware.hex` if you'd prefer to flash that way as opposed to with
12+
`pyocd`. You'll still have access to 256KB of the onboard flash, however, for
13+
storing your Python files, cat pictures, or whatever.
14+
15+
It's also interesting to note that all three LEDs and the "user button" on this
16+
device are wired through sinks, not sources, so flip your boolean expectations
17+
when dealing with `digitalio.DigitalInOut` on this device - `my_led.value =
18+
True` turns the LED off! Likewise, the user button will read `False` when
19+
pressed.
20+
21+
## Installing CircuitPython submodules
22+
23+
Before you can build, you will need to run the following commands once, which
24+
will install the submodules that are part of the CircuitPython ecosystem, and
25+
build the `mpy-cross` tool:
26+
27+
```
28+
$ cd circuitpython
29+
$ git submodule update --init
30+
$ make -C mpy-cross
31+
```
32+
33+
You then need to download the SD and Nordic SDK files via:
34+
35+
> This script relies on `wget`, which must be available from the command line.
36+
37+
```
38+
$ cd ports/nrf
39+
$ ./drivers/bluetooth/download_ble_stack.sh
40+
```
41+
42+
## Note about bootloaders
43+
44+
While most Adafruit devices come with (or can easily be flashed with) an
45+
Adafruit-provided bootloader (supporting niceties like UF2 flashing), this
46+
board comes with DAPLink which (apparently?) handles everything from debugging
47+
to programming the device, as well as the boot sequence. What's particularly
48+
awesome about this board is that there is no physical interaction with the board
49+
required to flash new code (read: CircuitPython builds) - the device is _always_
50+
listening for new firmware uploads (via `pyocd-flashtool`), even if userspace
51+
code is running.
52+
53+
## Building and Flashing CircuitPython
54+
55+
You'll need to have [pyocd](https://github.com/mbedmicro/pyOCD) installed as
56+
appropriate for your system.
57+
58+
```sh
59+
make BOARD=makerdiary_nrf52840_mdk FLASHER=pyocd SD=s140 flash
60+
```
61+
62+
This should give you the following (or very similar) output, and you will see
63+
a DFU blinky pattern on one of the board LEDs:
64+
65+
```
66+
$ make BOARD=makerdiary_nrf52840_mdk FLASHER=pyocd SD=s140 flash
67+
Use make V=1, make V=2 or set BUILD_VERBOSE similarly in your environment to increase build verbosity.
68+
pyocd-flashtool -t nrf52 build-makerdiary_nrf52840_mdk-s140/firmware.hex --sector_erase
69+
INFO:root:DAP SWD MODE initialised
70+
INFO:root:ROM table #0 @ 0xe00ff000 cidr=b105100d pidr=2002c4008
71+
INFO:root:[0]<e000e000:SCS-M4 cidr=b105e00d, pidr=4000bb00c, class=14>
72+
WARNING:root:Invalid coresight component, cidr=0x0
73+
INFO:root:[1]<e0001000: cidr=0, pidr=0, component invalid>
74+
INFO:root:[2]<e0002000:FPB cidr=b105e00d, pidr=4002bb003, class=14>
75+
WARNING:root:Invalid coresight component, cidr=0x1010101
76+
INFO:root:[3]<e0000000: cidr=1010101, pidr=101010101010101, component invalid>
77+
WARNING:root:Invalid coresight component, cidr=0x0
78+
INFO:root:[4]<e0040000: cidr=0, pidr=0, component invalid>
79+
INFO:root:[5]<e0041000:ETM-M4 cidr=b105900d, pidr=4000bb925, class=9, devtype=13, devid=0>
80+
INFO:root:CPU core is Cortex-M4
81+
INFO:root:FPU present
82+
INFO:root:6 hardware breakpoints, 4 literal comparators
83+
INFO:root:4 hardware watchpoints
84+
[====================] 100%
85+
INFO:root:Programmed 237568 bytes (58 pages) at 14.28 kB/s
86+
#pyocd-tool -t nrf52 erase 0xFF000
87+
pyocd-tool -t nrf52 write32 0xFF000 0x00000001
88+
WARNING:root:Invalid coresight component, cidr=0x0
89+
WARNING:root:Invalid coresight component, cidr=0x1010101
90+
WARNING:root:Invalid coresight component, cidr=0x0
91+
pyocd-tool -t nrf52 reset
92+
WARNING:root:Invalid coresight component, cidr=0x0
93+
WARNING:root:Invalid coresight component, cidr=0x1010101
94+
WARNING:root:Invalid coresight component, cidr=0x0
95+
Resetting target
96+
```
97+
98+
Alternatively (and untested by me), it's apparently possible to copy
99+
`firmware.hex` to the MSC device provided by DAPLink and flash that way. Refer
100+
to [the upstream
101+
documentation](https://wiki.makerdiary.com/nrf52840-mdk/getting-started/#drag-n-drop-programming)
102+
for details.
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/*
2+
* This file is part of the MicroPython project, http://micropython.org/
3+
*
4+
* The MIT License (MIT)
5+
*
6+
* Copyright (c) 2017 Scott Shawcroft for Adafruit Industries
7+
*
8+
* Permission is hereby granted, free of charge, to any person obtaining a copy
9+
* of this software and associated documentation files (the "Software"), to deal
10+
* in the Software without restriction, including without limitation the rights
11+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12+
* copies of the Software, and to permit persons to whom the Software is
13+
* furnished to do so, subject to the following conditions:
14+
*
15+
* The above copyright notice and this permission notice shall be included in
16+
* all copies or substantial portions of the Software.
17+
*
18+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24+
* THE SOFTWARE.
25+
*/
26+
27+
#include "boards/board.h"
28+
#include "usb.h"
29+
30+
void board_init(void) {
31+
usb_init();
32+
}
33+
34+
bool board_requests_safe_mode(void) {
35+
return false;
36+
}
37+
38+
void reset_board(void) {
39+
40+
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
/*
2+
* This file is part of the MicroPython project, http://micropython.org/
3+
*
4+
* The MIT License (MIT)
5+
*
6+
* Copyright (c) 2016 Glenn Ruben Bakke
7+
* Copyright (c) 2018 Dan Halbert for Adafruit Industries
8+
*
9+
* Permission is hereby granted, free of charge, to any person obtaining a copy
10+
* of this software and associated documentation files (the "Software"), to deal
11+
* in the Software without restriction, including without limitation the rights
12+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13+
* copies of the Software, and to permit persons to whom the Software is
14+
* furnished to do so, subject to the following conditions:
15+
*
16+
* The above copyright notice and this permission notice shall be included in
17+
* all copies or substantial portions of the Software.
18+
*
19+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25+
* THE SOFTWARE.
26+
*/
27+
28+
#define MAKERDIARYNRF52840MDK
29+
30+
#define MICROPY_HW_BOARD_NAME "MakerDiary nRF52840 MDK"
31+
#define MICROPY_HW_MCU_NAME "nRF52840"
32+
#define MICROPY_PY_SYS_PLATFORM "MakerDiary52840MDK"
33+
34+
#define MICROPY_QSPI_DATA0 (&pin_P1_05)
35+
#define MICROPY_QSPI_DATA1 (&pin_P1_04)
36+
#define MICROPY_QSPI_DATA2 (&pin_P1_02)
37+
#define MICROPY_QSPI_DATA3 (&pin_P1_01)
38+
#define MICROPY_QSPI_SCK (&pin_P1_03)
39+
#define MICROPY_QSPI_CS (&pin_P1_06)
40+
41+
#define CIRCUITPY_AUTORELOAD_DELAY_MS 500
42+
43+
// If you change this, then make sure to update the linker scripts as well to
44+
// make sure you don't overwrite code
45+
#define PORT_HEAP_SIZE (128 * 1024)
46+
// TODO #define CIRCUITPY_INTERNAL_NVM_SIZE 8192
47+
48+
#define BOARD_FLASH_SIZE (FLASH_SIZE - 0x4000 - CIRCUITPY_INTERNAL_NVM_SIZE)
49+
50+
// TODO #include "external_flash/devices.h"
51+
52+
#define EXTERNAL_FLASH_DEVICE_COUNT 1
53+
// Datasheet for when this is implemented:
54+
// http://www.mxic.com.tw/Lists/Datasheet/Attachments/7428/MX25R6435F,%20Wide%20Range,%2064Mb,%20v1.4.pdf
55+
#define EXTERNAL_FLASH_DEVICES MX25R6435F
56+
57+
#define EXTERNAL_FLASH_QSPI_DUAL
58+
59+
// TODO include "external_flash/external_flash.h"
60+
61+
#define BOARD_HAS_CRYSTAL 0
62+
63+
#define DEFAULT_UART_BUS_RX (&pin_P0_19)
64+
#define DEFAULT_UART_BUS_TX (&pin_P0_20)
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
MCU_SERIES = m4
2+
MCU_VARIANT = nrf52
3+
MCU_SUB_VARIANT = nrf52840
4+
MCU_CHIP = nrf52840
5+
SD ?= s140
6+
SOFTDEV_VERSION ?= 6.1.0
7+
8+
BOOT_SETTING_ADDR = 0xFF000
9+
10+
ifeq ($(SD),)
11+
LD_FILE = boards/nrf52840_1M_256k.ld
12+
else
13+
LD_FILE = boards/adafruit_$(MCU_SUB_VARIANT)_$(SD_LOWER)_v$(firstword $(subst ., ,$(SOFTDEV_VERSION))).ld
14+
endif
15+
16+
NRF_DEFINES += -DNRF52840_XXAA -DNRF52840
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
#include "shared-bindings/board/__init__.h"
2+
3+
#include "board_busses.h"
4+
5+
STATIC const mp_rom_map_elem_t board_module_globals_table[] = {
6+
{ MP_ROM_QSTR(MP_QSTR_AIN0), MP_ROM_PTR(&pin_P0_02) },
7+
{ MP_ROM_QSTR(MP_QSTR_AIN1), MP_ROM_PTR(&pin_P0_03) },
8+
{ MP_ROM_QSTR(MP_QSTR_AIN2), MP_ROM_PTR(&pin_P0_04) },
9+
{ MP_ROM_QSTR(MP_QSTR_AIN3), MP_ROM_PTR(&pin_P0_05) },
10+
{ MP_ROM_QSTR(MP_QSTR_AIN4), MP_ROM_PTR(&pin_P0_28) },
11+
{ MP_ROM_QSTR(MP_QSTR_AIN5), MP_ROM_PTR(&pin_P0_29) },
12+
{ MP_ROM_QSTR(MP_QSTR_AIN6), MP_ROM_PTR(&pin_P0_30) },
13+
{ MP_ROM_QSTR(MP_QSTR_AIN7), MP_ROM_PTR(&pin_P0_31) },
14+
15+
{ MP_ROM_QSTR(MP_QSTR_AREF), MP_ROM_PTR(&pin_P0_04) },
16+
{ MP_ROM_QSTR(MP_QSTR_VDIV), MP_ROM_PTR(&pin_P0_05) },
17+
18+
{ MP_ROM_QSTR(MP_QSTR_NFC1), MP_ROM_PTR(&pin_P0_09) },
19+
{ MP_ROM_QSTR(MP_QSTR_NFC2), MP_ROM_PTR(&pin_P0_10) },
20+
21+
{ MP_ROM_QSTR(MP_QSTR_P2), MP_ROM_PTR(&pin_P0_02) },
22+
{ MP_ROM_QSTR(MP_QSTR_P3), MP_ROM_PTR(&pin_P0_03) },
23+
{ MP_ROM_QSTR(MP_QSTR_P4), MP_ROM_PTR(&pin_P0_04) },
24+
{ MP_ROM_QSTR(MP_QSTR_P5), MP_ROM_PTR(&pin_P0_05) },
25+
{ MP_ROM_QSTR(MP_QSTR_P6), MP_ROM_PTR(&pin_P0_06) },
26+
{ MP_ROM_QSTR(MP_QSTR_P7), MP_ROM_PTR(&pin_P0_07) },
27+
{ MP_ROM_QSTR(MP_QSTR_P8), MP_ROM_PTR(&pin_P0_08) },
28+
{ MP_ROM_QSTR(MP_QSTR_P9), MP_ROM_PTR(&pin_P0_09) },
29+
{ MP_ROM_QSTR(MP_QSTR_P10), MP_ROM_PTR(&pin_P0_10) },
30+
{ MP_ROM_QSTR(MP_QSTR_P11), MP_ROM_PTR(&pin_P0_11) },
31+
{ MP_ROM_QSTR(MP_QSTR_P12), MP_ROM_PTR(&pin_P0_12) },
32+
{ MP_ROM_QSTR(MP_QSTR_P13), MP_ROM_PTR(&pin_P0_13) },
33+
{ MP_ROM_QSTR(MP_QSTR_P14), MP_ROM_PTR(&pin_P0_14) },
34+
{ MP_ROM_QSTR(MP_QSTR_P15), MP_ROM_PTR(&pin_P0_15) },
35+
{ MP_ROM_QSTR(MP_QSTR_P16), MP_ROM_PTR(&pin_P0_16) },
36+
{ MP_ROM_QSTR(MP_QSTR_P17), MP_ROM_PTR(&pin_P0_17) },
37+
{ MP_ROM_QSTR(MP_QSTR_P21), MP_ROM_PTR(&pin_P0_21) },
38+
{ MP_ROM_QSTR(MP_QSTR_P25), MP_ROM_PTR(&pin_P0_25) },
39+
{ MP_ROM_QSTR(MP_QSTR_P26), MP_ROM_PTR(&pin_P0_26) },
40+
{ MP_ROM_QSTR(MP_QSTR_P27), MP_ROM_PTR(&pin_P0_27) },
41+
{ MP_ROM_QSTR(MP_QSTR_P28), MP_ROM_PTR(&pin_P0_28) },
42+
{ MP_ROM_QSTR(MP_QSTR_P29), MP_ROM_PTR(&pin_P0_29) },
43+
{ MP_ROM_QSTR(MP_QSTR_P30), MP_ROM_PTR(&pin_P0_30) },
44+
{ MP_ROM_QSTR(MP_QSTR_P31), MP_ROM_PTR(&pin_P0_31) },
45+
46+
{ MP_ROM_QSTR(MP_QSTR_SCK), MP_ROM_PTR(&pin_P1_03) },
47+
{ MP_ROM_QSTR(MP_QSTR_CSN), MP_ROM_PTR(&pin_P1_06) },
48+
{ MP_ROM_QSTR(MP_QSTR_IO0), MP_ROM_PTR(&pin_P1_05) },
49+
{ MP_ROM_QSTR(MP_QSTR_IO1), MP_ROM_PTR(&pin_P1_04) },
50+
{ MP_ROM_QSTR(MP_QSTR_IO2), MP_ROM_PTR(&pin_P1_02) },
51+
{ MP_ROM_QSTR(MP_QSTR_IO3), MP_ROM_PTR(&pin_P1_01) },
52+
53+
{ MP_ROM_QSTR(MP_QSTR_TXD), MP_ROM_PTR(&pin_P0_20) },
54+
{ MP_ROM_QSTR(MP_QSTR_RXD), MP_ROM_PTR(&pin_P0_19) },
55+
56+
{ MP_ROM_QSTR(MP_QSTR_LED_RED), MP_ROM_PTR(&pin_P0_23) },
57+
{ MP_ROM_QSTR(MP_QSTR_LED_GREEN), MP_ROM_PTR(&pin_P0_22) },
58+
{ MP_ROM_QSTR(MP_QSTR_LED_BLUE), MP_ROM_PTR(&pin_P0_24) },
59+
60+
{ MP_ROM_QSTR(MP_QSTR_USR_BTN), MP_ROM_PTR(&pin_P1_00) },
61+
};
62+
63+
MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table);

tools/build_adafruit_bins.sh

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ grandcentral_m4_express \
2525
hallowing_m0_express \
2626
itsybitsy_m0_express \
2727
itsybitsy_m4_express \
28+
makerdiary_nrf52840_mdk \
2829
metro_m0_express \
2930
metro_m4_express \
3031
meowmeow \
@@ -82,6 +83,11 @@ for board in $boards; do
8283
(( exit_status = exit_status || $? ))
8384
temp_filename=ports/nrf/build-$board-s140/firmware.uf2
8485
extension=uf2
86+
elif [[ $board == "makerdiary_nrf52840_mdk" ]]; then
87+
make $PARALLEL -C ports/nrf TRANSLATION=$language BOARD=$board SD=s140
88+
(( exit_status = exit_status || $? ))
89+
temp_filename=ports/nrf/build-$board-s140/firmware.hex
90+
extension=hex
8591
else
8692
time make $PARALLEL -C ports/atmel-samd TRANSLATION=$language BOARD=$board
8793
(( exit_status = exit_status || $? ))

0 commit comments

Comments
 (0)