aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorKenneth Bell <[email protected]>2023-10-20 11:47:05 +0100
committerRon Evans <[email protected]>2023-10-27 13:25:32 +0200
commit9fb5a5b9a480c1fa407748b7defd8249ae94d537 (patch)
treeb00b38d4344ff5873323c8dfc0f338304ce96796 /src
parent9fd9d9c05a5c03c11c385c3d920cfb4e64016168 (diff)
downloadtinygo-9fb5a5b9a480c1fa407748b7defd8249ae94d537.tar.gz
tinygo-9fb5a5b9a480c1fa407748b7defd8249ae94d537.zip
nrf,sam,rp2040: add machine.HardwareID function
Diffstat (limited to 'src')
-rw-r--r--src/examples/device-id/main.go21
-rw-r--r--src/machine/deviceid.go17
-rw-r--r--src/machine/machine_atsam.go31
-rw-r--r--src/machine/machine_atsamd21.go3
-rw-r--r--src/machine/machine_atsamd51.go3
-rw-r--r--src/machine/machine_nrf.go28
-rw-r--r--src/machine/machine_rp2040_flash.go26
-rw-r--r--src/machine/machine_rp2040_rom.go76
8 files changed, 205 insertions, 0 deletions
diff --git a/src/examples/device-id/main.go b/src/examples/device-id/main.go
new file mode 100644
index 000000000..31e62baef
--- /dev/null
+++ b/src/examples/device-id/main.go
@@ -0,0 +1,21 @@
+package main
+
+import (
+ "encoding/hex"
+ "machine"
+ "time"
+)
+
+func main() {
+ time.Sleep(2 * time.Second)
+
+ // For efficiency, it's best to get the device ID once and cache it
+ // (e.g. on RP2040 XIP flash and interrupts disabled for period of
+ // retrieving the hardware ID from ROM chip)
+ id := machine.DeviceID()
+
+ for {
+ println("Device ID:", hex.EncodeToString(id))
+ time.Sleep(1 * time.Second)
+ }
+}
diff --git a/src/machine/deviceid.go b/src/machine/deviceid.go
new file mode 100644
index 000000000..cb2e1d0c1
--- /dev/null
+++ b/src/machine/deviceid.go
@@ -0,0 +1,17 @@
+//go:build rp2040 || nrf || sam
+
+package machine
+
+// DeviceID returns an identifier that is unique within
+// a particular chipset.
+//
+// The identity is one burnt into the MCU itself, or the
+// flash chip at time of manufacture.
+//
+// It's possible that two different vendors may allocate
+// the same DeviceID, so callers should take this into
+// account if needing to generate a globally unique id.
+//
+// The length of the hardware ID is vendor-specific, but
+// 8 bytes (64 bits) and 16 bytes (128 bits) are common.
+var _ = (func() []byte)(DeviceID)
diff --git a/src/machine/machine_atsam.go b/src/machine/machine_atsam.go
new file mode 100644
index 000000000..ad2f07378
--- /dev/null
+++ b/src/machine/machine_atsam.go
@@ -0,0 +1,31 @@
+//go:build sam
+
+package machine
+
+import (
+ "runtime/volatile"
+ "unsafe"
+)
+
+var deviceID [16]byte
+
+// DeviceID returns an identifier that is unique within
+// a particular chipset.
+//
+// The identity is one burnt into the MCU itself, or the
+// flash chip at time of manufacture.
+//
+// It's possible that two different vendors may allocate
+// the same DeviceID, so callers should take this into
+// account if needing to generate a globally unique id.
+//
+// The length of the hardware ID is vendor-specific, but
+// 8 bytes (64 bits) and 16 bytes (128 bits) are common.
+func DeviceID() []byte {
+ for i := 0; i < len(deviceID); i++ {
+ word := (*volatile.Register32)(unsafe.Pointer(deviceIDAddr[i/4])).Get()
+ deviceID[i] = byte(word >> ((i % 4) * 8))
+ }
+
+ return deviceID[:]
+}
diff --git a/src/machine/machine_atsamd21.go b/src/machine/machine_atsamd21.go
index 3ad93dccf..d84a85255 100644
--- a/src/machine/machine_atsamd21.go
+++ b/src/machine/machine_atsamd21.go
@@ -18,6 +18,9 @@ import (
const deviceName = sam.Device
+// DS40001882F, Section 10.3.3: Serial Number
+var deviceIDAddr = []uintptr{0x0080A00C, 0x0080A040, 0x0080A044, 0x0080A048}
+
const (
PinAnalog PinMode = 1
PinSERCOM PinMode = 2
diff --git a/src/machine/machine_atsamd51.go b/src/machine/machine_atsamd51.go
index bdc00c9af..7118792a7 100644
--- a/src/machine/machine_atsamd51.go
+++ b/src/machine/machine_atsamd51.go
@@ -18,6 +18,9 @@ import (
const deviceName = sam.Device
+// DS60001507, Section 9.6: Serial Number
+var deviceIDAddr = []uintptr{0x008061FC, 0x00806010, 0x00806014, 0x00806018}
+
func CPUFrequency() uint32 {
return 120000000
}
diff --git a/src/machine/machine_nrf.go b/src/machine/machine_nrf.go
index 3b79e376a..cc68c1d91 100644
--- a/src/machine/machine_nrf.go
+++ b/src/machine/machine_nrf.go
@@ -12,6 +12,34 @@ import (
const deviceName = nrf.Device
+var deviceID [8]byte
+
+// DeviceID returns an identifier that is unique within
+// a particular chipset.
+//
+// The identity is one burnt into the MCU itself, or the
+// flash chip at time of manufacture.
+//
+// It's possible that two different vendors may allocate
+// the same DeviceID, so callers should take this into
+// account if needing to generate a globally unique id.
+//
+// The length of the hardware ID is vendor-specific, but
+// 8 bytes (64 bits) is common.
+func DeviceID() []byte {
+ words := make([]uint32, 2)
+ words[0] = nrf.FICR.DEVICEID[0].Get()
+ words[1] = nrf.FICR.DEVICEID[1].Get()
+
+ for i := 0; i < 8; i++ {
+ shift := (i % 4) * 8
+ w := i / 4
+ deviceID[i] = byte(words[w] >> shift)
+ }
+
+ return deviceID[:]
+}
+
const (
PinInput PinMode = (nrf.GPIO_PIN_CNF_DIR_Input << nrf.GPIO_PIN_CNF_DIR_Pos) | (nrf.GPIO_PIN_CNF_INPUT_Connect << nrf.GPIO_PIN_CNF_INPUT_Pos)
PinInputPullup PinMode = PinInput | (nrf.GPIO_PIN_CNF_PULL_Pullup << nrf.GPIO_PIN_CNF_PULL_Pos)
diff --git a/src/machine/machine_rp2040_flash.go b/src/machine/machine_rp2040_flash.go
index f3d24e8e7..8ee881e19 100644
--- a/src/machine/machine_rp2040_flash.go
+++ b/src/machine/machine_rp2040_flash.go
@@ -13,6 +13,32 @@ func EnterBootloader() {
enterBootloader()
}
+// 13 = 1 + FLASH_RUID_DUMMY_BYTES(4) + FLASH_RUID_DATA_BYTES(8)
+var deviceIDBuf [13]byte
+
+// DeviceID returns an identifier that is unique within
+// a particular chipset.
+//
+// The identity is one burnt into the MCU itself, or the
+// flash chip at time of manufacture.
+//
+// It's possible that two different vendors may allocate
+// the same DeviceID, so callers should take this into
+// account if needing to generate a globally unique id.
+//
+// The length of the hardware ID is vendor-specific, but
+// 8 bytes (64 bits) is common.
+func DeviceID() []byte {
+ deviceIDBuf[0] = 0x4b // FLASH_RUID_CMD
+
+ err := doFlashCommand(deviceIDBuf[:], deviceIDBuf[:])
+ if err != nil {
+ panic(err)
+ }
+
+ return deviceIDBuf[5:13]
+}
+
// compile-time check for ensuring we fulfill BlockDevice interface
var _ BlockDevice = flashBlockDevice{}
diff --git a/src/machine/machine_rp2040_rom.go b/src/machine/machine_rp2040_rom.go
index fdb05bb62..2cf96d89d 100644
--- a/src/machine/machine_rp2040_rom.go
+++ b/src/machine/machine_rp2040_rom.go
@@ -93,6 +93,33 @@ static ram_func void flash_enable_xip_via_boot2() {
((void (*)(void))boot2_copyout+1)();
}
+#define IO_QSPI_BASE 0x40018000
+#define IO_QSPI_GPIO_QSPI_SS_CTRL_OUTOVER_BITS 0x00000300
+#define IO_QSPI_GPIO_QSPI_SS_CTRL_OUTOVER_MSB 9
+#define IO_QSPI_GPIO_QSPI_SS_CTRL_OUTOVER_LSB 8
+#define IO_QSPI_GPIO_QSPI_SS_CTRL_OUTOVER_VALUE_LOW 0x2
+#define IO_QSPI_GPIO_QSPI_SS_CTRL_OUTOVER_VALUE_HIGH 0x3
+
+#define XIP_SSI_BASE 0x18000000
+#define ssi_hw ((ssi_hw_t *)XIP_SSI_BASE)
+#define SSI_SR_OFFSET 0x00000028
+#define SSI_DR0_OFFSET 0x00000060
+#define SSI_SR_TFNF_BITS 0x00000002
+#define SSI_SR_RFNE_BITS 0x00000008
+
+void ram_func flash_cs_force(bool high) {
+ uint32_t field_val = high ?
+ IO_QSPI_GPIO_QSPI_SS_CTRL_OUTOVER_VALUE_HIGH :
+ IO_QSPI_GPIO_QSPI_SS_CTRL_OUTOVER_VALUE_LOW;
+
+ // &ioqspi_hw->io[1].ctrl
+ uint32_t *addr = (uint32_t*)(IO_QSPI_BASE + (1 * 8) + 4);
+
+ *addr = ((*addr) & !IO_QSPI_GPIO_QSPI_SS_CTRL_OUTOVER_BITS)
+ | (field_val << IO_QSPI_GPIO_QSPI_SS_CTRL_OUTOVER_LSB);
+
+}
+
// See https://github.com/raspberrypi/pico-sdk/blob/master/src/rp2_common/hardware_flash/flash.c#L86
void ram_func flash_range_write(uint32_t offset, const uint8_t *data, size_t count)
{
@@ -132,6 +159,42 @@ void ram_func flash_erase_blocks(uint32_t offset, size_t count)
flash_enable_xip_via_boot2();
}
+void ram_func flash_do_cmd(const uint8_t *txbuf, uint8_t *rxbuf, size_t count) {
+ flash_connect_internal_fn flash_connect_internal_func = (flash_connect_internal_fn) rom_func_lookup(ROM_FUNC_CONNECT_INTERNAL_FLASH);
+ flash_exit_xip_fn flash_exit_xip_func = (flash_exit_xip_fn) rom_func_lookup(ROM_FUNC_FLASH_EXIT_XIP);
+ flash_flush_cache_fn flash_flush_cache_func = (flash_flush_cache_fn) rom_func_lookup(ROM_FUNC_FLASH_FLUSH_CACHE);
+
+ flash_init_boot2_copyout();
+
+ __compiler_memory_barrier();
+
+ flash_connect_internal_func();
+ flash_exit_xip_func();
+
+ flash_cs_force(0);
+ size_t tx_remaining = count;
+ size_t rx_remaining = count;
+ // We may be interrupted -- don't want FIFO to overflow if we're distracted.
+ const size_t max_in_flight = 16 - 2;
+ while (tx_remaining || rx_remaining) {
+ uint32_t flags = *(uint32_t*)(XIP_SSI_BASE + SSI_SR_OFFSET);
+ bool can_put = !!(flags & SSI_SR_TFNF_BITS);
+ bool can_get = !!(flags & SSI_SR_RFNE_BITS);
+ if (can_put && tx_remaining && rx_remaining - tx_remaining < max_in_flight) {
+ *(uint32_t*)(XIP_SSI_BASE + SSI_DR0_OFFSET) = *txbuf++;
+ --tx_remaining;
+ }
+ if (can_get && rx_remaining) {
+ *rxbuf++ = (uint8_t)*(uint32_t*)(XIP_SSI_BASE + SSI_DR0_OFFSET);
+ --rx_remaining;
+ }
+ }
+ flash_cs_force(1);
+
+ flash_flush_cache_func();
+ flash_enable_xip_via_boot2();
+}
+
*/
import "C"
@@ -139,6 +202,19 @@ func enterBootloader() {
C.reset_usb_boot(0, 0)
}
+func doFlashCommand(tx []byte, rx []byte) error {
+ if len(tx) != len(rx) {
+ return errFlashInvalidWriteLength
+ }
+
+ C.flash_do_cmd(
+ (*C.uint8_t)(unsafe.Pointer(&tx[0])),
+ (*C.uint8_t)(unsafe.Pointer(&rx[0])),
+ C.ulong(len(tx)))
+
+ return nil
+}
+
// Flash related code
const memoryStart = C.XIP_BASE // memory start for purpose of erase