Tinygo: nrf52840-mdk support

Created on 1 Oct 2018  路  43Comments  路  Source: tinygo-org/tinygo

I really like this tinygo project and am trying to figure out how to add support for this neat little thing: https://wiki.makerdiary.com/nrf52840-mdk/

I've managed to add this as target:

{
    "llvm-target": "armv7em-none-eabi",
    "build-tags": ["nrf52840_mdk", "nrf52840", "nrf", "arm", "js", "wasm"],
    "linker": "arm-none-eabi-gcc",
    "pre-link-args": ["-nostdlib", "-nostartfiles", "-mcpu=cortex-m4", "-mthumb", "-T", "targets/nrf52.ld", "-Wl,--gc-sections", "-fno-exceptions", "-fno-unwind-tables", "-ffunction-sections", "-fdata-sections", "-Os", "-DNRF52840_XXAA", "-Ilib/CMSIS/CMSIS/Include", "lib/nrfx/mdk/system_nrf52.c", "src/device/nrf/nrf52.s"],
    "objcopy": "arm-none-eabi-objcopy",
    "flash": "nrfjprog -f nrf52 --sectorerase --program {hex} --reset"
}

And added machine/board_nrf52840-mdk.go (which is just a copy of board_pca10040.go for now)

// +build nrf,nrf52840_mdk

package machine

// LEDs on the nrf52840-mdk (nRF52840 dev board)
const (
    LED  = LED1
    LED1 = 17
    LED2 = 18
    LED3 = 19
    LED4 = 20
)

// Buttons on the nrf52840-mdk (nRF52840 dev board)
const (
    BUTTON  = BUTTON1
    BUTTON1 = 13
    BUTTON2 = 14
    BUTTON3 = 15
    BUTTON4 = 16
)

When I now run: tinygo flash -target=nrf52840-mdk examples/button

I get:

github.com/aykevl/tinygo/src/runtime/runtime_nrf.go:33:12: invalid operation: nrf.UART0 (variable of type *device/nrf.UART_Type) has no field or method PSELTXD

So, obviously, I'm missing something. But, I can't add "nrf52" to the build-tags, because then I get a bunch of re-declaration errors:

GPIO_PIN_CNF_DRIVE_D0S1 redeclared in this block
...

So, anyone here wanna help me adding support for this dev board? I'm new to this code, and figured it would be quicker to ask about this here since I couldn't find anything on the wiki about how to add a new board. Wasn't as straight forward as I thought, unless I'm missing something.

Thanks!

All 43 comments

I'm happy to see so much interest in this project :D

I just wrote this wiki page as a guide to adding support for new boards: https://github.com/aykevl/tinygo/wiki/Adding-a-new-board. Of course, feel free to add/change things if they're not quite right or there are missing parts.

Luckily, the nrf52832 is already supported so adding support for the nrf52840 shouldn't be too hard. However, there is an odd thing with the nrf52* chips. Originally, Nordic intended to use nrf52 as the chip family but later on decided to instead add the nrf52840 which is actually quite different (and more advanced) than the nrf52832 chip. But they already used "nrf52" as an identifier for the nrf52832 family so they decided to use new names (nrf52840 and nrf52810) for other chips. In other words, you are correct in using nrf52840 and not nrf52 in the list of build tags although it may seem strange.

Regarding the error in the runtime: you're probably hitting a problem with differences between these chips. You will most likely need to split UART support between nrf52832 and nrf52840, for example by adding two new files (runtime_nrf52832.go and runtime_nrf52840.go) and moving initUART() there.
In fact, currently the runtime uses a rather dirty hack by hardcoding the PCA10040 TX pin in the runtime, which made sense at the time but should be fixed at some point. For now, I'd suggest doing the same for the nrf52840 until this gets a proper fix.

Due to a bug / missing feature in the register descriptor generator script, UART pin selection wasn't included yet on the nrf52840. I have added it in a72d0b795925cb0d20d6c6ef3abb2c9bce01f07c, pins can be configured with UART0.PSEL.TXD. Make sure to update to master and to regenerate register descriptors with make gen-device-nrf.

Hey, thanks for quick response and fixing that issue. I'm hoping this project can grow super big. :)

However I get:

src/github.com/aykevl/tinygo/src/device/nrf/nrf52840.go:1596:3: _padding6 redeclared
src/github.com/aykevl/tinygo/src/device/nrf/nrf52840.go:1594:3:     other declaration of _padding6
src/github.com/aykevl/tinygo/src/device/nrf/nrf52840.go:1598:3: _padding6 redeclared
src/github.com/aykevl/tinygo/src/device/nrf/nrf52840.go:1594:3:     other declaration of _padding6
src/github.com/aykevl/tinygo/src/device/nrf/nrf52840.go:1600:3: _padding6 redeclared
src/github.com/aykevl/tinygo/src/device/nrf/nrf52840.go:1594:3:     other declaration of _padding6

when I try to build the button example.

Whoops, I made a mistake with the previous commit. That should be fixed now.

Ok, now it builds! Now I just need to get flashing going, which isn't straight forwards either. openocd was easy enough to install in Ubuntu. But, anyone here know what parameters to use for this board?

