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 \
|
||||
reset.c \
|
||||
$(CHIP_FAMILY)_peripherals.c \
|
||||
peripherals.c \
|
||||
$(CHIP_FAMILY)_pins.c \
|
||||
tick.c \
|
||||
usb.c \
|
||||
|
@ -260,6 +261,7 @@ SRC_COMMON_HAL = \
|
|||
microcontroller/Processor.c \
|
||||
neopixel_write/__init__.c \
|
||||
os/__init__.c \
|
||||
storage/__init__.c \
|
||||
time/__init__.c \
|
||||
# analogio/__init__.c \
|
||||
analogio/AnalogIn.c \
|
||||
|
@ -276,7 +278,6 @@ SRC_COMMON_HAL = \
|
|||
pulseio/PulseIn.c \
|
||||
pulseio/PulseOut.c \
|
||||
pulseio/PWMOut.c \
|
||||
storage/__init__.c \
|
||||
touchio/__init__.c \
|
||||
touchio/TouchIn.c \
|
||||
usb_hid/__init__.c \
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 72f76894ba08c9de2ec3ae231fb71daaf3eafb1e
|
||||
Subproject commit 0efc3407dd97ef617a5655674a3516693897a961
|
|
@ -3,25 +3,35 @@
|
|||
|
||||
#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_MUX_SETTING SPI_SIGNAL_MUX_SETTING_C
|
||||
#define SPI_FLASH_PAD0_PINMUX PINMUX_PA08D_SERCOM2_PAD0 // MOSI
|
||||
// Use default pinmux for the chip select since we manage it ourselves.
|
||||
#define SPI_FLASH_PAD1_PINMUX PINMUX_PA09D_SERCOM2_PAD1 // SCK
|
||||
#define SPI_FLASH_PAD2_PINMUX PINMUX_PA14C_SERCOM2_PAD2 // MISO
|
||||
#define SPI_FLASH_PAD3_PINMUX PINMUX_UNUSED // SCK
|
||||
#define SPI_FLASH_MOSI_PIN PIN_PA08
|
||||
#define SPI_FLASH_MISO_PIN PIN_PA14
|
||||
#define SPI_FLASH_SCK_PIN PIN_PA09
|
||||
#define SPI_FLASH_CS_PIN PIN_PA13
|
||||
#define SPI_FLASH_MOSI_PIN_FUNCTION PINMUX_PA08D_SERCOM2_PAD0
|
||||
#define SPI_FLASH_MISO_PIN_FUNCTION PINMUX_PA14C_SERCOM2_PAD2
|
||||
#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
|
||||
|
||||
#define MICROPY_PORT_A (PORT_PA06 | PORT_PA08 | PORT_PA09 | PORT_PA14 | PORT_PA13 | PORT_PA14 | PORT_PA24 | PORT_PA25)
|
||||
// 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_B ( 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
|
||||
// make sure you don't overwrite code.
|
||||
|
|
|
@ -4,8 +4,7 @@ USB_PID = 0x8023
|
|||
USB_PRODUCT = "Feather M0 Express"
|
||||
USB_MANUFACTURER = "Adafruit Industries LLC"
|
||||
|
||||
#SPI_FLASH_FILESYSTEM = 1
|
||||
INTERNAL_FLASH_FILESYSTEM = 1
|
||||
SPI_FLASH_FILESYSTEM = 1
|
||||
|
||||
CHIP_VARIANT = SAMD21G18A
|
||||
CHIP_FAMILY = samd21
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
#define USB_REPL
|
||||
|
||||
#define MICROPY_HW_BOARD_NAME "Adafruit Metro M0 Express"
|
||||
#define MICROPY_HW_MCU_NAME "samd21g18"
|
||||
|
||||
|
@ -8,24 +6,35 @@
|
|||
|
||||
#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_MUX_SETTING SPI_SIGNAL_MUX_SETTING_F
|
||||
#define SPI_FLASH_PAD0_PINMUX PINMUX_UNUSED // CS
|
||||
// Use default pinmux for the chip select since we manage it ourselves.
|
||||
#define SPI_FLASH_PAD1_PINMUX PINMUX_PB03D_SERCOM5_PAD1 // MISO
|
||||
#define SPI_FLASH_PAD2_PINMUX PINMUX_PB22D_SERCOM5_PAD2 // MOSI
|
||||
#define SPI_FLASH_PAD3_PINMUX PINMUX_PB23D_SERCOM5_PAD3 // SCK
|
||||
#define SPI_FLASH_CS PIN_PA13
|
||||
#define SPI_FLASH_MOSI_PIN PIN_PB22
|
||||
#define SPI_FLASH_MISO_PIN PIN_PB03
|
||||
#define SPI_FLASH_SCK_PIN PIN_PB23
|
||||
#define SPI_FLASH_CS_PIN PIN_PA13
|
||||
#define SPI_FLASH_MOSI_PIN_FUNCTION PINMUX_PB22D_SERCOM5_PAD2
|
||||
#define SPI_FLASH_MISO_PIN_FUNCTION PINMUX_PB03D_SERCOM5_PAD1
|
||||
#define SPI_FLASH_SCK_PIN_FUNCTION PINMUX_PB23D_SERCOM5_PAD3
|
||||
#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_B (PORT_PB03 | PORT_PB22 | PORT_PB23)
|
||||
#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
|
||||
// make sure you don't overwrite code.
|
||||
|
|
|
@ -4,8 +4,7 @@ USB_PID = 0x8014
|
|||
USB_PRODUCT = "Metro M0 Express"
|
||||
USB_MANUFACTURER = "Adafruit Industries LLC"
|
||||
|
||||
#SPI_FLASH_FILESYSTEM = 1
|
||||
INTERNAL_FLASH_FILESYSTEM = 1
|
||||
SPI_FLASH_FILESYSTEM = 1
|
||||
|
||||
CHIP_VARIANT = SAMD21G18A
|
||||
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_MOSI), MP_ROM_PTR(&pin_PB10) },
|
||||
{ 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);
|
||||
|
|
|
@ -8,29 +8,46 @@
|
|||
|
||||
#define MICROPY_HW_NEOPIXEL (&pin_PB17)
|
||||
|
||||
#define SPI_FLASH_BAUDRATE (1000000)
|
||||
#define SPI_FLASH_BAUDRATE (8000000)
|
||||
|
||||
// Rev F
|
||||
#define SPI_FLASH_MUX_SETTING SPI_SIGNAL_MUX_SETTING_F
|
||||
#define SPI_FLASH_PAD0_PINMUX PINMUX_PB08 // MOSI
|
||||
// Use default pinmux for the chip select since we manage it ourselves.
|
||||
#define SPI_FLASH_PAD1_PINMUX PINMUX_PB09 // SCK
|
||||
#define SPI_FLASH_PAD2_PINMUX PINMUX_DEFAULT // CS
|
||||
#define SPI_FLASH_PAD3_PINMUX PINMUX_PB11 // MISO
|
||||
#define SPI_FLASH_CS PIN_PB10
|
||||
#define SPI_FLASH_SERCOM SERCOM5
|
||||
// Rev B: single channel SPI
|
||||
// Rev C will be QSPI
|
||||
#define SPI_FLASH_MOSI_PIN PIN_PB08
|
||||
#define SPI_FLASH_MISO_PIN PIN_PB11
|
||||
#define SPI_FLASH_SCK_PIN PIN_PB09
|
||||
#define SPI_FLASH_CS_PIN PIN_PB10
|
||||
#define SPI_FLASH_MOSI_PIN_FUNCTION PINMUX_PB08D_SERCOM4_PAD0
|
||||
#define SPI_FLASH_MISO_PIN_FUNCTION PINMUX_PB11D_SERCOM4_PAD3
|
||||
#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_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_D (0)
|
||||
|
||||
#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
|
||||
// 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 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_MANUFACTURER = "Adafruit Industries LLC"
|
||||
|
||||
#SPI_FLASH_FILESYSTEM = 1
|
||||
INTERNAL_FLASH_FILESYSTEM = 1
|
||||
SPI_FLASH_FILESYSTEM = 1
|
||||
|
||||
CHIP_VARIANT = SAMD51J19A
|
||||
CHIP_FAMILY = samd51
|
||||
|
|
|
@ -72,7 +72,7 @@ void common_hal_busio_i2c_construct(busio_i2c_obj_t *self,
|
|||
|
||||
|
||||
// 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) {
|
||||
mp_raise_OSError(MP_EIO);
|
||||
|
|
|
@ -37,17 +37,7 @@
|
|||
|
||||
#include "peripherals.h"
|
||||
#include "pins.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;
|
||||
}
|
||||
//#include "shared_dma.h"
|
||||
|
||||
void common_hal_busio_spi_construct(busio_spi_obj_t *self,
|
||||
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_pad = clock->sercom[i].pad;
|
||||
if (!samd_peripheral_valid_spi_clock_pad(clock_pad)) {
|
||||
if (!samd_peripherals_valid_spi_clock_pad(clock_pad)) {
|
||||
continue;
|
||||
}
|
||||
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) {
|
||||
mosi_pinmux = PINMUX(mosi->pin, (j == 0) ? MUX_C : MUX_D);
|
||||
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) {
|
||||
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.
|
||||
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) {
|
||||
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
|
||||
// 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) {
|
||||
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);
|
||||
}
|
||||
|
||||
gpio_set_pin_direction(clock->pin, GPIO_DIRECTION_OUT);
|
||||
gpio_set_pin_pull_mode(clock->pin, GPIO_PULL_OFF);
|
||||
gpio_set_pin_function(clock->pin, clock_pinmux);
|
||||
claim_pin(clock);
|
||||
|
@ -150,6 +141,7 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self,
|
|||
if (mosi_none) {
|
||||
self->MOSI_pin = NO_PIN;
|
||||
} else {
|
||||
gpio_set_pin_direction(mosi->pin, GPIO_DIRECTION_OUT);
|
||||
gpio_set_pin_pull_mode(mosi->pin, GPIO_PULL_OFF);
|
||||
gpio_set_pin_function(mosi->pin, mosi_pinmux);
|
||||
self->MOSI_pin = mosi->pin;
|
||||
|
@ -159,6 +151,7 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self,
|
|||
if (miso_none) {
|
||||
self->MISO_pin = NO_PIN;
|
||||
} else {
|
||||
gpio_set_pin_direction(miso->pin, GPIO_DIRECTION_IN);
|
||||
gpio_set_pin_pull_mode(miso->pin, GPIO_PULL_OFF);
|
||||
gpio_set_pin_function(miso->pin, miso_pinmux);
|
||||
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,
|
||||
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) {
|
||||
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);
|
||||
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,
|
||||
|
@ -267,5 +260,5 @@ bool common_hal_busio_spi_read(busio_spi_obj_t *self,
|
|||
|
||||
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/runtime.h"
|
||||
#include "shared-bindings/storage/__init__.h"
|
||||
#include "usb.h"
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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.");
|
||||
}
|
||||
|
||||
|
|
|
@ -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_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 \
|
||||
|
@ -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_os), (mp_obj_t)&os_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_supervisor), (mp_obj_t)&supervisor_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
|
||||
#define MICROPY_INCLUDED_ATMEL_SAMD_PERIPHERALS_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "mpconfigport.h"
|
||||
|
||||
// Routines common across chip families.
|
||||
uint8_t samd_peripherals_baudrate_to_baud_reg_value(const uint32_t baudrate);
|
||||
|
||||
#ifdef SAMD21
|
||||
#include "samd21_peripherals.h"
|
||||
#endif
|
||||
|
|
|
@ -58,7 +58,7 @@ static const uint8_t SERCOMx_GCLK_ID_SLOW[] = {
|
|||
|
||||
|
||||
// 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);
|
||||
_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);
|
||||
|
@ -70,7 +70,7 @@ void samd_peripheral_sercom_clock_init(Sercom* sercom, uint8_t sercom_index) {
|
|||
// <0x1=>PAD[2,3]_DO_SCK
|
||||
// <0x2=>PAD[3,1]_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 (mosi_pad == 0) {
|
||||
return 0;
|
||||
|
@ -87,6 +87,6 @@ uint8_t samd_peripheral_get_spi_dopo(uint8_t clock_pad, uint8_t mosi_pad) {
|
|||
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;
|
||||
}
|
||||
|
|
|
@ -29,8 +29,8 @@
|
|||
|
||||
#include "include/sam.h"
|
||||
|
||||
void samd_peripheral_sercom_clock_init(Sercom* sercom, uint8_t sercom_index);
|
||||
uint8_t samd_peripheral_get_spi_dopo(uint8_t clock_pad, uint8_t mosi_pad);
|
||||
bool samd_peripheral_valid_spi_clock_pad(uint8_t clock_pad);
|
||||
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
|
||||
|
|
|
@ -62,7 +62,7 @@ static const uint8_t SERCOMx_GCLK_ID_SLOW[] = {
|
|||
|
||||
|
||||
// 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,
|
||||
SERCOMx_GCLK_ID_CORE[sercom_index],
|
||||
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]
|
||||
// <0x2=>PAD[3,1]_DO_SCK
|
||||
// <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) {
|
||||
return 255;
|
||||
}
|
||||
|
@ -126,6 +126,6 @@ uint8_t samd_peripheral_get_spi_dopo(uint8_t clock_pad, uint8_t mosi_pad) {
|
|||
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;
|
||||
}
|
||||
|
|
|
@ -29,9 +29,9 @@
|
|||
|
||||
#include "sam.h"
|
||||
|
||||
void samd_peripheral_sercom_clock_init(Sercom* sercom, uint8_t sercom_index);
|
||||
uint8_t samd_peripheral_get_spi_dopo(uint8_t clock_pad, uint8_t mosi_pad);
|
||||
bool samd_peripheral_valid_spi_clock_pad(uint8_t clock_pad);
|
||||
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_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;
|
||||
dma_get_config_defaults(&config);
|
||||
|
||||
// This allocates the lowest channel first so make sure the audio is first
|
||||
// so it gets the highest priority.
|
||||
config.peripheral_trigger = DAC_DMAC_ID_EMPTY;
|
||||
config.trigger_action = DMA_TRIGGER_ACTION_BEAT;
|
||||
config.event_config.input_action = DMA_EVENT_INPUT_TRIG;
|
||||
config.event_config.event_output_enable = true;
|
||||
dma_allocate(&audio_dma, &config);
|
||||
// See asf4_conf/hpl_dmac_config.h for initial settings for DMA channels
|
||||
// DMA Channel 0: audio, highest priority,
|
||||
// normal transfer on input, DAC 0 empty is trigger source, trigger on each beat, beat is one byte
|
||||
// output enable true.
|
||||
// asf3 settings:
|
||||
//config.peripheral_trigger = DAC_DMAC_ID_EMPTY;
|
||||
//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.
|
||||
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
|
||||
// overflow.
|
||||
dma_get_config_defaults(&config);
|
||||
config.trigger_action = DMA_TRIGGER_ACTION_BEAT;
|
||||
config.event_config.input_action = DMA_EVENT_INPUT_TRIG;
|
||||
|
||||
// DMA Channel 1: rx channel,
|
||||
// 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);
|
||||
g_chan_interrupt_flag[general_dma_rx.channel_id] |= (1UL << DMA_CALLBACK_TRANSFER_DONE);
|
||||
|
||||
dma_get_config_defaults(&config);
|
||||
config.trigger_action = DMA_TRIGGER_ACTION_BEAT;
|
||||
config.event_config.input_action = DMA_EVENT_INPUT_TRIG;
|
||||
dma_allocate(&general_dma_tx, &config);
|
||||
// DMA Channel 1: rx channel,
|
||||
// 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;
|
||||
g_chan_interrupt_flag[general_dma_tx.channel_id] |= (1UL << DMA_CALLBACK_TRANSFER_DONE);
|
||||
|
||||
// Be sneaky and reuse the active descriptor memory.
|
||||
|
|
|
@ -28,20 +28,19 @@
|
|||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
<<<<<<< HEAD
|
||||
#include "asf/sam0/drivers/sercom/spi/spi.h"
|
||||
|
||||
#include "extmod/vfs.h"
|
||||
#include "extmod/vfs_fat.h"
|
||||
=======
|
||||
>>>>>>> WIP
|
||||
#include "py/gc.h"
|
||||
#include "py/obj.h"
|
||||
#include "py/runtime.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)
|
||||
|
||||
|
@ -60,7 +59,7 @@
|
|||
|
||||
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.
|
||||
static uint32_t current_sector;
|
||||
|
@ -74,35 +73,37 @@ static uint32_t dirty_mask;
|
|||
|
||||
// Enable the flash over SPI.
|
||||
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.
|
||||
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.
|
||||
static bool wait_for_flash_ready(void) {
|
||||
uint8_t status_request[2] = {CMD_READ_STATUS, 0x00};
|
||||
uint8_t response[2] = {0x00, 0x01};
|
||||
enum status_code status = STATUS_OK;
|
||||
uint8_t read_status_request[2] = {CMD_READ_STATUS, 0x00};
|
||||
uint8_t read_status_response[2] = {0x00, 0x00};
|
||||
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.
|
||||
while (status == STATUS_OK && (response[1] & 0x3) != 0) {
|
||||
do {
|
||||
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();
|
||||
}
|
||||
return status == STATUS_OK;
|
||||
} while (status >= 0 && (read_status_response[1] & 0x3) != 0);
|
||||
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.
|
||||
static bool write_enable(void) {
|
||||
flash_enable();
|
||||
uint8_t command = CMD_ENABLE_WRITE;
|
||||
enum status_code status = spi_write_buffer_wait(&spi_flash_instance, &command, 1);
|
||||
uint8_t enable_write_request[1] = {CMD_ENABLE_WRITE};
|
||||
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();
|
||||
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.
|
||||
|
@ -120,17 +121,19 @@ static bool read_flash(uint32_t address, uint8_t* data, uint32_t data_length) {
|
|||
if (!wait_for_flash_ready()) {
|
||||
return false;
|
||||
}
|
||||
enum status_code status;
|
||||
// We can read as much as we want sequentially.
|
||||
uint8_t read_request[4] = {CMD_READ_DATA, 0x00, 0x00, 0x00};
|
||||
address_to_bytes(address, read_request + 1);
|
||||
uint8_t read_data_request[4] = {CMD_READ_DATA, 0x00, 0x00, 0x00};
|
||||
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();
|
||||
status = spi_write_buffer_wait(&spi_flash_instance, read_request, 4);
|
||||
if (status == STATUS_OK) {
|
||||
status = shared_dma_read(spi_flash_instance.hw, data, data_length, 0x00);
|
||||
int32_t status = spi_m_sync_transfer(&spi_flash_desc, &read_data_xfer);
|
||||
struct spi_xfer read_data_buffer_xfer = {0, data, data_length};
|
||||
if (status >= 0) {
|
||||
status = spi_m_sync_transfer(&spi_flash_desc, &read_data_buffer_xfer);
|
||||
}
|
||||
flash_disable();
|
||||
return status == STATUS_OK;
|
||||
return status >= 0;
|
||||
}
|
||||
|
||||
// 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()) {
|
||||
return false;
|
||||
}
|
||||
enum status_code status;
|
||||
int32_t status;
|
||||
|
||||
#ifdef SPI_FLASH_SECTOR_PROTECTION
|
||||
// Print out the protection status.
|
||||
// uint8_t protect_check[5] = {0x3C, 0x00, 0x00, 0x00, 0x00};
|
||||
// address_to_bytes(address + bytes_written, protect_check + 1);
|
||||
// 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();
|
||||
#endif
|
||||
|
||||
flash_enable();
|
||||
uint8_t command[4] = {CMD_PAGE_PROGRAM, 0x00, 0x00, 0x00};
|
||||
address_to_bytes(address + bytes_written, command + 1);
|
||||
status = spi_write_buffer_wait(&spi_flash_instance, command, 4);
|
||||
if (status == STATUS_OK) {
|
||||
status = shared_dma_write(spi_flash_instance.hw, data + bytes_written, SPI_FLASH_PAGE_SIZE);
|
||||
uint8_t page_program_request[4] = {CMD_PAGE_PROGRAM, 0x00, 0x00, 0x00};
|
||||
// Write the SPI flash write address into the bytes following the command byte.
|
||||
address_to_bytes(address + bytes_written, page_program_request + 1);
|
||||
struct spi_xfer page_program_xfer = {page_program_request, 0, 4};
|
||||
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();
|
||||
if (status != STATUS_OK) {
|
||||
if (status < 0) {
|
||||
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};
|
||||
address_to_bytes(sector_address, erase_request + 1);
|
||||
|
||||
struct spi_xfer erase_xfer = {erase_request, 0, 4};
|
||||
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();
|
||||
return status == STATUS_OK;
|
||||
return status >= 0;
|
||||
}
|
||||
|
||||
// Sector is really 24 bits.
|
||||
|
@ -247,45 +253,67 @@ static bool copy_block(uint32_t src_address, uint32_t dest_address) {
|
|||
}
|
||||
|
||||
void spi_flash_init(void) {
|
||||
if (!spi_flash_is_initialised) {
|
||||
struct spi_config config_spi_master;
|
||||
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);
|
||||
if (spi_flash_is_initialised) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Manage chip select ourselves.
|
||||
struct port_config pin_conf;
|
||||
port_get_config_defaults(&pin_conf);
|
||||
samd_peripherals_sercom_clock_init(SPI_FLASH_SERCOM, SPI_FLASH_SERCOM_INDEX);
|
||||
|
||||
pin_conf.direction = PORT_PIN_DIR_OUTPUT;
|
||||
port_pin_set_config(SPI_FLASH_CS, &pin_conf);
|
||||
// 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
|
||||
port_pin_set_config(MICROPY_HW_LED_MSC, &pin_conf);
|
||||
port_pin_set_output_level(MICROPY_HW_LED_MSC, false);
|
||||
#endif
|
||||
#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 response[4] = {0x00, 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_transceive_buffer_wait(&spi_flash_instance, jedec_id_request, response, 4);
|
||||
spi_m_sync_transfer(&spi_flash_desc, &jedec_id_xfer);
|
||||
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
|
||||
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
|
||||
) &&
|
||||
response[2] == SPI_FLASH_JEDEC_MEMORY_TYPE &&
|
||||
response[3] == SPI_FLASH_JEDEC_CAPACITY) {
|
||||
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!
|
||||
|
@ -294,25 +322,25 @@ void spi_flash_init(void) {
|
|||
}
|
||||
|
||||
if ((manufacturer == SPI_FLASH_JEDEC_MANUFACTURER && SPI_FLASH_SECTOR_PROTECTION)
|
||||
#ifdef SPI_FLASH_JEDEC_MANUFACTURER_2
|
||||
#ifdef SPI_FLASH_JEDEC_MANUFACTURER_2
|
||||
|| (manufacturer == SPI_FLASH_JEDEC_MANUFACTURER_2 && SPI_FLASH_SECTOR_PROTECTION_2)
|
||||
#endif
|
||||
#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};
|
||||
struct spi_xfer disable_protect_xfer = { disable_protect_request, 0, 4 };
|
||||
flash_enable();
|
||||
spi_transceive_buffer_wait(&spi_flash_instance, disable_protect_request, disable_protect_response, 2);
|
||||
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};
|
||||
uint8_t disable_response[1] = {0x00};
|
||||
struct spi_xfer disable_write_xfer = { disable_write_request, 0, 1 };
|
||||
flash_enable();
|
||||
spi_transceive_buffer_wait(&spi_flash_instance, disable_write_request, disable_response, 1);
|
||||
spi_m_sync_transfer(&spi_flash_desc, &disable_write_xfer);
|
||||
flash_disable();
|
||||
|
||||
wait_for_flash_ready();
|
||||
|
@ -322,7 +350,6 @@ void spi_flash_init(void) {
|
|||
MP_STATE_VM(flash_ram_cache) = NULL;
|
||||
|
||||
spi_flash_is_initialised = true;
|
||||
}
|
||||
}
|
||||
|
||||
// The size of each individual block.
|
||||
|
|
|
@ -271,7 +271,11 @@ int32_t usb_msc_xfer_done(uint8_t lun) {
|
|||
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) {
|
||||
if (active_read && !usb_busy) {
|
||||
if (active_nblocks == 0) {
|
||||
|
@ -290,7 +294,7 @@ void usb_msc_background(void) {
|
|||
fs_user_mount_t * vfs = get_vfs(active_lun);
|
||||
disk_write(vfs, sector_buffer, active_addr, 1);
|
||||
// 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.
|
||||
#if _MAX_SS != _MIN_SS
|
||||
if (vfs->ssize == FILESYSTEM_BLOCK_SIZE) {
|
||||
|
|
|
@ -38,7 +38,7 @@
|
|||
//|
|
||||
//| .. module:: storage
|
||||
//| :synopsis: storage management
|
||||
//| :platform: SAMD21
|
||||
//| :platform: SAMD21, SAMD51
|
||||
//|
|
||||
//| The `storage` provides storage management functionality such as mounting and
|
||||
//| unmounting which is typically handled by the operating system hosting Python.
|
||||
|
|
Loading…
Reference in New Issue