| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282 |
- /*
- * This file is part of the MicroPython project, http://micropython.org/
- *
- * The MIT License (MIT)
- *
- * Copyright (c) 2018 Damien P. George
- *
- * 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 <string.h>
- #include "py/mperrno.h"
- #include "py/mphal.h"
- #include "qspi.h"
- #if defined(MICROPY_HW_QSPIFLASH_SIZE_BITS_LOG2)
- void qspi_init(void) {
- // Configure pins
- mp_hal_pin_config(MICROPY_HW_QSPIFLASH_CS, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, 10);
- mp_hal_pin_config(MICROPY_HW_QSPIFLASH_SCK, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, 9);
- mp_hal_pin_config(MICROPY_HW_QSPIFLASH_IO0, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, 9);
- mp_hal_pin_config(MICROPY_HW_QSPIFLASH_IO1, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, 9);
- mp_hal_pin_config(MICROPY_HW_QSPIFLASH_IO2, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, 9);
- mp_hal_pin_config(MICROPY_HW_QSPIFLASH_IO3, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, 9);
- // Bring up the QSPI peripheral
- __HAL_RCC_QSPI_CLK_ENABLE();
- QUADSPI->CR =
- 2 << QUADSPI_CR_PRESCALER_Pos // F_CLK = F_AHB/3 (72MHz when CPU is 216MHz)
- | 3 << QUADSPI_CR_FTHRES_Pos // 4 bytes must be available to read/write
- #if defined(QUADSPI_CR_FSEL_Pos)
- | 0 << QUADSPI_CR_FSEL_Pos // FLASH 1 selected
- #endif
- #if defined(QUADSPI_CR_DFM_Pos)
- | 0 << QUADSPI_CR_DFM_Pos // dual-flash mode disabled
- #endif
- | 0 << QUADSPI_CR_SSHIFT_Pos // no sample shift
- | 1 << QUADSPI_CR_TCEN_Pos // timeout counter enabled
- | 1 << QUADSPI_CR_EN_Pos // enable the peripheral
- ;
- QUADSPI->DCR =
- (MICROPY_HW_QSPIFLASH_SIZE_BITS_LOG2 - 3 - 1) << QUADSPI_DCR_FSIZE_Pos
- | 1 << QUADSPI_DCR_CSHT_Pos // nCS stays high for 2 cycles
- | 0 << QUADSPI_DCR_CKMODE_Pos // CLK idles at low state
- ;
- }
- void qspi_memory_map(void) {
- // Enable memory-mapped mode
- QUADSPI->ABR = 0; // disable continuous read mode
- QUADSPI->LPTR = 100; // to tune
- QUADSPI->CCR =
- 0 << QUADSPI_CCR_DDRM_Pos // DDR mode disabled
- | 0 << QUADSPI_CCR_SIOO_Pos // send instruction every transaction
- | 3 << QUADSPI_CCR_FMODE_Pos // memory-mapped mode
- | 3 << QUADSPI_CCR_DMODE_Pos // data on 4 lines
- | 4 << QUADSPI_CCR_DCYC_Pos // 4 dummy cycles
- | 0 << QUADSPI_CCR_ABSIZE_Pos // 8-bit alternate byte
- | 3 << QUADSPI_CCR_ABMODE_Pos // alternate byte on 4 lines
- | 2 << QUADSPI_CCR_ADSIZE_Pos // 24-bit address size
- | 3 << QUADSPI_CCR_ADMODE_Pos // address on 4 lines
- | 1 << QUADSPI_CCR_IMODE_Pos // instruction on 1 line
- | 0xeb << QUADSPI_CCR_INSTRUCTION_Pos // quad read opcode
- ;
- }
- STATIC int qspi_ioctl(void *self_in, uint32_t cmd) {
- (void)self_in;
- switch (cmd) {
- case MP_QSPI_IOCTL_INIT:
- qspi_init();
- break;
- case MP_QSPI_IOCTL_BUS_RELEASE:
- // Switch to memory-map mode when bus is idle
- qspi_memory_map();
- break;
- }
- return 0; // success
- }
- STATIC void qspi_write_cmd_data(void *self_in, uint8_t cmd, size_t len, uint32_t data) {
- (void)self_in;
- QUADSPI->FCR = QUADSPI_FCR_CTCF; // clear TC flag
- if (len == 0) {
- QUADSPI->CCR =
- 0 << QUADSPI_CCR_DDRM_Pos // DDR mode disabled
- | 0 << QUADSPI_CCR_SIOO_Pos // send instruction every transaction
- | 0 << QUADSPI_CCR_FMODE_Pos // indirect write mode
- | 0 << QUADSPI_CCR_DMODE_Pos // no data
- | 0 << QUADSPI_CCR_DCYC_Pos // 0 dummy cycles
- | 0 << QUADSPI_CCR_ABMODE_Pos // no alternate byte
- | 0 << QUADSPI_CCR_ADMODE_Pos // no address
- | 1 << QUADSPI_CCR_IMODE_Pos // instruction on 1 line
- | cmd << QUADSPI_CCR_INSTRUCTION_Pos // write opcode
- ;
- } else {
- QUADSPI->DLR = len - 1;
- QUADSPI->CCR =
- 0 << QUADSPI_CCR_DDRM_Pos // DDR mode disabled
- | 0 << QUADSPI_CCR_SIOO_Pos // send instruction every transaction
- | 0 << QUADSPI_CCR_FMODE_Pos // indirect write mode
- | 1 << QUADSPI_CCR_DMODE_Pos // data on 1 line
- | 0 << QUADSPI_CCR_DCYC_Pos // 0 dummy cycles
- | 0 << QUADSPI_CCR_ABMODE_Pos // no alternate byte
- | 0 << QUADSPI_CCR_ADMODE_Pos // no address
- | 1 << QUADSPI_CCR_IMODE_Pos // instruction on 1 line
- | cmd << QUADSPI_CCR_INSTRUCTION_Pos // write opcode
- ;
- // This assumes len==2
- *(uint16_t*)&QUADSPI->DR = data;
- }
- // Wait for write to finish
- while (!(QUADSPI->SR & QUADSPI_SR_TCF)) {
- }
- QUADSPI->FCR = QUADSPI_FCR_CTCF; // clear TC flag
- }
- STATIC void qspi_write_cmd_addr_data(void *self_in, uint8_t cmd, uint32_t addr, size_t len, const uint8_t *src) {
- (void)self_in;
- QUADSPI->FCR = QUADSPI_FCR_CTCF; // clear TC flag
- if (len == 0) {
- QUADSPI->CCR =
- 0 << QUADSPI_CCR_DDRM_Pos // DDR mode disabled
- | 0 << QUADSPI_CCR_SIOO_Pos // send instruction every transaction
- | 0 << QUADSPI_CCR_FMODE_Pos // indirect write mode
- | 0 << QUADSPI_CCR_DMODE_Pos // no data
- | 0 << QUADSPI_CCR_DCYC_Pos // 0 dummy cycles
- | 0 << QUADSPI_CCR_ABMODE_Pos // no alternate byte
- | 2 << QUADSPI_CCR_ADSIZE_Pos // 24-bit address size
- | 1 << QUADSPI_CCR_ADMODE_Pos // address on 1 line
- | 1 << QUADSPI_CCR_IMODE_Pos // instruction on 1 line
- | cmd << QUADSPI_CCR_INSTRUCTION_Pos // write opcode
- ;
- QUADSPI->AR = addr;
- } else {
- QUADSPI->DLR = len - 1;
- QUADSPI->CCR =
- 0 << QUADSPI_CCR_DDRM_Pos // DDR mode disabled
- | 0 << QUADSPI_CCR_SIOO_Pos // send instruction every transaction
- | 0 << QUADSPI_CCR_FMODE_Pos // indirect write mode
- | 1 << QUADSPI_CCR_DMODE_Pos // data on 1 line
- | 0 << QUADSPI_CCR_DCYC_Pos // 0 dummy cycles
- | 0 << QUADSPI_CCR_ABMODE_Pos // no alternate byte
- | 2 << QUADSPI_CCR_ADSIZE_Pos // 24-bit address size
- | 1 << QUADSPI_CCR_ADMODE_Pos // address on 1 line
- | 1 << QUADSPI_CCR_IMODE_Pos // instruction on 1 line
- | cmd << QUADSPI_CCR_INSTRUCTION_Pos // write opcode
- ;
- QUADSPI->AR = addr;
- // Write out the data 1 byte at a time
- while (len) {
- while (!(QUADSPI->SR & QUADSPI_SR_FTF)) {
- }
- *(volatile uint8_t*)&QUADSPI->DR = *src++;
- --len;
- }
- }
- // Wait for write to finish
- while (!(QUADSPI->SR & QUADSPI_SR_TCF)) {
- }
- QUADSPI->FCR = QUADSPI_FCR_CTCF; // clear TC flag
- }
- STATIC uint32_t qspi_read_cmd(void *self_in, uint8_t cmd, size_t len) {
- (void)self_in;
- QUADSPI->FCR = QUADSPI_FCR_CTCF; // clear TC flag
- QUADSPI->DLR = len - 1; // number of bytes to read
- QUADSPI->CCR =
- 0 << QUADSPI_CCR_DDRM_Pos // DDR mode disabled
- | 0 << QUADSPI_CCR_SIOO_Pos // send instruction every transaction
- | 1 << QUADSPI_CCR_FMODE_Pos // indirect read mode
- | 1 << QUADSPI_CCR_DMODE_Pos // data on 1 line
- | 0 << QUADSPI_CCR_DCYC_Pos // 0 dummy cycles
- | 0 << QUADSPI_CCR_ABMODE_Pos // no alternate byte
- | 0 << QUADSPI_CCR_ADMODE_Pos // no address
- | 1 << QUADSPI_CCR_IMODE_Pos // instruction on 1 line
- | cmd << QUADSPI_CCR_INSTRUCTION_Pos // read opcode
- ;
- // Wait for read to finish
- while (!(QUADSPI->SR & QUADSPI_SR_TCF)) {
- }
- QUADSPI->FCR = QUADSPI_FCR_CTCF; // clear TC flag
- // Read result
- return QUADSPI->DR;
- }
- STATIC void qspi_read_cmd_qaddr_qdata(void *self_in, uint8_t cmd, uint32_t addr, size_t len, uint8_t *dest) {
- (void)self_in;
- QUADSPI->FCR = QUADSPI_FCR_CTCF; // clear TC flag
- QUADSPI->DLR = len - 1; // number of bytes to read
- QUADSPI->CCR =
- 0 << QUADSPI_CCR_DDRM_Pos // DDR mode disabled
- | 0 << QUADSPI_CCR_SIOO_Pos // send instruction every transaction
- | 1 << QUADSPI_CCR_FMODE_Pos // indirect read mode
- | 3 << QUADSPI_CCR_DMODE_Pos // data on 4 lines
- | 4 << QUADSPI_CCR_DCYC_Pos // 4 dummy cycles
- | 0 << QUADSPI_CCR_ABSIZE_Pos // 8-bit alternate byte
- | 3 << QUADSPI_CCR_ABMODE_Pos // alternate byte on 4 lines
- | 2 << QUADSPI_CCR_ADSIZE_Pos // 24-bit address size
- | 3 << QUADSPI_CCR_ADMODE_Pos // address on 4 lines
- | 1 << QUADSPI_CCR_IMODE_Pos // instruction on 1 line
- | cmd << QUADSPI_CCR_INSTRUCTION_Pos // quad read opcode
- ;
- QUADSPI->ABR = 0; // alternate byte: disable continuous read mode
- QUADSPI->AR = addr; // addres to read from
- // Read in the data 4 bytes at a time if dest is aligned
- if (((uintptr_t)dest & 3) == 0) {
- while (len >= 4) {
- while (!(QUADSPI->SR & QUADSPI_SR_FTF)) {
- }
- *(uint32_t*)dest = QUADSPI->DR;
- dest += 4;
- len -= 4;
- }
- }
- // Read in remaining data 1 byte at a time
- while (len) {
- while (!((QUADSPI->SR >> QUADSPI_SR_FLEVEL_Pos) & 0x3f)) {
- }
- *dest++ = *(volatile uint8_t*)&QUADSPI->DR;
- --len;
- }
- QUADSPI->FCR = QUADSPI_FCR_CTCF; // clear TC flag
- }
- const mp_qspi_proto_t qspi_proto = {
- .ioctl = qspi_ioctl,
- .write_cmd_data = qspi_write_cmd_data,
- .write_cmd_addr_data = qspi_write_cmd_addr_data,
- .read_cmd = qspi_read_cmd,
- .read_cmd_qaddr_qdata = qspi_read_cmd_qaddr_qdata,
- };
- #endif // defined(MICROPY_HW_QSPIFLASH_SIZE_BITS_LOG2)
|