"flash": "openocd -f interface/?.cfg -f target/nrf52??.cfg -c 'program {hex} reset exit'"

When this works, I can finally start to make sure pins and all other things match correctly.

Hi @Chillance you might want to investigate if you can use the jlink bootloader along with nrfjprog like described here https://learn.adafruit.com/circuitpython-on-the-nrf52/nrf52840-bootloader

Hi @deadprogram
I tried nrfjprog, but I got this:

ERROR: JLinkARM DLL not found. Please reinstall latest JLinkARM.

and got tired of trying to fix it since google search didn't help much...

The answer to that is to follow these instructions to install jlink & nrfjprog, which are the same for all the nrf boards:

https://docs.zephyrproject.org/1.8.0/boards/arm/nrf52_pca10040/doc/nordic_segger.html#nordic-segger

Yeah JLinkARM can be problematic. I know I had the same problem once but that was long ago so I don't know what the fix was anymore.

Regarding OpenOCD:
In general, the interface is the programmer you're using. When you're not really using any programmer, most likely one is included on the board itself so you'd have to look it up and how it can be used from OpenOCD. Reading the documentation it is DAPLink which appears to be supported with interface/cmsis-dap.cfg after some quick googling.
You could just try using target/nrf51.cfg as the target type, it might just work. Or if you have a newer OpenOCD target/nrf52.cfg.

Also, I see this board has drag-and-drop programming, probably using .hex files. TinyGo has support for .hex files, you can get a .hex file this way:

tinygo -o program.hex -target nrf52840-mdk examples/serial

Well, thanks and special thank you to @aykevl ! I've been doing AVR's before, so currently learning about this type of micro-controllers. Flashing with DFU or using DPI with AVR's has been quite a breeze. With this, there seems to be so many ways it's overwhelming.

But anyway:

"flash": "openocd -f interface/cmsis-dap.cfg -f target/nrf51.cfg -c 'program {hex} reset exit'"

certainly seemed to have worked! Well, it flashed, but need to fix the program. The tinygo way to create hex and drag that over also seemed to work.

Again, big thanks!

I will see if I can update the code and get it working properly. Then I could supply a pull req...

Whoho! LED seems to work. So freaking sweet. But for some reason Button doesn't.

According to https://wiki.makerdiary.com/nrf52840-mdk/images/nrf52840-mdk-pinout.jpg LED's are P0.22 to P0.24. Which I just translate to 22 to 24 like so:

// LEDs on the nrf52840-mdk (nRF52840 dev board)
const (
    LED  = LED1
    LED1 = 22
    LED2 = 23
    LED3 = 24
)

And this works. But button being P1.00, 100 doesn't for some reason...

Great that you got it working :D

Yes, P1.xx pins only exist on the nRF52840 so they have not been implemented yet. They can be controlled with nrf.P1 I guess. This means that the nrf52840 needs a separate GPIO implementation that also checks the port number.

This should not be too difficult to implement, the AVR does something similar. The nrfx HAL from Nordic simply counts further so P1.00 == 32, P1.01 == 33 etc, I think it's best to keep that convention.

Whoops closed by accident (wrong button)

So, there can never be a P0.32? :)

Setting buttonpin to 32 in the button example didn't seem to work. Button pressed should change the LED, but nothing happens still, so I can only assume it still is not the right number for the button for this board...

So, there can never be a P0.32? :)

The way I understand their numbering scheme, no.

Setting buttonpin to 32 in the button example didn't seem to work. Button pressed should change the LED, but nothing happens still, so I can only assume it still is not the right number for the button for this board...

Correct, it is not yet implemented as it wasn't necessary before.

EDIT: to be clear, it is the right number but pins >= 32 haven't been implemented by the machine package.

Hmm, should I create an issue for it to be done then or?

You can, but of course by now I'm aware of it. I could implement it but I don't have the hardware to test on.

However, you can try to implement it yourself. Patches are welcome :) GPIO is implemented in https://github.com/aykevl/tinygo/blob/master/src/machine/machine_nrf.go. You'll have to replace nrf.P0 with calls to a chip-specific getPort() like in the stm32 port: https://github.com/aykevl/tinygo/blob/master/src/machine/machine_stm32.go.

I can also test it for you, but sure, I can see if I can make it as well...

It will get a lot easier after #38 is merged. It splits up pin handling in chip-specific files.

Ok, cool. So, I wait until that is done. Or, you will also do the GPIO thing?

