Merge pull request #465 from dhalbert/3.0_spi_flash
Support SPI flash chips for CIRCUITPY, using non-DMA SPI for now.
This commit is contained in:
commit
93978bcd25
|
@ -218,6 +218,7 @@ SRC_C = \
|
||||||
mphalport.c \
|
mphalport.c \
|
||||||
reset.c \
|
reset.c \
|
||||||
$(CHIP_FAMILY)_peripherals.c \
|
$(CHIP_FAMILY)_peripherals.c \
|
||||||
|
peripherals.c \
|
||||||
$(CHIP_FAMILY)_pins.c \
|
$(CHIP_FAMILY)_pins.c \
|
||||||
tick.c \
|
tick.c \
|
||||||
usb.c \
|
usb.c \
|
||||||
|
@ -260,6 +261,7 @@ SRC_COMMON_HAL = \
|
||||||
microcontroller/Processor.c \
|
microcontroller/Processor.c \
|
||||||
neopixel_write/__init__.c \
|
neopixel_write/__init__.c \
|
||||||
os/__init__.c \
|
os/__init__.c \
|
||||||
|
storage/__init__.c \
|
||||||
time/__init__.c \
|
time/__init__.c \
|
||||||
# analogio/__init__.c \
|
# analogio/__init__.c \
|
||||||
analogio/AnalogIn.c \
|
analogio/AnalogIn.c \
|
||||||
|
@ -276,7 +278,6 @@ SRC_COMMON_HAL = \
|
||||||
pulseio/PulseIn.c \
|
pulseio/PulseIn.c \
|
||||||
pulseio/PulseOut.c \
|
pulseio/PulseOut.c \
|
||||||
pulseio/PWMOut.c \
|
pulseio/PWMOut.c \
|
||||||
storage/__init__.c \
|
|
||||||
touchio/__init__.c \
|
touchio/__init__.c \
|
||||||
touchio/TouchIn.c \
|
touchio/TouchIn.c \
|
||||||
usb_hid/__init__.c \
|
usb_hid/__init__.c \
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 72f76894ba08c9de2ec3ae231fb71daaf3eafb1e
|
Subproject commit 0efc3407dd97ef617a5655674a3516693897a961
|
|
@ -3,25 +3,35 @@
|
||||||
|
|
||||||
#define MICROPY_HW_NEOPIXEL (&pin_PA06)
|
#define MICROPY_HW_NEOPIXEL (&pin_PA06)
|
||||||
|
|
||||||
// Salae reads 12mhz which is the limit even though we set it to the safer 8mhz.
|
// Clock rates are off: Salae reads 12MHz which is the limit even though we set it to the safer 8MHz.
|
||||||
#define SPI_FLASH_BAUDRATE (8000000)
|
#define SPI_FLASH_BAUDRATE (8000000)
|
||||||
|
|
||||||
#define SPI_FLASH_MUX_SETTING SPI_SIGNAL_MUX_SETTING_C
|
#define SPI_FLASH_MOSI_PIN PIN_PA08
|
||||||
#define SPI_FLASH_PAD0_PINMUX PINMUX_PA08D_SERCOM2_PAD0 // MOSI
|
#define SPI_FLASH_MISO_PIN PIN_PA14
|
||||||
// Use default pinmux for the chip select since we manage it ourselves.
|
#define SPI_FLASH_SCK_PIN PIN_PA09
|
||||||
#define SPI_FLASH_PAD1_PINMUX PINMUX_PA09D_SERCOM2_PAD1 // SCK
|
#define SPI_FLASH_CS_PIN PIN_PA13
|
||||||
#define SPI_FLASH_PAD2_PINMUX PINMUX_PA14C_SERCOM2_PAD2 // MISO
|
#define SPI_FLASH_MOSI_PIN_FUNCTION PINMUX_PA08D_SERCOM2_PAD0
|
||||||
#define SPI_FLASH_PAD3_PINMUX PINMUX_UNUSED // SCK
|
#define SPI_FLASH_MISO_PIN_FUNCTION PINMUX_PA14C_SERCOM2_PAD2
|
||||||
#define SPI_FLASH_SERCOM SERCOM2
|
#define SPI_FLASH_SCK_PIN_FUNCTION PINMUX_PA09D_SERCOM2_PAD1
|
||||||
|
#define SPI_FLASH_SERCOM SERCOM2
|
||||||
|
#define SPI_FLASH_SERCOM_INDEX 2
|
||||||
|
#define SPI_FLASH_MOSI_PAD 0
|
||||||
|
#define SPI_FLASH_MISO_PAD 2
|
||||||
|
#define SPI_FLASH_SCK_PAD 1
|
||||||
|
// <o> Transmit Data Pinout
|
||||||
|
// <0x0=>PAD[0,1]_DO_SCK
|
||||||
|
// <0x1=>PAD[2,3]_DO_SCK
|
||||||
|
// <0x2=>PAD[3,1]_DO_SCK
|
||||||
|
// <0x3=>PAD[0,3]_DO_SCK
|
||||||
|
#define SPI_FLASH_DOPO 0
|
||||||
|
#define SPI_FLASH_DIPO 2 // same as MISO pad
|
||||||
|
|
||||||
#define SPI_FLASH_CS PIN_PA13
|
// These are pins not to reset.
|
||||||
|
#define MICROPY_PORT_A (PORT_PA06 | PORT_PA08 | PORT_PA09 | PORT_PA13 | PORT_PA14 | PORT_PA24 | PORT_PA25)
|
||||||
#define MICROPY_PORT_A (PORT_PA06 | PORT_PA08 | PORT_PA09 | PORT_PA14 | PORT_PA13 | PORT_PA14 | PORT_PA24 | PORT_PA25)
|
|
||||||
#define MICROPY_PORT_B ( 0 )
|
#define MICROPY_PORT_B ( 0 )
|
||||||
#define MICROPY_PORT_C ( 0 )
|
#define MICROPY_PORT_C ( 0 )
|
||||||
|
|
||||||
#include "internal_flash.h"
|
#include "spi_flash.h"
|
||||||
//#include "spi_flash.h"
|
|
||||||
|
|
||||||
// If you change this, then make sure to update the linker scripts as well to
|
// If you change this, then make sure to update the linker scripts as well to
|
||||||
// make sure you don't overwrite code.
|
// make sure you don't overwrite code.
|
||||||
|
|
|
@ -4,8 +4,7 @@ USB_PID = 0x8023
|
||||||
USB_PRODUCT = "Feather M0 Express"
|
USB_PRODUCT = "Feather M0 Express"
|
||||||
USB_MANUFACTURER = "Adafruit Industries LLC"
|
USB_MANUFACTURER = "Adafruit Industries LLC"
|
||||||
|
|
||||||
#SPI_FLASH_FILESYSTEM = 1
|
SPI_FLASH_FILESYSTEM = 1
|
||||||
INTERNAL_FLASH_FILESYSTEM = 1
|
|
||||||
|
|
||||||
CHIP_VARIANT = SAMD21G18A
|
CHIP_VARIANT = SAMD21G18A
|
||||||
CHIP_FAMILY = samd21
|
CHIP_FAMILY = samd21
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
#define USB_REPL
|
|
||||||
|
|
||||||
#define MICROPY_HW_BOARD_NAME "Adafruit Metro M0 Express"
|
#define MICROPY_HW_BOARD_NAME "Adafruit Metro M0 Express"
|
||||||
#define MICROPY_HW_MCU_NAME "samd21g18"
|
#define MICROPY_HW_MCU_NAME "samd21g18"
|
||||||
|
|
||||||
|
@ -8,24 +6,35 @@
|
||||||
|
|
||||||
#define MICROPY_HW_NEOPIXEL (&pin_PA30)
|
#define MICROPY_HW_NEOPIXEL (&pin_PA30)
|
||||||
|
|
||||||
// Salae reads 12mhz which is the limit even though we set it to the safer 8mhz.
|
// Clock rates are off: Salae reads 12MHz which is the limit even though we set it to the safer 8MHz.
|
||||||
#define SPI_FLASH_BAUDRATE (8000000)
|
#define SPI_FLASH_BAUDRATE (8000000)
|
||||||
|
|
||||||
#define SPI_FLASH_MUX_SETTING SPI_SIGNAL_MUX_SETTING_F
|
#define SPI_FLASH_MOSI_PIN PIN_PB22
|
||||||
#define SPI_FLASH_PAD0_PINMUX PINMUX_UNUSED // CS
|
#define SPI_FLASH_MISO_PIN PIN_PB03
|
||||||
// Use default pinmux for the chip select since we manage it ourselves.
|
#define SPI_FLASH_SCK_PIN PIN_PB23
|
||||||
#define SPI_FLASH_PAD1_PINMUX PINMUX_PB03D_SERCOM5_PAD1 // MISO
|
#define SPI_FLASH_CS_PIN PIN_PA13
|
||||||
#define SPI_FLASH_PAD2_PINMUX PINMUX_PB22D_SERCOM5_PAD2 // MOSI
|
#define SPI_FLASH_MOSI_PIN_FUNCTION PINMUX_PB22D_SERCOM5_PAD2
|
||||||
#define SPI_FLASH_PAD3_PINMUX PINMUX_PB23D_SERCOM5_PAD3 // SCK
|
#define SPI_FLASH_MISO_PIN_FUNCTION PINMUX_PB03D_SERCOM5_PAD1
|
||||||
#define SPI_FLASH_CS PIN_PA13
|
#define SPI_FLASH_SCK_PIN_FUNCTION PINMUX_PB23D_SERCOM5_PAD3
|
||||||
#define SPI_FLASH_SERCOM SERCOM5
|
#define SPI_FLASH_SERCOM SERCOM5
|
||||||
|
#define SPI_FLASH_SERCOM_INDEX 5
|
||||||
|
#define SPI_FLASH_MOSI_PAD 2
|
||||||
|
#define SPI_FLASH_MISO_PAD 1
|
||||||
|
#define SPI_FLASH_SCK_PAD 3
|
||||||
|
// <o> Transmit Data Pinout
|
||||||
|
// <0x0=>PAD[0,1]_DO_SCK
|
||||||
|
// <0x1=>PAD[2,3]_DO_SCK
|
||||||
|
// <0x2=>PAD[3,1]_DO_SCK
|
||||||
|
// <0x3=>PAD[0,3]_DO_SCK
|
||||||
|
#define SPI_FLASH_DOPO 1
|
||||||
|
#define SPI_FLASH_DIPO 1 // same as MISO pad
|
||||||
|
|
||||||
|
// These are pins not to reset.
|
||||||
#define MICROPY_PORT_A (PORT_PA13 |PORT_PA24 | PORT_PA25 | PORT_PA27 | PORT_PA30 | PORT_PA31)
|
#define MICROPY_PORT_A (PORT_PA13 |PORT_PA24 | PORT_PA25 | PORT_PA27 | PORT_PA30 | PORT_PA31)
|
||||||
#define MICROPY_PORT_B (PORT_PB03 | PORT_PB22 | PORT_PB23)
|
#define MICROPY_PORT_B (PORT_PB03 | PORT_PB22 | PORT_PB23)
|
||||||
#define MICROPY_PORT_C (0)
|
#define MICROPY_PORT_C (0)
|
||||||
|
|
||||||
#include "internal_flash.h"
|
#include "spi_flash.h"
|
||||||
//#include "spi_flash.h"
|
|
||||||
|
|
||||||
// If you change this, then make sure to update the linker scripts as well to
|
// If you change this, then make sure to update the linker scripts as well to
|
||||||
// make sure you don't overwrite code.
|
// make sure you don't overwrite code.
|
||||||
|
|
|
@ -4,8 +4,7 @@ USB_PID = 0x8014
|
||||||
USB_PRODUCT = "Metro M0 Express"
|
USB_PRODUCT = "Metro M0 Express"
|
||||||
USB_MANUFACTURER = "Adafruit Industries LLC"
|
USB_MANUFACTURER = "Adafruit Industries LLC"
|
||||||
|
|
||||||
#SPI_FLASH_FILESYSTEM = 1
|
SPI_FLASH_FILESYSTEM = 1
|
||||||
INTERNAL_FLASH_FILESYSTEM = 1
|
|
||||||
|
|
||||||
CHIP_VARIANT = SAMD21G18A
|
CHIP_VARIANT = SAMD21G18A
|
||||||
CHIP_FAMILY = samd21
|
CHIP_FAMILY = samd21
|
||||||
|
|
|
@ -29,6 +29,5 @@ STATIC const mp_rom_map_elem_t board_global_dict_table[] = {
|
||||||
{ MP_ROM_QSTR(MP_QSTR_SCK), MP_ROM_PTR(&pin_PB11) },
|
{ MP_ROM_QSTR(MP_QSTR_SCK), MP_ROM_PTR(&pin_PB11) },
|
||||||
{ MP_ROM_QSTR(MP_QSTR_MOSI), MP_ROM_PTR(&pin_PB10) },
|
{ MP_ROM_QSTR(MP_QSTR_MOSI), MP_ROM_PTR(&pin_PB10) },
|
||||||
{ MP_ROM_QSTR(MP_QSTR_MISO), MP_ROM_PTR(&pin_PA12) },
|
{ MP_ROM_QSTR(MP_QSTR_MISO), MP_ROM_PTR(&pin_PA12) },
|
||||||
{ MP_ROM_QSTR(MP_QSTR_FLASH_CS), MP_ROM_PTR(&pin_PA13) },
|
|
||||||
};
|
};
|
||||||
MP_DEFINE_CONST_DICT(board_module_globals, board_global_dict_table);
|
MP_DEFINE_CONST_DICT(board_module_globals, board_global_dict_table);
|
||||||
|
|
|
@ -8,29 +8,46 @@
|
||||||
|
|
||||||
#define MICROPY_HW_NEOPIXEL (&pin_PB17)
|
#define MICROPY_HW_NEOPIXEL (&pin_PB17)
|
||||||
|
|
||||||
#define SPI_FLASH_BAUDRATE (1000000)
|
#define SPI_FLASH_BAUDRATE (8000000)
|
||||||
|
|
||||||
// Rev F
|
// Rev B: single channel SPI
|
||||||
#define SPI_FLASH_MUX_SETTING SPI_SIGNAL_MUX_SETTING_F
|
// Rev C will be QSPI
|
||||||
#define SPI_FLASH_PAD0_PINMUX PINMUX_PB08 // MOSI
|
#define SPI_FLASH_MOSI_PIN PIN_PB08
|
||||||
// Use default pinmux for the chip select since we manage it ourselves.
|
#define SPI_FLASH_MISO_PIN PIN_PB11
|
||||||
#define SPI_FLASH_PAD1_PINMUX PINMUX_PB09 // SCK
|
#define SPI_FLASH_SCK_PIN PIN_PB09
|
||||||
#define SPI_FLASH_PAD2_PINMUX PINMUX_DEFAULT // CS
|
#define SPI_FLASH_CS_PIN PIN_PB10
|
||||||
#define SPI_FLASH_PAD3_PINMUX PINMUX_PB11 // MISO
|
#define SPI_FLASH_MOSI_PIN_FUNCTION PINMUX_PB08D_SERCOM4_PAD0
|
||||||
#define SPI_FLASH_CS PIN_PB10
|
#define SPI_FLASH_MISO_PIN_FUNCTION PINMUX_PB11D_SERCOM4_PAD3
|
||||||
#define SPI_FLASH_SERCOM SERCOM5
|
#define SPI_FLASH_SCK_PIN_FUNCTION PINMUX_PB09D_SERCOM4_PAD1
|
||||||
|
#define SPI_FLASH_SERCOM SERCOM4
|
||||||
|
#define SPI_FLASH_SERCOM_INDEX 4
|
||||||
|
#define SPI_FLASH_MOSI_PAD 0
|
||||||
|
#define SPI_FLASH_MISO_PAD 3
|
||||||
|
#define SPI_FLASH_SCK_PAD 1
|
||||||
|
// <o> Transmit Data Pinout
|
||||||
|
// <0x0=>PAD[0,1]_DO_SCK
|
||||||
|
// <0x1=>PAD[2,3]_DO_SCK
|
||||||
|
// <0x2=>PAD[3,1]_DO_SCK
|
||||||
|
// <0x3=>PAD[0,3]_DO_SCK
|
||||||
|
#define SPI_FLASH_DOPO 0
|
||||||
|
#define SPI_FLASH_DIPO 3 // same as MISO pad
|
||||||
|
|
||||||
|
// These are pins not to reset.
|
||||||
#define MICROPY_PORT_A (PORT_PA27)
|
#define MICROPY_PORT_A (PORT_PA27)
|
||||||
#define MICROPY_PORT_B (PORT_PB06 | PORT_PB08 | PORT_PB09 | PORT_PB11 | PORT_PB17)
|
#define MICROPY_PORT_B (PORT_PB06 | PORT_PB08 | PORT_PB09 | PORT_PB10 | PORT_PB11 | PORT_PB17)
|
||||||
#define MICROPY_PORT_C (0)
|
#define MICROPY_PORT_C (0)
|
||||||
#define MICROPY_PORT_D (0)
|
#define MICROPY_PORT_D (0)
|
||||||
|
|
||||||
#define AUTORESET_DELAY_MS 500
|
#define AUTORESET_DELAY_MS 500
|
||||||
|
|
||||||
#include "internal_flash.h"
|
#include "spi_flash.h"
|
||||||
|
|
||||||
// If you change this, then make sure to update the linker scripts as well to
|
// If you change this, then make sure to update the linker scripts as well to
|
||||||
// make sure you don't overwrite code.
|
// make sure you don't overwrite code
|
||||||
|
// #define CIRCUITPY_INTERNAL_NVM_SIZE 256
|
||||||
#define CIRCUITPY_INTERNAL_NVM_SIZE 0
|
#define CIRCUITPY_INTERNAL_NVM_SIZE 0
|
||||||
|
|
||||||
#define BOARD_FLASH_SIZE (FLASH_SIZE - 0x4000)
|
#define BOARD_FLASH_SIZE (FLASH_SIZE - 0x4000 - CIRCUITPY_INTERNAL_NVM_SIZE)
|
||||||
|
|
||||||
|
#include "flash_S25FL216K.h"
|
||||||
|
#include "flash_GD25Q16C.h"
|
||||||
|
|
|
@ -4,8 +4,7 @@ USB_PID = 0x8021
|
||||||
USB_PRODUCT = "Metro M4 Express"
|
USB_PRODUCT = "Metro M4 Express"
|
||||||
USB_MANUFACTURER = "Adafruit Industries LLC"
|
USB_MANUFACTURER = "Adafruit Industries LLC"
|
||||||
|
|
||||||
#SPI_FLASH_FILESYSTEM = 1
|
SPI_FLASH_FILESYSTEM = 1
|
||||||
INTERNAL_FLASH_FILESYSTEM = 1
|
|
||||||
|
|
||||||
CHIP_VARIANT = SAMD51J19A
|
CHIP_VARIANT = SAMD51J19A
|
||||||
CHIP_FAMILY = samd51
|
CHIP_FAMILY = samd51
|
||||||
|
|
|
@ -72,7 +72,7 @@ void common_hal_busio_i2c_construct(busio_i2c_obj_t *self,
|
||||||
|
|
||||||
|
|
||||||
// Set up I2C clocks on sercom.
|
// Set up I2C clocks on sercom.
|
||||||
samd_peripheral_sercom_clock_init(sercom, sercom_index);
|
samd_peripherals_sercom_clock_init(sercom, sercom_index);
|
||||||
|
|
||||||
if (i2c_m_sync_init(&self->i2c_desc, sercom) != ERR_NONE) {
|
if (i2c_m_sync_init(&self->i2c_desc, sercom) != ERR_NONE) {
|
||||||
mp_raise_OSError(MP_EIO);
|
mp_raise_OSError(MP_EIO);
|
||||||
|
|
|
@ -37,17 +37,7 @@
|
||||||
|
|
||||||
#include "peripherals.h"
|
#include "peripherals.h"
|
||||||
#include "pins.h"
|
#include "pins.h"
|
||||||
#include "shared_dma.h"
|
//#include "shared_dma.h"
|
||||||
|
|
||||||
// Convert frequency to clock-speed-dependent value. Return 0 if out of range.
|
|
||||||
static uint8_t baudrate_to_baud_reg_value(const uint32_t baudrate) {
|
|
||||||
uint32_t baud_reg_value = (uint32_t) (((float) PROTOTYPE_SERCOM_SPI_M_SYNC_CLOCK_FREQUENCY /
|
|
||||||
(2 * baudrate)) + 0.5f);
|
|
||||||
if (baud_reg_value > 0xff) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return (uint8_t) baud_reg_value;
|
|
||||||
}
|
|
||||||
|
|
||||||
void common_hal_busio_spi_construct(busio_spi_obj_t *self,
|
void common_hal_busio_spi_construct(busio_spi_obj_t *self,
|
||||||
const mcu_pin_obj_t * clock, const mcu_pin_obj_t * mosi,
|
const mcu_pin_obj_t * clock, const mcu_pin_obj_t * mosi,
|
||||||
|
@ -78,7 +68,7 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self,
|
||||||
}
|
}
|
||||||
clock_pinmux = PINMUX(clock->pin, (i == 0) ? MUX_C : MUX_D);
|
clock_pinmux = PINMUX(clock->pin, (i == 0) ? MUX_C : MUX_D);
|
||||||
clock_pad = clock->sercom[i].pad;
|
clock_pad = clock->sercom[i].pad;
|
||||||
if (!samd_peripheral_valid_spi_clock_pad(clock_pad)) {
|
if (!samd_peripherals_valid_spi_clock_pad(clock_pad)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
for (int j = 0; j < NUM_SERCOMS_PER_PIN; j++) {
|
for (int j = 0; j < NUM_SERCOMS_PER_PIN; j++) {
|
||||||
|
@ -86,7 +76,7 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self,
|
||||||
if(potential_sercom == mosi->sercom[j].sercom) {
|
if(potential_sercom == mosi->sercom[j].sercom) {
|
||||||
mosi_pinmux = PINMUX(mosi->pin, (j == 0) ? MUX_C : MUX_D);
|
mosi_pinmux = PINMUX(mosi->pin, (j == 0) ? MUX_C : MUX_D);
|
||||||
mosi_pad = mosi->sercom[j].pad;
|
mosi_pad = mosi->sercom[j].pad;
|
||||||
dopo = samd_peripheral_get_spi_dopo(clock_pad, mosi_pad);
|
dopo = samd_peripherals_get_spi_dopo(clock_pad, mosi_pad);
|
||||||
if (dopo > 0x3) {
|
if (dopo > 0x3) {
|
||||||
continue; // pad combination not possible
|
continue; // pad combination not possible
|
||||||
}
|
}
|
||||||
|
@ -121,7 +111,7 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set up SPI clocks on SERCOM.
|
// Set up SPI clocks on SERCOM.
|
||||||
samd_peripheral_sercom_clock_init(sercom, sercom_index);
|
samd_peripherals_sercom_clock_init(sercom, sercom_index);
|
||||||
|
|
||||||
if (spi_m_sync_init(&self->spi_desc, sercom) != ERR_NONE) {
|
if (spi_m_sync_init(&self->spi_desc, sercom) != ERR_NONE) {
|
||||||
mp_raise_OSError(MP_EIO);
|
mp_raise_OSError(MP_EIO);
|
||||||
|
@ -132,7 +122,7 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self,
|
||||||
|
|
||||||
// Always start at 250khz which is what SD cards need. They are sensitive to
|
// Always start at 250khz which is what SD cards need. They are sensitive to
|
||||||
// SPI bus noise before they are put into SPI mode.
|
// SPI bus noise before they are put into SPI mode.
|
||||||
uint8_t baud_value = baudrate_to_baud_reg_value(250000);
|
uint8_t baud_value = samd_peripherals_baudrate_to_baud_reg_value(250000);
|
||||||
if (baud_value == 0) {
|
if (baud_value == 0) {
|
||||||
mp_raise_RuntimeError("SPI initial baudrate out of range.");
|
mp_raise_RuntimeError("SPI initial baudrate out of range.");
|
||||||
}
|
}
|
||||||
|
@ -142,6 +132,7 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self,
|
||||||
mp_raise_OSError(MP_EIO);
|
mp_raise_OSError(MP_EIO);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gpio_set_pin_direction(clock->pin, GPIO_DIRECTION_OUT);
|
||||||
gpio_set_pin_pull_mode(clock->pin, GPIO_PULL_OFF);
|
gpio_set_pin_pull_mode(clock->pin, GPIO_PULL_OFF);
|
||||||
gpio_set_pin_function(clock->pin, clock_pinmux);
|
gpio_set_pin_function(clock->pin, clock_pinmux);
|
||||||
claim_pin(clock);
|
claim_pin(clock);
|
||||||
|
@ -150,6 +141,7 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self,
|
||||||
if (mosi_none) {
|
if (mosi_none) {
|
||||||
self->MOSI_pin = NO_PIN;
|
self->MOSI_pin = NO_PIN;
|
||||||
} else {
|
} else {
|
||||||
|
gpio_set_pin_direction(mosi->pin, GPIO_DIRECTION_OUT);
|
||||||
gpio_set_pin_pull_mode(mosi->pin, GPIO_PULL_OFF);
|
gpio_set_pin_pull_mode(mosi->pin, GPIO_PULL_OFF);
|
||||||
gpio_set_pin_function(mosi->pin, mosi_pinmux);
|
gpio_set_pin_function(mosi->pin, mosi_pinmux);
|
||||||
self->MOSI_pin = mosi->pin;
|
self->MOSI_pin = mosi->pin;
|
||||||
|
@ -159,6 +151,7 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self,
|
||||||
if (miso_none) {
|
if (miso_none) {
|
||||||
self->MISO_pin = NO_PIN;
|
self->MISO_pin = NO_PIN;
|
||||||
} else {
|
} else {
|
||||||
|
gpio_set_pin_direction(miso->pin, GPIO_DIRECTION_IN);
|
||||||
gpio_set_pin_pull_mode(miso->pin, GPIO_PULL_OFF);
|
gpio_set_pin_pull_mode(miso->pin, GPIO_PULL_OFF);
|
||||||
gpio_set_pin_function(miso->pin, miso_pinmux);
|
gpio_set_pin_function(miso->pin, miso_pinmux);
|
||||||
self->MISO_pin = miso->pin;
|
self->MISO_pin = miso->pin;
|
||||||
|
@ -186,7 +179,7 @@ void common_hal_busio_spi_deinit(busio_spi_obj_t *self) {
|
||||||
|
|
||||||
bool common_hal_busio_spi_configure(busio_spi_obj_t *self,
|
bool common_hal_busio_spi_configure(busio_spi_obj_t *self,
|
||||||
uint32_t baudrate, uint8_t polarity, uint8_t phase, uint8_t bits) {
|
uint32_t baudrate, uint8_t polarity, uint8_t phase, uint8_t bits) {
|
||||||
uint8_t baud_reg_value = baudrate_to_baud_reg_value(baudrate);
|
uint8_t baud_reg_value = samd_peripherals_baudrate_to_baud_reg_value(baudrate);
|
||||||
if (baud_reg_value == 0) {
|
if (baud_reg_value == 0) {
|
||||||
mp_raise_ValueError("baudrate out of range");
|
mp_raise_ValueError("baudrate out of range");
|
||||||
}
|
}
|
||||||
|
@ -248,7 +241,7 @@ bool common_hal_busio_spi_write(busio_spi_obj_t *self,
|
||||||
spi_m_sync_get_io_descriptor(&self->spi_desc, &spi_io);
|
spi_m_sync_get_io_descriptor(&self->spi_desc, &spi_io);
|
||||||
status = spi_io->write(spi_io, data, len);
|
status = spi_io->write(spi_io, data, len);
|
||||||
// }
|
// }
|
||||||
return status > 0; // Status is number of chars read or an error code < 0.
|
return status >= 0; // Status is number of chars read or an error code < 0.
|
||||||
}
|
}
|
||||||
|
|
||||||
bool common_hal_busio_spi_read(busio_spi_obj_t *self,
|
bool common_hal_busio_spi_read(busio_spi_obj_t *self,
|
||||||
|
@ -267,5 +260,5 @@ bool common_hal_busio_spi_read(busio_spi_obj_t *self,
|
||||||
|
|
||||||
status = spi_io->read(spi_io, data, len);
|
status = spi_io->read(spi_io, data, len);
|
||||||
// }
|
// }
|
||||||
return status > 0; // Status is number of chars read or an error code < 0.
|
return status >= 0; // Status is number of chars read or an error code < 0.
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
#include "py/mperrno.h"
|
#include "py/mperrno.h"
|
||||||
#include "py/runtime.h"
|
#include "py/runtime.h"
|
||||||
#include "shared-bindings/storage/__init__.h"
|
#include "shared-bindings/storage/__init__.h"
|
||||||
|
#include "usb.h"
|
||||||
|
|
||||||
extern volatile bool mp_msc_enabled;
|
extern volatile bool mp_msc_enabled;
|
||||||
|
|
||||||
|
@ -38,7 +39,9 @@ void common_hal_storage_remount(const char* mount_path, bool readonly) {
|
||||||
mp_raise_OSError(MP_EINVAL);
|
mp_raise_OSError(MP_EINVAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mp_msc_enabled) {
|
// TODO(dhalbert): is this is a good enough check? It checks for
|
||||||
|
// CDC enabled. There is no "MSC enabled" check.
|
||||||
|
if (usb_connected()) {
|
||||||
mp_raise_RuntimeError("Cannot remount '/' when USB is active.");
|
mp_raise_RuntimeError("Cannot remount '/' when USB is active.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -215,7 +215,6 @@ extern const struct _mp_obj_module_t usb_hid_module;
|
||||||
|
|
||||||
// { MP_OBJ_NEW_QSTR(MP_QSTR_gamepad),(mp_obj_t)&gamepad_module },
|
// { MP_OBJ_NEW_QSTR(MP_QSTR_gamepad),(mp_obj_t)&gamepad_module },
|
||||||
// { MP_OBJ_NEW_QSTR(MP_QSTR_usb_hid),(mp_obj_t)&usb_hid_module },
|
// { MP_OBJ_NEW_QSTR(MP_QSTR_usb_hid),(mp_obj_t)&usb_hid_module },
|
||||||
// { MP_OBJ_NEW_QSTR(MP_QSTR_storage), (mp_obj_t)&storage_module },
|
|
||||||
|
|
||||||
|
|
||||||
#define MICROPY_PORT_BUILTIN_MODULES \
|
#define MICROPY_PORT_BUILTIN_MODULES \
|
||||||
|
@ -226,6 +225,7 @@ extern const struct _mp_obj_module_t usb_hid_module;
|
||||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_neopixel_write),(mp_obj_t)&neopixel_write_module }, \
|
{ MP_OBJ_NEW_QSTR(MP_QSTR_neopixel_write),(mp_obj_t)&neopixel_write_module }, \
|
||||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_os), (mp_obj_t)&os_module }, \
|
{ MP_OBJ_NEW_QSTR(MP_QSTR_os), (mp_obj_t)&os_module }, \
|
||||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_random), (mp_obj_t)&random_module }, \
|
{ MP_OBJ_NEW_QSTR(MP_QSTR_random), (mp_obj_t)&random_module }, \
|
||||||
|
{ MP_OBJ_NEW_QSTR(MP_QSTR_storage), (mp_obj_t)&storage_module }, \
|
||||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_struct), (mp_obj_t)&struct_module }, \
|
{ MP_OBJ_NEW_QSTR(MP_QSTR_struct), (mp_obj_t)&struct_module }, \
|
||||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_supervisor), (mp_obj_t)&supervisor_module }, \
|
{ MP_OBJ_NEW_QSTR(MP_QSTR_supervisor), (mp_obj_t)&supervisor_module }, \
|
||||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_math), (mp_obj_t)&math_module }, \
|
{ MP_OBJ_NEW_QSTR(MP_QSTR_math), (mp_obj_t)&math_module }, \
|
||||||
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
/*
|
||||||
|
* This file is part of the Micro Python project, http://micropython.org/
|
||||||
|
*
|
||||||
|
* The MIT License (MIT)
|
||||||
|
*
|
||||||
|
* Copyright (c) 2017 Dan Halbert for Adafruit Industries
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "peripherals.h"
|
||||||
|
|
||||||
|
#include "hpl_sercom_config.h"
|
||||||
|
|
||||||
|
// Routines that are the same across all samd variants.
|
||||||
|
|
||||||
|
|
||||||
|
// Convert frequency to clock-speed-dependent value. Return 0 if out of range.
|
||||||
|
uint8_t samd_peripherals_baudrate_to_baud_reg_value(const uint32_t baudrate) {
|
||||||
|
uint32_t baud_reg_value = (uint32_t) (((float) PROTOTYPE_SERCOM_SPI_M_SYNC_CLOCK_FREQUENCY /
|
||||||
|
(2 * baudrate)) + 0.5f);
|
||||||
|
if (baud_reg_value > 0xff) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return (uint8_t) baud_reg_value;
|
||||||
|
}
|
||||||
|
|
|
@ -27,8 +27,13 @@
|
||||||
#ifndef MICROPY_INCLUDED_ATMEL_SAMD_PERIPHERALS_H
|
#ifndef MICROPY_INCLUDED_ATMEL_SAMD_PERIPHERALS_H
|
||||||
#define MICROPY_INCLUDED_ATMEL_SAMD_PERIPHERALS_H
|
#define MICROPY_INCLUDED_ATMEL_SAMD_PERIPHERALS_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
#include "mpconfigport.h"
|
#include "mpconfigport.h"
|
||||||
|
|
||||||
|
// Routines common across chip families.
|
||||||
|
uint8_t samd_peripherals_baudrate_to_baud_reg_value(const uint32_t baudrate);
|
||||||
|
|
||||||
#ifdef SAMD21
|
#ifdef SAMD21
|
||||||
#include "samd21_peripherals.h"
|
#include "samd21_peripherals.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -58,7 +58,7 @@ static const uint8_t SERCOMx_GCLK_ID_SLOW[] = {
|
||||||
|
|
||||||
|
|
||||||
// Clock initialization as done in Atmel START.
|
// Clock initialization as done in Atmel START.
|
||||||
void samd_peripheral_sercom_clock_init(Sercom* sercom, uint8_t sercom_index) {
|
void samd_peripherals_sercom_clock_init(Sercom* sercom, uint8_t sercom_index) {
|
||||||
_pm_enable_bus_clock(PM_BUS_APBC, sercom);
|
_pm_enable_bus_clock(PM_BUS_APBC, sercom);
|
||||||
_gclk_enable_channel(SERCOMx_GCLK_ID_CORE[sercom_index], GCLK_CLKCTRL_GEN_GCLK0_Val);
|
_gclk_enable_channel(SERCOMx_GCLK_ID_CORE[sercom_index], GCLK_CLKCTRL_GEN_GCLK0_Val);
|
||||||
_gclk_enable_channel(SERCOMx_GCLK_ID_SLOW[sercom_index], GCLK_CLKCTRL_GEN_GCLK3_Val);
|
_gclk_enable_channel(SERCOMx_GCLK_ID_SLOW[sercom_index], GCLK_CLKCTRL_GEN_GCLK3_Val);
|
||||||
|
@ -70,7 +70,7 @@ void samd_peripheral_sercom_clock_init(Sercom* sercom, uint8_t sercom_index) {
|
||||||
// <0x1=>PAD[2,3]_DO_SCK
|
// <0x1=>PAD[2,3]_DO_SCK
|
||||||
// <0x2=>PAD[3,1]_DO_SCK
|
// <0x2=>PAD[3,1]_DO_SCK
|
||||||
// <0x3=>PAD[0,3]_DO_SCK
|
// <0x3=>PAD[0,3]_DO_SCK
|
||||||
uint8_t samd_peripheral_get_spi_dopo(uint8_t clock_pad, uint8_t mosi_pad) {
|
uint8_t samd_peripherals_get_spi_dopo(uint8_t clock_pad, uint8_t mosi_pad) {
|
||||||
if (clock_pad == 1) {
|
if (clock_pad == 1) {
|
||||||
if (mosi_pad == 0) {
|
if (mosi_pad == 0) {
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -87,6 +87,6 @@ uint8_t samd_peripheral_get_spi_dopo(uint8_t clock_pad, uint8_t mosi_pad) {
|
||||||
return 255;
|
return 255;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool samd_peripheral_valid_spi_clock_pad(uint8_t clock_pad) {
|
bool samd_peripherals_valid_spi_clock_pad(uint8_t clock_pad) {
|
||||||
return clock_pad == 1 || clock_pad == 3;
|
return clock_pad == 1 || clock_pad == 3;
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,8 +29,8 @@
|
||||||
|
|
||||||
#include "include/sam.h"
|
#include "include/sam.h"
|
||||||
|
|
||||||
void samd_peripheral_sercom_clock_init(Sercom* sercom, uint8_t sercom_index);
|
void samd_peripherals_sercom_clock_init(Sercom* sercom, uint8_t sercom_index);
|
||||||
uint8_t samd_peripheral_get_spi_dopo(uint8_t clock_pad, uint8_t mosi_pad);
|
uint8_t samd_peripherals_get_spi_dopo(uint8_t clock_pad, uint8_t mosi_pad);
|
||||||
bool samd_peripheral_valid_spi_clock_pad(uint8_t clock_pad);
|
bool samd_peripherals_valid_spi_clock_pad(uint8_t clock_pad);
|
||||||
|
|
||||||
#endif // MICROPY_INCLUDED_ATMEL_SAMD_SAMD21_PERIPHERALS_H
|
#endif // MICROPY_INCLUDED_ATMEL_SAMD_SAMD21_PERIPHERALS_H
|
||||||
|
|
|
@ -62,7 +62,7 @@ static const uint8_t SERCOMx_GCLK_ID_SLOW[] = {
|
||||||
|
|
||||||
|
|
||||||
// Clock initialization as done in Atmel START.
|
// Clock initialization as done in Atmel START.
|
||||||
void samd_peripheral_sercom_clock_init(Sercom* sercom, uint8_t sercom_index) {
|
void samd_peripherals_sercom_clock_init(Sercom* sercom, uint8_t sercom_index) {
|
||||||
hri_gclk_write_PCHCTRL_reg(GCLK,
|
hri_gclk_write_PCHCTRL_reg(GCLK,
|
||||||
SERCOMx_GCLK_ID_CORE[sercom_index],
|
SERCOMx_GCLK_ID_CORE[sercom_index],
|
||||||
GCLK_PCHCTRL_GEN_GCLK1_Val | (1 << GCLK_PCHCTRL_CHEN_Pos));
|
GCLK_PCHCTRL_GEN_GCLK1_Val | (1 << GCLK_PCHCTRL_CHEN_Pos));
|
||||||
|
@ -113,7 +113,7 @@ void samd_peripheral_sercom_clock_init(Sercom* sercom, uint8_t sercom_index) {
|
||||||
// <0x1=>PAD[2,3]_DO_SCK [RESERVED]
|
// <0x1=>PAD[2,3]_DO_SCK [RESERVED]
|
||||||
// <0x2=>PAD[3,1]_DO_SCK
|
// <0x2=>PAD[3,1]_DO_SCK
|
||||||
// <0x3=>PAD[0,3]_DO_SCK [RESERVED]
|
// <0x3=>PAD[0,3]_DO_SCK [RESERVED]
|
||||||
uint8_t samd_peripheral_get_spi_dopo(uint8_t clock_pad, uint8_t mosi_pad) {
|
uint8_t samd_peripherals_get_spi_dopo(uint8_t clock_pad, uint8_t mosi_pad) {
|
||||||
if (clock_pad != 1) {
|
if (clock_pad != 1) {
|
||||||
return 255;
|
return 255;
|
||||||
}
|
}
|
||||||
|
@ -126,6 +126,6 @@ uint8_t samd_peripheral_get_spi_dopo(uint8_t clock_pad, uint8_t mosi_pad) {
|
||||||
return 255;
|
return 255;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool samd_peripheral_valid_spi_clock_pad(uint8_t clock_pad) {
|
bool samd_peripherals_valid_spi_clock_pad(uint8_t clock_pad) {
|
||||||
return clock_pad == 1;
|
return clock_pad == 1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,9 +29,9 @@
|
||||||
|
|
||||||
#include "sam.h"
|
#include "sam.h"
|
||||||
|
|
||||||
void samd_peripheral_sercom_clock_init(Sercom* sercom, uint8_t sercom_index);
|
void samd_peripherals_sercom_clock_init(Sercom* sercom, uint8_t sercom_index);
|
||||||
uint8_t samd_peripheral_get_spi_dopo(uint8_t clock_pad, uint8_t mosi_pad);
|
uint8_t samd_peripherals_get_spi_dopo(uint8_t clock_pad, uint8_t mosi_pad);
|
||||||
bool samd_peripheral_valid_spi_clock_pad(uint8_t clock_pad);
|
bool samd_peripherals_valid_spi_clock_pad(uint8_t clock_pad);
|
||||||
|
|
||||||
#endif // MICROPY_INCLUDED_ATMEL_SAMD_SAMD51_PERIPHERALS_H
|
#endif // MICROPY_INCLUDED_ATMEL_SAMD_SAMD51_PERIPHERALS_H
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
/*
|
||||||
|
* This file is part of the MicroPython project, http://micropython.org/
|
||||||
|
*
|
||||||
|
* The MIT License (MIT)
|
||||||
|
*
|
||||||
|
* Copyright (c) 2017 by Dan Halbert for Adafruit Industries
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MICROPY_INCLUDED_ATMEL_SAMD_SAMD21_PERIPHERALS_H
|
||||||
|
#define MICROPY_INCLUDED_ATMEL_SAMD_SAMD21_PERIPHERALS_H
|
||||||
|
|
||||||
|
#include "include/sam.h"
|
||||||
|
|
||||||
|
void samd_peripherals_sercom_clock_init(Sercom* sercom, uint8_t sercom_index);
|
||||||
|
uint8_t samd_peripherals_get_spi_dopo(uint8_t clock_pad, uint8_t mosi_pad);
|
||||||
|
bool samd_peripherals_valid_spi_clock_pad(uint8_t clock_pad);
|
||||||
|
|
||||||
|
#endif // MICROPY_INCLUDED_ATMEL_SAMD_SAMD21_PERIPHERALS_H
|
|
@ -43,28 +43,33 @@ void init_shared_dma(void) {
|
||||||
struct dma_resource_config config;
|
struct dma_resource_config config;
|
||||||
dma_get_config_defaults(&config);
|
dma_get_config_defaults(&config);
|
||||||
|
|
||||||
// This allocates the lowest channel first so make sure the audio is first
|
// See asf4_conf/hpl_dmac_config.h for initial settings for DMA channels
|
||||||
// so it gets the highest priority.
|
// DMA Channel 0: audio, highest priority,
|
||||||
config.peripheral_trigger = DAC_DMAC_ID_EMPTY;
|
// normal transfer on input, DAC 0 empty is trigger source, trigger on each beat, beat is one byte
|
||||||
config.trigger_action = DMA_TRIGGER_ACTION_BEAT;
|
// output enable true.
|
||||||
config.event_config.input_action = DMA_EVENT_INPUT_TRIG;
|
// asf3 settings:
|
||||||
config.event_config.event_output_enable = true;
|
//config.peripheral_trigger = DAC_DMAC_ID_EMPTY;
|
||||||
dma_allocate(&audio_dma, &config);
|
//config.trigger_action = DMA_TRIGGER_ACTION_BEAT;
|
||||||
|
//config.event_config.input_action = DMA_EVENT_INPUT_TRIG;
|
||||||
|
//config.event_config.event_output_enable = true;
|
||||||
|
|
||||||
// Turn on the transfer complete interrupt so that the job_status changes to done.
|
// Turn on the transfer complete interrupt so that the job_status changes to done.
|
||||||
g_chan_interrupt_flag[audio_dma.channel_id] |= (1UL << DMA_CALLBACK_TRANSFER_DONE);
|
g_chan_interrupt_flag[audio_dma.channel_id] |= (1UL << DMA_CALLBACK_TRANSFER_DONE);
|
||||||
|
|
||||||
// Prioritize the RX channel over the TX channel because TX can cause an RX
|
// Prioritize the RX channel over the TX channel because TX can cause an RX
|
||||||
// overflow.
|
// overflow.
|
||||||
dma_get_config_defaults(&config);
|
|
||||||
config.trigger_action = DMA_TRIGGER_ACTION_BEAT;
|
// DMA Channel 1: rx channel,
|
||||||
config.event_config.input_action = DMA_EVENT_INPUT_TRIG;
|
// normal transfer on input, trigger on each beat, beat is one byte
|
||||||
|
//config.trigger_action = DMA_TRIGGER_ACTION_BEAT;
|
||||||
|
//config.event_config.input_action = DMA_EVENT_INPUT_TRIG;
|
||||||
dma_allocate(&general_dma_rx, &config);
|
dma_allocate(&general_dma_rx, &config);
|
||||||
g_chan_interrupt_flag[general_dma_rx.channel_id] |= (1UL << DMA_CALLBACK_TRANSFER_DONE);
|
g_chan_interrupt_flag[general_dma_rx.channel_id] |= (1UL << DMA_CALLBACK_TRANSFER_DONE);
|
||||||
|
|
||||||
dma_get_config_defaults(&config);
|
// DMA Channel 1: rx channel,
|
||||||
config.trigger_action = DMA_TRIGGER_ACTION_BEAT;
|
// normal transfer on input, trigger on each beat, beat is one byte
|
||||||
config.event_config.input_action = DMA_EVENT_INPUT_TRIG;
|
//config.trigger_action = DMA_TRIGGER_ACTION_BEAT;
|
||||||
dma_allocate(&general_dma_tx, &config);
|
//config.event_config.input_action = DMA_EVENT_INPUT_TRIG;
|
||||||
g_chan_interrupt_flag[general_dma_tx.channel_id] |= (1UL << DMA_CALLBACK_TRANSFER_DONE);
|
g_chan_interrupt_flag[general_dma_tx.channel_id] |= (1UL << DMA_CALLBACK_TRANSFER_DONE);
|
||||||
|
|
||||||
// Be sneaky and reuse the active descriptor memory.
|
// Be sneaky and reuse the active descriptor memory.
|
||||||
|
|
|
@ -28,20 +28,19 @@
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
<<<<<<< HEAD
|
|
||||||
#include "asf/sam0/drivers/sercom/spi/spi.h"
|
|
||||||
|
|
||||||
#include "extmod/vfs.h"
|
#include "extmod/vfs.h"
|
||||||
#include "extmod/vfs_fat.h"
|
#include "extmod/vfs_fat.h"
|
||||||
=======
|
|
||||||
>>>>>>> WIP
|
|
||||||
#include "py/gc.h"
|
#include "py/gc.h"
|
||||||
#include "py/obj.h"
|
#include "py/obj.h"
|
||||||
#include "py/runtime.h"
|
#include "py/runtime.h"
|
||||||
#include "lib/oofatfs/ff.h"
|
#include "lib/oofatfs/ff.h"
|
||||||
|
#include "peripherals.h"
|
||||||
|
#include "supervisor/shared/rgb_led_status.h"
|
||||||
|
|
||||||
#include "rgb_led_status.h"
|
//#include "shared_dma.h"
|
||||||
#include "shared_dma.h"
|
|
||||||
|
#include "hal_gpio.h"
|
||||||
|
#include "hal_spi_m_sync.h"
|
||||||
|
|
||||||
#define SPI_FLASH_PART1_START_BLOCK (0x1)
|
#define SPI_FLASH_PART1_START_BLOCK (0x1)
|
||||||
|
|
||||||
|
@ -60,7 +59,7 @@
|
||||||
|
|
||||||
static bool spi_flash_is_initialised = false;
|
static bool spi_flash_is_initialised = false;
|
||||||
|
|
||||||
struct spi_module spi_flash_instance;
|
struct spi_m_sync_descriptor spi_flash_desc;
|
||||||
|
|
||||||
// The currently cached sector in the cache, ram or flash based.
|
// The currently cached sector in the cache, ram or flash based.
|
||||||
static uint32_t current_sector;
|
static uint32_t current_sector;
|
||||||
|
@ -74,35 +73,37 @@ static uint32_t dirty_mask;
|
||||||
|
|
||||||
// Enable the flash over SPI.
|
// Enable the flash over SPI.
|
||||||
static void flash_enable(void) {
|
static void flash_enable(void) {
|
||||||
port_pin_set_output_level(SPI_FLASH_CS, false);
|
gpio_set_pin_level(SPI_FLASH_CS_PIN, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Disable the flash over SPI.
|
// Disable the flash over SPI.
|
||||||
static void flash_disable(void) {
|
static void flash_disable(void) {
|
||||||
port_pin_set_output_level(SPI_FLASH_CS, true);
|
gpio_set_pin_level(SPI_FLASH_CS_PIN, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wait until both the write enable and write in progress bits have cleared.
|
// Wait until both the write enable and write in progress bits have cleared.
|
||||||
static bool wait_for_flash_ready(void) {
|
static bool wait_for_flash_ready(void) {
|
||||||
uint8_t status_request[2] = {CMD_READ_STATUS, 0x00};
|
uint8_t read_status_request[2] = {CMD_READ_STATUS, 0x00};
|
||||||
uint8_t response[2] = {0x00, 0x01};
|
uint8_t read_status_response[2] = {0x00, 0x00};
|
||||||
enum status_code status = STATUS_OK;
|
struct spi_xfer read_status_xfer = {read_status_request, read_status_response, 2};
|
||||||
|
int32_t status;
|
||||||
// Both the write enable and write in progress bits should be low.
|
// Both the write enable and write in progress bits should be low.
|
||||||
while (status == STATUS_OK && (response[1] & 0x3) != 0) {
|
do {
|
||||||
flash_enable();
|
flash_enable();
|
||||||
status = spi_transceive_buffer_wait(&spi_flash_instance, status_request, response, 2);
|
status = spi_m_sync_transfer(&spi_flash_desc, &read_status_xfer);
|
||||||
flash_disable();
|
flash_disable();
|
||||||
}
|
} while (status >= 0 && (read_status_response[1] & 0x3) != 0);
|
||||||
return status == STATUS_OK;
|
return status >= 0; // status is number of chars read or a negative error code.
|
||||||
}
|
}
|
||||||
|
|
||||||
// Turn on the write enable bit so we can program and erase the flash.
|
// Turn on the write enable bit so we can program and erase the flash.
|
||||||
static bool write_enable(void) {
|
static bool write_enable(void) {
|
||||||
flash_enable();
|
flash_enable();
|
||||||
uint8_t command = CMD_ENABLE_WRITE;
|
uint8_t enable_write_request[1] = {CMD_ENABLE_WRITE};
|
||||||
enum status_code status = spi_write_buffer_wait(&spi_flash_instance, &command, 1);
|
struct spi_xfer enable_write_xfer = {enable_write_request, 0, 1};
|
||||||
|
int32_t status = spi_m_sync_transfer(&spi_flash_desc, &enable_write_xfer);
|
||||||
flash_disable();
|
flash_disable();
|
||||||
return status == STATUS_OK;
|
return status >= 0; // status is number of chars read or a negative error code.
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pack the low 24 bits of the address into a uint8_t array.
|
// Pack the low 24 bits of the address into a uint8_t array.
|
||||||
|
@ -120,17 +121,19 @@ static bool read_flash(uint32_t address, uint8_t* data, uint32_t data_length) {
|
||||||
if (!wait_for_flash_ready()) {
|
if (!wait_for_flash_ready()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
enum status_code status;
|
|
||||||
// We can read as much as we want sequentially.
|
// We can read as much as we want sequentially.
|
||||||
uint8_t read_request[4] = {CMD_READ_DATA, 0x00, 0x00, 0x00};
|
uint8_t read_data_request[4] = {CMD_READ_DATA, 0x00, 0x00, 0x00};
|
||||||
address_to_bytes(address, read_request + 1);
|
struct spi_xfer read_data_xfer = {read_data_request, 0, 4};
|
||||||
|
// Write the SPI flash read address into the bytes following the command byte.
|
||||||
|
address_to_bytes(address, read_data_request + 1);
|
||||||
flash_enable();
|
flash_enable();
|
||||||
status = spi_write_buffer_wait(&spi_flash_instance, read_request, 4);
|
int32_t status = spi_m_sync_transfer(&spi_flash_desc, &read_data_xfer);
|
||||||
if (status == STATUS_OK) {
|
struct spi_xfer read_data_buffer_xfer = {0, data, data_length};
|
||||||
status = shared_dma_read(spi_flash_instance.hw, data, data_length, 0x00);
|
if (status >= 0) {
|
||||||
|
status = spi_m_sync_transfer(&spi_flash_desc, &read_data_buffer_xfer);
|
||||||
}
|
}
|
||||||
flash_disable();
|
flash_disable();
|
||||||
return status == STATUS_OK;
|
return status >= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Writes data_length's worth of bytes starting at address from data. Assumes
|
// Writes data_length's worth of bytes starting at address from data. Assumes
|
||||||
|
@ -159,26 +162,29 @@ static bool write_flash(uint32_t address, const uint8_t* data, uint32_t data_len
|
||||||
if (!wait_for_flash_ready() || !write_enable()) {
|
if (!wait_for_flash_ready() || !write_enable()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
enum status_code status;
|
int32_t status;
|
||||||
|
|
||||||
#ifdef SPI_FLASH_SECTOR_PROTECTION
|
#ifdef SPI_FLASH_SECTOR_PROTECTION
|
||||||
// Print out the protection status.
|
// Print out the protection status.
|
||||||
// uint8_t protect_check[5] = {0x3C, 0x00, 0x00, 0x00, 0x00};
|
// uint8_t protect_check[5] = {0x3C, 0x00, 0x00, 0x00, 0x00};
|
||||||
// address_to_bytes(address + bytes_written, protect_check + 1);
|
// address_to_bytes(address + bytes_written, protect_check + 1);
|
||||||
// flash_enable();
|
// flash_enable();
|
||||||
// status = spi_write_buffer_wait(&spi_flash_instance, protect_check, 5);
|
// status = spi_write_buffer_wait(&spi_flash_desc, protect_check, 5);
|
||||||
// flash_disable();
|
// flash_disable();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
flash_enable();
|
flash_enable();
|
||||||
uint8_t command[4] = {CMD_PAGE_PROGRAM, 0x00, 0x00, 0x00};
|
uint8_t page_program_request[4] = {CMD_PAGE_PROGRAM, 0x00, 0x00, 0x00};
|
||||||
address_to_bytes(address + bytes_written, command + 1);
|
// Write the SPI flash write address into the bytes following the command byte.
|
||||||
status = spi_write_buffer_wait(&spi_flash_instance, command, 4);
|
address_to_bytes(address + bytes_written, page_program_request + 1);
|
||||||
if (status == STATUS_OK) {
|
struct spi_xfer page_program_xfer = {page_program_request, 0, 4};
|
||||||
status = shared_dma_write(spi_flash_instance.hw, data + bytes_written, SPI_FLASH_PAGE_SIZE);
|
status = spi_m_sync_transfer(&spi_flash_desc, &page_program_xfer);
|
||||||
|
if (status >= 0) {
|
||||||
|
struct spi_xfer write_data_buffer_xfer = {(uint8_t*) data + bytes_written, 0, SPI_FLASH_PAGE_SIZE};
|
||||||
|
status = spi_m_sync_transfer(&spi_flash_desc, &write_data_buffer_xfer);
|
||||||
}
|
}
|
||||||
flash_disable();
|
flash_disable();
|
||||||
if (status != STATUS_OK) {
|
if (status < 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -224,11 +230,11 @@ static bool erase_sector(uint32_t sector_address) {
|
||||||
|
|
||||||
uint8_t erase_request[4] = {CMD_SECTOR_ERASE, 0x00, 0x00, 0x00};
|
uint8_t erase_request[4] = {CMD_SECTOR_ERASE, 0x00, 0x00, 0x00};
|
||||||
address_to_bytes(sector_address, erase_request + 1);
|
address_to_bytes(sector_address, erase_request + 1);
|
||||||
|
struct spi_xfer erase_xfer = {erase_request, 0, 4};
|
||||||
flash_enable();
|
flash_enable();
|
||||||
enum status_code status = spi_write_buffer_wait(&spi_flash_instance, erase_request, 4);
|
int32_t status = spi_m_sync_transfer(&spi_flash_desc, &erase_xfer);
|
||||||
flash_disable();
|
flash_disable();
|
||||||
return status == STATUS_OK;
|
return status >= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sector is really 24 bits.
|
// Sector is really 24 bits.
|
||||||
|
@ -247,82 +253,103 @@ static bool copy_block(uint32_t src_address, uint32_t dest_address) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void spi_flash_init(void) {
|
void spi_flash_init(void) {
|
||||||
if (!spi_flash_is_initialised) {
|
if (spi_flash_is_initialised) {
|
||||||
struct spi_config config_spi_master;
|
return;
|
||||||
spi_get_config_defaults(&config_spi_master);
|
|
||||||
config_spi_master.mux_setting = SPI_FLASH_MUX_SETTING;
|
|
||||||
config_spi_master.pinmux_pad0 = SPI_FLASH_PAD0_PINMUX;
|
|
||||||
config_spi_master.pinmux_pad1 = SPI_FLASH_PAD1_PINMUX;
|
|
||||||
config_spi_master.pinmux_pad2 = SPI_FLASH_PAD2_PINMUX;
|
|
||||||
config_spi_master.pinmux_pad3 = SPI_FLASH_PAD3_PINMUX;
|
|
||||||
config_spi_master.mode_specific.master.baudrate = SPI_FLASH_BAUDRATE;
|
|
||||||
spi_init(&spi_flash_instance, SPI_FLASH_SERCOM, &config_spi_master);
|
|
||||||
spi_enable(&spi_flash_instance);
|
|
||||||
|
|
||||||
// Manage chip select ourselves.
|
|
||||||
struct port_config pin_conf;
|
|
||||||
port_get_config_defaults(&pin_conf);
|
|
||||||
|
|
||||||
pin_conf.direction = PORT_PIN_DIR_OUTPUT;
|
|
||||||
port_pin_set_config(SPI_FLASH_CS, &pin_conf);
|
|
||||||
flash_disable();
|
|
||||||
|
|
||||||
// Activity LED for flash writes.
|
|
||||||
#ifdef MICROPY_HW_LED_MSC
|
|
||||||
port_pin_set_config(MICROPY_HW_LED_MSC, &pin_conf);
|
|
||||||
port_pin_set_output_level(MICROPY_HW_LED_MSC, false);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
uint8_t jedec_id_request[4] = {CMD_READ_JEDEC_ID, 0x00, 0x00, 0x00};
|
|
||||||
uint8_t response[4] = {0x00, 0x00, 0x00, 0x00};
|
|
||||||
flash_enable();
|
|
||||||
spi_transceive_buffer_wait(&spi_flash_instance, jedec_id_request, response, 4);
|
|
||||||
flash_disable();
|
|
||||||
uint8_t manufacturer = response[1];
|
|
||||||
if ((response[1] == SPI_FLASH_JEDEC_MANUFACTURER
|
|
||||||
#ifdef SPI_FLASH_JEDEC_MANUFACTURER_2
|
|
||||||
|| response[1] == SPI_FLASH_JEDEC_MANUFACTURER_2
|
|
||||||
#endif
|
|
||||||
) &&
|
|
||||||
response[2] == SPI_FLASH_JEDEC_MEMORY_TYPE &&
|
|
||||||
response[3] == SPI_FLASH_JEDEC_CAPACITY) {
|
|
||||||
spi_flash_is_initialised = true;
|
|
||||||
} else {
|
|
||||||
// Unknown flash chip!
|
|
||||||
spi_flash_is_initialised = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((manufacturer == SPI_FLASH_JEDEC_MANUFACTURER && SPI_FLASH_SECTOR_PROTECTION)
|
|
||||||
#ifdef SPI_FLASH_JEDEC_MANUFACTURER_2
|
|
||||||
|| (manufacturer == SPI_FLASH_JEDEC_MANUFACTURER_2 && SPI_FLASH_SECTOR_PROTECTION_2)
|
|
||||||
#endif
|
|
||||||
) {
|
|
||||||
write_enable();
|
|
||||||
|
|
||||||
// Turn off sector protection
|
|
||||||
uint8_t disable_protect_request[2] = {CMD_WRITE_STATUS_BYTE1, 0x00};
|
|
||||||
uint8_t disable_protect_response[2] = {0x00, 0x00};
|
|
||||||
flash_enable();
|
|
||||||
spi_transceive_buffer_wait(&spi_flash_instance, disable_protect_request, disable_protect_response, 2);
|
|
||||||
flash_disable();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Turn off writes in case this is a microcontroller only reset.
|
|
||||||
uint8_t disable_write_request[1] = {CMD_DISABLE_WRITE};
|
|
||||||
uint8_t disable_response[1] = {0x00};
|
|
||||||
flash_enable();
|
|
||||||
spi_transceive_buffer_wait(&spi_flash_instance, disable_write_request, disable_response, 1);
|
|
||||||
flash_disable();
|
|
||||||
|
|
||||||
wait_for_flash_ready();
|
|
||||||
|
|
||||||
current_sector = NO_SECTOR_LOADED;
|
|
||||||
dirty_mask = 0;
|
|
||||||
MP_STATE_VM(flash_ram_cache) = NULL;
|
|
||||||
|
|
||||||
spi_flash_is_initialised = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
samd_peripherals_sercom_clock_init(SPI_FLASH_SERCOM, SPI_FLASH_SERCOM_INDEX);
|
||||||
|
|
||||||
|
// Set up with defaults, then change.
|
||||||
|
spi_m_sync_init(&spi_flash_desc, SPI_FLASH_SERCOM);
|
||||||
|
|
||||||
|
hri_sercomspi_write_CTRLA_DOPO_bf(SPI_FLASH_SERCOM, SPI_FLASH_DOPO);
|
||||||
|
hri_sercomspi_write_CTRLA_DIPO_bf(SPI_FLASH_SERCOM, SPI_FLASH_DIPO);
|
||||||
|
|
||||||
|
gpio_set_pin_direction(SPI_FLASH_SCK_PIN, GPIO_DIRECTION_OUT);
|
||||||
|
gpio_set_pin_pull_mode(SPI_FLASH_SCK_PIN, GPIO_PULL_OFF);
|
||||||
|
gpio_set_pin_function(SPI_FLASH_SCK_PIN, SPI_FLASH_SCK_PIN_FUNCTION);
|
||||||
|
|
||||||
|
gpio_set_pin_direction(SPI_FLASH_MOSI_PIN, GPIO_DIRECTION_OUT);
|
||||||
|
gpio_set_pin_pull_mode(SPI_FLASH_MOSI_PIN, GPIO_PULL_OFF);
|
||||||
|
gpio_set_pin_function(SPI_FLASH_MOSI_PIN, SPI_FLASH_MOSI_PIN_FUNCTION);
|
||||||
|
|
||||||
|
gpio_set_pin_direction(SPI_FLASH_MISO_PIN, GPIO_DIRECTION_IN);
|
||||||
|
gpio_set_pin_pull_mode(SPI_FLASH_MISO_PIN, GPIO_PULL_OFF);
|
||||||
|
gpio_set_pin_function(SPI_FLASH_MISO_PIN, SPI_FLASH_MISO_PIN_FUNCTION);
|
||||||
|
|
||||||
|
hri_sercomspi_write_CTRLA_DOPO_bf(SPI_FLASH_SERCOM, SPI_FLASH_DOPO);
|
||||||
|
hri_sercomspi_write_CTRLA_DIPO_bf(SPI_FLASH_SERCOM, SPI_FLASH_DIPO);
|
||||||
|
|
||||||
|
spi_m_sync_set_baudrate(&spi_flash_desc, samd_peripherals_baudrate_to_baud_reg_value(SPI_FLASH_BAUDRATE));
|
||||||
|
|
||||||
|
gpio_set_pin_direction(SPI_FLASH_CS_PIN, GPIO_DIRECTION_OUT);
|
||||||
|
// There's already a pull-up on the board.
|
||||||
|
gpio_set_pin_pull_mode(SPI_FLASH_CS_PIN, GPIO_PULL_OFF);
|
||||||
|
gpio_set_pin_function(SPI_FLASH_CS_PIN, GPIO_PIN_FUNCTION_OFF);
|
||||||
|
|
||||||
|
// Set CS high (disabled).
|
||||||
|
flash_disable();
|
||||||
|
|
||||||
|
spi_m_sync_enable(&spi_flash_desc);
|
||||||
|
|
||||||
|
// Activity LED for flash writes.
|
||||||
|
#ifdef MICROPY_HW_LED_MSC
|
||||||
|
gpio_set_pin_function(SPI_FLASH_CS_PIN, GPIO_PIN_FUNCTION_OFF);
|
||||||
|
gpio_set_pin_direction(MICROPY_HW_LED_MSC, GPIO_DIRECTION_OUT);
|
||||||
|
// There's already a pull-up on the board.
|
||||||
|
gpio_set_pin_level(MICROPY_HW_LED_MSC, false);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
uint8_t jedec_id_request[4] = {CMD_READ_JEDEC_ID, 0x00, 0x00, 0x00};
|
||||||
|
uint8_t jedec_id_response[4] = {0x00, 0x00, 0x00, 0x00};
|
||||||
|
struct spi_xfer jedec_id_xfer = { jedec_id_request, jedec_id_response, 4 };
|
||||||
|
flash_enable();
|
||||||
|
spi_m_sync_transfer(&spi_flash_desc, &jedec_id_xfer);
|
||||||
|
flash_disable();
|
||||||
|
uint8_t manufacturer = jedec_id_response[1];
|
||||||
|
if ((jedec_id_response[1] == SPI_FLASH_JEDEC_MANUFACTURER
|
||||||
|
#ifdef SPI_FLASH_JEDEC_MANUFACTURER_2
|
||||||
|
|| jedec_id_response[1] == SPI_FLASH_JEDEC_MANUFACTURER_2
|
||||||
|
#endif
|
||||||
|
) &&
|
||||||
|
jedec_id_response[2] == SPI_FLASH_JEDEC_MEMORY_TYPE &&
|
||||||
|
jedec_id_response[3] == SPI_FLASH_JEDEC_CAPACITY) {
|
||||||
|
spi_flash_is_initialised = true;
|
||||||
|
} else {
|
||||||
|
// Unknown flash chip!
|
||||||
|
spi_flash_is_initialised = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((manufacturer == SPI_FLASH_JEDEC_MANUFACTURER && SPI_FLASH_SECTOR_PROTECTION)
|
||||||
|
#ifdef SPI_FLASH_JEDEC_MANUFACTURER_2
|
||||||
|
|| (manufacturer == SPI_FLASH_JEDEC_MANUFACTURER_2 && SPI_FLASH_SECTOR_PROTECTION_2)
|
||||||
|
#endif
|
||||||
|
) {
|
||||||
|
write_enable();
|
||||||
|
|
||||||
|
// Turn off sector protection
|
||||||
|
uint8_t disable_protect_request[2] = {CMD_WRITE_STATUS_BYTE1, 0x00};
|
||||||
|
struct spi_xfer disable_protect_xfer = { disable_protect_request, 0, 4 };
|
||||||
|
flash_enable();
|
||||||
|
spi_m_sync_transfer(&spi_flash_desc, &disable_protect_xfer);
|
||||||
|
flash_disable();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Turn off writes in case this is a microcontroller only reset.
|
||||||
|
uint8_t disable_write_request[1] = {CMD_DISABLE_WRITE};
|
||||||
|
struct spi_xfer disable_write_xfer = { disable_write_request, 0, 1 };
|
||||||
|
flash_enable();
|
||||||
|
spi_m_sync_transfer(&spi_flash_desc, &disable_write_xfer);
|
||||||
|
flash_disable();
|
||||||
|
|
||||||
|
wait_for_flash_ready();
|
||||||
|
|
||||||
|
current_sector = NO_SECTOR_LOADED;
|
||||||
|
dirty_mask = 0;
|
||||||
|
MP_STATE_VM(flash_ram_cache) = NULL;
|
||||||
|
|
||||||
|
spi_flash_is_initialised = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The size of each individual block.
|
// The size of each individual block.
|
||||||
|
|
|
@ -271,7 +271,11 @@ int32_t usb_msc_xfer_done(uint8_t lun) {
|
||||||
return ERR_NONE;
|
return ERR_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The start_read callback begins a read transaction which we accept but delay our response until the "main thread" calls usb_msc_background. Once it does, we read immediately from the drive into our cache and trigger the USB DMA to output the sector. Once the sector is transmitted, xfer_done will be called.
|
// The start_read callback begins a read transaction which we accept
|
||||||
|
// but delay our response until the "main thread" calls
|
||||||
|
// usb_msc_background. Once it does, we read immediately from the
|
||||||
|
// drive into our cache and trigger the USB DMA to output the
|
||||||
|
// sector. Once the sector is transmitted, xfer_done will be called.
|
||||||
void usb_msc_background(void) {
|
void usb_msc_background(void) {
|
||||||
if (active_read && !usb_busy) {
|
if (active_read && !usb_busy) {
|
||||||
if (active_nblocks == 0) {
|
if (active_nblocks == 0) {
|
||||||
|
@ -290,7 +294,7 @@ void usb_msc_background(void) {
|
||||||
fs_user_mount_t * vfs = get_vfs(active_lun);
|
fs_user_mount_t * vfs = get_vfs(active_lun);
|
||||||
disk_write(vfs, sector_buffer, active_addr, 1);
|
disk_write(vfs, sector_buffer, active_addr, 1);
|
||||||
// Since by getting here we assume the mount is read-only to
|
// Since by getting here we assume the mount is read-only to
|
||||||
// MicroPython lets update the cached FatFs sector if its the one
|
// MicroPython let's update the cached FatFs sector if it's the one
|
||||||
// we just wrote.
|
// we just wrote.
|
||||||
#if _MAX_SS != _MIN_SS
|
#if _MAX_SS != _MIN_SS
|
||||||
if (vfs->ssize == FILESYSTEM_BLOCK_SIZE) {
|
if (vfs->ssize == FILESYSTEM_BLOCK_SIZE) {
|
||||||
|
|
|
@ -38,7 +38,7 @@
|
||||||
//|
|
//|
|
||||||
//| .. module:: storage
|
//| .. module:: storage
|
||||||
//| :synopsis: storage management
|
//| :synopsis: storage management
|
||||||
//| :platform: SAMD21
|
//| :platform: SAMD21, SAMD51
|
||||||
//|
|
//|
|
||||||
//| The `storage` provides storage management functionality such as mounting and
|
//| The `storage` provides storage management functionality such as mounting and
|
||||||
//| unmounting which is typically handled by the operating system hosting Python.
|
//| unmounting which is typically handled by the operating system hosting Python.
|
||||||
|
|
Loading…
Reference in New Issue