Skip to content

Commit 8e33f1c

Browse files
kenbelldeadprogram
authored andcommitted
rp2040: support Adafruit Feather RP2040
1 parent 1913cb7 commit 8e33f1c

File tree

9 files changed

+145
-27
lines changed

9 files changed

+145
-27
lines changed

Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -358,6 +358,8 @@ smoketest:
358358
@$(MD5SUM) test.hex
359359
$(TINYGO) build -size short -o test.hex -target=pico examples/blinky1
360360
@$(MD5SUM) test.hex
361+
$(TINYGO) build -size short -o test.hex -target=feather-rp2040 examples/blinky1
362+
@$(MD5SUM) test.hex
361363
# test pwm
362364
$(TINYGO) build -size short -o test.hex -target=itsybitsy-m0 examples/pwm
363365
@$(MD5SUM) test.hex

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ See the [getting started instructions](https://tinygo.org/getting-started/) for
4343

4444
You can compile TinyGo programs for microcontrollers, WebAssembly and Linux.
4545

46-
The following 62 microcontroller boards are currently supported:
46+
The following 63 microcontroller boards are currently supported:
4747

4848
* [Adafruit Circuit Playground Bluefruit](https://www.adafruit.com/product/4333)
4949
* [Adafruit Circuit Playground Express](https://www.adafruit.com/product/3333)
@@ -52,6 +52,7 @@ The following 62 microcontroller boards are currently supported:
5252
* [Adafruit Feather M4](https://www.adafruit.com/product/3857)
5353
* [Adafruit Feather M4 CAN](https://www.adafruit.com/product/4759)
5454
* [Adafruit Feather nRF52840 Express](https://www.adafruit.com/product/4062)
55+
* [Adafruit Feather RP2040](https://www.adafruit.com/product/4884)
5556
* [Adafruit Feather STM32F405 Express](https://www.adafruit.com/product/4382)
5657
* [Adafruit Grand Central M4](https://www.adafruit.com/product/4064)
5758
* [Adafruit ItsyBitsy M0](https://www.adafruit.com/product/3727)
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// +build feather_rp2040
2+
3+
package machine
4+
5+
const (
6+
LED = GPIO13
7+
8+
// Onboard crystal oscillator frequency, in MHz.
9+
xoscFreq = 12 // MHz
10+
)
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// Adafruit Feather RP2040 Stage 2 Bootloader
2+
3+
//
4+
// This file defines the parameters specific to the flash-chip found
5+
// on the Adafruit Feather RP2040. The generic implementation is in
6+
// rp2040-boot-stage2.S
7+
//
8+
9+
#define BOARD_PICO_FLASH_SPI_CLKDIV 2
10+
#define BOARD_CMD_READ 0xe7
11+
#define BOARD_QUAD_OK 1
12+
#define BOARD_QUAD_ENABLE_STATUS_BYTE 2
13+
#define BOARD_QUAD_ENABLE_BIT_MASK 2
14+
#define BOARD_SPLIT_STATUS_WRITE 1
15+
#define BOARD_WAIT_CYCLES 2
16+
17+
#include "rp2040-boot-stage2.S"

targets/feather-rp2040.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"inherits": [
3+
"rp2040"
4+
],
5+
"build-tags": ["feather_rp2040"],
6+
"linkerscript": "targets/feather-rp2040.ld",
7+
"extra-files": [
8+
"targets/feather-rp2040-boot-stage2.S"
9+
]
10+
}

targets/feather-rp2040.ld

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
2+
MEMORY
3+
{
4+
/* Reserve exactly 256 bytes at start of flash for second stage bootloader */
5+
BOOT2_TEXT (rx) : ORIGIN = 0x10000000, LENGTH = 256
6+
FLASH_TEXT (rx) : ORIGIN = 0x10000000 + 256, LENGTH = 8192K - 256
7+
RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 256k
8+
}
9+
10+
INCLUDE "targets/rp2040.ld"

targets/pico-boot-stage2.S

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// Raspberry Pi Pico Stage 2 Bootloader
2+
3+
//
4+
// This file defines the parameters specific to the flash-chip found
5+
// on the official Pico boards. The generic implementation is in
6+
// rp2040-boot-stage2.S
7+
//
8+
9+
#define BOARD_PICO_FLASH_SPI_CLKDIV 2
10+
#define BOARD_CMD_READ 0xeb
11+
#define BOARD_QUAD_OK 1
12+
#define BOARD_QUAD_ENABLE_STATUS_BYTE 2
13+
#define BOARD_QUAD_ENABLE_BIT_MASK 2
14+
#define BOARD_SPLIT_STATUS_WRITE 0
15+
#define BOARD_WAIT_CYCLES 4
16+
17+
#include "rp2040-boot-stage2.S"

targets/pico.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,6 @@
55
"build-tags": ["pico"],
66
"linkerscript": "targets/pico.ld",
77
"extra-files": [
8-
"targets/pico_boot_stage2.S"
8+
"targets/pico-boot-stage2.S"
99
]
1010
}

targets/pico_boot_stage2.S renamed to targets/rp2040-boot-stage2.S

Lines changed: 76 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,21 @@
11
//
2-
// Implementation of Pico stage 2 boot loader. This code is for the Winbond W25Q080
3-
// (as found in the Pico) from the official Pico SDK.
2+
// Implementation of RP2040 stage 2 boot loader. This code is derived from the
3+
// Winbond W25Q080 implementation (as found in the Pico) in the official Pico SDK.
44
//
55
// This implementation has been made 'stand-alone' by including necessary code /
66
// symbols from the included files in the reference implementation directly into
7-
// the source. Care has been taken to preserve ordering and it has been verified
8-
// the generated binary is byte-for-byte identical to the reference code binary.
7+
// the source. It has also been modified to include the conditional logic from
8+
// the CircuitPython implementation that supports additional flash chips. The
9+
// CiruitPython source is here:
10+
// https://github.com/adafruit/circuitpython/blob/main/ports/raspberrypi/stage2.c.jinja
11+
//
12+
// This file cannot be assembled directly, instead assemble the board-specific file
13+
// (such as pico-boot-stage2.S) which defines the parameters specific to the flash
14+
// chip included on that board.
15+
//
16+
// Care has been taken to preserve ordering and it has been verified the generated
17+
// binary is byte-for-byte identical to the reference code binary when assembled for
18+
// the Pico.
919
//
1020
// Note: the stage 2 boot loader must be 256 bytes in length and have a checksum
1121
// present. In TinyGo, the linker script is responsible for allocating 256 bytes
@@ -19,10 +29,6 @@
1929
// https://github.com/raspberrypi/pico-sdk/blob/master/src/rp2_common/boot_stage2/boot2_w25q080.S
2030
//
2131

22-
// Board Parameters
23-
#define PICO_FLASH_SPI_CLKDIV 2
24-
25-
2632

2733
// ----------------------------------------------------------------------------
2834
// Second stage boot code
@@ -59,7 +65,8 @@
5965
#define CMD_WRITE_ENABLE 0x06
6066
#define CMD_READ_STATUS 0x05
6167
#define CMD_READ_STATUS2 0x35
62-
#define CMD_WRITE_STATUS 0x01
68+
#define CMD_WRITE_STATUS1 0x01
69+
#define CMD_WRITE_STATUS2 0x31
6370
#define SREG_DATA 0x02 // Enable quad-SPI mode
6471

6572
#define XIP_BASE 0x10000000
@@ -123,32 +130,43 @@
123130
// The bootrom is very conservative with SPI frequency, but here we should be
124131
// as aggressive as possible.
125132

126-
#ifndef PICO_FLASH_SPI_CLKDIV
127-
#define PICO_FLASH_SPI_CLKDIV 4
128-
#endif
133+
#define PICO_FLASH_SPI_CLKDIV BOARD_PICO_FLASH_SPI_CLKDIV
129134
#if PICO_FLASH_SPI_CLKDIV & 1
130135
#error PICO_FLASH_SPI_CLKDIV must be even
131136
#endif
132137

138+
#if BOARD_QUAD_OK==1
133139
// Define interface width: single/dual/quad IO
134-
#define FRAME_FORMAT SSI_CTRLR0_SPI_FRF_VALUE_QUAD
140+
#define FRAME_FORMAT SSI_CTRLR0_SPI_FRF_VALUE_QUAD
141+
#define TRANSACTION_TYPE SSI_SPI_CTRLR0_TRANS_TYPE_VALUE_2C2A
142+
// Note that the INST_L field is used to select what XIP data gets pushed into
143+
// the TX FIFO:
144+
// INST_L_0_BITS {ADDR[23:0],XIP_CMD[7:0]} Load "mode bits" into XIP_CMD
145+
// Anything else {XIP_CMD[7:0],ADDR[23:0]} Load SPI command into XIP_CMD
146+
#define INSTRUCTION_LENGTH SSI_SPI_CTRLR0_INST_L_VALUE_NONE
147+
#define READ_INSTRUCTION MODE_CONTINUOUS_READ
148+
#define ADDR_L 8 // 6 for address, 2 for mode
149+
#else
150+
#define FRAME_FORMAT SSI_CTRLR0_SPI_FRF_VALUE_STD
151+
#define TRANSACTION_TYPE SSI_SPI_CTRLR0_TRANS_TYPE_VALUE_1C1A
152+
#define INSTRUCTION_LENGTH SSI_SPI_CTRLR0_INST_L_VALUE_8B
153+
#define READ_INSTRUCTION BOARD_CMD_READ
154+
#define ADDR_L 6 // * 4 = 24
155+
#endif
135156

136-
// For W25Q080 this is the "Read data fast quad IO" instruction:
137-
#define CMD_READ 0xeb
157+
// The flash-chip specific read isntruction
158+
#define CMD_READ BOARD_CMD_READ
138159

139160
// "Mode bits" are 8 special bits sent immediately after
140161
// the address bits in a "Read Data Fast Quad I/O" command sequence.
141162
// On W25Q080, the four LSBs are don't care, and if MSBs == 0xa, the
142163
// next read does not require the 0xeb instruction prefix.
143164
#define MODE_CONTINUOUS_READ 0xa0
144165

145-
// The number of address + mode bits, divided by 4 (always 4, not function of
146-
// interface width).
147-
#define ADDR_L 8
148-
149166
// How many clocks of Hi-Z following the mode bits. For W25Q080, 4 dummy cycles
150167
// are required.
151-
#define WAIT_CYCLES 4
168+
#define WAIT_CYCLES BOARD_WAIT_CYCLES
169+
152170

153171
// If defined, we will read status reg, compare to SREG_DATA, and overwrite
154172
// with our value if the SR doesn't match.
@@ -184,10 +202,14 @@ _stage2_boot:
184202
ldr r0, [r3, #PADS_QSPI_GPIO_QSPI_SD0_OFFSET]
185203
movs r1, #PADS_QSPI_GPIO_QSPI_SD0_SCHMITT_BITS
186204
bics r0, r1
205+
#if BOARD_QUAD_OK==1
187206
str r0, [r3, #PADS_QSPI_GPIO_QSPI_SD0_OFFSET]
207+
#endif
188208
str r0, [r3, #PADS_QSPI_GPIO_QSPI_SD1_OFFSET]
209+
#if BOARD_QUAD_OK==1
189210
str r0, [r3, #PADS_QSPI_GPIO_QSPI_SD2_OFFSET]
190211
str r0, [r3, #PADS_QSPI_GPIO_QSPI_SD3_OFFSET]
212+
#endif
191213

192214
ldr r3, =XIP_SSI_BASE
193215

@@ -225,9 +247,15 @@ program_sregs:
225247
str r1, [r3, #SSI_SSIENR_OFFSET]
226248

227249
// Check whether SR needs updating
250+
#if BOARD_QUAD_OK==1
251+
# if BOARD_QUAD_ENABLE_STATUS_BYTE==1
252+
movs r0, #CMD_READ_STATUS1
253+
# elif BOARD_QUAD_ENABLE_STATUS_BYTE==2
228254
movs r0, #CMD_READ_STATUS2
255+
# endif
256+
229257
bl read_flash_sreg
230-
movs r2, #SREG_DATA
258+
movs r2, #BOARD_QUAD_ENABLE_BIT_MASK
231259
cmp r0, r2
232260
beq skip_sreg_programming
233261

@@ -240,24 +268,45 @@ program_sregs:
240268
ldr r1, [r3, #SSI_DR0_OFFSET]
241269

242270
// Send status write command followed by data bytes
243-
movs r1, #CMD_WRITE_STATUS
271+
# if BOARD_SPLIT_STATUS_WRITE==1
272+
# if BOARD_QUAD_ENABLE_STATUS_BYTE==1
273+
movs r1, #CMD_WRITE_STATUS1
274+
# elif BOARD_QUAD_ENABLE_STATUS_BYTE==2
275+
movs r1, #CMD_WRITE_STATUS2
276+
# endif
277+
str r1, [r3, #SSI_DR0_OFFSET]
278+
str r2, [r3, #SSI_DR0_OFFSET]
279+
280+
bl wait_ssi_ready
281+
//ldr r1, [r3, #SSI_DR0_OFFSET]
282+
ldr r1, [r3, #SSI_DR0_OFFSET]
283+
ldr r1, [r3, #SSI_DR0_OFFSET]
284+
285+
# else
286+
movs r1, #CMD_WRITE_STATUS1
244287
str r1, [r3, #SSI_DR0_OFFSET]
288+
# if BOARD_QUAD_ENABLE_STATUS_BYTE==2
245289
movs r0, #0
246290
str r0, [r3, #SSI_DR0_OFFSET]
291+
# endif
247292
str r2, [r3, #SSI_DR0_OFFSET]
248293

249294
bl wait_ssi_ready
250295
ldr r1, [r3, #SSI_DR0_OFFSET]
251296
ldr r1, [r3, #SSI_DR0_OFFSET]
297+
# if BOARD_QUAD_ENABLE_STATUS_BYTE==2
252298
ldr r1, [r3, #SSI_DR0_OFFSET]
299+
# endif
253300

301+
# endif
254302
// Poll status register for write completion
255303
1:
256304
movs r0, #CMD_READ_STATUS
257305
bl read_flash_sreg
258306
movs r1, #1
259307
tst r0, r1
260308
bne 1b
309+
#endif
261310

262311
skip_sreg_programming:
263312

@@ -286,6 +335,7 @@ dummy_read:
286335
movs r1, #0x0 // NDF=0 (single 32b read)
287336
str r1, [r3, #SSI_CTRLR1_OFFSET]
288337

338+
#if BOARD_QUAD_OK==1
289339
#define SPI_CTRLR0_ENTER_XIP \
290340
(ADDR_L << SSI_SPI_CTRLR0_ADDR_L_LSB) | /* Address + mode bits */ \
291341
(WAIT_CYCLES << SSI_SPI_CTRLR0_WAIT_CYCLES_LSB) | /* Hi-Z dummy clocks following address + mode */ \
@@ -315,20 +365,21 @@ dummy_read:
315365

316366
movs r1, #0
317367
str r1, [r3, #SSI_SSIENR_OFFSET] // Disable SSI (and clear FIFO) to allow further config
368+
#endif
318369

319370
// Note that the INST_L field is used to select what XIP data gets pushed into
320371
// the TX FIFO:
321372
// INST_L_0_BITS {ADDR[23:0],XIP_CMD[7:0]} Load "mode bits" into XIP_CMD
322373
// Anything else {XIP_CMD[7:0],ADDR[23:0]} Load SPI command into XIP_CMD
323374
configure_ssi:
324375
#define SPI_CTRLR0_XIP \
325-
(MODE_CONTINUOUS_READ /* Mode bits to keep flash in continuous read mode */ \
376+
(READ_INSTRUCTION /* Mode bits to keep flash in continuous read mode */ \
326377
<< SSI_SPI_CTRLR0_XIP_CMD_LSB) | \
327378
(ADDR_L << SSI_SPI_CTRLR0_ADDR_L_LSB) | /* Total number of address + mode bits */ \
328379
(WAIT_CYCLES << SSI_SPI_CTRLR0_WAIT_CYCLES_LSB) | /* Hi-Z dummy clocks following address + mode */ \
329-
(SSI_SPI_CTRLR0_INST_L_VALUE_NONE /* Do not send a command, instead send XIP_CMD as mode bits after address */ \
380+
(INSTRUCTION_LENGTH /* Do not send a command, instead send XIP_CMD as mode bits after address */ \
330381
<< SSI_SPI_CTRLR0_INST_L_LSB) | \
331-
(SSI_SPI_CTRLR0_TRANS_TYPE_VALUE_2C2A /* Send Address in Quad I/O mode (and Command but that is zero bits long) */ \
382+
(TRANSACTION_TYPE /* Send Address in Quad I/O mode (and Command but that is zero bits long) */ \
332383
<< SSI_SPI_CTRLR0_TRANS_TYPE_LSB)
333384

334385
ldr r1, =(SPI_CTRLR0_XIP)

0 commit comments

Comments
 (0)