I think it's best to wait until that PR is merged.
I can also write the necessary code (shouldn't be too hard) so you can test it on the device?

Sounds good to me. I'm setup to being able to code and flash, so I'm good to go here I suppose. Let me know when you have something to test, and I will do that. Any idea when this might happen?

Turns out that it was a bit more difficult than I expected. Here is a branch you can try: https://github.com/aykevl/tinygo/tree/nrf52840-mdk

Any progress?

@Chillance did you have a chance to try out the https://github.com/aykevl/tinygo/tree/nrf52840-mdk branch? Seems like the GPIO and UART should both work from looking at the code.

Yes, that branch is ready for testing. It should compile just fine but of course I couldn't test it.

Ok, I updated the button example to use pin 32 and using pullup and not using it. Still, the LED doesn't toggle when pressing the button. Here is full example:

package main

import (
    "machine"
    "time"
)

// This example assumes that the button is connected to pin 8. Change the value
// below to use a different pin.
const buttonPin = 32

func main() {
    led := machine.GPIO{machine.LED}
    led.Configure(machine.GPIOConfig{Mode: machine.GPIO_OUTPUT})

    button := machine.GPIO{buttonPin}
    button.Configure(machine.GPIOConfig{Mode: machine.GPIO_INPUT_PULLUP})
    //button.Configure(machine.GPIOConfig{Mode: machine.GPIO_INPUT})

    for {
        if button.Get() {
            led.Low()
        } else {
            led.High()
        }

        time.Sleep(time.Millisecond * 10)
    }
}

I also have this added to "board_nrf52840-mdk.go":

// LEDs on the nrf52840-mdk (nRF52840 dev board)
const (
    LED  = LED1
    LED1 = 22
    LED2 = 23
    LED3 = 24
)
````

I noticed that there now is:
```go
// Get peripheral and pin number for this GPIO pin.
func (p GPIO) getPortPin() (*nrf.GPIO_Type, uint8) {
    if p.Pin > 31 {
        return nrf.P1, p.Pin - 31
    } else {
        return nrf.P0, p.Pin
    }
}

and that seems to build. I also ran "make gen-device". Still no change with LED when I press the button. The LED lights up on PULLUP. Also, the example/blinky1 works.

Any thoughts as to why the button example doesn't work?

@Chillance do you have the Nordic DK board https://www.nordicsemi.com/eng/Products/nRF52840-DK with built-in buttons or do you have a kit like https://wiki.makerdiary.com/nrf52840-mdk which is same SoC but different board? The latter board does not appear to have any built-in buttons nor pins to access the P1 GPIO port.

@deadprogram I have the nrf52840-mdk. If you take a look here: https://wiki.makerdiary.com/nrf52840-mdk/images/nrf52840-mdk-pinout.jpg you can see that 9 is a "User Button", P1.00. This is the button I'm trying to get working.

Aaaah I see, I made an off-by-one error. Subtracted 31 from the pin number instead of 32.

Can you try pin 33 for the button? That's the wrong number but should correct the error until I've pushed a fix.

Setting to 33, it would be 33-31 = 2, so that didn't work. Basically, it would not be 0 on P1, which explains why it didn't work. However, thanks for the tip! I changed the code myself to:

return nrf.P1, p.Pin - 32

and voil谩!

buttonPin = 32 now works!

Thank you for testing!
I have sent two extra commits that should get your program to run without modifications to the machine module. If they work as well, I'll merge it all.

After push, it doesn't work for me.
Pin 32 is P1, 0 right? So shouldn't it be?

    if p.Pin > 31 {
        return nrf.P1, p.Pin - 32
    } else {
        return nrf.P0, p.Pin
    }

or

    if p.Pin >= 32 {
        return nrf.P1, p.Pin - 32
    } else {
        return nrf.P0, p.Pin
    }

Also, I need to do:

button.Configure(machine.GPIOConfig{Mode: machine.GPIO_INPUT_PULLUP})

to pullup that one for the LED to be lit and be off when pressing the button.

```go
if p.Pin >= 32 {
return nrf.P1, p.Pin - 32
} else {
return nrf.P0, p.Pin
}

Isn't that exactly what I pushed?

Also, I need to do:

button.Configure(machine.GPIOConfig{Mode: machine.GPIO_INPUT_PULLUP})

to pullup that one for the LED to be lit and be off when pressing the button.

That's expected, otherwise the button input will be floating. You could just use GPIO_INPUT but you would have needed an external pull-up in that case.

Oh, yes, you did. My bad. Must have been some miss somewhere, where I ran wrong code or something. Your commit works! (after I updated buttonPin and did PULLUP)

Merged in daf92226d835d9eac6360087b7853499ea871af5. Thank you for testing!

Hi @Chillance have you ever tried to use the UART on your nrf52840 board? For example, using the "serial" or "echo" examples?

I have a different nrf52840 board I am working with, but not able to get the UART working.

@deadprogram No, I haven't tried it yet... But I suppose I could.. :)

Yes, please!

Ok, finally had some time to take a look. Remind me again how to test this properly.

Flashing the "echo" example and running:

sudo screen /dev/ttyACM0 115200

and start typing something, I see no output...

Hi @Chillance please make sure that you have done the following first:

  • pull latest code
  • git submodule update --init
  • re-run the wrapper generator make gen-device-nrf

That should address the core issue that I originally was asking you to retest, because since then several changes have been made.

By the way, I just tested the echo example with tinygo latest in docker (v0.5.0?) and that seems to work too:
hello
You typed: hello

Was this page helpful?
0 / 5 - 0 ratings

Related issues

justinclift picture justinclift  路  5Comments

ellemlabs picture ellemlabs  路  3Comments

sh0rez picture sh0rez  路  4Comments

alankrantas picture alankrantas  路  4Comments

torntrousers picture torntrousers  路  8Comments