rp2040: support Adafruit Feather RP2040

Этот коммит содержится в:
Kenneth Bell 2021-06-14 18:50:28 -07:00 коммит произвёл Ron Evans
родитель 1913cb76a5
коммит 8e33f1c9eb
9 изменённых файлов: 145 добавлений и 27 удалений

Просмотреть файл

@ -358,6 +358,8 @@ smoketest:
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=pico examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=feather-rp2040 examples/blinky1
@$(MD5SUM) test.hex
# test pwm
$(TINYGO) build -size short -o test.hex -target=itsybitsy-m0 examples/pwm
@$(MD5SUM) test.hex

Просмотреть файл

@ -43,7 +43,7 @@ See the [getting started instructions](https://tinygo.org/getting-started/) for
You can compile TinyGo programs for microcontrollers, WebAssembly and Linux.
The following 62 microcontroller boards are currently supported:
The following 63 microcontroller boards are currently supported:
* [Adafruit Circuit Playground Bluefruit](https://www.adafruit.com/product/4333)
* [Adafruit Circuit Playground Express](https://www.adafruit.com/product/3333)
@ -52,6 +52,7 @@ The following 62 microcontroller boards are currently supported:
* [Adafruit Feather M4](https://www.adafruit.com/product/3857)
* [Adafruit Feather M4 CAN](https://www.adafruit.com/product/4759)
* [Adafruit Feather nRF52840 Express](https://www.adafruit.com/product/4062)
* [Adafruit Feather RP2040](https://www.adafruit.com/product/4884)
* [Adafruit Feather STM32F405 Express](https://www.adafruit.com/product/4382)
* [Adafruit Grand Central M4](https://www.adafruit.com/product/4064)
* [Adafruit ItsyBitsy M0](https://www.adafruit.com/product/3727)

10
src/machine/board_feather_rp2040.go Обычный файл
Просмотреть файл

@ -0,0 +1,10 @@
// +build feather_rp2040
package machine
const (
LED = GPIO13
// Onboard crystal oscillator frequency, in MHz.
xoscFreq = 12 // MHz
)

17
targets/feather-rp2040-boot-stage2.S Обычный файл
Просмотреть файл

@ -0,0 +1,17 @@
// Adafruit Feather RP2040 Stage 2 Bootloader
//
// This file defines the parameters specific to the flash-chip found
// on the Adafruit Feather RP2040. The generic implementation is in
// rp2040-boot-stage2.S
//
#define BOARD_PICO_FLASH_SPI_CLKDIV 2
#define BOARD_CMD_READ 0xe7
#define BOARD_QUAD_OK 1
#define BOARD_QUAD_ENABLE_STATUS_BYTE 2
#define BOARD_QUAD_ENABLE_BIT_MASK 2
#define BOARD_SPLIT_STATUS_WRITE 1
#define BOARD_WAIT_CYCLES 2
#include "rp2040-boot-stage2.S"

10
targets/feather-rp2040.json Обычный файл
Просмотреть файл

@ -0,0 +1,10 @@
{
"inherits": [
"rp2040"
],
"build-tags": ["feather_rp2040"],
"linkerscript": "targets/feather-rp2040.ld",
"extra-files": [
"targets/feather-rp2040-boot-stage2.S"
]
}

10
targets/feather-rp2040.ld Обычный файл
Просмотреть файл

@ -0,0 +1,10 @@
MEMORY
{
/* Reserve exactly 256 bytes at start of flash for second stage bootloader */
BOOT2_TEXT (rx) : ORIGIN = 0x10000000, LENGTH = 256
FLASH_TEXT (rx) : ORIGIN = 0x10000000 + 256, LENGTH = 8192K - 256
RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 256k
}
INCLUDE "targets/rp2040.ld"

17
targets/pico-boot-stage2.S Обычный файл
Просмотреть файл

@ -0,0 +1,17 @@
// Raspberry Pi Pico Stage 2 Bootloader
//
// This file defines the parameters specific to the flash-chip found
// on the official Pico boards. The generic implementation is in
// rp2040-boot-stage2.S
//
#define BOARD_PICO_FLASH_SPI_CLKDIV 2
#define BOARD_CMD_READ 0xeb
#define BOARD_QUAD_OK 1
#define BOARD_QUAD_ENABLE_STATUS_BYTE 2
#define BOARD_QUAD_ENABLE_BIT_MASK 2
#define BOARD_SPLIT_STATUS_WRITE 0
#define BOARD_WAIT_CYCLES 4
#include "rp2040-boot-stage2.S"

Просмотреть файл

@ -5,6 +5,6 @@
"build-tags": ["pico"],
"linkerscript": "targets/pico.ld",
"extra-files": [
"targets/pico_boot_stage2.S"
"targets/pico-boot-stage2.S"
]
}

Просмотреть файл

@ -1,11 +1,21 @@
//
// Implementation of Pico stage 2 boot loader. This code is for the Winbond W25Q080
// (as found in the Pico) from the official Pico SDK.
// Implementation of RP2040 stage 2 boot loader. This code is derived from the
// Winbond W25Q080 implementation (as found in the Pico) in the official Pico SDK.
//
// This implementation has been made 'stand-alone' by including necessary code /
// symbols from the included files in the reference implementation directly into
// the source. Care has been taken to preserve ordering and it has been verified
// the generated binary is byte-for-byte identical to the reference code binary.
// the source. It has also been modified to include the conditional logic from
// the CircuitPython implementation that supports additional flash chips. The
// CiruitPython source is here:
// https://github.com/adafruit/circuitpython/blob/main/ports/raspberrypi/stage2.c.jinja
//
// This file cannot be assembled directly, instead assemble the board-specific file
// (such as pico-boot-stage2.S) which defines the parameters specific to the flash
// chip included on that board.
//
// Care has been taken to preserve ordering and it has been verified the generated
// binary is byte-for-byte identical to the reference code binary when assembled for
// the Pico.
//
// Note: the stage 2 boot loader must be 256 bytes in length and have a checksum
// present. In TinyGo, the linker script is responsible for allocating 256 bytes
@ -19,10 +29,6 @@
// https://github.com/raspberrypi/pico-sdk/blob/master/src/rp2_common/boot_stage2/boot2_w25q080.S
//
// Board Parameters
#define PICO_FLASH_SPI_CLKDIV 2
// ----------------------------------------------------------------------------
// Second stage boot code
@ -59,7 +65,8 @@
#define CMD_WRITE_ENABLE 0x06
#define CMD_READ_STATUS 0x05
#define CMD_READ_STATUS2 0x35
#define CMD_WRITE_STATUS 0x01
#define CMD_WRITE_STATUS1 0x01
#define CMD_WRITE_STATUS2 0x31
#define SREG_DATA 0x02 // Enable quad-SPI mode
#define XIP_BASE 0x10000000
@ -123,18 +130,32 @@
// The bootrom is very conservative with SPI frequency, but here we should be
// as aggressive as possible.
#ifndef PICO_FLASH_SPI_CLKDIV
#define PICO_FLASH_SPI_CLKDIV 4
#endif
#define PICO_FLASH_SPI_CLKDIV BOARD_PICO_FLASH_SPI_CLKDIV
#if PICO_FLASH_SPI_CLKDIV & 1
#error PICO_FLASH_SPI_CLKDIV must be even
#endif
#if BOARD_QUAD_OK==1
// Define interface width: single/dual/quad IO
#define FRAME_FORMAT SSI_CTRLR0_SPI_FRF_VALUE_QUAD
#define TRANSACTION_TYPE SSI_SPI_CTRLR0_TRANS_TYPE_VALUE_2C2A
// Note that the INST_L field is used to select what XIP data gets pushed into
// the TX FIFO:
// INST_L_0_BITS {ADDR[23:0],XIP_CMD[7:0]} Load "mode bits" into XIP_CMD
// Anything else {XIP_CMD[7:0],ADDR[23:0]} Load SPI command into XIP_CMD
#define INSTRUCTION_LENGTH SSI_SPI_CTRLR0_INST_L_VALUE_NONE
#define READ_INSTRUCTION MODE_CONTINUOUS_READ
#define ADDR_L 8 // 6 for address, 2 for mode
#else
#define FRAME_FORMAT SSI_CTRLR0_SPI_FRF_VALUE_STD
#define TRANSACTION_TYPE SSI_SPI_CTRLR0_TRANS_TYPE_VALUE_1C1A
#define INSTRUCTION_LENGTH SSI_SPI_CTRLR0_INST_L_VALUE_8B
#define READ_INSTRUCTION BOARD_CMD_READ
#define ADDR_L 6 // * 4 = 24
#endif
// For W25Q080 this is the "Read data fast quad IO" instruction:
#define CMD_READ 0xeb
// The flash-chip specific read isntruction
#define CMD_READ BOARD_CMD_READ
// "Mode bits" are 8 special bits sent immediately after
// the address bits in a "Read Data Fast Quad I/O" command sequence.
@ -142,13 +163,10 @@
// next read does not require the 0xeb instruction prefix.
#define MODE_CONTINUOUS_READ 0xa0
// The number of address + mode bits, divided by 4 (always 4, not function of
// interface width).
#define ADDR_L 8
// How many clocks of Hi-Z following the mode bits. For W25Q080, 4 dummy cycles
// are required.
#define WAIT_CYCLES 4
#define WAIT_CYCLES BOARD_WAIT_CYCLES
// If defined, we will read status reg, compare to SREG_DATA, and overwrite
// with our value if the SR doesn't match.
@ -184,10 +202,14 @@ _stage2_boot:
ldr r0, [r3, #PADS_QSPI_GPIO_QSPI_SD0_OFFSET]
movs r1, #PADS_QSPI_GPIO_QSPI_SD0_SCHMITT_BITS
bics r0, r1
#if BOARD_QUAD_OK==1
str r0, [r3, #PADS_QSPI_GPIO_QSPI_SD0_OFFSET]
#endif
str r0, [r3, #PADS_QSPI_GPIO_QSPI_SD1_OFFSET]
#if BOARD_QUAD_OK==1
str r0, [r3, #PADS_QSPI_GPIO_QSPI_SD2_OFFSET]
str r0, [r3, #PADS_QSPI_GPIO_QSPI_SD3_OFFSET]
#endif
ldr r3, =XIP_SSI_BASE
@ -225,9 +247,15 @@ program_sregs:
str r1, [r3, #SSI_SSIENR_OFFSET]
// Check whether SR needs updating
#if BOARD_QUAD_OK==1
# if BOARD_QUAD_ENABLE_STATUS_BYTE==1
movs r0, #CMD_READ_STATUS1
# elif BOARD_QUAD_ENABLE_STATUS_BYTE==2
movs r0, #CMD_READ_STATUS2
# endif
bl read_flash_sreg
movs r2, #SREG_DATA
movs r2, #BOARD_QUAD_ENABLE_BIT_MASK
cmp r0, r2
beq skip_sreg_programming
@ -240,17 +268,37 @@ program_sregs:
ldr r1, [r3, #SSI_DR0_OFFSET]
// Send status write command followed by data bytes
movs r1, #CMD_WRITE_STATUS
# if BOARD_SPLIT_STATUS_WRITE==1
# if BOARD_QUAD_ENABLE_STATUS_BYTE==1
movs r1, #CMD_WRITE_STATUS1
# elif BOARD_QUAD_ENABLE_STATUS_BYTE==2
movs r1, #CMD_WRITE_STATUS2
# endif
str r1, [r3, #SSI_DR0_OFFSET]
str r2, [r3, #SSI_DR0_OFFSET]
bl wait_ssi_ready
//ldr r1, [r3, #SSI_DR0_OFFSET]
ldr r1, [r3, #SSI_DR0_OFFSET]
ldr r1, [r3, #SSI_DR0_OFFSET]
# else
movs r1, #CMD_WRITE_STATUS1
str r1, [r3, #SSI_DR0_OFFSET]
# if BOARD_QUAD_ENABLE_STATUS_BYTE==2
movs r0, #0
str r0, [r3, #SSI_DR0_OFFSET]
# endif
str r2, [r3, #SSI_DR0_OFFSET]
bl wait_ssi_ready
ldr r1, [r3, #SSI_DR0_OFFSET]
ldr r1, [r3, #SSI_DR0_OFFSET]
# if BOARD_QUAD_ENABLE_STATUS_BYTE==2
ldr r1, [r3, #SSI_DR0_OFFSET]
# endif
# endif
// Poll status register for write completion
1:
movs r0, #CMD_READ_STATUS
@ -258,6 +306,7 @@ program_sregs:
movs r1, #1
tst r0, r1
bne 1b
#endif
skip_sreg_programming:
@ -286,6 +335,7 @@ dummy_read:
movs r1, #0x0 // NDF=0 (single 32b read)
str r1, [r3, #SSI_CTRLR1_OFFSET]
#if BOARD_QUAD_OK==1
#define SPI_CTRLR0_ENTER_XIP \
(ADDR_L << SSI_SPI_CTRLR0_ADDR_L_LSB) | /* Address + mode bits */ \
(WAIT_CYCLES << SSI_SPI_CTRLR0_WAIT_CYCLES_LSB) | /* Hi-Z dummy clocks following address + mode */ \
@ -315,6 +365,7 @@ dummy_read:
movs r1, #0
str r1, [r3, #SSI_SSIENR_OFFSET] // Disable SSI (and clear FIFO) to allow further config
#endif
// Note that the INST_L field is used to select what XIP data gets pushed into
// the TX FIFO:
@ -322,13 +373,13 @@ dummy_read:
// Anything else {XIP_CMD[7:0],ADDR[23:0]} Load SPI command into XIP_CMD
configure_ssi:
#define SPI_CTRLR0_XIP \
(MODE_CONTINUOUS_READ /* Mode bits to keep flash in continuous read mode */ \
(READ_INSTRUCTION /* Mode bits to keep flash in continuous read mode */ \
<< SSI_SPI_CTRLR0_XIP_CMD_LSB) | \
(ADDR_L << SSI_SPI_CTRLR0_ADDR_L_LSB) | /* Total number of address + mode bits */ \
(WAIT_CYCLES << SSI_SPI_CTRLR0_WAIT_CYCLES_LSB) | /* Hi-Z dummy clocks following address + mode */ \
(SSI_SPI_CTRLR0_INST_L_VALUE_NONE /* Do not send a command, instead send XIP_CMD as mode bits after address */ \
(INSTRUCTION_LENGTH /* Do not send a command, instead send XIP_CMD as mode bits after address */ \
<< SSI_SPI_CTRLR0_INST_L_LSB) | \
(SSI_SPI_CTRLR0_TRANS_TYPE_VALUE_2C2A /* Send Address in Quad I/O mode (and Command but that is zero bits long) */ \
(TRANSACTION_TYPE /* Send Address in Quad I/O mode (and Command but that is zero bits long) */ \
<< SSI_SPI_CTRLR0_TRANS_TYPE_LSB)
ldr r1, =(SPI_CTRLR0_XIP)