targets: add target circuitplay-bluefruit
Add a target for the Adafruit Circuit Playground Bluefruit, which is based on the nRF52840. Adds the necessary code for the machine package and the json and linker script files in the targets directory. The machine package code is based on board_circuitplay_express.go, with modifications made by consulting the wiring diagram on the adafruit website here: https://learn.adafruit.com/adafruit-circuit-playground-bluefruit/downloads Also adds support to the uf2 conversion packacge to set the familyID field. The Circuit Playground Bluefruit firmware rejects uf2 files without the family id set to 0xADA52840 (and without the flag specifying that the family id is present).
Этот коммит содержится в:
родитель
25cff20117
коммит
1cb9b948bc
9 изменённых файлов: 182 добавлений и 10 удалений
2
Makefile
2
Makefile
|
@ -226,6 +226,8 @@ smoketest:
|
|||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=stm32f4disco examples/blinky2
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=circuitplay-bluefruit examples/blinky1
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=circuitplay-express examples/i2s
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.gba -target=gameboy-advance examples/gba-display
|
||||
|
|
|
@ -46,6 +46,7 @@ You can compile TinyGo programs for microcontrollers, WebAssembly and Linux.
|
|||
The following 22 microcontroller boards are currently supported:
|
||||
|
||||
* [Adafruit Circuit Playground Express](https://www.adafruit.com/product/3333)
|
||||
* [Adafruit Circuit Playground Bluefruit](https://www.adafruit.com/product/4333)
|
||||
* [Adafruit Feather M0](https://www.adafruit.com/product/2772)
|
||||
* [Adafruit Feather M4](https://www.adafruit.com/product/3857)
|
||||
* [Adafruit ItsyBitsy M0](https://www.adafruit.com/product/3727)
|
||||
|
|
|
@ -207,7 +207,7 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(stri
|
|||
} else if outext == ".uf2" {
|
||||
// Get UF2 from the .elf file.
|
||||
tmppath = filepath.Join(dir, "main"+outext)
|
||||
err := convertELFFileToUF2File(executable, tmppath)
|
||||
err := convertELFFileToUF2File(executable, tmppath, config.Target.UF2FamilyID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -11,26 +11,33 @@ import (
|
|||
"bytes"
|
||||
"encoding/binary"
|
||||
"io/ioutil"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// convertELFFileToUF2File converts an ELF file to a UF2 file.
|
||||
func convertELFFileToUF2File(infile, outfile string) error {
|
||||
func convertELFFileToUF2File(infile, outfile string, uf2FamilyID string) error {
|
||||
// Read the .text segment.
|
||||
targetAddress, data, err := extractROM(infile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
output, _ := convertBinToUF2(data, uint32(targetAddress))
|
||||
output, _, err := convertBinToUF2(data, uint32(targetAddress), uf2FamilyID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return ioutil.WriteFile(outfile, output, 0644)
|
||||
}
|
||||
|
||||
// convertBinToUF2 converts the binary bytes in input to UF2 formatted data.
|
||||
func convertBinToUF2(input []byte, targetAddr uint32) ([]byte, int) {
|
||||
func convertBinToUF2(input []byte, targetAddr uint32, uf2FamilyID string) ([]byte, int, error) {
|
||||
blocks := split(input, 256)
|
||||
output := make([]byte, 0)
|
||||
|
||||
bl := newUF2Block(targetAddr)
|
||||
bl, err := newUF2Block(targetAddr, uf2FamilyID)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
bl.SetNumBlocks(len(blocks))
|
||||
|
||||
for i := 0; i < len(blocks); i++ {
|
||||
|
@ -41,7 +48,7 @@ func convertBinToUF2(input []byte, targetAddr uint32) ([]byte, int) {
|
|||
bl.IncrementAddress(bl.payloadSize)
|
||||
}
|
||||
|
||||
return output, len(blocks)
|
||||
return output, len(blocks), nil
|
||||
}
|
||||
|
||||
const (
|
||||
|
@ -65,18 +72,32 @@ type uf2Block struct {
|
|||
}
|
||||
|
||||
// newUF2Block returns a new uf2Block struct that has been correctly populated
|
||||
func newUF2Block(targetAddr uint32) *uf2Block {
|
||||
func newUF2Block(targetAddr uint32, uf2FamilyID string) (*uf2Block, error) {
|
||||
var flags uint32
|
||||
var familyID uint32
|
||||
if uf2FamilyID != "" {
|
||||
flags |= flagFamilyIDPresent
|
||||
v, err := strconv.ParseUint(uf2FamilyID, 0, 32)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
familyID = uint32(v)
|
||||
}
|
||||
return &uf2Block{magicStart0: uf2MagicStart0,
|
||||
magicStart1: uf2MagicStart1,
|
||||
magicEnd: uf2MagicEnd,
|
||||
targetAddr: targetAddr,
|
||||
flags: 0x0,
|
||||
familyID: 0x0,
|
||||
flags: flags,
|
||||
familyID: familyID,
|
||||
payloadSize: 256,
|
||||
data: make([]byte, 476),
|
||||
}
|
||||
}, nil
|
||||
}
|
||||
|
||||
const (
|
||||
flagFamilyIDPresent = 0x00002000
|
||||
)
|
||||
|
||||
// Bytes converts the uf2Block to a slice of bytes that can be written to file.
|
||||
func (b *uf2Block) Bytes() []byte {
|
||||
buf := bytes.NewBuffer(make([]byte, 0, 512))
|
||||
|
|
|
@ -43,6 +43,7 @@ type TargetSpec struct {
|
|||
FlashMethod string `json:"flash-method"`
|
||||
FlashVolume string `json:"msd-volume-name"`
|
||||
FlashFilename string `json:"msd-firmware-name"`
|
||||
UF2FamilyID string `json:"uf2-family-id"`
|
||||
OpenOCDInterface string `json:"openocd-interface"`
|
||||
OpenOCDTarget string `json:"openocd-target"`
|
||||
OpenOCDTransport string `json:"openocd-transport"`
|
||||
|
@ -109,6 +110,9 @@ func (spec *TargetSpec) copyProperties(spec2 *TargetSpec) {
|
|||
if spec2.FlashFilename != "" {
|
||||
spec.FlashFilename = spec2.FlashFilename
|
||||
}
|
||||
if spec2.UF2FamilyID != "" {
|
||||
spec.UF2FamilyID = spec2.UF2FamilyID
|
||||
}
|
||||
if spec2.OpenOCDInterface != "" {
|
||||
spec.OpenOCDInterface = spec2.OpenOCDInterface
|
||||
}
|
||||
|
|
73
src/machine/board_circuitplay_bluefruit.go
Обычный файл
73
src/machine/board_circuitplay_bluefruit.go
Обычный файл
|
@ -0,0 +1,73 @@
|
|||
// +build circuitplay_bluefruit
|
||||
|
||||
package machine
|
||||
|
||||
const HasLowFrequencyCrystal = true
|
||||
|
||||
// GPIO Pins
|
||||
const (
|
||||
D0 = P0_30
|
||||
D1 = P0_14
|
||||
D2 = P0_05
|
||||
D3 = P0_04
|
||||
D4 = P1_02
|
||||
D5 = P1_15
|
||||
D6 = P0_02
|
||||
D7 = P1_06
|
||||
D8 = P0_13
|
||||
D9 = P0_29
|
||||
D10 = P0_03
|
||||
D11 = P1_04
|
||||
D12 = P0_26
|
||||
D13 = P1_14
|
||||
)
|
||||
|
||||
// Analog Pins
|
||||
const (
|
||||
A1 = P0_02
|
||||
A2 = P0_29
|
||||
A3 = P0_03
|
||||
A4 = P0_04
|
||||
A5 = P0_05
|
||||
A6 = P0_30
|
||||
A7 = P0_14
|
||||
A8 = P0_28
|
||||
A9 = P0_31
|
||||
)
|
||||
|
||||
const (
|
||||
LED = D13
|
||||
NEOPIXELS = D8
|
||||
|
||||
BUTTONA = D4
|
||||
BUTTONB = D5
|
||||
SLIDER = D7 // built-in slide switch
|
||||
|
||||
BUTTON = BUTTONA
|
||||
BUTTON1 = BUTTONB
|
||||
|
||||
LIGHTSENSOR = A8
|
||||
TEMPSENSOR = A9
|
||||
)
|
||||
|
||||
// UART0 pins (logical UART1)
|
||||
const (
|
||||
UART_TX_PIN = P0_14 // PORTB
|
||||
UART_RX_PIN = P0_30 // PORTB
|
||||
)
|
||||
|
||||
// I2C pins
|
||||
const (
|
||||
SDA_PIN = P0_05 // I2C0 external
|
||||
SCL_PIN = P0_04 // I2C0 external
|
||||
|
||||
SDA1_PIN = P0_00 // I2C1 internal
|
||||
SCL1_PIN = P0_01 // I2C1 internal
|
||||
)
|
||||
|
||||
// SPI pins (internal flash)
|
||||
const (
|
||||
SPI0_SCK_PIN = P0_19 // SCK
|
||||
SPI0_MOSI_PIN = P0_21 // MOSI
|
||||
SPI0_MISO_PIN = P0_23 // MISO
|
||||
)
|
|
@ -11,6 +11,58 @@ func CPUFrequency() uint32 {
|
|||
return 64000000
|
||||
}
|
||||
|
||||
// Hardware pins
|
||||
const (
|
||||
P0_00 Pin = 0
|
||||
P0_01 Pin = 1
|
||||
P0_02 Pin = 2
|
||||
P0_03 Pin = 3
|
||||
P0_04 Pin = 4
|
||||
P0_05 Pin = 5
|
||||
P0_06 Pin = 6
|
||||
P0_07 Pin = 7
|
||||
P0_08 Pin = 8
|
||||
P0_09 Pin = 9
|
||||
P0_10 Pin = 10
|
||||
P0_11 Pin = 11
|
||||
P0_12 Pin = 12
|
||||
P0_13 Pin = 13
|
||||
P0_14 Pin = 14
|
||||
P0_15 Pin = 15
|
||||
P0_16 Pin = 16
|
||||
P0_17 Pin = 17
|
||||
P0_18 Pin = 18
|
||||
P0_19 Pin = 19
|
||||
P0_20 Pin = 20
|
||||
P0_21 Pin = 21
|
||||
P0_22 Pin = 22
|
||||
P0_23 Pin = 23
|
||||
P0_24 Pin = 24
|
||||
P0_25 Pin = 25
|
||||
P0_26 Pin = 26
|
||||
P0_27 Pin = 27
|
||||
P0_28 Pin = 28
|
||||
P0_29 Pin = 29
|
||||
P0_30 Pin = 30
|
||||
P0_31 Pin = 31
|
||||
P1_00 Pin = 32
|
||||
P1_01 Pin = 33
|
||||
P1_02 Pin = 34
|
||||
P1_03 Pin = 35
|
||||
P1_04 Pin = 36
|
||||
P1_05 Pin = 37
|
||||
P1_06 Pin = 38
|
||||
P1_07 Pin = 39
|
||||
P1_08 Pin = 40
|
||||
P1_09 Pin = 41
|
||||
P1_10 Pin = 42
|
||||
P1_11 Pin = 43
|
||||
P1_12 Pin = 44
|
||||
P1_13 Pin = 45
|
||||
P1_14 Pin = 46
|
||||
P1_15 Pin = 47
|
||||
)
|
||||
|
||||
// Get peripheral and pin number for this GPIO pin.
|
||||
func (p Pin) getPortPin() (*nrf.GPIO_Type, uint32) {
|
||||
if p >= 32 {
|
||||
|
|
9
targets/circuitplay-bluefruit.json
Обычный файл
9
targets/circuitplay-bluefruit.json
Обычный файл
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"inherits": ["nrf52840"],
|
||||
"build-tags": ["circuitplay_bluefruit"],
|
||||
"flash-method": "msd",
|
||||
"msd-volume-name": "CPLAYBTBOOT",
|
||||
"msd-firmware-name": "firmware.uf2",
|
||||
"uf2-family-id": "0xADA52840",
|
||||
"linkerscript": "targets/circuitplay-bluefruit.ld"
|
||||
}
|
10
targets/circuitplay-bluefruit.ld
Обычный файл
10
targets/circuitplay-bluefruit.ld
Обычный файл
|
@ -0,0 +1,10 @@
|
|||
|
||||
MEMORY
|
||||
{
|
||||
FLASH_TEXT (rw) : ORIGIN = 0x00000000+0x26000, LENGTH = 0xED000-0x26000 /* SoftDevice S140. See https://learn.adafruit.com/introducing-the-adafruit-nrf52840-feather/hathach-memory-map. Application starts at 0x26000; user data starts at 0xED000 */
|
||||
RAM (xrw) : ORIGIN = 0x20004180, LENGTH = 37K
|
||||
}
|
||||
|
||||
_stack_size = 2K;
|
||||
|
||||
INCLUDE "targets/arm.ld"
|
Загрузка…
Создание таблицы
Сослаться в новой задаче