commit
64bd95ea01
|
@ -32,6 +32,7 @@
|
||||||
#include "mpconfigboard.h" // for EXTERNAL_FLASH_QSPI_DUAL
|
#include "mpconfigboard.h" // for EXTERNAL_FLASH_QSPI_DUAL
|
||||||
|
|
||||||
#include "external_flash/common_commands.h"
|
#include "external_flash/common_commands.h"
|
||||||
|
#include "peripherals.h"
|
||||||
#include "shared_dma.h"
|
#include "shared_dma.h"
|
||||||
|
|
||||||
#include "atmel_start_pins.h"
|
#include "atmel_start_pins.h"
|
||||||
|
@ -55,6 +56,8 @@ bool spi_flash_command(uint8_t command) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool spi_flash_read_command(uint8_t command, uint8_t* response, uint32_t length) {
|
bool spi_flash_read_command(uint8_t command, uint8_t* response, uint32_t length) {
|
||||||
|
samd_peripherals_disable_and_clear_cache();
|
||||||
|
|
||||||
QSPI->INSTRCTRL.bit.INSTR = command;
|
QSPI->INSTRCTRL.bit.INSTR = command;
|
||||||
|
|
||||||
QSPI->INSTRFRAME.reg = QSPI_INSTRFRAME_WIDTH_SINGLE_BIT_SPI |
|
QSPI->INSTRFRAME.reg = QSPI_INSTRFRAME_WIDTH_SINGLE_BIT_SPI |
|
||||||
|
@ -63,6 +66,11 @@ bool spi_flash_read_command(uint8_t command, uint8_t* response, uint32_t length)
|
||||||
QSPI_INSTRFRAME_INSTREN |
|
QSPI_INSTRFRAME_INSTREN |
|
||||||
QSPI_INSTRFRAME_DATAEN;
|
QSPI_INSTRFRAME_DATAEN;
|
||||||
|
|
||||||
|
// Dummy read of INSTRFRAME needed to synchronize.
|
||||||
|
// See Instruction Transmission Flow Diagram, figure 37.9, page 995
|
||||||
|
// and Example 4, page 998, section 37.6.8.5.
|
||||||
|
(volatile uint32_t) QSPI->INSTRFRAME.reg;
|
||||||
|
|
||||||
memcpy(response, (uint8_t *) QSPI_AHB, length);
|
memcpy(response, (uint8_t *) QSPI_AHB, length);
|
||||||
|
|
||||||
QSPI->CTRLA.reg = QSPI_CTRLA_ENABLE | QSPI_CTRLA_LASTXFER;
|
QSPI->CTRLA.reg = QSPI_CTRLA_ENABLE | QSPI_CTRLA_LASTXFER;
|
||||||
|
@ -71,20 +79,28 @@ bool spi_flash_read_command(uint8_t command, uint8_t* response, uint32_t length)
|
||||||
|
|
||||||
QSPI->INTFLAG.reg = QSPI_INTFLAG_INSTREND;
|
QSPI->INTFLAG.reg = QSPI_INTFLAG_INSTREND;
|
||||||
|
|
||||||
|
samd_peripherals_enable_cache();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool spi_flash_write_command(uint8_t command, uint8_t* data, uint32_t length) {
|
bool spi_flash_write_command(uint8_t command, uint8_t* data, uint32_t length) {
|
||||||
|
samd_peripherals_disable_and_clear_cache();
|
||||||
|
|
||||||
QSPI->INSTRCTRL.bit.INSTR = command;
|
QSPI->INSTRCTRL.bit.INSTR = command;
|
||||||
|
|
||||||
QSPI->INSTRFRAME.reg = QSPI_INSTRFRAME_WIDTH_SINGLE_BIT_SPI |
|
QSPI->INSTRFRAME.reg = QSPI_INSTRFRAME_WIDTH_SINGLE_BIT_SPI |
|
||||||
QSPI_INSTRFRAME_ADDRLEN_24BITS |
|
QSPI_INSTRFRAME_ADDRLEN_24BITS |
|
||||||
QSPI_INSTRFRAME_TFRTYPE_WRITE |
|
QSPI_INSTRFRAME_TFRTYPE_WRITE |
|
||||||
QSPI_INSTRFRAME_INSTREN;
|
QSPI_INSTRFRAME_INSTREN |
|
||||||
|
(data != NULL ? QSPI_INSTRFRAME_DATAEN : 0);
|
||||||
|
|
||||||
|
// Dummy read of INSTRFRAME needed to synchronize.
|
||||||
|
// See Instruction Transmission Flow Diagram, figure 37.9, page 995
|
||||||
|
// and Example 4, page 998, section 37.6.8.5.
|
||||||
|
(volatile uint32_t) QSPI->INSTRFRAME.reg;
|
||||||
|
|
||||||
if (data != NULL) {
|
if (data != NULL) {
|
||||||
QSPI->INSTRFRAME.bit.DATAEN = true;
|
|
||||||
|
|
||||||
memcpy((uint8_t *) QSPI_AHB, data, length);
|
memcpy((uint8_t *) QSPI_AHB, data, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,6 +110,8 @@ bool spi_flash_write_command(uint8_t command, uint8_t* data, uint32_t length) {
|
||||||
|
|
||||||
QSPI->INTFLAG.reg = QSPI_INTFLAG_INSTREND;
|
QSPI->INTFLAG.reg = QSPI_INTFLAG_INSTREND;
|
||||||
|
|
||||||
|
samd_peripherals_enable_cache();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -117,6 +135,8 @@ bool spi_flash_sector_command(uint8_t command, uint32_t address) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool spi_flash_write_data(uint32_t address, uint8_t* data, uint32_t length) {
|
bool spi_flash_write_data(uint32_t address, uint8_t* data, uint32_t length) {
|
||||||
|
samd_peripherals_disable_and_clear_cache();
|
||||||
|
|
||||||
QSPI->INSTRCTRL.bit.INSTR = CMD_PAGE_PROGRAM;
|
QSPI->INSTRCTRL.bit.INSTR = CMD_PAGE_PROGRAM;
|
||||||
uint32_t mode = QSPI_INSTRFRAME_WIDTH_SINGLE_BIT_SPI;
|
uint32_t mode = QSPI_INSTRFRAME_WIDTH_SINGLE_BIT_SPI;
|
||||||
|
|
||||||
|
@ -137,10 +157,14 @@ bool spi_flash_write_data(uint32_t address, uint8_t* data, uint32_t length) {
|
||||||
|
|
||||||
QSPI->INTFLAG.reg = QSPI_INTFLAG_INSTREND;
|
QSPI->INTFLAG.reg = QSPI_INTFLAG_INSTREND;
|
||||||
|
|
||||||
|
samd_peripherals_enable_cache();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool spi_flash_read_data(uint32_t address, uint8_t* data, uint32_t length) {
|
bool spi_flash_read_data(uint32_t address, uint8_t* data, uint32_t length) {
|
||||||
|
samd_peripherals_disable_and_clear_cache();
|
||||||
|
|
||||||
#ifdef EXTERNAL_FLASH_QSPI_DUAL
|
#ifdef EXTERNAL_FLASH_QSPI_DUAL
|
||||||
QSPI->INSTRCTRL.bit.INSTR = CMD_DUAL_READ;
|
QSPI->INSTRCTRL.bit.INSTR = CMD_DUAL_READ;
|
||||||
uint32_t mode = QSPI_INSTRFRAME_WIDTH_DUAL_OUTPUT;
|
uint32_t mode = QSPI_INSTRFRAME_WIDTH_DUAL_OUTPUT;
|
||||||
|
@ -167,6 +191,8 @@ bool spi_flash_read_data(uint32_t address, uint8_t* data, uint32_t length) {
|
||||||
|
|
||||||
QSPI->INTFLAG.reg = QSPI_INTFLAG_INSTREND;
|
QSPI->INTFLAG.reg = QSPI_INTFLAG_INSTREND;
|
||||||
|
|
||||||
|
samd_peripherals_enable_cache();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -183,7 +209,7 @@ void spi_flash_init(void) {
|
||||||
// QSPI->BAUD.bit.BAUD = 32;
|
// QSPI->BAUD.bit.BAUD = 32;
|
||||||
// Super fast, may be unreliable when Saleae is connected to high speed lines.
|
// Super fast, may be unreliable when Saleae is connected to high speed lines.
|
||||||
QSPI->BAUD.bit.BAUD = 2;
|
QSPI->BAUD.bit.BAUD = 2;
|
||||||
QSPI->CTRLB.reg = QSPI_CTRLB_MODE_MEMORY |
|
QSPI->CTRLB.reg = QSPI_CTRLB_MODE_MEMORY | // Serial memory mode (map to QSPI_AHB)
|
||||||
QSPI_CTRLB_DATALEN_8BITS |
|
QSPI_CTRLB_DATALEN_8BITS |
|
||||||
QSPI_CTRLB_CSMODE_LASTXFER;
|
QSPI_CTRLB_CSMODE_LASTXFER;
|
||||||
|
|
||||||
|
|
|
@ -163,3 +163,15 @@ void samd_peripherals_adc_setup(struct adc_sync_descriptor *adc, Adc *instance)
|
||||||
hri_adc_write_CALIB_BIASR2R_bf(instance, biasr2r);
|
hri_adc_write_CALIB_BIASR2R_bf(instance, biasr2r);
|
||||||
hri_adc_write_CALIB_BIASCOMP_bf(instance, biascomp);
|
hri_adc_write_CALIB_BIASCOMP_bf(instance, biascomp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Turn off cache and invalidate all data in it.
|
||||||
|
void samd_peripherals_disable_and_clear_cache(void) {
|
||||||
|
CMCC->CTRL.bit.CEN = 0;
|
||||||
|
while (CMCC->SR.bit.CSTS) {}
|
||||||
|
CMCC->MAINT0.bit.INVALL = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enable cache
|
||||||
|
void samd_peripherals_enable_cache(void) {
|
||||||
|
CMCC->CTRL.bit.CEN = 1;
|
||||||
|
}
|
||||||
|
|
|
@ -35,4 +35,7 @@ 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);
|
bool samd_peripherals_valid_spi_clock_pad(uint8_t clock_pad);
|
||||||
void samd_peripherals_adc_setup(struct adc_sync_descriptor *adc, Adc *instance);
|
void samd_peripherals_adc_setup(struct adc_sync_descriptor *adc, Adc *instance);
|
||||||
|
|
||||||
|
void samd_peripherals_disable_and_clear_cache(void);
|
||||||
|
void samd_peripherals_enable_cache(void);
|
||||||
|
|
||||||
#endif // MICROPY_INCLUDED_ATMEL_SAMD_SAMD51_PERIPHERALS_H
|
#endif // MICROPY_INCLUDED_ATMEL_SAMD_SAMD51_PERIPHERALS_H
|
||||||
|
|
|
@ -57,6 +57,7 @@
|
||||||
#include "shared-bindings/rtc/__init__.h"
|
#include "shared-bindings/rtc/__init__.h"
|
||||||
#include "clocks.h"
|
#include "clocks.h"
|
||||||
#include "events.h"
|
#include "events.h"
|
||||||
|
#include "peripherals.h"
|
||||||
#include "shared_dma.h"
|
#include "shared_dma.h"
|
||||||
#include "tick.h"
|
#include "tick.h"
|
||||||
|
|
||||||
|
@ -105,9 +106,47 @@ safe_mode_t port_init(void) {
|
||||||
SUPC->BOD33.bit.ENABLE = 0;
|
SUPC->BOD33.bit.ENABLE = 0;
|
||||||
SUPC->BOD33.bit.LEVEL = 200; // 2.7V: 1.5V + LEVEL * 6mV.
|
SUPC->BOD33.bit.LEVEL = 200; // 2.7V: 1.5V + LEVEL * 6mV.
|
||||||
SUPC->BOD33.bit.ENABLE = 1;
|
SUPC->BOD33.bit.ENABLE = 1;
|
||||||
|
|
||||||
|
// MPU (Memory Protection Unit) setup.
|
||||||
|
// We hoped we could make the QSPI region be non-cachable with the MPU,
|
||||||
|
// but the CMCC doesn't seem to pay attention to the MPU settings.
|
||||||
|
// Leaving this code here disabled,
|
||||||
|
// because it was hard enough to figure out, and maybe there's
|
||||||
|
// a mistake that could make it work in the future.
|
||||||
|
#if 0
|
||||||
|
// Designate QSPI memory mapped region as not cachable.
|
||||||
|
|
||||||
|
// Turn off MPU in case it is on.
|
||||||
|
MPU->CTRL = 0;
|
||||||
|
// Configure region 0.
|
||||||
|
MPU->RNR = 0;
|
||||||
|
// Region base: start of QSPI mapping area.
|
||||||
|
// QSPI region runs from 0x04000000 up to and not including 0x05000000: 16 megabytes
|
||||||
|
MPU->RBAR = QSPI_AHB;
|
||||||
|
MPU->RASR =
|
||||||
|
0b011 << MPU_RASR_AP_Pos | // full read/write access for privileged and user mode
|
||||||
|
0b000 << MPU_RASR_TEX_Pos | // caching not allowed, strongly ordered
|
||||||
|
1 << MPU_RASR_S_Pos | // sharable
|
||||||
|
0 << MPU_RASR_C_Pos | // not cachable
|
||||||
|
0 << MPU_RASR_B_Pos | // not bufferable
|
||||||
|
0b10111 << MPU_RASR_SIZE_Pos | // 16MB region size
|
||||||
|
1 << MPU_RASR_ENABLE_Pos // enable this region
|
||||||
|
;
|
||||||
|
// Turn off regions 1-7.
|
||||||
|
for (uint32_t i = 1; i < 8; i ++) {
|
||||||
|
MPU->RNR = i;
|
||||||
|
MPU->RBAR = 0;
|
||||||
|
MPU->RASR = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Turn on MPU. Turn on PRIVDEFENA, which defines a default memory
|
||||||
|
// map for all privileged access, so we don't have to set up other regions
|
||||||
|
// besides QSPI.
|
||||||
|
MPU->CTRL = MPU_CTRL_PRIVDEFENA_Msk | MPU_CTRL_ENABLE_Msk;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
samd_peripherals_enable_cache();
|
||||||
|
#endif
|
||||||
|
|
||||||
// On power on start or external reset, set _ezero to the canary word. If it
|
// On power on start or external reset, set _ezero to the canary word. If it
|
||||||
// gets killed, we boot in safe mode. _ezero is the boundary between statically
|
// gets killed, we boot in safe mode. _ezero is the boundary between statically
|
||||||
|
|
Loading…
Reference in New Issue